From 3e5dac8ed4c4e3d081b815c4ac3c3047c8ca926d Mon Sep 17 00:00:00 2001 From: "john.j.camilleri" Date: Fri, 16 Nov 2012 14:35:37 +0000 Subject: [PATCH] Syntax editor: work on importing AST as string (eg for generate random) But it's still not complete. Need an efficient way of getting the cat info to accompany funs. --- src/www/syntax-editor/README.md | 2 + src/www/syntax-editor/js/ast.js | 132 ++++++++++++++++++------ src/www/syntax-editor/js/editor.js | 55 ++++++++-- src/www/syntax-editor/js/editor_menu.js | 15 ++- 4 files changed, 160 insertions(+), 44 deletions(-) diff --git a/src/www/syntax-editor/README.md b/src/www/syntax-editor/README.md index e47d67518..647792d48 100644 --- a/src/www/syntax-editor/README.md +++ b/src/www/syntax-editor/README.md @@ -13,6 +13,8 @@ Tested with latest Chrome and Firefox. ## TODO +- Clicking on tokens to select tree node +- Use local caching - Enter string/float/int literals - UI issue with DisambPhrasebookEng - more prominence to Disamb-linearizations diff --git a/src/www/syntax-editor/js/ast.js b/src/www/syntax-editor/js/ast.js index 0bcb75a16..651f949cd 100644 --- a/src/www/syntax-editor/js/ast.js +++ b/src/www/syntax-editor/js/ast.js @@ -1,25 +1,40 @@ /* --- Tree representation -------------------------------------------------- */ -function Tree(value) { - - // Create node as JS object - var createNode = function(value, children) { - var node = { - value: value, - children: [], - hasChildren: function(){ return this.children.length > 0; } - }; - if (children != undefined) - for (c in children) - node.children.push( createNode(children[c],[]) ); - return node; +function Node(value, children) { + this.value = value; + this.children = []; + if (children != undefined) + for (c in children) + this.children.push( new Node(children[c],[]) ); + this.hasChildren = function(){ + return this.children.length > 0; } - this.root = createNode(value, []); + // generic HOF for traversing tree + this.traverse = function(f) { + function visit(node) { + f(node); + for (i in node.children) { + visit(node.children[i]); + } + } + visit(this); + } +} + +function Tree(value) { + this.root = new Node(value, []); // add value as child of id this.add = function(id, value, children) { var x = this.find(id); - x.children.push( createNode(value, children) ); + x.children.push( new Node(value, children) ); + } + + // set tree at given id to + this.setSubtree = function(id, node) { + var x = this.find(id); + x.value = node.value; + x.children = node.children; } // id should be a list of child indices [0,1,0] @@ -40,6 +55,20 @@ function Tree(value) { return undefined; return node; } + + // generic HOF for traversing tree + this.traverse = function(f) { + function visit(id, node) { + f(node); + for (i in node.children) { + var newid = new NodeID(id); + newid.add(parseInt(i)); + visit(newid, node.children[i]); + } + } + visit(new NodeID(), this.root); + } + } /* --- ID for a node in a tree ---------------------------------------------- */ @@ -77,12 +106,12 @@ function NodeID(x) { /* --- Abstract Syntax Tree (with state)------------------------------------- */ function AST(fun, cat) { - function Node(fun, cat) { + function ASTNode(fun, cat) { this.fun = fun; this.cat = cat; } - this.tree = new Tree(new Node(fun, cat)); + this.tree = new Tree(new ASTNode(fun, cat)); this.current = new NodeID(); // current id in tree this.getFun = function() { @@ -98,8 +127,14 @@ function AST(fun, cat) { this.tree.find(this.current).value.cat = c; } + // Add a single fun at current node this.add = function(fun, cat) { - this.tree.add(this.current, new Node(fun,cat)); + this.tree.add(this.current, new ASTNode(fun,cat)); + } + + // Set entire subtree at current node + this.setSubtree = function(node) { + this.tree.setSubtree(this.current, node); } // Clear children of current node @@ -107,19 +142,6 @@ function AST(fun, cat) { this.tree.find(this.current).children = []; } - // generic HOF for traversing tree - this.traverse = function(f) { - function visit(id, node) { - f(node); - for (i in node.children) { - var newid = new NodeID(id); - newid.add(parseInt(i)); - visit(newid, node.children[i]); - } - } - visit(new NodeID(), this.tree.root); - } - // Move current ID to next hole this.toNextHole = function() { var id = new NodeID(this.current); @@ -149,6 +171,11 @@ function AST(fun, cat) { this.current.add(i); } + // + this.traverse = function(f) { + this.tree.traverse(f); + } + // Return tree as string this.toString = function() { var s = ""; @@ -157,13 +184,52 @@ function AST(fun, cat) { if (node.children.length == 0) return; for (i in node.children) { - s += "("; + s += " ("; visit(node.children[i]); - s += ")"; + s += ")"; } } visit(this.tree.root); return s; } + + // Parse AST string into node tree + this.parseTree = function(str) { + + function trim(str) { + return str.trim().replace(/^\(\s*(.*)\s*\)$/, "$1"); + } + + function visit(node, str) { + var parts = []; + var ix_last = 0; + var par_cnt = 0; + for (i in str) { + if (str[i] == " ") { + if (par_cnt == 0) { + parts.push(trim(str.substring(ix_last, i))); + ix_last = i; + } + } + else if (str[i] == "(") + par_cnt++; + else if (str[i] == ")") + par_cnt--; + } + parts.push(trim(str.substring(ix_last))); + + var fun = parts.shift(); + var cat = null; // will be filled later + + node.value = new ASTNode(fun, cat); + for (i in parts) { + node.children.push(new Node()); + visit(node.children[i], parts[i]); + } + } + var tree = new Node(); + visit(tree, str); + return tree; + } } diff --git a/src/www/syntax-editor/js/editor.js b/src/www/syntax-editor/js/editor.js index 608770edb..b0663b816 100644 --- a/src/www/syntax-editor/js/editor.js +++ b/src/www/syntax-editor/js/editor.js @@ -101,24 +101,22 @@ Editor.prototype.get_refinements=function(cat) { }; var err = function(data){ clear(t.ui.refinements); - alert("No refinements"); + alert("Error"); }; t.server.browse(args, cont, err); } Editor.prototype.select_refinement=function(fun) { with (this) { - clear(ui.refinements); + ui.refinements.innerHTML = "..."; ast.removeChildren(); ast.setFun(fun); -// redraw_tree(); - var args = { id: fun, format: "json" }; var err = function(data){ - alert("no refinements"); + alert("Error"); }; server.browse(args, bind(complete_refinement,this), err); } @@ -148,7 +146,6 @@ Editor.prototype.complete_refinement=function(data) { // Select next hole & get its refinements ast.toNextHole(); update_current_node(); - get_refinements(); } } @@ -166,7 +163,9 @@ Editor.prototype.redraw_tree=function() { var elem = node; // function from support.js function visit(container, id, node) { var container2 = empty_class("div", "node"); - var label = ((node.value.fun) ? node.value.fun : "?") + " : " + node.value.cat; + var label = + ((node.value.fun) ? node.value.fun : "?") + " : " + + ((node.value.cat) ? node.value.cat : "?"); var current = id.equals(t.ast.current); var element = elem("a", {class:(current?"current":"")}, [text(label)]); element.onclick = function() { @@ -217,3 +216,45 @@ Editor.prototype.update_linearisation=function(){ } } +// +Editor.prototype.delete_refinement = function() { + var t = this; + t.ast.removeChildren(); + t.ast.setFun(null); + t.redraw_tree(); +// t.get_refinements(); +} + +// Generate random subtree from current node +Editor.prototype.generate_random = function() { + var t = this; + t.ui.refinements.innerHTML = "..."; + t.ast.removeChildren(); + var args = { + cat: t.ast.getCat(), + limit: 1 + }; + var cont = function(data){ + // Build tree of just fun, then populate with cats + var tree = t.ast.parseTree(data[0].tree); + tree.traverse(function(node){ + var info = t.lookup_fun(node.value.fun); + node.value.cat = info.cat; + }); + t.ast.setSubtree(tree); + t.redraw_tree(); + }; + var err = function(data){ + alert("Error"); + }; + server.get_random(args, cont, err); +} + +// Look up information for a function, hopefully from cache +Editor.prototype.lookup_fun = function(fun) { + // TODO + return { + cat: null + } +} + diff --git a/src/www/syntax-editor/js/editor_menu.js b/src/www/syntax-editor/js/editor_menu.js index ce0894ee0..c5e2e9912 100644 --- a/src/www/syntax-editor/js/editor_menu.js +++ b/src/www/syntax-editor/js/editor_menu.js @@ -26,11 +26,19 @@ function EditorMenu(editor,opts) { id: "to_menu", multiple: "multiple", class: "hidden" - } ) + }), + clear_button: button("Clear", function(){ + t.editor.delete_refinement(); + }), + random_button: button("Random", function(){ + t.editor.generate_random(); + }), }; with(this.ui) { appendChildren(this.container, [text(" Startcat: "),startcat_menu]); appendChildren(this.container, [text(" To: "), to_toggle, to_menu]); +// appendChildren(this.container, [clear_button, random_button]); + appendChildren(this.container, [clear_button]); startcat_menu.onchange=bind(this.change_startcat,this); to_menu.onchange=bind(this.change_language,this); } @@ -157,9 +165,8 @@ EditorMenu.prototype.update_language_menu=function(menu,grammar) { menu.appendChild(option(lp,ln)); } } - - insertFirst(menu,option("All","All")); - menu.value="All"; + // insertFirst(menu,option("All","All")); + // menu.value="All"; }