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:
hallgren
2012-02-15 17:35:09 +00:00
parent 1a64606819
commit 7cac11c8e8
2 changed files with 84 additions and 18 deletions

View File

@@ -64,7 +64,7 @@ table.tabs {
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.inactive {
background: #cef;

View File

@@ -1,6 +1,7 @@
var editor=element("editor");
var compiler_output=element("compiler_output")
/* -------------------------------------------------------------------------- */
@@ -43,8 +44,7 @@ function draw_grammar_list() {
return node("tr",{"class":"extensible deletable"},
[td(delete_button(del(i),"Delete this grammar")),
td(link),
td(more(grammar,clone(i),"Clone this grammar")),
td(more(grammar,new_extension(i),"Create an extension of this grammar"))])
td(more(grammar,clone(i),"Clone this grammar"))])
}
if(local.get("count",null)==null)
home.appendChild(text("You have not created any grammars yet."));
@@ -108,8 +108,9 @@ function delete_grammar(i) {
function clone_grammar(i) {
var old=local.get(i);
var g={basename:old.basename,abstract:old.abstract,concretes:old.concretes}
save_grammar(g);
var g={basename:old.basename,extends:old.extends || [],
abstract:old.abstract,concretes:old.concretes}
save_grammar(g); // we rely on the serialization to eliminate sharing
draw_grammar_list();
}
@@ -121,7 +122,7 @@ function open_grammar(i) {
}
function close_grammar(g) {
var o=element("compiler_output");
var o=compiler_output;
if(o) o.innerHTML="";
save_grammar(g);
draw_grammar_list();
@@ -182,7 +183,7 @@ function draw_plainbutton(g,files) {
}
function show_compile_error(res) {
var dst=element("compiler_output")
var dst=compiler_output
if(dst) {
dst.innerHTML="";
var minibarlink=a(res.minibar_url,[text("Minibar")])
@@ -198,7 +199,11 @@ function show_compile_error(res) {
}
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";
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";
return b;
}
@@ -372,14 +381,53 @@ function draw_startcat(g) {
return indent([kw("flags startcat"),sep(" = "),m]);
}
function draw_extends(exts) {
function draw_conc_extends(g,conc) {
var kw_extends=kw("extends ")
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(", "))])
: 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) {
var kw_cat = kw("cat");
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",
[kw("abstract "),ident(g.basename),sep(" = "),
draw_timestamp(g.abstract),
draw_extends(g.extends),
draw_extends(g),
flags,
indent([extensible([kw_cat,
indent(draw_cats(g))]),
@@ -542,6 +590,7 @@ function draw_fun(g,fun,dc,df) {
function draw_type(t,dc) {
var el=empty("span");
function check(t,el) {
if(dc[t]) el.title=dc[t]+"."+t;
return ifError(!dc[t],"Undefined category",el);
}
for(var i in t) {
@@ -593,7 +642,7 @@ function draw_concrete(g,i) {
edit_langcode,"Change language"),
kw(" of "),ident(g.basename),sep(" = "),
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([kw_lincat,draw_lincats(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_grammars(g) {
// Load the available grammars once
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() {
var gix=cached_grammar_array_byname()
function grammar_byname(name) { return gix[name]; }
return grammar_byname;
}
function cached_grammar_array_byname() {
var gix={};
for(var i=0;i<local.count;i++) {
var g=local.get(i,null);
if(g) gix[g.basename]=g; // basenames are not necessarily unique!!
}
function grammar_byname(name) { return gix[name]; }
return grammar_byname;
return gix
}
/* -------------------------------------------------------------------------- */
@@ -1125,9 +1191,9 @@ function node_sortable(cls,name,ls) {
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"},
[text(" + ")]);
[text(label || " + ")]);
b.onclick=function() { action(g,b); }
return b;
}