forked from GitHub/gf-core
Syntax editor: add wrap feature
This commit is contained in:
@@ -35,6 +35,10 @@ function NodeID(x) {
|
|||||||
return new NodeID( this );
|
return new NodeID( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return NodeID as string
|
||||||
|
this.toString = function() {
|
||||||
|
return this.id.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Abstract Syntax Tree (with state)------------------------------------- */
|
/* --- Abstract Syntax Tree (with state)------------------------------------- */
|
||||||
@@ -42,7 +46,7 @@ function NodeID(x) {
|
|||||||
function ASTNode(data) {
|
function ASTNode(data) {
|
||||||
for (var d in data) this[d]=data[d];
|
for (var d in data) this[d]=data[d];
|
||||||
this.children = [];
|
this.children = [];
|
||||||
for (var c in data.children) {
|
if (data) for (var c in data.children) {
|
||||||
this.children.push( new ASTNode(data.children[c]) );
|
this.children.push( new ASTNode(data.children[c]) );
|
||||||
}
|
}
|
||||||
this.hasChildren = function(){
|
this.hasChildren = function(){
|
||||||
@@ -103,6 +107,10 @@ function AST(fun, cat) {
|
|||||||
this.currentNode.cat = c;
|
this.currentNode.cat = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.hasParent = function() {
|
||||||
|
return this.currentID.get().length > 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Add a single type dependency at current node
|
// Add a single type dependency at current node
|
||||||
this.addDep = function(k, type) {
|
this.addDep = function(k, type) {
|
||||||
// Add unassigned type variable to current
|
// Add unassigned type variable to current
|
||||||
@@ -115,7 +123,7 @@ function AST(fun, cat) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a single fun at current node
|
// Add a node as child of current node
|
||||||
this.add = function(fun, cat) {
|
this.add = function(fun, cat) {
|
||||||
var node = newNode(fun,cat);
|
var node = newNode(fun,cat);
|
||||||
this._add(this.currentID, node);
|
this._add(this.currentID, node);
|
||||||
@@ -128,6 +136,19 @@ function AST(fun, cat) {
|
|||||||
x.children.push(node);
|
x.children.push(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrap the current node inside another node
|
||||||
|
this.wrap = function(typeobj, childid) {
|
||||||
|
var subtree = new ASTNode(this.currentNode);
|
||||||
|
this.currentNode.fun = typeobj.name.join(" ");
|
||||||
|
this.currentNode.cat = typeobj.ret;
|
||||||
|
this.currentNode.children = [];
|
||||||
|
for (var i in typeobj.args) {
|
||||||
|
this.add(null, typeobj.args[i]);
|
||||||
|
}
|
||||||
|
this.currentNode.children[i] = subtree;
|
||||||
|
return subtree;
|
||||||
|
}
|
||||||
|
|
||||||
// Determine if current node is writable (empty/no children)
|
// Determine if current node is writable (empty/no children)
|
||||||
this.is_writable=function() {
|
this.is_writable=function() {
|
||||||
var cn = this.currentNode;
|
var cn = this.currentNode;
|
||||||
|
|||||||
@@ -142,6 +142,29 @@ Editor.prototype.start_fresh=function () {
|
|||||||
|
|
||||||
/* --- Functions for handling tree manipulation ----------------------------- */
|
/* --- Functions for handling tree manipulation ----------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
Editor.prototype.add_refinement=function(t,fun,callback,disable_destructive) {
|
||||||
|
// var t = this;
|
||||||
|
// hide refinement if identical to current fun?
|
||||||
|
|
||||||
|
var opt = span_class("refinement", text(fun));
|
||||||
|
opt.onclick = bind(function(){
|
||||||
|
callback(this.innerHTML)
|
||||||
|
}, opt);
|
||||||
|
|
||||||
|
// If refinement would be destructive, disable it
|
||||||
|
if (disable_destructive) {
|
||||||
|
var blank = t.ast.is_writable();
|
||||||
|
var typeobj = t.lookup_fun(fun);
|
||||||
|
var inplace = t.ast.fits_in_place(typeobj);
|
||||||
|
if (!blank && !inplace) {
|
||||||
|
opt.classList.add("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ui.refinements.appendChild(opt);
|
||||||
|
}
|
||||||
|
|
||||||
// Show refinements for given cat (usually that of current node)
|
// Show refinements for given cat (usually that of current node)
|
||||||
Editor.prototype.get_refinements=function(cat) {
|
Editor.prototype.get_refinements=function(cat) {
|
||||||
var t = this;
|
var t = this;
|
||||||
@@ -155,23 +178,8 @@ Editor.prototype.get_refinements=function(cat) {
|
|||||||
var cont = function(data){
|
var cont = function(data){
|
||||||
clear(t.ui.refinements);
|
clear(t.ui.refinements);
|
||||||
for (var pi in data.producers) {
|
for (var pi in data.producers) {
|
||||||
// hide refinement if identical to current fun?
|
|
||||||
|
|
||||||
var fun = data.producers[pi];
|
var fun = data.producers[pi];
|
||||||
var opt = span_class("refinement", text(fun));
|
t.add_refinement(t, fun, bind(t.select_refinement,t), true);
|
||||||
opt.onclick = bind(function(){
|
|
||||||
t.select_refinement(this.innerHTML)
|
|
||||||
}, opt);
|
|
||||||
|
|
||||||
// If refinement would be destructive, disable it
|
|
||||||
var blank = t.ast.is_writable();
|
|
||||||
var typeobj = t.lookup_fun(fun);
|
|
||||||
var inplace = t.ast.fits_in_place(typeobj);
|
|
||||||
if (!blank && !inplace) {
|
|
||||||
opt.classList.add("disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
t.ui.refinements.appendChild(opt);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var err = function(data){
|
var err = function(data){
|
||||||
@@ -238,6 +246,84 @@ Editor.prototype.update_current_node=function(newID) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear current node and all its children
|
||||||
|
Editor.prototype.clear_node = function() {
|
||||||
|
var t = this;
|
||||||
|
t.ast.removeChildren();
|
||||||
|
t.ast.setFun(null);
|
||||||
|
t.redraw_tree();
|
||||||
|
t.get_refinements();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show wrap candidates
|
||||||
|
Editor.prototype.wrap_candidates = function() {
|
||||||
|
var t = this;
|
||||||
|
|
||||||
|
// we need to end with this
|
||||||
|
var cat = t.ast.getCat();
|
||||||
|
|
||||||
|
// if no parent, then cat can be anything as long
|
||||||
|
// as the current tree fits somewhere
|
||||||
|
var refinements = [];
|
||||||
|
for (var i in t.grammar_constructors.funs) {
|
||||||
|
var obj = t.grammar_constructors.funs[i];
|
||||||
|
if (elem(cat, obj.args)) {
|
||||||
|
if (!t.ast.hasParent() || obj.ret==cat) {
|
||||||
|
refinements.push(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refinements.length == 0) {
|
||||||
|
alert("No functions exist which can wrap the selected node.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ui.refinements.innerHTML = "Wrap with: ";
|
||||||
|
for (var i in refinements) {
|
||||||
|
var fun = refinements[i].name;
|
||||||
|
t.add_refinement(t, fun, bind(t.wrap,t), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap the current node inside another function
|
||||||
|
Editor.prototype.wrap = function(fun,childid) {
|
||||||
|
var t = this;
|
||||||
|
|
||||||
|
var typeobj = t.grammar_constructors.funs[fun];
|
||||||
|
|
||||||
|
// do actual replacement
|
||||||
|
t.ast.wrap(typeobj, childid);
|
||||||
|
|
||||||
|
// refresh stuff
|
||||||
|
t.redraw_tree();
|
||||||
|
t.update_linearisation();
|
||||||
|
t.ast.toNextHole();
|
||||||
|
t.update_current_node();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate random subtree from current node
|
||||||
|
Editor.prototype.generate_random = function() {
|
||||||
|
var t = this;
|
||||||
|
t.ast.removeChildren();
|
||||||
|
var args = {
|
||||||
|
cat: t.ast.getCat(),
|
||||||
|
limit: 1
|
||||||
|
};
|
||||||
|
if (!args.cat) {
|
||||||
|
alert("Missing category at current node");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var cont = function(data){
|
||||||
|
var tree = data[0].tree;
|
||||||
|
t.import_ast(tree);
|
||||||
|
};
|
||||||
|
var err = function(data){
|
||||||
|
alert("Error");
|
||||||
|
};
|
||||||
|
server.get_random(args, cont, err);
|
||||||
|
}
|
||||||
|
|
||||||
Editor.prototype.redraw_tree=function() {
|
Editor.prototype.redraw_tree=function() {
|
||||||
var t = this;
|
var t = this;
|
||||||
var elem = node; // function from support.js
|
var elem = node; // function from support.js
|
||||||
@@ -298,37 +384,6 @@ Editor.prototype.update_linearisation=function(){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear current node and all its children
|
|
||||||
Editor.prototype.clear_node = 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.ast.removeChildren();
|
|
||||||
var args = {
|
|
||||||
cat: t.ast.getCat(),
|
|
||||||
limit: 1
|
|
||||||
};
|
|
||||||
if (!args.cat) {
|
|
||||||
alert("Missing category at current node");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var cont = function(data){
|
|
||||||
var tree = data[0].tree;
|
|
||||||
t.import_ast(tree);
|
|
||||||
};
|
|
||||||
var err = function(data){
|
|
||||||
alert("Error");
|
|
||||||
};
|
|
||||||
server.get_random(args, cont, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import AST from string representation, setting at current node
|
// Import AST from string representation, setting at current node
|
||||||
Editor.prototype.import_ast = function(abstr) {
|
Editor.prototype.import_ast = function(abstr) {
|
||||||
var t = this;
|
var t = this;
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ function EditorMenu(editor,opts) {
|
|||||||
multiple: "multiple",
|
multiple: "multiple",
|
||||||
class: "hidden"
|
class: "hidden"
|
||||||
}),
|
}),
|
||||||
// wrap_button: button("Wrap", function(){
|
wrap_button: button("Wrap", function(){
|
||||||
// t.editor.wrap();
|
t.editor.wrap_candidates();
|
||||||
// }),
|
}),
|
||||||
clear_button: button("Clear", function(){
|
clear_button: button("Clear", function(){
|
||||||
t.editor.clear_node();
|
t.editor.clear_node();
|
||||||
}),
|
}),
|
||||||
@@ -72,6 +72,7 @@ function EditorMenu(editor,opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
appendChildren(t.container, [t.ui.clear_button]);
|
appendChildren(t.container, [t.ui.clear_button]);
|
||||||
|
appendChildren(t.container, [t.ui.wrap_button]);
|
||||||
if (t.options.show.random_button) {
|
if (t.options.show.random_button) {
|
||||||
appendChildren(t.container, [t.ui.random_button]);
|
appendChildren(t.container, [t.ui.random_button]);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user