comparison hip.js @ 5:a049cb93db46

Now doing a much smarter parsing of the rest of the sentence after the verb, and describing expected arguments in (italics).
author jonathandicarlo@jonathan-dicarlos-macbook-pro.local
date Tue, 13 May 2008 18:57:55 -0700
parents 4ea09b7ce820
children 98935af12b04
comparison
equal deleted inserted replaced
4:4ea09b7ce820 5:a049cb93db46
50 suggest: function( fragment ) { 50 suggest: function( fragment ) {
51 return [ fragment ]; 51 return [ fragment ];
52 } 52 }
53 }; 53 };
54 54
55 function ParsedSentence( rawText, verb, DO, DOType, modifiers ) { 55 function ParsedSentence( verb, DO, modifiers ) {
56 this._init( rawText, verb, DO, DOType, modifiers ); 56 this._init( verb, DO, modifiers );
57 } 57 }
58 ParsedSentence.prototype = { 58 ParsedSentence.prototype = {
59 _init: function( rawText, verb, DO, DOType, modifiers ) { 59 _init: function( verb, DO, modifiers ) {
60 60 /* modifiers is dictionary of preposition: noun */
61 // needs state to represent what's locked in so far. 61 this._verb = verb;
62 }, 62 this._DO = DO;
63 63 this._modifiers = modifiers;
64 lockInLatestWord: function( selectedCompletion ) { 64 },
65 // 65
66 66 getCompletionText: function() {
67 }, 67 // returns completed and canonicalized sentence
68 68 var sentence = this._verb._name;
69 getCompletions: function() { 69 if ( this._verb._DOType ) {
70 if ( this._DO ) {
71 sentence = sentence + " " + this._DO;
72 } else {
73 sentence = sentence + " <span class=\"needarg\">(" + this._verb._DOLabel + ")</span>";
74 }
75 }
76
77 for ( var x in this._verb._modifiers ) {
78 if ( this._modifiers[ x ] ) {
79 sentence = sentence + " " + x + " " + this._modifiers[x];
80 } else {
81 sentence = sentence + " <span class=\"needarg\">(" + this._verb._modifiers[x]._name + ")</span>";
82 }
83 }
84 return sentence;
70 }, 85 },
71 86
72 getDescription: function() { 87 getDescription: function() {
73 // returns a string describing what the sentence will do if executed 88 // returns a string describing what the sentence will do if executed
74 }, 89 }
75 90
76 }; 91 };
77 92
78 93
79 function Verb( name, DOLabel, DOType, modifiers ) { 94 function Verb( name, DOLabel, DOType, modifiers ) {
89 // keys are prepositions 104 // keys are prepositions
90 // values are NounTypes. 105 // values are NounTypes.
91 // example: { "from" : City, "to" : City, "on" : Day } 106 // example: { "from" : City, "to" : City, "on" : Day }
92 }, 107 },
93 108
94 getCompletions: function( words ) { 109 recursiveParse: function( unusedWords, filledMods, unfilledMods ) {
110 var x;
111 var suggestions = [];
112 var completions = [];
113 var directObject = "";
114 if ( [key for (key in unfilledMods)].length == 0 ) {
115 // Done with modifiers, try to parse direct object.
116 if ( unusedWords.length == 0 ) {
117 // No words left, no direct object. Try parsing sentence
118 // without them.
119 return [ new ParsedSentence( this, "", filledMods ) ];
120 }
121
122 if ( this._DOType == null ) {
123 // intransitive verb; no direct object, only modifiers.
124 // We can't use the extra words, so fail.
125 return [];
126 } else {
127 // Transitive verb, can have direct object. Try to use the
128 // remaining words in that slot.
129 directObject = unusedWords.join( " " );
130 if ( this._DOType.match( directObject ) ) {
131 // it's a valid direct object. Make a sentence for each
132 // possible noun completion based on it; return them all.
133 suggestions = this._DOType.suggest( unusedWords[0] );
134 for ( var x in suggestions ) {
135 completions.push( new ParsedSentence( this, suggestions[x],
136 filledMods ) );
137 }
138 return completions;
139 } else {
140 // word is invalid direct object. Fail!
141 return [];
142 }
143 }
144 }
145 },
146
147 /*
148 else {
149 // "pop" a preposition off of the properties of unfilledMods
150 var preposition = [key for (key in unfilledMods)][0];
151 var newUnfilledMods = unfilledMods.splice();
152 delete newUnfilledMods[preposition];
153
154 // Look for a match for this preposition
155 var nounType = unfilledMods[ preposition ];
156 var matchIndices = [];
157 for ( var x = 0; x < unusedWords.length - 1; x++ ) {
158 if ( preposition.indexOf( unusedWords[x] ) == 0 ) {
159 if ( nounType.match( unusedWords[ x + 1 ] ) == 0 ) {
160 // Match for the preposition at index x followed by
161 // an appropriate noun at index x+1
162 matchIndices.push( x );
163 }
164 }
165 }
166 if ( matchIndices.length == 0 ) {
167 // no match for this preposition.
168 // Leave it blank and try to parse the rest:
169 filledMods[preposition] = "";
170 return recursiveParse( unusedWords, filledMods, newUnfilledMods );
171 } else {
172 for ( x in matchIndices ) {
173 // remove the words that matched the preposition and following
174 // noun:
175 var noun = unusedWords[ matchIndices[x]+1 ];
176 var newUnusedWords = unusedWords.slice();
177 newUnusedWords.splice( possibilities[x], 2 );
178 // add every noun completion from every possibility...
179 suggestions = nounType.suggest( noun );
180 for ( var y in suggestions ) {
181 var newFilledMods = filledMods.slice();
182 newFilledMods[ preposition ] = suggestions[y];
183 var newCompletions = recursiveParse( newUnusedWords,
184 newFilledMods,
185 newUnfilledMods );
186 completions = completions.concat( newCompletions );
187 }
188 }
189 return completions;
190 }
191 }
192 }, */
193
194 parse: function( words ) {
195 /* returns a list of ParsedSentences. */
95 /* words is an array of words that were space-separated. 196 /* words is an array of words that were space-separated.
96 already determined that words[0] matches this verb; 197 The first word, which matched this verb, has already been removed.
97 Everything after that is either: 198 Everything after that is either:
98 1. my direct object 199 1. my direct object
99 2. a preposition 200 2. a preposition
100 3. a noun following a preposition. 201 3. a noun following a preposition.
101 */ 202 */
102 var predicate = ""; 203 return this.recursiveParse( words, {}, this._modifiers );
103 var completions = []; 204 },
104 var suggestions = []; 205
105 var x; 206 getCompletions: function( words ) {
106 var y; 207 var sentences = this.parse( words );
107 208 return [ sentences[x].getCompletionText() for ( x in sentences ) ];
108 // TODO pull out things that might be modifiers, try using
109 // the remainder as the direct object.
110
111 for ( x = 1; x < words.length; x++ ) {
112 // a horrible way of reassembling input minus verb
113 predicate = predicate + words[x];
114 if ( x < words.length - 1 ) {
115 predicate = predicate + " ";
116 }
117 }
118
119 // first approx: just try out each word as direct object
120 if ( this._DOType == null ) {
121 // No direct object accepted!!
122 if ( predicate.length == 0 ) {
123 return [this._name];
124 } else {
125 return [];
126 }
127 } else if ( this._DOType.match( predicate ) ){
128 // direct object accepts whole input at once?
129 suggestions = this._DOType.suggest( predicate );
130 for( y in suggestions ) {
131 completions.push( this._name + " " + suggestions[y] );
132 }
133 return completions;
134 } else {
135 // try each word as the direct object
136 for ( x=1; x<words.length; x++ ) {
137 if ( this._DOType.match( words[x] ) ){
138 suggestions = this._DOType.suggest( predicate );
139 for( y in suggestions ) {
140 completions.push( this._name + " " + suggestions[y] );
141 }
142 }
143 }
144 return completions;
145 }
146
147
148 }, 209 },
149 210
150 match: function( sentence ) { 211 match: function( sentence ) {
151 // returns a float from 0 to 1 telling how good of a match the input 212 // returns a float from 0 to 1 telling how good of a match the input
152 // is to this verb. 213 // is to this verb.
201 var completions = []; 262 var completions = [];
202 var words = query.split( " " ); 263 var words = query.split( " " );
203 for ( var x in verbs ) { 264 for ( var x in verbs ) {
204 var verb = verbs[x]; 265 var verb = verbs[x];
205 if ( verb.match( words[0] ) ) { 266 if ( verb.match( words[0] ) ) {
206 completions = verb.getCompletions( words ); 267 completions = verb.getCompletions( words.slice(1) );
207 this._suggestionList = this._suggestionList.concat( completions ); 268 this._suggestionList = this._suggestionList.concat( completions );
208 } 269 }
209 } // TODO sort in order of match quality 270 } // TODO sort in order of match quality
210 this._hilitedSuggestion = 0; 271 this._hilitedSuggestion = 0;
211 }, 272 },
301 case 13: // enter 362 case 13: // enter
302 gQs.execute(); 363 gQs.execute();
303 break; 364 break;
304 case 32: // spacebar 365 case 32: // spacebar
305 event.target.value = gQs.autocomplete( event.target.value ); 366 event.target.value = gQs.autocomplete( event.target.value );
367 gQs.updateSuggestionList( event.target.value );
306 break; 368 break;
307 default: 369 default:
308 gQs.updateSuggestionList( event.target.value ); 370 gQs.updateSuggestionList( event.target.value );
309 break; 371 break;
310 // todo: delete key "unlocks" if you delete past a space? 372 // todo: delete key "unlocks" if you delete past a space?
320 $("#autocomplete-popup").css( 382 $("#autocomplete-popup").css(
321 "width", 383 "width",
322 $("#search-box").css("width") 384 $("#search-box").css("width")
323 ); 385 );
324 }); 386 });
387
388 /* Minor problems:
389 1. verbs with indirect objects are returning empty completion lists
390 2. multiple word direct objects are truncated to single word
391 */