forked from GitHub/gf-core
gfse: more work on grammar extension
Grammars can now inherit from several other grammars. Hovering over a catagory name in a function type in the abstract syntax shows where the category was inherited from.
This commit is contained in:
@@ -64,7 +64,7 @@ table.tabs {
|
|||||||
border-width: 0; border-spacing: 0; empty-cells: show;
|
border-width: 0; border-spacing: 0; empty-cells: show;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tabs td { text-align: center; border: 2px solid #009; padding: 2px; }
|
table.tabs td { text-align: center; border: 2px solid #009; padding: 2px; white-space: nowrap; }
|
||||||
table.tabs td.active { background: white; border-bottom-width: 0; }
|
table.tabs td.active { background: white; border-bottom-width: 0; }
|
||||||
table.tabs td.inactive {
|
table.tabs td.inactive {
|
||||||
background: #cef;
|
background: #cef;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
var editor=element("editor");
|
var editor=element("editor");
|
||||||
|
var compiler_output=element("compiler_output")
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
@@ -43,8 +44,7 @@ function draw_grammar_list() {
|
|||||||
return node("tr",{"class":"extensible deletable"},
|
return node("tr",{"class":"extensible deletable"},
|
||||||
[td(delete_button(del(i),"Delete this grammar")),
|
[td(delete_button(del(i),"Delete this grammar")),
|
||||||
td(link),
|
td(link),
|
||||||
td(more(grammar,clone(i),"Clone this grammar")),
|
td(more(grammar,clone(i),"Clone this grammar"))])
|
||||||
td(more(grammar,new_extension(i),"Create an extension of this grammar"))])
|
|
||||||
}
|
}
|
||||||
if(local.get("count",null)==null)
|
if(local.get("count",null)==null)
|
||||||
home.appendChild(text("You have not created any grammars yet."));
|
home.appendChild(text("You have not created any grammars yet."));
|
||||||
@@ -108,8 +108,9 @@ function delete_grammar(i) {
|
|||||||
|
|
||||||
function clone_grammar(i) {
|
function clone_grammar(i) {
|
||||||
var old=local.get(i);
|
var old=local.get(i);
|
||||||
var g={basename:old.basename,abstract:old.abstract,concretes:old.concretes}
|
var g={basename:old.basename,extends:old.extends || [],
|
||||||
save_grammar(g);
|
abstract:old.abstract,concretes:old.concretes}
|
||||||
|
save_grammar(g); // we rely on the serialization to eliminate sharing
|
||||||
draw_grammar_list();
|
draw_grammar_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ function open_grammar(i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function close_grammar(g) {
|
function close_grammar(g) {
|
||||||
var o=element("compiler_output");
|
var o=compiler_output;
|
||||||
if(o) o.innerHTML="";
|
if(o) o.innerHTML="";
|
||||||
save_grammar(g);
|
save_grammar(g);
|
||||||
draw_grammar_list();
|
draw_grammar_list();
|
||||||
@@ -182,7 +183,7 @@ function draw_plainbutton(g,files) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function show_compile_error(res) {
|
function show_compile_error(res) {
|
||||||
var dst=element("compiler_output")
|
var dst=compiler_output
|
||||||
if(dst) {
|
if(dst) {
|
||||||
dst.innerHTML="";
|
dst.innerHTML="";
|
||||||
var minibarlink=a(res.minibar_url,[text("Minibar")])
|
var minibarlink=a(res.minibar_url,[text("Minibar")])
|
||||||
@@ -198,7 +199,11 @@ function show_compile_error(res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function compile_button(g) {
|
function compile_button(g) {
|
||||||
var b=button("Compile",function(){upload(g,show_compile_error);});
|
function compile() {
|
||||||
|
if(compiler_output) compiler_output.innerHTML="<h3>Compiling...</h3>";
|
||||||
|
upload(g,show_compile_error);
|
||||||
|
}
|
||||||
|
var b=button("Compile",compile);
|
||||||
b.title="Upload the grammar to the server to check it in GF for errors";
|
b.title="Upload the grammar to the server to check it in GF for errors";
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
@@ -231,7 +236,11 @@ function minibar_button(g,files) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b=button("Minibar",function(){upload(g,goto_minibar);});
|
function compile() {
|
||||||
|
if(compiler_output) compiler_output.innerHTML="<h3>Compiling...</h3>";
|
||||||
|
upload(g,goto_minibar);
|
||||||
|
}
|
||||||
|
var b=button("Minibar",compile);
|
||||||
b.title="Upload the grammar and test it in the minibar";
|
b.title="Upload the grammar and test it in the minibar";
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
@@ -372,14 +381,53 @@ function draw_startcat(g) {
|
|||||||
return indent([kw("flags startcat"),sep(" = "),m]);
|
return indent([kw("flags startcat"),sep(" = "),m]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw_extends(exts) {
|
function draw_conc_extends(g,conc) {
|
||||||
var kw_extends=kw("extends ")
|
var kw_extends=kw("extends ")
|
||||||
kw_extends.title="This grammar is an extension of the grammars listed here."
|
kw_extends.title="This grammar is an extension of the grammars listed here."
|
||||||
return exts && exts.length>0
|
var exts=(g.extends || []).map(conc_extends(conc))
|
||||||
|
return exts.length>0
|
||||||
? indent([kw_extends,ident(exts.join(", "))])
|
? indent([kw_extends,ident(exts.join(", "))])
|
||||||
: text("")
|
: text("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function draw_extends(g) {
|
||||||
|
var kw_extends=kw("extends ")
|
||||||
|
var exts= g.extends || [];
|
||||||
|
kw_extends.title="This grammar is an extension of the grammars listed here."
|
||||||
|
var m1=more(g,add_extends,"Inherit from other grammars");
|
||||||
|
var m2=more(g,add_extends,"Inherit from more grammars");
|
||||||
|
return exts.length>0
|
||||||
|
? indent([extensible([kw_extends,ident(exts.join(", ")),m2])])
|
||||||
|
: indent([extensible([span_class("more",kw_extends),m1])])
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_extends(g,el) {
|
||||||
|
var file=element("file");
|
||||||
|
file.innerHTML="";
|
||||||
|
var gs=cached_grammar_array_byname();
|
||||||
|
var list=[]
|
||||||
|
for(var i in gs) {
|
||||||
|
if(gs[i].basename!=g.basename
|
||||||
|
&& !elem(gs[i].basename,g.extends || [])
|
||||||
|
&& !elem(g.basename,gs[i].extends || [])
|
||||||
|
// also exclude indirectly inherited grammars!!
|
||||||
|
)
|
||||||
|
list.push(li([a(jsurl("add_extends2("+g.index+","+gs[i].index+")"),
|
||||||
|
[text(gs[i].basename)])]));
|
||||||
|
}
|
||||||
|
file.appendChild(p(text("Pick a grammar to inherit:")));
|
||||||
|
file.appendChild(node("ul",{"class":"grammars"},list));
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_extends2(gix,igix) {
|
||||||
|
var g=local.get(gix);
|
||||||
|
var ig=local.get(igix);
|
||||||
|
if(!g.extends) g.extends=[];
|
||||||
|
g.extends.push(ig.basename);
|
||||||
|
//timestamp(g)
|
||||||
|
reload_grammar(g);
|
||||||
|
}
|
||||||
|
|
||||||
function draw_abstract(g) {
|
function draw_abstract(g) {
|
||||||
var kw_cat = kw("cat");
|
var kw_cat = kw("cat");
|
||||||
kw_cat.title = "The categories (nonterminals) of the grammar are enumerated here. [C.3.2]";
|
kw_cat.title = "The categories (nonterminals) of the grammar are enumerated here. [C.3.2]";
|
||||||
@@ -397,7 +445,7 @@ function draw_abstract(g) {
|
|||||||
return div_id("file",
|
return div_id("file",
|
||||||
[kw("abstract "),ident(g.basename),sep(" = "),
|
[kw("abstract "),ident(g.basename),sep(" = "),
|
||||||
draw_timestamp(g.abstract),
|
draw_timestamp(g.abstract),
|
||||||
draw_extends(g.extends),
|
draw_extends(g),
|
||||||
flags,
|
flags,
|
||||||
indent([extensible([kw_cat,
|
indent([extensible([kw_cat,
|
||||||
indent(draw_cats(g))]),
|
indent(draw_cats(g))]),
|
||||||
@@ -542,6 +590,7 @@ function draw_fun(g,fun,dc,df) {
|
|||||||
function draw_type(t,dc) {
|
function draw_type(t,dc) {
|
||||||
var el=empty("span");
|
var el=empty("span");
|
||||||
function check(t,el) {
|
function check(t,el) {
|
||||||
|
if(dc[t]) el.title=dc[t]+"."+t;
|
||||||
return ifError(!dc[t],"Undefined category",el);
|
return ifError(!dc[t],"Undefined category",el);
|
||||||
}
|
}
|
||||||
for(var i in t) {
|
for(var i in t) {
|
||||||
@@ -593,7 +642,7 @@ function draw_concrete(g,i) {
|
|||||||
edit_langcode,"Change language"),
|
edit_langcode,"Change language"),
|
||||||
kw(" of "),ident(g.basename),sep(" = "),
|
kw(" of "),ident(g.basename),sep(" = "),
|
||||||
draw_timestamp(conc),
|
draw_timestamp(conc),
|
||||||
draw_extends((g.extends || []).map(conc_extends(conc))),
|
draw_conc_extends(g,conc),
|
||||||
indent([extensible([kw("open "),draw_opens(g,i)])]),
|
indent([extensible([kw("open "),draw_opens(g,i)])]),
|
||||||
indent([kw_lincat,draw_lincats(g,i)]),
|
indent([kw_lincat,draw_lincats(g,i)]),
|
||||||
indent([kw_lin,draw_lins(g,i)]),
|
indent([kw_lin,draw_lins(g,i)]),
|
||||||
@@ -956,18 +1005,35 @@ function inherited_cats(g) {return all_inherited_cats(inherited_grammars(g),{})}
|
|||||||
function inherited_funs(g) {return all_inherited_funs(inherited_grammars(g),{})}
|
function inherited_funs(g) {return all_inherited_funs(inherited_grammars(g),{})}
|
||||||
|
|
||||||
function inherited_grammars(g) {
|
function inherited_grammars(g) {
|
||||||
|
// Load the available grammars once
|
||||||
var grammar_byname=cached_grammar_byname();
|
var grammar_byname=cached_grammar_byname();
|
||||||
return (g.extends || []).map(grammar_byname)
|
var visited={};
|
||||||
|
// Then traverse the dependencies to collect all inherited grammars
|
||||||
|
function ihgs(g) {
|
||||||
|
if(visited[g.basename]) return []; // avoid cycles and diamonds
|
||||||
|
else {
|
||||||
|
visited[g.basename]=true;
|
||||||
|
var igs=(g.extends || []).map(grammar_byname)
|
||||||
|
var igss=igs.map(ihgs)
|
||||||
|
for(var i in igss) igs.concat(igss[i]);
|
||||||
|
return igs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ihgs(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
function cached_grammar_byname() {
|
function cached_grammar_byname() {
|
||||||
|
var gix=cached_grammar_array_byname()
|
||||||
|
function grammar_byname(name) { return gix[name]; }
|
||||||
|
return grammar_byname;
|
||||||
|
}
|
||||||
|
function cached_grammar_array_byname() {
|
||||||
var gix={};
|
var gix={};
|
||||||
for(var i=0;i<local.count;i++) {
|
for(var i=0;i<local.count;i++) {
|
||||||
var g=local.get(i,null);
|
var g=local.get(i,null);
|
||||||
if(g) gix[g.basename]=g; // basenames are not necessarily unique!!
|
if(g) gix[g.basename]=g; // basenames are not necessarily unique!!
|
||||||
}
|
}
|
||||||
function grammar_byname(name) { return gix[name]; }
|
return gix
|
||||||
return grammar_byname;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
@@ -1125,9 +1191,9 @@ function node_sortable(cls,name,ls) {
|
|||||||
|
|
||||||
function extensible(cs) { return div_class("extensible",cs); }
|
function extensible(cs) { return div_class("extensible",cs); }
|
||||||
|
|
||||||
function more(g,action,hint) {
|
function more(g,action,hint,label) {
|
||||||
var b=node("span",{"class":"more","title":hint || "Add more"},
|
var b=node("span",{"class":"more","title":hint || "Add more"},
|
||||||
[text(" + ")]);
|
[text(label || " + ")]);
|
||||||
b.onclick=function() { action(g,b); }
|
b.onclick=function() { action(g,b); }
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user