function GFGrammar(abstract, concretes) { this.abstract = abstract; this.concretes = concretes; } /* Translates a string from any concrete syntax to all concrete syntaxes. Uses the start category of the grammar. */ GFGrammar.prototype.translate = function (input, fromLang, toLang) { var outputs = new Object(); var fromConcs = this.concretes; if (fromLang) { fromConcs = new Object(); fromConcs[fromLang] = this.concretes[fromLang]; } var toConcs = this.concretes; if (toLang) { toConcs = new Object(); toConcs[toLang] = this.concretes[toLang]; } for (var c1 in fromConcs) { var p = this.concretes[c1].parser; if (p) { var trees = p.parseString(input, this.abstract.startcat); if (trees.length > 0) { outputs[c1] = new Array(); for (var i in trees) { outputs[c1][i] = new Object(); for (var c2 in toConcs) { outputs[c1][i][c2] = this.concretes[c2].linearize(trees[i]); } } } } } return outputs; } /* ------------------------------------------------------------------------- */ /* ----------------------------- LINEARIZATION ----------------------------- */ /* ------------------------------------------------------------------------- */ /* Extension to the String object */ String.prototype.tag = ""; String.prototype.setTag = function (tag) { this.tag = tag; }; /* Abstract syntax trees */ function Fun(name) { this.name = name; this.args = copy_arguments(arguments, 1); } Fun.prototype.print = function () { return this.show(0); } ; Fun.prototype.show = function (prec) { if (this.isMeta()) { if (isUndefined(this.type)) { return '?'; } else { var s = '?:' + this.type; if (prec > 0) { s = "(" + s + ")" ; } return s; } } else { var s = this.name; var cs = this.args; for (var i in cs) { s += " " + (isUndefined(cs[i]) ? "undefined" : cs[i].show(1)); } if (prec > 0 && cs.length > 0) { s = "(" + s + ")" ; } return s; } }; Fun.prototype.getArg = function (i) { return this.args[i]; }; Fun.prototype.setArg = function (i,c) { this.args[i] = c; }; Fun.prototype.isMeta = function() { return this.name == '?'; } ; Fun.prototype.isComplete = function() { if (this.isMeta()) { return false; } else { for (var i in this.args) { if (!this.args[i].isComplete()) { return false; } } return true; } } ; /* Concrete syntax terms */ function Arr() { this.arr = copy_arguments(arguments, 0); } Arr.prototype.tokens = function() { return this.arr[0].tokens(); }; Arr.prototype.sel = function(i) { return this.arr[i.toIndex()]; }; Arr.prototype.setTag = function(tag) { for (var i = 0, j = this.arr.length; i < j; i++) { this.arr[i].setTag(tag); } }; function Seq() { this.seq = copy_arguments(arguments, 0); } Seq.prototype.tokens = function() { var xs = new Array(); for (var i in this.seq) { var ys = this.seq[i].tokens(); for (var j in ys) { xs.push(ys[j]); } } return xs; }; Seq.prototype.setTag = function(tag) { for (var i = 0, j = this.seq.length; i < j; i++) { this.seq[i].setTag(tag); } }; function Variants() { this.variants = copy_arguments(arguments, 0); } Variants.prototype.tokens = function() { return this.variants[0].tokens(); }; Variants.prototype.sel = function(i) { return this.variants[0].sel(i); }; Variants.prototype.toIndex = function() { return this.variants[0].toIndex(); }; Variants.prototype.setTag = function(tag) { for (var i = 0, j = this.variants.length; i < j; i++) { this.variants[i].setTag(tag); } }; function Rp(index,value) { this.index = index; this.value = value; } Rp.prototype.tokens = function() { return new Array(this.index.tokens()); }; Rp.prototype.sel = function(i) { return this.value.arr[i.toIndex()]; }; Rp.prototype.toIndex = function() { return this.index.toIndex(); }; Rp.prototype.setTag = function(tag) { this.index.setTag(tag) }; function Suffix(prefix,suffix) { this.prefix = new String(prefix); if (prefix.tag) { this.prefix.tag = prefix.tag; } this.suffix = suffix; }; Suffix.prototype.tokens = function() { var xs = this.suffix.tokens(); for (var i in xs) { xs[i] = new String(this.prefix + xs[i]); xs[i].setTag(this.prefix.tag); } return xs; }; Suffix.prototype.sel = function(i) { return new Suffix(this.prefix, this.suffix.sel(i)); }; Suffix.prototype.setTag = function(tag) { if (!this.prefix.tag) { this.prefix.setTag(tag); } }; function Meta() { } Meta.prototype.tokens = function() { var newString = new String("?"); newString.setTag(this.tag); return new Array(newString); }; Meta.prototype.toIndex = function() { return 0; }; Meta.prototype.sel = function(i) { return this; }; Meta.prototype.setTag = function(tag) { if (!this.tag) { this.tag = tag; } }; function Str(value) { this.value = value; } Str.prototype.tokens = function() { var newString = new String(this.value); newString.setTag(this.tag); return new Array(newString); }; Str.prototype.setTag = function(tag) { if (!this.tag) { this.tag = tag; } }; function Int(value) { this.value = value; } Int.prototype.tokens = function() { var newString = new String(this.value.toString()); newString.setTag(this.tag); return new Array(newString); }; Int.prototype.toIndex = function() { return this.value; }; Int.prototype.setTag = function(tag) { if (!this.tag) { this.tag = tag; } }; /* Type annotation */ function GFAbstract(startcat, types) { this.startcat = startcat; this.types = types; } GFAbstract.prototype.addType = function(fun, args, cat) { this.types[fun] = new Type(args, cat); } ; GFAbstract.prototype.getArgs = function(fun) { return this.types[fun].args; } GFAbstract.prototype.getCat = function(fun) { return this.types[fun].cat; }; GFAbstract.prototype.annotate = function(tree, type) { if (tree.name == '?') { tree.type = type; } else { var typ = this.types[tree.name]; for (var i in tree.args) { this.annotate(tree.args[i], typ.args[i]); } } return tree; } ; GFAbstract.prototype.handleLiterals = function(tree, type) { if (tree.name != '?') { if (type == "String" || type == "Int" || type == "Float") { tree.name = type + "_Literal_" + tree.name; } else { var typ = this.types[tree.name]; for (var i in tree.args) { this.handleLiterals(tree.args[i], typ.args[i]); } } } return tree; } ; /* Hack to get around the fact that our SISR doesn't build real Fun objects. */ GFAbstract.prototype.copyTree = function(x) { var t = new Fun(x.name); if (!isUndefined(x.type)) { t.type = x.type; } var cs = x.args; if (!isUndefined(cs)) { for (var i in cs) { t.setArg(i, this.copyTree(cs[i])); } } return t; } ; GFAbstract.prototype.parseTree = function(str, type) { return this.annotate(this.parseTree_(str.match(/[\w\'\.\"]+|\(|\)|\?|\:/g), 0), type); } ; GFAbstract.prototype.parseTree_ = function(tokens, prec) { if (tokens.length == 0 || tokens[0] == ")") { return null; } var t = tokens.shift(); if (t == "(") { var tree = this.parseTree_(tokens, 0); tokens.shift(); return tree; } else if (t == '?') { var tree = this.parseTree_(tokens, 0); return new Fun('?'); } else { var tree = new Fun(t); if (prec == 0) { var c, i; for (i = 0; (c = this.parseTree_(tokens, 1)) !== null; i++) { tree.setArg(i,c); } } return tree; } } ; function Type(args, cat) { this.args = args; this.cat = cat; } /* Linearization */ function GFConcrete(flags, rules, parser) { this.flags = flags; this.rules = rules; if (parser) { this.parser = parser; } else { this.parser = undefined; } } GFConcrete.prototype.rule = function (name, cs) { return this.rules[name](cs); }; GFConcrete.prototype.addRule = function (name, f) { this.rules[name] = f; }; GFConcrete.prototype.lindef = function (cat, v) { return this.rules[cat]([new Str(v)]); } ; GFConcrete.prototype.linearize = function (tree) { return this.unlex(this.linearizeToTerm(tree).tokens()); }; GFConcrete.prototype.linearizeToTerm = function (tree) { if (tree.isMeta()) { if (isUndefined(tree.type)) { return new Meta(); } else { return this.lindef(tree.type, tree.name); } } else { var cs = new Array(); for (var i in tree.args) { cs.push(this.linearizeToTerm(tree.args[i])); } var newTerm = this.rule(tree.name, cs); return newTerm; } }; GFConcrete.prototype.unlex = function (ts) { if (ts.length == 0) { return ""; } var noSpaceAfter = /^[\(\-\[]/; var noSpaceBefore = /^[\.\,\?\!\)\:\;\-\]]/; var s = ""; for (var i = 0; i < ts.length; i++) { var t = ts[i]; var after = i < ts.length-1 ? ts[i+1] : null; s += t; if (after != null && !t.match(noSpaceAfter) && !after.match(noSpaceBefore)) { s += " "; } } return s; }; GFConcrete.prototype.tagAndLinearize = function (tree) { return this.tagAndLinearizeToTerm(tree, "0").tokens(); }; GFConcrete.prototype.tagAndLinearizeToTerm = function (tree, route) { if (tree.isMeta()) { if (isUndefined(tree.type)) { var newMeta = new Meta(); newMeta.setTag(route); return newMeta; } else { var newTerm = this.lindef(tree.type, tree.name); newTerm.setTag(route); return newTerm; } } else { var cs = new Array(); for (var i in tree.args) { cs.push(this.tagAndLinearizeToTerm(tree.args[i], route + "-" + i)); } var newTerm = this.rule(tree.name, cs); newTerm.setTag(route); return newTerm; } }; /* Utilities */ /* from Remedial JavaScript by Douglas Crockford, http://javascript.crockford.com/remedial.html */ function isString(a) { return typeof a == 'string'; } function isArray(a) { return a && typeof a == 'object' && a.constructor == Array; } function isUndefined(a) { return typeof a == 'undefined'; } function isBoolean(a) { return typeof a == 'boolean'; } function isNumber(a) { return typeof a == 'number' && isFinite(a); } function isFunction(a) { return typeof a == 'function'; } function dumpObject (obj) { if (isUndefined(obj)) { return "undefined"; } else if (isString(obj)) { return '"' + obj.toString() + '"'; // FIXME: escape } else if (isBoolean(obj) || isNumber(obj)) { return obj.toString(); } else if (isArray(obj)) { var x = "["; for (var i in obj) { x += dumpObject(obj[i]); if (i < obj.length-1) { x += ","; } } return x + "]"; } else { var x = "{"; for (var y in obj) { x += y + "=" + dumpObject(obj[y]) + ";" ; } return x + "}"; } } function copy_arguments(args, start) { var arr = new Array(); for (var i = 0; i < args.length - start; i++) { arr[i] = args[i + start]; } return arr; } /* ------------------------------------------------------------------------- */ /* -------------------------------- PARSING -------------------------------- */ /* ------------------------------------------------------------------------- */ function Parser(startcat, rules, cats) { this.startcat = startcat; this.rules = rules; this.cats = cats; } Parser.prototype.showRules = function () { var ruleStr = new Array(); ruleStr.push(""); for (i = 0, j = this.rules.length; i < j; i++) { ruleStr.push(this.rules[i].show()); } return ruleStr.join(""); }; Parser.prototype.parseString = function (string, cat) { var tokens = string.split(" "); chart = new Chart(true); predict(this.rules, tokens); while (chart.updated) { chart.updated = false; completeAndConvert(); scan(); combine(); } var catToParse = this.startcat; if (cat) { catToParse = cat; } var goalRange = new Range(0, tokens.length); if (tokens.length == 1 && tokens[0] == "") { goalRange = new EmptyRange(); } var activeEdges = filterActiveEdges(); var trees = new Array(); for (var i = 0, j = this.cats[catToParse].length; i < j; i++) { if (foundTarget(this.cats[catToParse][i], new Array(new Array(goalRange)))) { trees = trees.concat(extractTrees(this.cats[catToParse][i], new Array(new Array(goalRange)), activeEdges, "")); } } for (var i = trees.length - 1; i >= 0; i--) { if (trees[i] == undefined) { trees.splice(i, 1); } } return trees; }; // Rule Object Definition function Rule(cat, profile, args, linRec) { this.cat = cat; this.profile = profile; this.args = args; this.linRec = linRec; } Rule.prototype.show = function () { var recStr = new Array(); recStr.push(this.cat, " -> ", this.profile.show(), " [", this.args, "] = ", showLinRec(this.linRec, "")); return recStr.join(""); }; // Profile definitions // Function application // The function (name) is applied to its arguments (args) function FunApp(name, args) { this.id = "FunApp"; this.name = name; this.args = args.slice(0); } FunApp.prototype.show = function () { var funAppStr = new Array(); funAppStr.push("(", this.name); for (var i = 0, j = this.args.length; i < j; i++) { funAppStr.push(this.args[i].show()); } funAppStr.push(")"); return funAppStr.join(" "); }; // Literal function Lit(name) { this.id = "Lit"; this.name = name; } Lit.prototype.show = function () { return this.name; }; // Metavariable function MetaVar() { this.id = "MetaVar"; } MetaVar.prototype.show = function () { return "?"; }; // Argument function Arg(i) { this.id = "Arg"; this.name = "_"; this.i = i; } Arg.prototype.show = function () { var argStr = new Array(); argStr.push(this.id, "(", this.i, ")"); return argStr.join(""); }; // Unification // The arguments (args) must be unified function Unify(args){ this.id = "Unify"; this.args = args.slice(0); } Unify.prototype.show = function () { var unifyStr = new Array(); unifyStr.push("(", this.id); for (var i = 0, j = this.args.length; i < j; i++) { unifyStr.push(this.args[i].show()); } unifyStr.push(")"); return unifyStr.join(" "); }; // Definition of symbols present in linearization records // Object to represent argument projections in grammar rules function ArgProj(i, label) { this.id = "argProj"; this.i = i; this.label = label; } ArgProj.prototype.getId = function () { return this.id; }; ArgProj.prototype.getArgNum = function () { return this.i }; ArgProj.prototype.show = function () { var argStr = new Array(); argStr.push(this.i, this.label); return argStr.join("."); }; ArgProj.prototype.isEqual = function (obj) { return (this.id == obj.id && this.i == obj.i && this.label == obj.label); } // Object to represent terminals in grammar rules function Terminal (str) { this.id = "terminal"; this.str = str; } Terminal.prototype.getId = function () { return this.id; }; Terminal.prototype.show = function () { var terminalStr = new Array(); terminalStr.push('"', this.str, '"'); return terminalStr.join(""); }; Terminal.prototype.isEqual = function (obj) { return (this.id == obj.id && this.str == obj.str); } // Object to represent ranges in grammar rules function Range (i, j) { this.id = "range"; this.i = i; this.j = j; } Range.prototype.getId = function () { return this.id; }; Range.prototype.show = function () { var terminalStr = new Array(); terminalStr.push("(", this.i, ",", this.j, ")"); return terminalStr.join(""); }; Range.prototype.isEqual = function (obj) { return (this.id == obj.id && this.i == obj.i && this.j == obj.j); } // Object to represent the empty range in grammar rules function EmptyRange () { this.id = "emptyRange"; } EmptyRange.prototype.getId = function () { return this.id; }; EmptyRange.prototype.show = function () { return "emptyRange" }; EmptyRange.prototype.isEqual = function (obj) { return (this.id == obj.id); } // Chart Object Definition function Chart(updated) { this.passive = new Array(); this.active = new Array(); this.updated = updated; } Chart.prototype.show = function () { var chartStr = new Array(); chartStr.push("(", this.showPassive(), ", ", this.showActive(), ")"); return chartStr.join(""); }; Chart.prototype.addPassiveEdge = function (cat, linRec) { if (!this.passive[cat] || !this.passive[cat].length) { this.passive[cat] = new Array(); } this.passive[cat].push(linRec); }; Chart.prototype.isPassiveElem = function (cat, linRec) { if (this.passive[cat]) { for (var i = 0, j = this.passive[cat].length; i < j; i++) { if (linRecsAreEqual(this.passive[cat][i], linRec)) { return true; } } } return false; }; Chart.prototype.showPassive = function () { var edgesStr = new Array(); edgesStr.push("[ "); for (var cat in this.passive) { for (var i = 0, j = this.passive[cat].length; i < j; i++) { edgesStr.push("( ", cat, ", ", showLinRec(this.passive[cat][i], ""), ")"); if (i != j - 1) { edgesStr.push(", "); }; } edgesStr.push(", "); } edgesStr.push(" ]"); return edgesStr.join(""); return edgesStr.join("") + "
"; }; Chart.prototype.addActiveEdge = function (cat, edge) { if (!this.active[cat] || !this.active[cat].length) { this.active[cat] = new Array(); } this.active[cat].push(edge); }; Chart.prototype.isActiveElem = function (cat, edge) { if (this.active[cat]) { for (var i = 0, j = this.active[cat].length; i < j; i++) { var currentEdge = this.active[cat][i]; if (currentEdge.name == edge.name && (areArgsEqual(currentEdge.args, edge.args)) && currentEdge.currLabel == edge.currLabel && currentEdge.currLin.isEqual(edge.currLin) && linRecsAreEqual(currentEdge.linFound, edge.linFound) && linRowsAreEqual(currentEdge.remLin, edge.remLin) && linRecsAreEqual(currentEdge.remLinRows, edge.remLinRows) && arraysOfLinRecsAreEqual(currentEdge.children, edge.children)) { return true; } } } return false; }; Chart.prototype.showActive = function () { var edgesStr = new Array() edgesStr.push("[ "); for (var cat in this.active) { for (var i = 0, j = this.active[cat].length; i < j; i++) { edgesStr.push("( ", this.active[cat][i].show(), " )"); if (i != j - 1) { edgesStr.push(", "); }; } edgesStr.push(", "); } edgesStr.push(" ]"); return edgesStr.join(""); }; // Object to represent the active edges in a chart function ActiveEdge(profile, cat, name, args, linFound, currLabel, currLin, remLin, remLinRows, children) { this.profile = profile; this.cat = cat; this.name = name; this.args = args; this.linFound = linFound; this.currLabel = currLabel; this.currLin = currLin; this.remLin = remLin; this.remLinRows = remLinRows; this.children = children.slice(0); } ActiveEdge.prototype.show = function () { var linRecStr = new Array(); linRecStr.push(this.profile.show(), ", ", this.cat, ", ", this.name, ", [ ", this.args, " ], ", showLinRec(this.linFound, ""), ", ", this.currLabel, ", ", this.currLin.show(), ", ", showLinRow(this.remLin, " ++ "), ", ", showLinRec(this.remLinRows, ""), ", [ "); for (var i = 0, j = this.children.length; i < j; i++) { linRecStr.push(showLinRec(this.children[i], "")); if (i != j - 1) { linRecStr.push(", "); }; } linRecStr.push(" ]"); return linRecStr.join(""); }; function areArgsEqual(args1, args2) { if (args1.length == args1.length && args1.join() == args2.join()) { return true } return false; } // Functions to manipulate linearization records // Returns a string representation of a linearization row function showLinRow(linRow, separator) { var linRowStr = new Array(); linRowStr.push(" [ "); for (var i = 0, j = linRow.length; i < j; i ++) { linRowStr.push(linRow[i].show()); if (i != j - 1) { linRowStr.push(separator) }; } linRowStr.push(" ] "); return linRowStr.join(""); } // Returns a string representation of a linearization record function showLinRec(linRec, separator) { var linRecStr = new Array(); linRecStr.push(" [ "); for (var i = 0, j = linRec.length; i < j; i ++) { linRecStr.push(showLinRow(linRec[i], " ++ ")); if (i != j - 1) { linRecStr.push(separator); }; } linRecStr.push(" ] "); return linRecStr.join(""); } // Checks if two linearization rows are equal function linRowsAreEqual(linRow1, linRow2) { if (linRow1.length == linRow2.length) { for (var i = 0, j = linRow1.length; i < j; i++) { if (linRow1[i].id && linRow2[i].id && !linRow1[i].isEqual(linRow2[i])) { return false; } } return true; } return false; } // Checks if two linearization records are equal function linRecsAreEqual(linRec1, linRec2) { if (linRec1.length == linRec2.length) { for (var i = 0, j = linRec1.length; i < j; i++) { if (!linRowsAreEqual(linRec1[i], linRec2[i])) { return false; } } return true; } return false; } // Checks if two arrays of linearization records are equal function arraysOfLinRecsAreEqual(array1, array2) { if (array1.length == array2.length) { for (var i = 0, j = array1.length; i < j; i++) { if (!linRecsAreEqual(array1[i], array2[i])) { return false; } } return true; } return false; } // Functions to manipulate ranges (restriction and concatenation) // Concatenates two ranges function rangeConcatLin (lin1, lin2) { if (lin1.id == "range" && lin2.id == "range") { if (lin1.j == lin2.i) { return (new Range(lin1.i, lin2.j)) } } else if (lin1.id == "range" && lin2.id == "emptyRange") { return lin1; } else if (lin1.id == "emptyRange" && lin2.id == "range") { return lin2; } else if (lin1.id == "emptyRange" && lin2.id == "emptyRange") { return lin1; } return undefined; } // Performs range concatenation on a linearization row function rangeConcatLins (lins) { var newLins = new Array(); newLins.push(lins.shift()); while (lins.length > 0) { if (!newLins[newLins.length - 1]) { return new Array(); } if (newLins[newLins.length - 1].id == "range" && lins[0].id == "range") { var rangeConcat = rangeConcatLin(newLins.pop(), lins[0]); if (typeof rangeConcat == 'undefined') { return new Array(); } newLins.push(rangeConcat); lins.shift(); } else { newLins.push(lins.shift()); } } return newLins; } // Performs range restriction on an element of a linearization row // while keeping track of the tokens that have been used function rangeRestLinTerm(tokens, lin, rangesNotConsumed) { if (lin.id == "argProj") { return new Array(lin); } else if (lin.id == "terminal") { var ranges = new Array(); for (var i = 0, j = tokens.length; i < j; i++) { if (tokens[i] == lin.str) { ranges.push(new Range(i, i + 1)); rangesNotConsumed[i] = undefined; } } if (ranges.length == 0) { return undefined; } else { return ranges; } } else { return new Array(); } } // Performs range restriction on a linearization record // while keeping track of the tokens that have been used function rangeRestRecTerm(linRec, tokens, rangesNotConsumed) { var ranges = new Array(); for (var i = 0, j = linRec.length; i < j; i++) { var rangeRestLins = new Array(); for (var k = 0, l = linRec[i].length; k < l; k++) { rangeRestLins.push(rangeRestLinTerm(tokens, linRec[i][k], rangesNotConsumed)); } var combinedLins = combineLins(rangeRestLins); if (typeof combinedLins != 'undefined') { var filteredLins = new Array(); if (combinedLins.length == 0) { filteredLins.push(new Array()); } else { for (var m = 0, n = combinedLins.length; m < n; m++) { var temp = rangeConcatLins(combinedLins[m]); if (temp.length != 0) { filteredLins.push(temp); } } } ranges.push(filteredLins); } else { ranges.push(undefined); } } for (var k = 0, l = ranges.length; k < l; k++) { if (ranges[k] == undefined) { return undefined; } } return combineLins(ranges); } // Returns the combinations of the elements of an array of arrays function combineLins(linss) { if (linss.length > 0) { var combinedLins = new Array(); var lins = linss.shift(); if (lins) { if (lins.length != 0) { var tail = combineLins(linss); if (typeof tail == 'undefined') { return undefined; } for (var i = 0, j = lins.length; i < j; i++) { var head = new Array(); head.push(lins[i]); if (tail.length == 0) { combinedLins.push(head); } else { for (var k = 0, l = tail.length; k < l; k++) { combinedLins.push(head.concat(tail[k])); } } } } else { return new Array(); } } else { return undefined; } return combinedLins; } else { return new Array(); } } // Inference Rules function predict(rules, tokens) { var rangesNotConsumed = genRanges(tokens.length); for (var i = 0, j = rules.length; i < j; i++) { var currentRule = rules[i]; var linRec = rangeRestRecTerm(currentRule.linRec, tokens, rangesNotConsumed); if (linRec) { for (var k = 0, l = linRec.length; k < l; k++) { var currentRow = linRec[k].shift(); var remlinRows = linRec[k]; var children = new Array(); for (var m = 0, n = currentRule.args.length; m < n; m++) { children.push(new Array()); } var newActive = new ActiveEdge(currentRule.profile, currentRule.cat, currentRule.profile.name, currentRule.args, new Array(), 0, new EmptyRange(), currentRow, remlinRows, children); if (!chart.isActiveElem(currentRule.cat, newActive)) { chart.addActiveEdge(currentRule.cat, newActive); chart.updated = true; } } } } for (var i = 0, j = rangesNotConsumed.length; i < j; i++) { if (rangesNotConsumed[i] != undefined) { var cat = undefined; if (isNaN(tokens[i])) { cat = "-1"; } else if (tokens[i].lastIndexOf(".") == -1) { cat = "-2"; } else { cat = "-3"; } var lit = undefined; if (cat == "-1") { lit = "\"" + tokens[i] + "\""; } else { lit = tokens[i]; } var newActive = new ActiveEdge(new Lit(lit), cat, tokens[i], new Array(), new Array(), 0, new Range(i, i + 1), new Array(), new Array(), new Array()); if (!chart.isActiveElem(cat, newActive)) { chart.addActiveEdge(cat, newActive); chart.updated = true; } } } } function genRanges(inputLength) { var ranges = new Array(); for (var i = 0; i < inputLength; i++) { ranges.push(i); } return ranges; } function completeAndConvert() { for (var cat in chart.active) { var currentEdge = chart.active[cat]; for (var i = 0, j = currentEdge.length; i < j; i++) { if (currentEdge[i].remLin.length == 0) { if (currentEdge[i].remLinRows.length == 0) { var linFound = currentEdge[i].linFound.slice(0); linFound.push(new Array(currentEdge[i].currLin)); if (!chart.isPassiveElem(cat, linFound)) { chart.addPassiveEdge(cat, linFound); chart.updated = true; } } else { var linFound = currentEdge[i].linFound.slice(0); linFound.push(new Array(currentEdge[i].currLin)); var remLinRows = currentEdge[i].remLinRows.slice(0); var currentRow = remLinRows.shift(); var newActive = new ActiveEdge(currentEdge[i].profile, cat, currentEdge[i].name, currentEdge[i].args, linFound, linFound.length, new EmptyRange(), currentRow, remLinRows, currentEdge[i].children); if (!chart.isActiveElem(cat, newActive)) { chart.active[cat].push(newActive); chart.updated = true; } } } } } } function scan() { for (var cat in chart.active) { var currentEdge = chart.active[cat]; for (var i = 0, j = currentEdge.length; i < j; i++) { if (currentEdge[i].remLin.length > 0 && currentEdge[i].remLin[0].id == "range") { var newRange = rangeConcatLin(currentEdge[i].currLin, currentEdge[i].remLin[0]); if (typeof newRange != 'undefined') { var remLin = currentEdge[i].remLin.slice(0); remLin.shift(); var newActive = new ActiveEdge(currentEdge[i].profile, cat, currentEdge[i].name, currentEdge[i].args, currentEdge[i].linFound, currentEdge[i].currLabel, newRange, remLin, currentEdge[i].remLinRows, currentEdge[i].children); if (!chart.isActiveElem(cat, newActive)) { chart.active[cat].push(newActive); chart.updated = true; } } } } } } function combine() { for (var cat in chart.active) { for (var i = 0; i < chart.active[cat].length; i++) { var currentEdge = chart.active[cat][i]; if (currentEdge.remLin.length && currentEdge.remLin[0].id == "argProj") { var argNumber = currentEdge.remLin[0].i; var catToCombine = currentEdge.args[argNumber]; if (chart.passive[catToCombine]) { for (var k = 0, l = chart.passive[catToCombine].length; k < l; k++) { var currentPassive = chart.passive[catToCombine][k]; var remLin = currentEdge.remLin.slice(0); var linRow = currentPassive[remLin[0].label]; if (typeof linRow != 'undefined') { var newLinRow = linRow.slice(0); if (currentEdge.children[argNumber].length == 0) { var newRange = rangeConcatLin(currentEdge.currLin, newLinRow.shift()); if (typeof newRange != 'undefined') { remLin.shift(); var children = currentEdge.children.slice(0); children[argNumber] = currentPassive.slice(0); var newActive = new ActiveEdge(currentEdge.profile, currentEdge.cat, currentEdge.name, currentEdge.args, currentEdge.linFound, currentEdge.currLabel, newRange, remLin, currentEdge.remLinRows, children); if (!chart.isActiveElem(cat, newActive)) { chart.active[cat].push(newActive); chart.updated = true; } } } else { var child = currentEdge.children[argNumber]; if (linRecsAreEqual(currentPassive, child)) { var newRange = rangeConcatLin(currentEdge.currLin, newLinRow.shift()); if (typeof newRange != 'undefined') { remLin.shift(); var children = currentEdge.children.slice(0); children[argNumber] = currentPassive.slice(0); var newActive = new ActiveEdge(currentEdge.profile, currentEdge.cat, currentEdge.name, currentEdge.args, currentEdge.linFound, currentEdge.currLabel, newRange, remLin, currentEdge.remLinRows, children); if (!chart.isActiveElem(cat, newActive)) { chart.active[cat].push(newActive); chart.updated = true; } } } } } } } } } } } // Checks if the parsing goal is in the chart function foundTarget(cat, linRec) { if (chart.passive[cat]) { for (var i = 0, j = chart.passive[cat].length; i < j; i++) { if (linRecsAreEqual(linRec, chart.passive[cat][i])) { return true; } } } return false; } // Filters the active edges that are relevant for tree extraction function filterActiveEdges() { var activeEdges = new Array(); for (var cat in chart.active) { activeEdges[cat] = new Array(); for (var i = 0, j = chart.active[cat].length; i < j; i++) { var currentEdge = chart.active[cat][i]; if (currentEdge.remLin.length == 0 && currentEdge.remLinRows.length == 0) { var linFound = currentEdge.linFound.slice(0); linFound.push(new Array(currentEdge.currLin)); var newActive = new ActiveEdge(currentEdge.profile, currentEdge.cat, currentEdge.name, currentEdge.args, linFound, "", "", "", "", currentEdge.children); activeEdges[cat].push(newActive); } } } return activeEdges; } // Extracts the parse trees from the chart function extractTrees(cat, linRec, activeEdges, currentTree) { var trees = new Array(); for (var i = 0, j = activeEdges[cat].length; i < j; i++) { var currentEdge = activeEdges[cat][i]; var currentNode = "(" + cat + "-" + i + ")"; if (currentTree.indexOf(currentNode) == -1 && cat == currentEdge.cat && linRecsAreEqual(linRec, currentEdge.linFound)) { var subTrees = new Array(); for (var k = 0, l = currentEdge.children.length; k < l; k++) { subTrees.push(extractTrees(currentEdge.args[k], currentEdge.children[k].slice(0), activeEdges, currentTree + currentNode)); } var combinedSubTrees = combineLins(subTrees); if (combinedSubTrees) { if (currentEdge.children.length == 0) { combinedSubTrees.push(new Array()); } for (var m = 0, n = combinedSubTrees.length; m < n; m++) { var tree = buildTree(currentEdge.profile, combinedSubTrees[m]); if (tree) { trees.push(tree); } } } } } if (trees.length == 0) { return undefined; } else { return trees; } } // Builds a tree according to the profile function buildTree(profile, args) { switch(profile.id) { case "FunApp": var tree = new Fun(profile.name); for (var i = 0, j = profile.args.length; i < j; i++) { var subTree = buildTree(profile.args[i], args); if (subTree) { tree.setArg(i, subTree); } else { return undefined; } } return tree; case "Lit": return new Fun(profile.name); case "MetaVar": return new Fun("?"); case "Arg": return args[profile.i]; case "Unify": var subTrees = new Array(); for (var i = 0, j = profile.args.length; i < j; i++) { subTrees.push(buildTree(profile.args[i], args)) } return unifySubTrees(subTrees); } } // Tree unification functions function unifySubTrees(subTrees) { var t = subTrees[0]; for (var i = 1, j = subTrees.length; i < j; i++) { t = unify(t, subTrees[i]); if (!t) { return undefined; } } return t; } function unify(a, b) { if (a.isMeta()) { return b }; if (b.isMeta()) { return a }; if (a.name == b.name && a.args.length == b.args.length) { for (var i = 0, j = a.args.length; i < j; i++) { if (!unify(a.args[i], b.args[i])) { return undefined; } } return a }; return undefined; }