Skip to content

Commit

Permalink
define/undefine/redefine, eliminate/introduce, reroot, unlabel/design…
Browse files Browse the repository at this point in the history
…ate are (re)done; also, a GDT-like grammar differ is implemented in a very agile Rascal-specific way
  • Loading branch information
grammarware committed Jun 2, 2012
1 parent d170127 commit 7679623
Show file tree
Hide file tree
Showing 5 changed files with 541 additions and 187 deletions.
4 changes: 2 additions & 2 deletions shared/prolog/xbgf1.pro
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ introduce(Ps1,G1,G2)
ps2n(Ps1,N),
require(
( \+ member(N,Uses) ),
'Nonterminal ~q must not be fresh.',
'Nonterminal ~q must be fresh.',
[N]),
new(Ps1,N,G1,G2).

Expand Down Expand Up @@ -1448,7 +1448,7 @@ unchain(P1,g(Rs,Ps1),g(Rs,Ps4))
allNs(Ps4,Ns),
require(
(\+ member(N2,Ns) ),
'Nonterminal ~q must appear occur exactly once.',
'Nonterminal ~q must occur exactly once.',
[N2]).


Expand Down
15 changes: 10 additions & 5 deletions shared/rascal/src/Sync.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,29 @@ import io::ReadXBGF;
public void main()
{
loc base = |home:///projects/slps/topics/transformation/xbgf/tests|;
int cx = 1;
str buffer = "@contributor{Super Awesome Automated XBGF Test Suite Synchroniser}
'@contributor{Vadim Zaytsev - vadim@grammarware.net - SWAT, CWI}
'module transform::XBGFTest
'
'import IO;
'import syntax::BGF;
'import syntax::XBGF;
'import transform::XBGF;
'import diff::GDT;
'
'";
'map[str,tuple[XBGFSequence,BGFGrammar,BGFGrammar]] test_data = (
'",
buffer2 = "";
for (f <- listEntries(base), endsWith(f,".xbgf"))
{
xbgf = readXBGF(base+f);
bgf = readBGF(base+replaceLast(f,".xbgf",".bgf"));
bl = readBGF(base+replaceLast(f,".xbgf",".baseline"));
buffer += "test bool test_<replaceLast(f,".xbgf","")>() { return transform(<xbgf>,<bgf>)==<bl>; }\n";
cx+=1;
//buffer += "test bool test_<replaceLast(f,".xbgf","")>() { return gdt(transform(<xbgf>,<bgf>),<bl>); }\n";
buffer += "\"<replaceLast(f,".xbgf","")>\": \<<xbgf>,<bgf>,<bl>\>,\n";
buffer2 += "test bool test_<replaceLast(f,".xbgf","")>() { \<xbgf,bgf1,bgf2\> = test_data[\"<replaceLast(f,".xbgf","")>\"]; return gdt(transform(xbgf,bgf1),bgf2); }\n";
buffer2 += "void show_<replaceLast(f,".xbgf","")>() { \<xbgf,bgf1,bgf2\> = test_data[\"<replaceLast(f,".xbgf","")>\"]; println(\"Input \<bgf1\>\");println(\"Transformations: \<xbgf\>\");println(\"Expected output \<bgf2\>\");println(\"Actual output \<transform(xbgf,bgf1)\>\"); }\n";
}
writeFile(|project://slps/src/transform/XBGFTest.rsc|, buffer);
writeFile(|project://slps/src/transform/XBGFTest.rsc|, replaceLast(buffer,",","")+");\n\n"+buffer2);
}
12 changes: 12 additions & 0 deletions shared/rascal/src/diff/GDT.rsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@contributor{Vadim Zaytsev - vadim@grammarware.net - SWAT, CWI}
@doc{Grammar Diff Tool}
module diff::GDT

import syntax::BGF;
import List;

public bool gdt(grammar(rs1,ps1), grammar(rs2,ps2))
{
if (toSet(rs1)==toSet(rs2) && toSet(ps1)==toSet(ps2)) return true;
return false;
}
120 changes: 83 additions & 37 deletions shared/rascal/src/transform/XBGF.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module transform::XBGF

import IO;
import List;
import Set; // toList
import syntax::BGF;
import syntax::XBGF;
import normal::BGF;
Expand Down Expand Up @@ -190,16 +191,22 @@ BGFGrammar runDeanonymize(BGFProduction p1, grammar(roots, ps))
return grammar(roots, ps - p3 + p2);
}
BGFGrammar runDefine(list[BGFProduction] ps, BGFGrammar g)
BGFGrammar runDefine(list[BGFProduction] ps1, grammar(roots, ps2))
{
// TODO
return g;
if ({str n} := definedNs(ps1))
{
if (n notin usedNs(ps2)) throw "Nonterminal <n> must not be fresh, use introduce instead.";
return grammar(roots, ps2 + ps1);
}
else throw "Multiple defined nonterminals found.";
}
BGFGrammar runDesignate(BGFProduction p, BGFGrammar g)
BGFGrammar runDesignate(production(str l,str n,BGFExpression e), grammar(rs,ps))
//BGFGrammar runUnlabel(str x, grammar(rs,ps))
{
// TODO
return g;
if (l == "") throw "Production <production(l,n,e)> must be labeled.";
if (production("",n,e) notin ps) throw "Production rule defining <n> as <e> not found.";
return grammar(rs,replaceP(ps,production("",n,e),production(l,n,e)));
}
BGFGrammar runDetour(BGFProduction p, BGFGrammar g)
Expand Down Expand Up @@ -236,10 +243,14 @@ BGFGrammar runDowngrade(BGFProduction p1,BGFProduction p2, BGFGrammar g)
return g;
}
BGFGrammar runEliminate(str x, BGFGrammar g)
BGFGrammar runEliminate(str x, grammar(roots, ps))
{
// TODO
return g;
// TODO: can we eliminate root?
if (x in roots) throw "Cannot eliminate root nonterminal <x>";
if (x notin definedNs(ps)) throw "Nonterminal <x> must be defined.";
<ps1,_,ps3> = splitPbyW(ps,innt(x));
if (x in usedNs(ps1+ps3)) throw "Nonterminal <x> must not be used.";
return grammar(roots, ps1 + ps3);
}
BGFGrammar runEquate(str x, str y, BGFGrammar g)
Expand Down Expand Up @@ -293,10 +304,15 @@ BGFGrammar runInline(str x, BGFGrammar g)
return g;
}
BGFGrammar runIntroduce(list[BGFProduction] ps, BGFGrammar g)
BGFGrammar runIntroduce(list[BGFProduction] ps1, grammar(roots, ps2))
{
// TODO
return g;
if ({str n} := definedNs(ps1))
{
if (n in usedNs(ps2)) throw "Nonterminal <n> must be fresh, use define instead.";
if (n in definedNs(ps2)) throw "Definition for <n> clashes with existing definition.";
return grammar(roots, ps2 + ps1);
}
else throw "Multiple defined nonterminals found.";
}
BGFGrammar runIterate(BGFProduction p, BGFGrammar g)
Expand Down Expand Up @@ -345,10 +361,18 @@ BGFGrammar runRAssoc(BGFProduction p, BGFGrammar g)
return g;
}
BGFGrammar runRedefine(list[BGFProduction] ps, BGFGrammar g)
BGFGrammar runRedefine(list[BGFProduction] ps1, grammar(list[str] rs, ps2))
{
// TODO
return g;
// inlined superposition of undefine and define, with two exceptional details:
// (1) if ps1.n is a root, undefine would have stripped it from this status
// (2) redefine preserves original order of production rules
if ({str x} := definedNs(ps1))
{
if (x notin definedNs(ps2)) throw "Nonterminal <x> must be defined.";
if (x notin usedNs(ps2)) throw "Nonterminal <x> must be used.";
<ps3,_,ps4> = splitPbyW(ps2,innt(x));
return grammar(rs,ps3 + ps1 + ps4);
}
}
BGFGrammar runRemoveH(BGFProduction p1, grammar(roots, ps))
Expand Down Expand Up @@ -411,10 +435,12 @@ BGFGrammar runReplace(BGFExpression e1, BGFExpression e2, XBGFContext w, grammar
return grammar(roots, ps1 + ps4 + ps3);
}
BGFGrammar runReroot(list[str] xs, BGFGrammar g)
BGFGrammar runReroot(list[str] xs, grammar(rs, ps))
{
// TODO
return g;
if (toSet(xs) == toSet(rs)) throw "Vacuous reroot of <xs>.";
// xbgf1.pro only asked for it to be a subset of allNs, not definedNs; we're more strict here
if (toSet(xs) <= definedNs(ps)) return grammar(xs,ps);
else throw "Not all nonterminals in <xs> are defined.";
}
BGFGrammar runSplitN(str x, list[BGFProduction] ps, XBGFContext w, BGFGrammar g)
Expand All @@ -423,10 +449,12 @@ BGFGrammar runSplitN(str x, list[BGFProduction] ps, XBGFContext w, BGFGrammar g)
return g;
}
BGFGrammar runSplitT(str x, list[str] ys, XBGFContext w, BGFGrammar g)
BGFGrammar runSplitT(str x, list[str] ys, XBGFContext w, grammar(rs, ps))
{
// TODO
return g;
<ps1,ps2,ps3> = splitPbyW(ps, w);
BGFGrammar g2 = runReplace(terminal(x),sequence([terminal(y) | y <- ys]),grammar([],ps2));
if (grammar(_, ps4) := runReplace(terminal(x),sequence([terminal(y) | y <- ys]),grammar([],ps2)))
return grammar(rs,ps1 + normalise(ps2) + ps3);
}
BGFGrammar runUnchain(BGFProduction p, grammar(roots, ps))
Expand All @@ -446,10 +474,22 @@ BGFGrammar runUnchain(BGFProduction p, grammar(roots, ps))
}
else throw "Production <p> must be a chain production.";
}
BGFGrammar runUndefine(list[str] xs, BGFGrammar g)
//TODO: undefine only one nonterminal per transformation
BGFGrammar runUndefine(list[str] xs, grammar(roots, ps))
{
// TODO
return g;
list[BGFProduction] myps = ps;
list[str] rs = roots;
for (str x <- xs)
{
if (x notin definedNs(ps)) throw "Nonterminal <x> must be defined.";
if (x notin usedNs(ps)) throw "Nonterminal <x> must be used.";
//throw "Cannot undefine root nonterminal <x>."; // check was not in xbgf1.pro
rs -= x;
<ps1,_,ps3> = splitPbyW(myps,innt(x));
myps = ps1 + ps3;
}
return grammar(roots,myps);
}
BGFGrammar runUnfold(str x, XBGFContext w, BGFGrammar g)
Expand All @@ -464,10 +504,14 @@ BGFGrammar runUnite(str x, str y, BGFGrammar g)
return g;
}
BGFGrammar runUnlabel(str x, BGFGrammar g)
BGFGrammar runUnlabel(str x, grammar(rs,ps))
{
// TODO
return g;
if (x == "") throw "Please specify which label to unlabel.";
<ps1,ps2,ps3> = splitPbyW(ps,inlabel(x));
if ([production(str l, str x, BGFExpression e)] := ps2)
return grammar(rs, ps1 + production("", x, e) + ps3);
else
throw "Label <x> is not found or not unique"; // the latter should never happen
}
BGFGrammar runUpgrade(BGFProduction p1, BGFProduction p2, BGFGrammar g)
Expand Down Expand Up @@ -605,15 +649,17 @@ bool narrowing(plus(e),e) = true;
bool narrowing(optional(e),e) = true;
bool narrowing(_,_) = false;
list[str] allNs(list[BGFProduction] ps)
set[str] allNs(list[BGFProduction] ps) = definedNs(ps) + usedNs(ps);
set[str] usedNs(list[BGFProduction] ps) = {s | /nonterminal(str s) := ps};
set[str] definedNs(list[BGFProduction] ps) = {s | production(_,str s,_) <- ps};
list[BGFProduction] replaceP(list[BGFProduction] ps, p1, p2)
{
list[str] ns = [];
// defined
for (production(_,str s,_) <- ps)
if (s notin ns) ns += s;
// used
for (/nonterminal(str s) := ps)
if (s notin ns) ns += s;
return ns;
list[BGFProduction] ps2 = [];
for (p <- ps)
if (p == p1)
ps2 += p2;
else
ps2 += p;
return ps2;
}
Loading

0 comments on commit 7679623

Please sign in to comment.