Mercurial > hip
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 */ |