From 60f8a6b647b4c7b33c520b668016982a6ae83c1e Mon Sep 17 00:00:00 2001 From: "john.j.camilleri" Date: Tue, 11 Dec 2012 15:09:16 +0000 Subject: [PATCH] Syntax editor: unwrap feature --- src/www/syntax-editor/ast.js | 27 +++++++++++-- src/www/syntax-editor/editor.js | 67 +++++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/src/www/syntax-editor/ast.js b/src/www/syntax-editor/ast.js index ed8235a79..50c417e96 100644 --- a/src/www/syntax-editor/ast.js +++ b/src/www/syntax-editor/ast.js @@ -103,6 +103,9 @@ function AST(fun, cat) { // return !this.hasParent(); } + this.getRoot = function() { + return this.root; + } this.getFun = function() { return this.currentNode.fun; } @@ -142,8 +145,8 @@ function AST(fun, cat) { } // Wrap the current node inside another node - // Doesn't check whether child_id is within in range - this.wrap = function(typeobj, child_id) { + // Doesn't check whether child_ix is within in range + this.wrap = function(typeobj, child_ix) { var subtree = new ASTNode(this.currentNode); this.currentNode.fun = typeobj.name; this.currentNode.cat = typeobj.ret; @@ -151,10 +154,28 @@ function AST(fun, cat) { for (var i in typeobj.args) { this.add(null, typeobj.args[i]); } - this.currentNode.children[child_id] = subtree; + this.currentNode.children[child_ix] = subtree; return subtree; } + // Wrap the current node inside another node + // Doesn't check whether child_ix is within in range + this.unwrap = function() { + var parent_id = this.currentID.clone(); + parent_id.get().pop(); + if (parent_id.get().length==1) { + this.root = this.currentNode; + this.currentID = new NodeID(); + } else { + var gparent_id = parent_id.clone(); + gparent_id.get().pop(); + var gparent = this.find(gparent_id); + child_ix = parent_id.clone().get().pop(); + gparent.children[child_ix] = this.currentNode; + this.currentID = parent_id; + } + } + // Determine if current node is writable (empty/no children) this.is_writable=function() { var cn = this.currentNode; diff --git a/src/www/syntax-editor/editor.js b/src/www/syntax-editor/editor.js index 1dd858f21..a8d280db5 100644 --- a/src/www/syntax-editor/editor.js +++ b/src/www/syntax-editor/editor.js @@ -40,7 +40,7 @@ function Editor(gm,opts) { t.wrap_candidates(); }), unwrap_button: button("Unwrap", function(){ - t.wrap_candidates(); + t.unwrap(); }), refinements: div_id("refinements"), @@ -56,7 +56,7 @@ function Editor(gm,opts) { appendChildren(this.ui.actionbar, [ t.ui.clear_button, t.ui.wrap_button, - // t.ui.unwrap_button, + t.ui.unwrap_button, t.ui.refinements ]); @@ -157,6 +157,7 @@ Editor.prototype.start_fresh=function () { t.ast = new AST(null, t.get_startcat()); if (t.options.initial.abstr) { t.import_ast(t.options.initial.abstr); + t.options.initial.abstr = null; // don't use again } t.update_current_node(); clear(t.ui.lin); @@ -316,9 +317,9 @@ Editor.prototype.wrap_candidates = function() { } // Display wrap refinements - function addClickHandler(fun, child_id) { + function addClickHandler(fun, child_ix) { return function() { - t.wrap.apply(t,[fun, child_id]); + t.wrap.apply(t,[fun, child_ix]); } } t.ui.refinements.innerHTML = "Wrap with: "; @@ -327,20 +328,20 @@ Editor.prototype.wrap_candidates = function() { var fun = typeobj.name; // Find valid child ids - var child_ids = []; + var child_ixs = []; for (var a in typeobj.args) { if (typeobj.args[a] == cat) { - child_ids.push(a); + child_ixs.push(a); } } - // if (child_ids.length < 2) { + // if (child_ixs.length < 2) { // var ref = t.add_refinement(fun); // ref.onclick = addClickHandler(typeobj.name, a); // } else { // Show a refinement for each potential child position - for (var c in child_ids) { - var id = child_ids[c]; + for (var c in child_ixs) { + var id = child_ixs[c]; var label = fun; for (var a in typeobj.args) { if (a == id) @@ -359,7 +360,7 @@ Editor.prototype.wrap_candidates = function() { } // Wrap the current node inside another function -Editor.prototype.wrap = function(fun, child_id) { +Editor.prototype.wrap = function(fun, child_ix) { var t = this; var typeobj = t.grammar_constructors.funs[fun]; @@ -372,7 +373,7 @@ Editor.prototype.wrap = function(fun, child_id) { } // do actual replacement - t.ast.wrap(typeobj, child_id); + t.ast.wrap(typeobj, child_ix); // refresh stuff t.redraw_tree(); @@ -381,6 +382,50 @@ Editor.prototype.wrap = function(fun, child_id) { t.update_current_node(); } +// Unwrap a node by deleting a fun with same input/output category +Editor.prototype.unwrap = function() { + var t = this; + var fun = t.ast.getFun(); + var typeobj = t.grammar_constructors.funs[fun]; + + // Cannot unwrap when at root + if (t.ast.atRoot()) { + alert("It is not possible to unwrap the top node"); + return; + } + + var child = t.ast.getCurrentNode(); + var parent = t.ast.getParent(); + + // TODO: We can also unwrap when at level one and cats don't match + + // Check if unwrap is possible + if (parent.children.length==1 && + (parent.cat==child.cat || parent==t.ast.getRoot()) + ) { + + // do actual unwrap + t.ast.unwrap(); + + // if root node changed, potentially change startcat + var rootcat = t.ast.getRoot().cat; + if (rootcat != t.get_startcat()) { + var old_val = t.clear_on_change_startcat; + t.clear_on_change_startcat = false; + t.gm.change_startcat(rootcat); + t.clear_on_change_startcat = old_val; + } + + // refresh stuff + t.redraw_tree(); + t.update_linearisation(); + // t.ast.toNextHole(); + // t.update_current_node(); + } else { + alert("Cannot unwrap this node"); + } +} + // Generate random subtree from current node Editor.prototype.generate_random = function() { var t = this;