allow lifts on any position
[sbp.git] / src / edu / berkeley / sbp / meta / GrammarAST.java
index 63c4392..19f12a3 100644 (file)
@@ -10,26 +10,11 @@ import java.lang.annotation.*;
 import java.lang.reflect.*;
 import java.io.*;
 
-// FIXME: deal with question-marks
-
-// FIXME: put back in associativity: ^")"
-//            A = A "->" (A)
-//        means that the FIRST "A" cannot match the SAME sequence in
-//        which the (A) occurs
-//        -- and add a test case
-
-// FIXME: make it so that we can have multi-result nonterminals
-//        so long as they always appear under double-colons?
-//        auto-insert the unwrap?
-
-// FIXME: put associativity back in
-
-// FIXME: "flat" sequences (no subtrees contain "::"s?)
-
-// freezing problem is related to comments in grammar files
-
-/** The java classes typically used to represent a parsed grammar AST; each inner class is a type of AST node. */
-public class GrammarBuilder {
+/**
+ *  The inner classes of this class represent nodes in the Abstract
+ *  Syntax Tree of a grammar.
+ */
+public class GrammarAST {
 
     /**
      *  Create a grammar from a parse tree and binding resolver
@@ -94,46 +79,47 @@ public class GrammarBuilder {
         if (head.equals("Word")) return stringifyChildren(t);
         if (head.equals("Elements")) return seq2((ElementNode[])Reflection.rebuild(walkChildren(t), ElementNode[].class));
         if (head.equals("NonTerminalReference")) return new ReferenceNode(stringifyChildren(t.child(0)));
-        //if (head.equals(")")) return new ReferenceNode(stringifyChildren(t.child(0)));
-        if (head.equals("{")) return new XTree((Seq)walk(t.child(0)));
-        if (head.equals("::")) return tag((String)walk(t.child(0)), (Seq)walk(t.child(1)));
-        if (head.equals("++")) return plusmax((ElementNode)walk(t.child(0)));
-        if (head.equals("...")) return star(new TildeNode(new AtomNode()));
-        if (head.equals("+")) return plus((ElementNode)walk(t.child(0)));
-        if (head.equals("++/")) return plusmaxfollow((ElementNode)walk(t.child(0)), (ElementNode)walk(t.child(1)));
-        if (head.equals("+/")) return plusfollow((ElementNode)walk(t.child(0)), (ElementNode)walk(t.child(1)));
-        if (head.equals("**")) return starmax((ElementNode)walk(t.child(0)));
-        if (head.equals("*")) return star((ElementNode)walk(t.child(0)));
-        if (head.equals("**/")) return starmaxfollow((ElementNode)walk(t.child(0)), (ElementNode)walk(t.child(1)));
-        if (head.equals("*/")) return starfollow((ElementNode)walk(t.child(0)), (ElementNode)walk(t.child(1)));
-        if (head.equals("?")) return question((ElementNode)walk(t.child(0)));
-        if (head.equals("!")) return new DropNode((ElementNode)walk(t.child(0)));
-        if (head.equals("^")) return new LiteralNode((String)walk(t.child(0)), true);
-        if (head.equals("`")) {
-            ElementNode ret = (ElementNode)walk(t.child(0));
-            ret.lifted = true;
-            return ret;
-        }
+        if (head.equals(")"))   return new ReferenceNode(stringifyChildren(t.child(0)), true);
+        if (head.equals("{"))   return new BracedNode(walkSeq(t.child(0)));
+        if (head.equals("::"))  return walkSeq(t.child(1)).tag(walkString(t.child(0)));
+        if (head.equals("...")) return new DropNode(new RepeatNode(new TildeNode(new AtomNode()), null, true,  true,  false));
+
+        if (head.equals("++"))  return new RepeatNode(walkElement(t.child(0)), null,                      false, true,  true);
+        if (head.equals("+"))   return new RepeatNode(walkElement(t.child(0)), null,                      false, true,  false);
+        if (head.equals("++/")) return new RepeatNode(walkElement(t.child(0)), walkElement(t.child(1)),   false, true,  true);
+        if (head.equals("+/"))  return new RepeatNode(walkElement(t.child(0)), walkElement(t.child(1)),   false, true,  false);
+        if (head.equals("**"))  return new RepeatNode(walkElement(t.child(0)), null,                      true,  true,  true);
+        if (head.equals("*"))   return new RepeatNode(walkElement(t.child(0)), null,                      true,  true,  false);
+        if (head.equals("**/")) return new RepeatNode(walkElement(t.child(0)), walkElement(t.child(1)),   true,  true,  true);
+        if (head.equals("*/"))  return new RepeatNode(walkElement(t.child(0)), walkElement(t.child(1)),   true,  true,  false);
+        if (head.equals("?"))   return new RepeatNode(walkElement(t.child(0)), null,                      true,  false, false);
+
+        if (head.equals("!"))   return new DropNode(walkElement(t.child(0)));
+        if (head.equals("^"))   return new LiteralNode(walkString(t.child(0)), true);
+        if (head.equals("`"))   return walkElement(t.child(0)).lifted();
         if (head.equals("Quoted")) return stringifyChildren(t);
-        if (head.equals("Literal")) return new LiteralNode((String)walk(t.child(0)));
-        if (head.equals("->")) return arrow((Seq)walk(t.child(0)), (ElementNode)walk(t.child(1)));
-        if (head.equals("DropNT")) return new NonTerminalNode((String)walk(t.child(0)), (Seq[][])walkChildren(t.child(1)), false, null, true);
-        if (head.equals("=") && t.size()==2) return new NonTerminalNode((String)walk(t.child(0)), (Seq[][])walk(t.child(1)), true, null, false);
-        if (head.equals("=")) return new NonTerminalNode((String)walk(t.child(0)), (Seq[][])walk(t.child(2)), true, (String)walk(t.child(1)), false);
-        if (head.equals("&")) return and2((Seq)walk(t.child(0)), (Seq)walk(t.child(1)));
-        if (head.equals("&~")) return andnot2((Seq)walk(t.child(0)), (Seq)walk(t.child(1)));
-        if (head.equals("/")) return ((Seq)walk(t.child(0))).separate((ElementNode)walk(t.child(1)));
-        if (head.equals("()")) return epsilon;
-        if (head.equals("[")) return new AtomNode((AtomNodeRange[])Reflection.rebuild(walkChildren(t), AtomNodeRange[].class));
-        if (head.equals("\\{")) return new DropNode(new AtomNode(new AtomNodeRange(CharAtom.left, CharAtom.left)));
-        if (head.equals("\\}")) return new DropNode(new AtomNode(new AtomNodeRange(CharAtom.right, CharAtom.right)));
-        if (head.equals("~")) return new TildeNode((ElementNode)walk(t.child(0)));
-        if (head.equals("~~")) {
-            Seq seq = new Seq(star(new TildeNode(new AtomNode())));
-            return seq.andnot((Seq)walk(t.child(0)));
-        }
-        if (head.equals("Range") && t.size()==1) return new AtomNodeRange(unescape(t).charAt(0));
-        if (head.equals("Range")) return new AtomNodeRange(unescape(t).charAt(0), unescape(t).charAt(1));
+        if (head.equals("Literal")) return new LiteralNode(walkString(t.child(0)));
+        if (head.equals("->")) return walkSeq(t.child(0)).follow(walkElement(t.child(1)));
+        if (head.equals("DropNT")) return new NonTerminalNode(walkString(t.child(0)), (Seq[][])walkChildren(t.child(1)), false, null, true);
+        if (head.equals("=")) return new NonTerminalNode(walkString(t.child(0)), (Seq[][])walk(t.child(2)),
+                                                         true, t.size()==2 ? null : walkString(t.child(1)), false);
+        if (head.equals("&"))   return and2(walkSeq(t.child(0)), walkSeq(t.child(1)));
+        if (head.equals("&~"))  return andnot2(walkSeq(t.child(0)), walkSeq(t.child(1)));
+        if (head.equals("/"))   return (walkSeq(t.child(0))).separate(walkElement(t.child(1)));
+        if (head.equals("()"))  return new LiteralNode("");
+        if (head.equals("["))   return new AtomNode((char[][])Reflection.rebuild(walkChildren(t), char[][].class));
+        if (head.equals("\\{")) return new DropNode(new AtomNode(new char[] { CharAtom.left, CharAtom.left }));
+        if (head.equals("\\}")) return new DropNode(new AtomNode(new char[] { CharAtom.right, CharAtom.right }));
+        if (head.equals(">>"))  return new DropNode(new AtomNode(new char[] { CharAtom.left, CharAtom.left }));
+        if (head.equals("<<"))  return new DropNode(new AtomNode(new char[] { CharAtom.right, CharAtom.right }));
+        if (head.equals("~"))   return new TildeNode(walkElement(t.child(0)));
+        if (head.equals("~~"))  return new Seq(new RepeatNode(new TildeNode(new AtomNode()), null, true,  true,  false)).andnot(walkSeq(t.child(0)));
+        if (head.equals("Range") && t.size()==2 && ">".equals(t.child(0).head()))
+            return new char[] { CharAtom.left, CharAtom.left };
+        if (head.equals("Range") && t.size()==2 && "<".equals(t.child(0).head()))
+            return new char[] { CharAtom.right, CharAtom.right };
+        if (head.equals("Range") && t.size()==1) return new char[] { unescape(t).charAt(0), unescape(t).charAt(0) };
+        if (head.equals("Range")) return new char[] { unescape(t).charAt(0), unescape(t).charAt(1) };
         if (head.equals("\"\"")) return "";
         if (head.equals("\n")) return "\n";
         if (head.equals("\r")) return "\r";
@@ -210,7 +196,7 @@ public class GrammarBuilder {
         public Union build(String rootNonterminal) {
             Context cx = new Context(this);
             Union u = null;
-            for(GrammarBuilder.NonTerminalNode nt : values())
+            for(GrammarAST.NonTerminalNode nt : values())
                 if (nt.name.equals(rootNonterminal))
                     return (Union)cx.get(nt.name);
             return null;
@@ -359,20 +345,20 @@ public class GrammarBuilder {
                     els[i] = elements[i].build(cx, cnt, dropall);
             }
             if (tag==null && multiNonDrop)
-                throw new RuntimeException("multiple non-dropped elements in sequence: " + Sequence.create(els, ""));
-            boolean lift = false;
-            if (elements.length > 0 && elements[0].lifted)
-                lift = true;
+                throw new RuntimeException("multiple non-dropped elements in sequence: " + Sequence.create("", els));
+            boolean[] lifts = new boolean[elements.length];
+            for(int i=0; i<elements.length; i++)
+                lifts[i] = elements[i].lifted;
             if (!multiNonDrop) {
                 if (idx == -1) 
                     ret = tag==null
-                        ? Sequence.create(els, illegalTag)
-                        : Sequence.createLeft(tag, els, drops, lift);
+                        ? Sequence.create(illegalTag, els)
+                        : Sequence.create(tag, els, drops, lifts);
                 else if (tag==null) ret = Sequence.create(els, idx);
-                else ret = Sequence.createLeft(tag, els, drops, lift);
+                else ret = Sequence.create(tag, els, drops, lifts);
             }
             if (multiNonDrop)
-                ret = Sequence.createLeft(tag, els, drops, lift);
+                ret = Sequence.create(tag, els, drops, lifts);
             if (this.follow != null)
                 ret = ret.followedBy(this.follow.toAtom(cx));
             return ret;