summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkrasimir <krasimir@chalmers.se>2010-03-23 08:55:56 +0000
committerkrasimir <krasimir@chalmers.se>2010-03-23 08:55:56 +0000
commit472c5e8ee732aed2c59eb814b688d616d74e7c24 (patch)
tree6994e6ea86e561653be02dab48364efba81e6905 /src
parente7f01aa5f098f7425c618f1491d1370a6fc61ed2 (diff)
add JavaScript API for completion. contributed by John J. Camilleri
Diffstat (limited to 'src')
-rw-r--r--src/runtime/javascript/gflib.js100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/runtime/javascript/gflib.js b/src/runtime/javascript/gflib.js
index 6fb937407..03df363a4 100644
--- a/src/runtime/javascript/gflib.js
+++ b/src/runtime/javascript/gflib.js
@@ -494,6 +494,69 @@ Parser.prototype.parseString = function (string, cat) {
}
return ps.extractTrees();
};
+/**
+ * Generate list of suggestions given an input string
+ */
+Parser.prototype.complete = function (input, cat) {
+
+ // Parameter defaults
+ if (input == null) input = "";
+ if (cat == null) cat = grammar.abstract.startcat;
+
+ // Tokenise input string & remove empty tokens
+ tokens = input.trim().split(' ');
+ for (var i = tokens.length - 1; i >= 0; i--) {
+ if (tokens[i] == "") { tokens.splice(i, 1); }
+ }
+
+ // Capture last token as it may be partial
+ current = tokens.pop();
+ if (current == null) current = "";
+
+ // Init parse state objects.
+ // ps2 is used for testing whether the final token is parsable or not.
+ var ps = new ParseState(this, cat);
+ var ps2 = new ParseState(this, cat);
+
+ // Iterate over tokens, feed one by one to parser
+ for (var i = 0; i < tokens.length ; i++) {
+ if (!ps.next(tokens[i])) {
+ return new Array(); // Incorrect parse, nothing to suggest
+ }
+ ps2.next(tokens[i]); // also consume token in ps2
+ }
+
+ // Attempt to also parse current, knowing it may be incomplete
+ if (ps2.next(current)) {
+ ps.next(current);
+ tokens.push(current);
+ current = "";
+ }
+ delete(ps2); // don't need this anymore
+
+ // Parse is successful so far, now get suggestions
+ var acc = ps.complete(current);
+
+ // Format into just a list of strings & return
+ // (I know the multiple nesting looks horrible)
+ var suggs = new Array();
+ if (acc.value) {
+ // Iterate over all acc.value[]
+ for (var v = 0; v < acc.value.length; v++) {
+ // Iterate over all acc.value[].seq[]
+ for (var s = 0; s < acc.value[v].seq.length; s++) {
+ if (acc.value[v].seq[s].tokens == null) continue;
+ // Iterate over all acc.value[].seq[].tokens
+ for (var t = 0; t < acc.value[v].seq[s].tokens.length; t++) {
+ suggs.push( acc.value[v].seq[s].tokens[t] );
+ }
+ }
+ }
+ }
+
+ // Note: return used tokens too
+ return { 'consumed' : tokens, 'suggestions' : suggs };
+}
// Rule Object Definition
@@ -731,6 +794,43 @@ ParseState.prototype.next = function (token) {
return !this.items.isEmpty();
}
+/**
+ * For a ParseState and a partial input, return all possible completions
+ * Based closely on ParseState.next()
+ * currentToken could be empty or a partial string
+ */
+ParseState.prototype.complete = function (currentToken) {
+
+ // Initialise accumulator for suggestions
+ var acc = this.items.lookup(currentToken);
+ if (acc == null)
+ acc = new Trie();
+
+ this.process(
+ // Items
+ this.items.value,
+
+ // Deal with literal categories
+ function (fid) {
+ // Always return null, as suggested by Krasimir
+ return null;
+ },
+
+ // Takes an array of tokens and populates the accumulator
+ function (tokens, item) {
+ if (currentToken == "" || tokens[0].indexOf(currentToken) == 0) { //if begins with...
+ var tokens1 = new Array();
+ for (var i = 1; i < tokens.length; i++) {
+ tokens1[i-1] = tokens[i];
+ }
+ acc.insertChain1(tokens1, item);
+ }
+ }
+ );
+
+ // Return matches
+ return acc;
+}
ParseState.prototype.extractTrees = function() {
this.process( this.items.value
, function (fid) {