diff --git a/src/editor/simple/TODO b/src/editor/simple/TODO
index 9e064dabc..df64d2b1e 100644
--- a/src/editor/simple/TODO
+++ b/src/editor/simple/TODO
@@ -22,6 +22,8 @@
+ Show lincat and lin before params and opers below
+ Create a new concrete syntax by copying an existing one.
- Easy access to compute_concrete from the editor
+- Instead of starting with an empty grammar, start a new grammar by copying
+ an example.
+ compile only the uploaded grammar even if other grammars are present
+ 'flags startcat' is needed for grammars with only one category (since the
diff --git a/src/editor/simple/about.html b/src/editor/simple/about.html
index 5c9f88879..40d9df347 100644
--- a/src/editor/simple/about.html
+++ b/src/editor/simple/about.html
@@ -137,6 +137,11 @@ Also,
is usually easier than creating something new from scratch.
(If the abstract syntax is currently open, the new conrete syntax will
start out empty.)
+
When adding a new concrete syntax, you normally pick one of the supported
+ languages from a list. The language code and the file name is determined
+ automatically. But you can also pick Other from the list and change
+ the language code afterwards to add a concrete syntax for a language
+ that is not in the list.
Error checks:
@@ -180,7 +185,7 @@ to be accessed from multiple devices.
- Last modified: Mon Mar 28 16:24:24 CEST 2011
+ Last modified: Fri May 6 17:24:02 CEST 2011
TH
diff --git a/src/editor/simple/editor.js b/src/editor/simple/editor.js
index d08948be5..f6e47fc5d 100644
--- a/src/editor/simple/editor.js
+++ b/src/editor/simple/editor.js
@@ -142,22 +142,21 @@ function lang1(name) {
}
var languages =
map(lang1,"Amharic Arabic Bulgarian Catalan Danish Dutch English Finnish French German Hindi Ina/Interlingua Italian Latin Norwegian Polish Ron/Romanian Russian Spanish Swedish Thai Turkish Urdu".split(" "));
-//languages.push(lang("Other","Other"));
+languages.push(lang("Other","Other"));
var langname={};
-//for(var i=0;i0
- ? "a copy of "+langname[g.concretes[g.current-1].langcode]
+ ? "a copy of "+concname(g.concretes[g.current-1].langcode)
:"scratch";
file.appendChild(p(text("You are about to create a new concrete syntax by starting from "+from+".")));
file.appendChild(p(text("Pick a language for the new concrete syntax:")));
- file.appendChild(node("ul",{},list));
+ file.appendChild(node("ul",{class:"languages"},list));
}
function new_concrete(code) {
return { langcode:code,params:[],lincats:[],opers:[],lins:[] };
}
+function adjust_opens(cnc,oldcode,code) {
+ for(var oi in cnc.opens)
+ for(var li in rgl_modules)
+ if(cnc.opens[oi]==rgl_modules[li]+oldcode)
+ cnc.opens[oi]=rgl_modules[li]+code;
+}
+
function add_concrete2(ix,code) {
var g=local.get(ix);
var cs=g.concretes;
@@ -189,10 +195,7 @@ function add_concrete2(ix,code) {
var oldcode=cs[g.current-1].langcode;
var cnc=g.concretes[ci];
cnc.langcode=code;
- for(var oi in cnc.opens)
- for(var li in rgl_modules)
- if(cnc.opens[oi]==rgl_modules[li]+oldcode)
- cnc.opens[oi]=rgl_modules[li]+code;
+ adjust_opens(cnc,oldcode,code);
}
else
cs.push(new_concrete(code))
@@ -216,7 +219,7 @@ function delete_concrete(g,ci) {
var ok=c.params.length==0 && c.lincats.length==0 && c.opers.length==0
&& c.lins.length==0
|| confirm("Do you really want to delete the concrete syntax for "+
- langname[c.langcode]+"?");
+ concname(c.langcode)+"?");
if(ok) {
g.concretes=delete_ix(g.concretes,ci)
if(g.current && g.current-1>=ci) g.current--;
@@ -233,11 +236,10 @@ function draw_filebar(g) {
var cs=g.concretes;
function del(ci) { return function() { delete_concrete(g,ci); }}
function open_conc(i) { return function() {open_concrete(g,1*i); }}
-// for(var i=0;i0) el.appendChild(sep(" → "));
el.appendChild(check(t[i],ident(t[i])));
@@ -432,8 +432,21 @@ function edit_name(g,el) {
function draw_concrete(g,i) {
var conc=g.concretes[i];
+ function edit_langcode(g,el) {
+ function change_langcode(code) {
+ var err=check_name(g.basename+code,"Name of concrete syntax");
+ if(err) return err;
+ adjust_opens(conc,conc.langcode,code);
+ conc.langcode=code;
+ reload_grammar(g);
+ }
+ string_editor(el,conc.langcode,change_langcode)
+ }
return div_id("file",
- [kw("concrete "),ident(g.basename+conc.langcode),
+ [kw("concrete "),
+ ident(g.basename),
+ editable("span",ident(conc.langcode),g,
+ edit_langcode,"Change language"),
kw(" of "),ident(g.basename),sep(" = "),
indent([extensible([kw("open "),draw_opens(g,i)])]),
indent([kw("lincat"),draw_lincats(g,i)]),
@@ -570,18 +583,13 @@ function draw_lincats(g,i) {
var conc=g.concretes[i];
function edit(c) {
return function(g,el) {
- function check(s,cont) {
- function check2(msg) {
- if(!msg) {
- if(c.template) conc.lincats.push({cat:c.cat,type:s});
- else c.type=s;
- reload_grammar(g);
- }
- cont(msg);
- }
- check_exp(s,check2);
+ function ok(s) {
+ if(c.template) conc.lincats.push({cat:c.cat,type:s});
+ else c.type=s;
+ reload_grammar(g);
+ return null;
}
- string_editor(el,c.type,check,true)
+ string_editor(el,c.type,ok)
}
}
function del(c) { return function() { delete_lincat(g,i,c); } }
@@ -708,19 +716,14 @@ function draw_lins(g,i) {
var conc=g.concretes[i];
function edit(f) {
return function(g,el) {
- function check(s,cont) {
- function check2(msg) {
- if(!msg) {
- if(f.template)
- conc.lins.push({fun:f.fun,args:f.args,lin:s});
- else f.lin=s;
- reload_grammar(g);
- }
- cont(msg);
- }
- check_exp(s,check2);
+ function ok(s) {
+ if(f.template)
+ conc.lins.push({fun:f.fun,args:f.args,lin:s});
+ else f.lin=s;
+ reload_grammar(g);
+ return null;
}
- string_editor(el,f.lin,check,true)
+ string_editor(el,f.lin,ok)
}
}
function del(fun) { return function () { delete_lin(g,i,fun); } }
@@ -765,55 +768,25 @@ function draw_lins(g,i) {
/* -------------------------------------------------------------------------- */
-function with_dir(cont) {
+function upload(g) {
var dir=local.get("dir","");
- if(/^\/tmp\//.test(dir)) cont(dir);
- else ajax_http_get("/new",
+ if(dir) upload2(g,dir);
+ else ajax_http_get("upload.cgi?dir",
function(dir) {
local.put("dir",dir);
- cont(dir);
+ upload2(g,dir);
});
}
-// Send a command to the GF shell
-function gfshell(cmd,cont) {
- with_dir(function(dir) {
- var enc=encodeURIComponent;
- ajax_http_get("/gfshell?dir="+enc(dir)+"&command="+enc(cmd),cont)
- })
-}
-
-// Check the syntax of an expression
-function check_exp(s,cont) {
- function check(gf_message) {
- debug("cc "+s+" = "+gf_message);
- cont(/parse error/.test(gf_message) ? "parse error" : null);
- }
- gfshell("cc "+s,check);
-}
-
-// Upload the grammar to the server and check it for errors
-function upload(g) {
- function upload2(dir) {
- var form=node("form",{method:"post",action:"/upload"},
- [hidden("dir",dir),hidden(g.basename,show_abstract(g))])
- var files = [g.basename+".gf"]
- for(var i in g.concretes) {
- var cname=g.basename+g.concretes[i].langcode;
- files.push(cname+".gf");
- form.appendChild(hidden(cname,
- show_concrete(g.basename)(g.concretes[i])));
- }
- editor.appendChild(form);
- form.submit();
- form.parentNode.removeChild(form);
- /* wait until upload is done */
- gfshell("i -retain "+files.join(" "),upload3)
- }
-
- function upload3(message) { if(message) alert(message); }
-
- with_dir(upload2)
+function upload2(g,dir) {
+ var form=node("form",{method:"post",action:"upload.cgi"+dir},
+ [hidden(g.basename,show_abstract(g))])
+ for(var i in g.concretes)
+ form.appendChild(hidden(g.basename+g.concretes[i].langcode,
+ show_concrete(g.basename)(g.concretes[i])));
+ editor.appendChild(form);
+ form.submit();
+ form.parentNode.removeChild(form);
}
function hidden(name,value) {
@@ -824,7 +797,6 @@ function hidden(name,value) {
function delete_ix(old,ix) {
var a=[];
-// for(var i=0;i0) open_grammar(current-1);
+ else draw_grammar_list();
+ //debug(local.get("dir","no server directory yet"));
+}
+
+function draw_grammar_list() {
+ local.put("current",0);
+ editor.innerHTML="";
+ editor.appendChild(node("h3",{},[text("Your grammars")]));
+ var gs=ul([]);
+ function del(i) { return function () { delete_grammar(i); } }
+ for(var i=0;i0 && !local.get(local.count-1))
+ local.count--;
+ initial_view();
+ }
+}
+
+function open_grammar(i) {
+ var g=local.get(i);
+ g.index=i;
+ local.put("current",i+1);
+ edit_grammar(g);
+}
+
+function close_grammar(g) { save_grammar(g); draw_grammar_list(); }
+function reload_grammar(g) { save_grammar(g); edit_grammar(g); }
+
+function save_grammar(g) {
+ if(g.index==null) g.index=local.count++;
+ local.put(g.index,g);
+}
+
+function edit_grammar(g) {
+ editor.innerHTML="";
+ editor.appendChild(draw_grammar(g));
+}
+
+
+function draw_grammar(g) {
+ var files=div_class("files",[draw_filebar(g),draw_file(g)]);
+ return div_class("grammar",[draw_namebar(g,files),files])
+
+}
+
+function draw_namebar(g,files) {
+ return div_class("namebar",
+ [table([tr([td(draw_name(g)),
+ td_right([draw_plainbutton(g,files),
+ upload_button(g),
+ draw_closebutton(g)])])])])
+}
+
+function draw_name(g) {
+ return editable("h3",text(g.basename),g,edit_name,"Rename grammar");
+}
+
+function draw_closebutton(g) {
+ var b=button("X",function(){close_grammar(g);});
+ b.title="Save and Close this grammar";
+ return b;
+}
+
+function draw_plainbutton(g,files) {
+ var b2;
+ function show_editor() { edit_grammar(g); }
+ function show_plain() {
+ files.innerHTML=""+show_grammar(g)+"
"
+ b.style.display="none";
+ if(b2) b2.style.display="";
+ else {
+ b2=button("Show editor",show_editor);
+ insertAfter(b2,b);
+ }
+ }
+ var b=button("Show plain",show_plain);
+ b.title="Show plain text representaiton of the grammar";
+ return b;
+}
+
+function upload_button(g) {
+ var b=button("Upload",function(){upload(g);});
+ b.title="Upload the grammar to the server to check it in GF and test it in the minibar";
+ return b;
+}
+
+function lang(code,name) { return { code:code, name:name} }
+function lang1(name) {
+ var ws=name.split("/");
+ return ws.length==1 ? lang(name.substr(0,3),name) : lang(ws[0],ws[1]);
+}
+var languages =
+ map(lang1,"Amharic Arabic Bulgarian Catalan Danish Dutch English Finnish French German Hindi Ina/Interlingua Italian Latin Norwegian Polish Ron/Romanian Russian Spanish Swedish Thai Turkish Urdu".split(" "));
+//languages.push(lang("Other","Other"));
+
+var langname={};
+//for(var i=0;i0
+ ? "a copy of "+langname[g.concretes[g.current-1].langcode]
+ :"scratch";
+ file.appendChild(p(text("You are about to create a new concrete syntax by starting from "+from+".")));
+ file.appendChild(p(text("Pick a language for the new concrete syntax:")));
+ file.appendChild(node("ul",{},list));
+}
+
+function new_concrete(code) {
+ return { langcode:code,params:[],lincats:[],opers:[],lins:[] };
+}
+
+function add_concrete2(ix,code) {
+ var g=local.get(ix);
+ var cs=g.concretes;
+ var ci;
+ for(var ci=0;ci0) {
+ cs.push(cs[g.current-1]); // old and new are shared at this point
+ save_grammar(g); // serialization loses sharing
+ g=local.get(ix); // old and new are separate now
+ var oldcode=cs[g.current-1].langcode;
+ var cnc=g.concretes[ci];
+ cnc.langcode=code;
+ for(var oi in cnc.opens)
+ for(var li in rgl_modules)
+ if(cnc.opens[oi]==rgl_modules[li]+oldcode)
+ cnc.opens[oi]=rgl_modules[li]+code;
+ }
+ else
+ cs.push(new_concrete(code))
+ save_grammar(g);
+ }
+ open_concrete(g,ci);
+}
+
+function open_abstract(g) { g.current=0; reload_grammar(g); }
+function open_concrete(g,i) { g.current=i+1; reload_grammar(g); }
+
+function td_gap(c) {return wrap_class("td","gap",c); }
+function gap() { return td_gap(text(" ")); }
+
+function tab(active,link) {
+ return wrap_class("td",active ? "active" : "inactive",link);
+}
+
+function delete_concrete(g,ci) {
+ var c=g.concretes[ci];
+ var ok=c.params.length==0 && c.lincats.length==0 && c.opers.length==0
+ && c.lins.length==0
+ || confirm("Do you really want to delete the concrete syntax for "+
+ langname[c.langcode]+"?");
+ if(ok) {
+ g.concretes=delete_ix(g.concretes,ci)
+ if(g.current && g.current-1>=ci) g.current--;
+ reload_grammar(g);
+ }
+}
+
+function draw_filebar(g) {
+ var cur=(g.current||0)-1;
+ var filebar = empty_class("tr","extensible")
+ filebar.appendChild(gap());
+ filebar.appendChild(
+ tab(cur== -1,button("Abstract",function(){open_abstract(g);})));
+ var cs=g.concretes;
+ function del(ci) { return function() { delete_concrete(g,ci); }}
+ function open_conc(i) { return function() {open_concrete(g,1*i); }}
+// for(var i=0;i0 // && g.current<=g.concretes.length
+ ? draw_concrete(g,g.current-1)
+ : draw_abstract(g);
+}
+
+function draw_startcat(g) {
+ var abs=g.abstract;
+ var startcat = abs.startcat || abs.cats[0];
+ function opt(cat) { return option(cat,cat); }
+ var m= node("select",{},map(opt,abs.cats));
+ m.value=startcat;
+ m.onchange=function() { abs.startcat=m.value; save_grammar(g); }
+ return indent([kw("flags startcat"),sep(" = "),m]);
+}
+
+function draw_abstract(g) {
+ var kw_cat = kw("cat");
+ kw_cat.title = "The categories (nonterminals) of the grammar are enumerated here.";
+ var kw_fun = kw("fun");
+ kw_fun.title = "The functions (productions) of the grammar are enumerated here.";
+ var flags=g.abstract.startcat || g.abstract.cats.length>1
+ ? draw_startcat(g)
+ : text("");
+ function sort_funs() {
+ g.abstract.funs=sort_list(this,g.abstract.funs,"name");
+ save_grammar(g);
+ }
+ return div_id("file",
+ [kw("abstract "),ident(g.basename),sep(" = "),
+ flags,
+ indent([extensible([kw_cat,
+ indent(draw_cats(g))]),
+ extensible([kw_fun,
+ indent_sortable(draw_funs(g),sort_funs)])])]);
+}
+
+function add_cat(g,el) {
+ function add(s) {
+ var cats=s.split(/\s*(?:\s|[;])\s*/); // allow separating spaces or ";"
+ if(cats.length>0 && cats[cats.length-1]=="") cats.pop();
+ for(var i in cats) {
+ var err=check_name(cats[i],"Category");
+ if(err) return err;
+ }
+ for(var i in cats) g.abstract.cats.push(cats[i]);
+ reload_grammar(g);
+ return null;
+ }
+ string_editor(el,"",add);
+}
+
+function delete_cat(g,ix) {
+ with(g.abstract) cats=delete_ix(cats,ix);
+ reload_grammar(g);
+}
+
+function rename_cat(g,el,cat) {
+ function ren(newcat) {
+ if(newcat!="" && newcat!=cat) {
+ var err=check_name(newcat,"Category");
+ if(err) return err;
+ var dc=defined_cats(g);
+ if(dc[newcat]) return newcat+" is already in use";
+ g=rename_category(g,cat,newcat);
+ reload_grammar(g);
+ }
+ return null;
+ }
+ string_editor(el,cat,ren);
+}
+
+function draw_cats(g) {
+ var cs=g.abstract.cats;
+ var es=[];
+ var defined={};
+ function eident(cat) {
+ function ren(g,el) { rename_cat(g,el,cat); }
+ return editable("span",ident(cat),g,ren,"Rename category");
+ }
+ function check(cat,el) {
+ return ifError(defined[cat],"Same category named twice",el);
+ }
+ function del(i) { return function() { delete_cat(g,i); }}
+ for(var i in cs) {
+ es.push(deletable(del(i),check(cs[i],eident(cs[i])),"Delete this category"));
+ defined[cs[i]]=true;
+ es.push(sep("; "));
+ }
+ es.push(more(g,add_cat,"Add more categories"));
+ return es;
+}
+
+function add_fun(g,el) {
+ function add(s) {
+ var p=parse_fun(s);
+ if(p.ok) {
+ g.abstract.funs.push(p.ok);
+ reload_grammar(g);
+ return null;
+ }
+ else
+ return p.error
+ }
+ string_editor(el,"",add);
+}
+
+function edit_fun(i) {
+ return function (g,el) {
+ function replace(s) {
+ var p=parse_fun(s);
+ if(p.ok) {
+ var old=g.abstract.funs[i];
+ g.abstract.funs[i]=p.ok;
+ if(p.ok.name!=old.name) g=rename_function(g,old.name,p.ok.name);
+ if(show_type(p.ok.type)!=show_type(old.type))
+ g=change_lin_lhs(g,p.ok);
+ reload_grammar(g);
+ return null;
+ }
+ else
+ return p.error;
+ }
+ string_editor(el,show_fun(g.abstract.funs[i]),replace);
+ }
+}
+
+function delete_fun(g,ix) {
+ with(g.abstract) funs=delete_ix(funs,ix);
+ reload_grammar(g);
+}
+
+function draw_funs(g) {
+ var funs=g.abstract.funs;
+ var es=[];
+ var dc=defined_cats(g);
+ var df={};
+ function del(i) { return function() { delete_fun(g,i); }}
+ function draw_efun(i,df) {
+ return editable("span",draw_fun(funs[i],dc,df),g,edit_fun(i),"Edit this function");
+ }
+// for(var i=0;i0) el.appendChild(sep(" → "));
+ el.appendChild(check(t[i],ident(t[i])));
+ }
+ return el;
+}
+
+function edit_name(g,el) {
+ function change_name(name) {
+ if(name!=g.basename && name!="") {
+ var err=check_name(name,"Grammar");
+ if(err) return err;
+ g.basename=name
+ reload_grammar(g);
+ }
+ return null;
+ }
+ string_editor(el,g.basename,change_name)
+}
+/* -------------------------------------------------------------------------- */
+
+function draw_concrete(g,i) {
+ var conc=g.concretes[i];
+ return div_id("file",
+ [kw("concrete "),ident(g.basename+conc.langcode),
+ kw(" of "),ident(g.basename),sep(" = "),
+ indent([extensible([kw("open "),draw_opens(g,i)])]),
+ indent([kw("lincat"),draw_lincats(g,i)]),
+ indent([kw("lin"),draw_lins(g,i)]),
+ indent([extensible([kw("param"),draw_params(g,i)])]),
+ indent([extensible([kw("oper"),draw_opers(g,i)])])
+ ])
+}
+
+var rgl_modules=["Paradigms","Syntax"];
+
+function add_open(ci) {
+ return function (g,el) {
+ var conc=g.concretes[ci];
+ var os=conc.opens;
+ var ds={};
+ for(var i in os) ds[os[i]]=true;
+ var list=[]
+ for(var i in rgl_modules) {
+ var b=rgl_modules[i], m=b+conc.langcode;
+ if(!ds[m])
+ list.push(li([a(jsurl("add_open2("+g.index+","+ci+",'"+m+"')"),
+ [text(m)])]));
+ }
+ if(list.length>0) {
+ var file=element("file");
+ file.innerHTML="";
+ file.appendChild(p(text("Pick a resource library module to open:")));
+ file.appendChild(node("ul",{},list));
+ }
+ }
+}
+
+function add_open2(ix,ci,m) {
+ var g=local.get(ix);
+ var conc=g.concretes[ci];
+ conc.opens || (conc.opens=[]);
+ conc.opens.push(m);
+ save_grammar(g);
+ open_concrete(g,ci);
+}
+
+function delete_open(g,ci,ix) {
+ with(g.concretes[ci]) opens=delete_ix(opens,ix);
+ reload_grammar(g);
+}
+
+function draw_opens(g,ci) {
+ var conc=g.concretes[ci];
+ var os=conc.opens || [] ;
+ var es=[];
+ function del(i) { return function() { delete_open(g,ci,i); }}
+ var first=true;
+ for(var i in os) {
+ if(!first) es.push(sep(", "))
+ es.push(deletable(del(i),ident(os[i]),"Don't open this module"));
+ first=false;
+ }
+ es.push(more(g,add_open(ci),"Open more modules"));
+ return indent(es);
+}
+
+function draw_param(p,dp) {
+ function check(el) {
+ return ifError(dp[p.name],"Same parameter type defined twice",el);
+ }
+ return node("span",{},[check(ident(p.name)),sep(" = "),text(p.rhs)]);
+}
+
+function add_param(g,ci,el) {
+ function add(s) {
+ var p=parse_param(s);
+ if(p.ok) {
+ g.concretes[ci].params.push(p.ok);
+ reload_grammar(g);
+ return null;
+ }
+ else
+ return p.error
+ }
+ string_editor(el,"",add);
+}
+
+function edit_param(ci,i) {
+ return function (g,el) {
+ function replace(s) {
+ var p=parse_param(s);
+ if(p.ok) {
+ g.concretes[ci].params[i]=p.ok;
+ reload_grammar(g);
+ return null;
+ }
+ else
+ return p.error;
+ }
+ string_editor(el,show_param(g.concretes[ci].params[i]),replace);
+ }
+}
+
+
+function delete_param(g,ci,ix) {
+ with(g.concretes[ci]) params=delete_ix(params,ix);
+ reload_grammar(g);
+}
+
+function draw_params(g,ci) {
+ var conc=g.concretes[ci];
+ conc.params || (conc.params=[]);
+ var params=conc.params;
+ var es=[];
+ var dp={};
+ function del(i) { return function() { delete_param(g,ci,i); }}
+ function draw_eparam(i,dp) {
+ return editable("span",draw_param(params[i],dp),g,edit_param(ci,i),"Edit this parameter type");
+ }
+ for(var i in params) {
+ es.push(div_class("param",[deletable(del(i),draw_eparam(i,dp),"Delete this parameter type")]));
+ dp[params[i].name]=true;
+ }
+ es.push(more(g,function(g,el) { return add_param(g,ci,el)},
+ "Add a new parameter type"));
+ return indent(es);
+}
+
+function delete_lincat(g,ci,cat) {
+ var i;
+ var c=g.concretes[ci];
+ for(i=0;i1 ? n+(++use[n]) : n;
+ }
+ return map(unique,names);
+}
+
+function draw_lins(g,i) {
+ var conc=g.concretes[i];
+ function edit(f) {
+ return function(g,el) {
+ function check(s,cont) {
+ function check2(msg) {
+ if(!msg) {
+ if(f.template)
+ conc.lins.push({fun:f.fun,args:f.args,lin:s});
+ else f.lin=s;
+ reload_grammar(g);
+ }
+ cont(msg);
+ }
+ check_exp(s,check2);
+ }
+ string_editor(el,f.lin,check,true)
+ }
+ }
+ function del(fun) { return function () { delete_lin(g,i,fun); } }
+ function dl(f,cls) {
+ var l=[ident(f.fun)]
+ for(var i in f.args) {
+ l.push(text(" "));
+ l.push(ident(f.args[i]));
+ }
+ l.push(sep(" = "));
+ var t=editable("span",text(f.lin),g,edit(f),"Edit lin for "+f.fun);
+ l.push(t);
+ return node("span",{"class":cls},l);
+ }
+ var df=defined_funs(g);
+ function draw_lin(f) {
+ var fun=f.fun;
+ var err= !df[fun];
+ var l= err ? deletable(del(fun),dl(f,"lin"),"Delete this function") : dl(f,"lin")
+ var l=ifError(err,"Function "+fun+" is not part of the abstract syntax",l);
+ delete df[fun];
+ return node_sortable("lin",fun,[l]);
+ }
+ function largs(f) {
+ var funs=g.abstract.funs;
+ for(var i=0;i10) i.size=init.length+5;
+// var i=node("textarea",{name:"it",rows:"2",cols:"60"},[text(init)]);
+ var e=node("form",{},
+ [i,
+ node("input",{type:"submit",value:"OK"},[]),
+ button("Cancel",restore),
+ text(" "),
+ m])
+ e.onsubmit=done
+ start("");
+}
+
+function ifError(b,msg,el) { return b ? inError(msg,el) : el; }
+
+function inError(msg,el) {
+ return node("span",{"class":"inError",title:msg},[el]);
+}
+
+function kw(txt) { return wrap_class("span","kw",text(txt)); }
+function sep(txt) { return wrap_class("span","sep",text(txt)); }
+function ident(txt) { return wrap_class("span","ident",text(txt)); }
+function indent(cs) { return div_class("indent",cs); }
+
+function indent_sortable(cs,sort) {
+ var n= indent(cs);
+ n.onsort=sort;
+ return n;
+}
+
+function node_sortable(cls,name,ls) {
+ return node("div",{"class":cls,"ident":name},ls);
+}
+
+function extensible(cs) { return div_class("extensible",cs); }
+
+function more(g,action,hint) {
+ var b=node("span",{"class":"more","title":hint || "Add more"},
+ [text(" + ")]);
+ b.onclick=function() { action(g,b); }
+ return b;
+}
+
+function editable(tag,cs,g,f,hint) {
+ var b=edit_button(function(){f(g,e)},hint);
+ var e=node(tag,{"class":"editable"},[cs,b]);
+ return e;
+}
+
+function edit_button(action,hint) {
+ var b=node("span",{"class":"edit","title":hint || "Edit"},[text("%")]);
+ b.onclick=action;
+ return b;
+}
+
+function deletable(del,el,hint) {
+ var b=node("span",{"class":"delete",title:hint || "Delete"},[text("×")])
+ b.onclick=del;
+ return node("span",{"class":"deletable"},[b,el])
+}
+
+function touch_edit() {
+ var b=node("input",{type:"checkbox"},[]);
+ function touch() {
+ document.body.className=b.checked ? "nohover" : "hover";
+ }
+ b.onchange=touch;
+ insertAfter(b,editor);
+ insertAfter(wrap("small",text("Enable editing on touch devices. ")),b);
+
+}
+
+/* --- Initialization ------------------------------------------------------- */
+
+//document.body.appendChild(empty_id("div","debug"));
+
+initial_view();
+touch_edit();