Mercurial > hip
changeset 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 |
files | hip.css hip.js |
diffstat | 2 files changed, 131 insertions(+), 59 deletions(-) [+] |
line wrap: on
line diff
--- a/hip.css Tue May 13 13:04:25 2008 -0700 +++ b/hip.css Tue May 13 18:57:55 2008 -0700 @@ -14,4 +14,9 @@ .hilited { background: #00aa00; +} + +.needarg { + font-style: italic; + color: #999999; } \ No newline at end of file
--- a/hip.js Tue May 13 13:04:25 2008 -0700 +++ b/hip.js Tue May 13 18:57:55 2008 -0700 @@ -52,26 +52,41 @@ } }; -function ParsedSentence( rawText, verb, DO, DOType, modifiers ) { - this._init( rawText, verb, DO, DOType, modifiers ); +function ParsedSentence( verb, DO, modifiers ) { + this._init( verb, DO, modifiers ); } ParsedSentence.prototype = { - _init: function( rawText, verb, DO, DOType, modifiers ) { - - // needs state to represent what's locked in so far. + _init: function( verb, DO, modifiers ) { + /* modifiers is dictionary of preposition: noun */ + this._verb = verb; + this._DO = DO; + this._modifiers = modifiers; }, - lockInLatestWord: function( selectedCompletion ) { - // + getCompletionText: function() { + // returns completed and canonicalized sentence + var sentence = this._verb._name; + if ( this._verb._DOType ) { + if ( this._DO ) { + sentence = sentence + " " + this._DO; + } else { + sentence = sentence + " <span class=\"needarg\">(" + this._verb._DOLabel + ")</span>"; + } + } - }, - - getCompletions: function() { + for ( var x in this._verb._modifiers ) { + if ( this._modifiers[ x ] ) { + sentence = sentence + " " + x + " " + this._modifiers[x]; + } else { + sentence = sentence + " <span class=\"needarg\">(" + this._verb._modifiers[x]._name + ")</span>"; + } + } + return sentence; }, getDescription: function() { // returns a string describing what the sentence will do if executed - }, + } }; @@ -91,60 +106,106 @@ // example: { "from" : City, "to" : City, "on" : Day } }, - getCompletions: function( words ) { + recursiveParse: function( unusedWords, filledMods, unfilledMods ) { + var x; + var suggestions = []; + var completions = []; + var directObject = ""; + if ( [key for (key in unfilledMods)].length == 0 ) { + // Done with modifiers, try to parse direct object. + if ( unusedWords.length == 0 ) { + // No words left, no direct object. Try parsing sentence + // without them. + return [ new ParsedSentence( this, "", filledMods ) ]; + } + + if ( this._DOType == null ) { + // intransitive verb; no direct object, only modifiers. + // We can't use the extra words, so fail. + return []; + } else { + // Transitive verb, can have direct object. Try to use the + // remaining words in that slot. + directObject = unusedWords.join( " " ); + if ( this._DOType.match( directObject ) ) { + // it's a valid direct object. Make a sentence for each + // possible noun completion based on it; return them all. + suggestions = this._DOType.suggest( unusedWords[0] ); + for ( var x in suggestions ) { + completions.push( new ParsedSentence( this, suggestions[x], + filledMods ) ); + } + return completions; + } else { + // word is invalid direct object. Fail! + return []; + } + } + } + }, + + /* + else { + // "pop" a preposition off of the properties of unfilledMods + var preposition = [key for (key in unfilledMods)][0]; + var newUnfilledMods = unfilledMods.splice(); + delete newUnfilledMods[preposition]; + + // Look for a match for this preposition + var nounType = unfilledMods[ preposition ]; + var matchIndices = []; + for ( var x = 0; x < unusedWords.length - 1; x++ ) { + if ( preposition.indexOf( unusedWords[x] ) == 0 ) { + if ( nounType.match( unusedWords[ x + 1 ] ) == 0 ) { + // Match for the preposition at index x followed by + // an appropriate noun at index x+1 + matchIndices.push( x ); + } + } + } + if ( matchIndices.length == 0 ) { + // no match for this preposition. + // Leave it blank and try to parse the rest: + filledMods[preposition] = ""; + return recursiveParse( unusedWords, filledMods, newUnfilledMods ); + } else { + for ( x in matchIndices ) { + // remove the words that matched the preposition and following + // noun: + var noun = unusedWords[ matchIndices[x]+1 ]; + var newUnusedWords = unusedWords.slice(); + newUnusedWords.splice( possibilities[x], 2 ); + // add every noun completion from every possibility... + suggestions = nounType.suggest( noun ); + for ( var y in suggestions ) { + var newFilledMods = filledMods.slice(); + newFilledMods[ preposition ] = suggestions[y]; + var newCompletions = recursiveParse( newUnusedWords, + newFilledMods, + newUnfilledMods ); + completions = completions.concat( newCompletions ); + } + } + return completions; + } + } + }, */ + + parse: function( words ) { + /* returns a list of ParsedSentences. */ /* words is an array of words that were space-separated. - already determined that words[0] matches this verb; + The first word, which matched this verb, has already been removed. Everything after that is either: 1. my direct object 2. a preposition 3. a noun following a preposition. */ - var predicate = ""; - var completions = []; - var suggestions = []; - var x; - var y; - - // TODO pull out things that might be modifiers, try using - // the remainder as the direct object. - - for ( x = 1; x < words.length; x++ ) { - // a horrible way of reassembling input minus verb - predicate = predicate + words[x]; - if ( x < words.length - 1 ) { - predicate = predicate + " "; - } - } + return this.recursiveParse( words, {}, this._modifiers ); + }, - // first approx: just try out each word as direct object - if ( this._DOType == null ) { - // No direct object accepted!! - if ( predicate.length == 0 ) { - return [this._name]; - } else { - return []; - } - } else if ( this._DOType.match( predicate ) ){ - // direct object accepts whole input at once? - suggestions = this._DOType.suggest( predicate ); - for( y in suggestions ) { - completions.push( this._name + " " + suggestions[y] ); - } - return completions; - } else { - // try each word as the direct object - for ( x=1; x<words.length; x++ ) { - if ( this._DOType.match( words[x] ) ){ - suggestions = this._DOType.suggest( predicate ); - for( y in suggestions ) { - completions.push( this._name + " " + suggestions[y] ); - } - } - } - return completions; - } - - + getCompletions: function( words ) { + var sentences = this.parse( words ); + return [ sentences[x].getCompletionText() for ( x in sentences ) ]; }, match: function( sentence ) { @@ -203,7 +264,7 @@ for ( var x in verbs ) { var verb = verbs[x]; if ( verb.match( words[0] ) ) { - completions = verb.getCompletions( words ); + completions = verb.getCompletions( words.slice(1) ); this._suggestionList = this._suggestionList.concat( completions ); } } // TODO sort in order of match quality @@ -303,6 +364,7 @@ break; case 32: // spacebar event.target.value = gQs.autocomplete( event.target.value ); + gQs.updateSuggestionList( event.target.value ); break; default: gQs.updateSuggestionList( event.target.value ); @@ -322,3 +384,8 @@ $("#search-box").css("width") ); }); + +/* Minor problems: +1. verbs with indirect objects are returning empty completion lists +2. multiple word direct objects are truncated to single word +*/