forked from GitHub/gf-core
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.
This commit is contained in:
@@ -13,6 +13,8 @@ Tested with latest Chrome and Firefox.
|
|||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
|
- Clicking on tokens to select tree node
|
||||||
|
- Use local caching
|
||||||
- Enter string/float/int literals
|
- Enter string/float/int literals
|
||||||
- UI issue with DisambPhrasebookEng
|
- UI issue with DisambPhrasebookEng
|
||||||
- more prominence to Disamb-linearizations
|
- more prominence to Disamb-linearizations
|
||||||
|
|||||||
@@ -1,25 +1,40 @@
|
|||||||
/* --- Tree representation -------------------------------------------------- */
|
/* --- Tree representation -------------------------------------------------- */
|
||||||
function Tree(value) {
|
function Node(value, children) {
|
||||||
|
this.value = value;
|
||||||
// Create node as JS object
|
this.children = [];
|
||||||
var createNode = function(value, children) {
|
if (children != undefined)
|
||||||
var node = {
|
for (c in children)
|
||||||
value: value,
|
this.children.push( new Node(children[c],[]) );
|
||||||
children: [],
|
this.hasChildren = function(){
|
||||||
hasChildren: function(){ return this.children.length > 0; }
|
return this.children.length > 0;
|
||||||
};
|
|
||||||
if (children != undefined)
|
|
||||||
for (c in children)
|
|
||||||
node.children.push( createNode(children[c],[]) );
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// add value as child of id
|
||||||
this.add = function(id, value, children) {
|
this.add = function(id, value, children) {
|
||||||
var x = this.find(id);
|
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]
|
// id should be a list of child indices [0,1,0]
|
||||||
@@ -40,6 +55,20 @@ function Tree(value) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
return node;
|
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 ---------------------------------------------- */
|
/* --- ID for a node in a tree ---------------------------------------------- */
|
||||||
@@ -77,12 +106,12 @@ function NodeID(x) {
|
|||||||
/* --- Abstract Syntax Tree (with state)------------------------------------- */
|
/* --- Abstract Syntax Tree (with state)------------------------------------- */
|
||||||
function AST(fun, cat) {
|
function AST(fun, cat) {
|
||||||
|
|
||||||
function Node(fun, cat) {
|
function ASTNode(fun, cat) {
|
||||||
this.fun = fun;
|
this.fun = fun;
|
||||||
this.cat = cat;
|
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.current = new NodeID(); // current id in tree
|
||||||
|
|
||||||
this.getFun = function() {
|
this.getFun = function() {
|
||||||
@@ -98,8 +127,14 @@ function AST(fun, cat) {
|
|||||||
this.tree.find(this.current).value.cat = c;
|
this.tree.find(this.current).value.cat = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a single fun at current node
|
||||||
this.add = function(fun, cat) {
|
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
|
// Clear children of current node
|
||||||
@@ -107,19 +142,6 @@ function AST(fun, cat) {
|
|||||||
this.tree.find(this.current).children = [];
|
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
|
// Move current ID to next hole
|
||||||
this.toNextHole = function() {
|
this.toNextHole = function() {
|
||||||
var id = new NodeID(this.current);
|
var id = new NodeID(this.current);
|
||||||
@@ -149,6 +171,11 @@ function AST(fun, cat) {
|
|||||||
this.current.add(i);
|
this.current.add(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
this.traverse = function(f) {
|
||||||
|
this.tree.traverse(f);
|
||||||
|
}
|
||||||
|
|
||||||
// Return tree as string
|
// Return tree as string
|
||||||
this.toString = function() {
|
this.toString = function() {
|
||||||
var s = "";
|
var s = "";
|
||||||
@@ -157,13 +184,52 @@ function AST(fun, cat) {
|
|||||||
if (node.children.length == 0)
|
if (node.children.length == 0)
|
||||||
return;
|
return;
|
||||||
for (i in node.children) {
|
for (i in node.children) {
|
||||||
s += "(";
|
s += " (";
|
||||||
visit(node.children[i]);
|
visit(node.children[i]);
|
||||||
s += ")";
|
s += ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visit(this.tree.root);
|
visit(this.tree.root);
|
||||||
return s;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,24 +101,22 @@ Editor.prototype.get_refinements=function(cat) {
|
|||||||
};
|
};
|
||||||
var err = function(data){
|
var err = function(data){
|
||||||
clear(t.ui.refinements);
|
clear(t.ui.refinements);
|
||||||
alert("No refinements");
|
alert("Error");
|
||||||
};
|
};
|
||||||
t.server.browse(args, cont, err);
|
t.server.browse(args, cont, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
Editor.prototype.select_refinement=function(fun) {
|
Editor.prototype.select_refinement=function(fun) {
|
||||||
with (this) {
|
with (this) {
|
||||||
clear(ui.refinements);
|
ui.refinements.innerHTML = "...";
|
||||||
ast.removeChildren();
|
ast.removeChildren();
|
||||||
ast.setFun(fun);
|
ast.setFun(fun);
|
||||||
// redraw_tree();
|
|
||||||
|
|
||||||
var args = {
|
var args = {
|
||||||
id: fun,
|
id: fun,
|
||||||
format: "json"
|
format: "json"
|
||||||
};
|
};
|
||||||
var err = function(data){
|
var err = function(data){
|
||||||
alert("no refinements");
|
alert("Error");
|
||||||
};
|
};
|
||||||
server.browse(args, bind(complete_refinement,this), err);
|
server.browse(args, bind(complete_refinement,this), err);
|
||||||
}
|
}
|
||||||
@@ -148,7 +146,6 @@ Editor.prototype.complete_refinement=function(data) {
|
|||||||
// Select next hole & get its refinements
|
// Select next hole & get its refinements
|
||||||
ast.toNextHole();
|
ast.toNextHole();
|
||||||
update_current_node();
|
update_current_node();
|
||||||
get_refinements();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +163,9 @@ Editor.prototype.redraw_tree=function() {
|
|||||||
var elem = node; // function from support.js
|
var elem = node; // function from support.js
|
||||||
function visit(container, id, node) {
|
function visit(container, id, node) {
|
||||||
var container2 = empty_class("div", "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 current = id.equals(t.ast.current);
|
||||||
var element = elem("a", {class:(current?"current":"")}, [text(label)]);
|
var element = elem("a", {class:(current?"current":"")}, [text(label)]);
|
||||||
element.onclick = function() {
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,11 +26,19 @@ function EditorMenu(editor,opts) {
|
|||||||
id: "to_menu",
|
id: "to_menu",
|
||||||
multiple: "multiple",
|
multiple: "multiple",
|
||||||
class: "hidden"
|
class: "hidden"
|
||||||
} )
|
}),
|
||||||
|
clear_button: button("Clear", function(){
|
||||||
|
t.editor.delete_refinement();
|
||||||
|
}),
|
||||||
|
random_button: button("Random", function(){
|
||||||
|
t.editor.generate_random();
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
with(this.ui) {
|
with(this.ui) {
|
||||||
appendChildren(this.container, [text(" Startcat: "),startcat_menu]);
|
appendChildren(this.container, [text(" Startcat: "),startcat_menu]);
|
||||||
appendChildren(this.container, [text(" To: "), to_toggle, to_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);
|
startcat_menu.onchange=bind(this.change_startcat,this);
|
||||||
to_menu.onchange=bind(this.change_language,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));
|
menu.appendChild(option(lp,ln));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// insertFirst(menu,option("All","All"));
|
||||||
insertFirst(menu,option("All","All"));
|
// menu.value="All";
|
||||||
menu.value="All";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user