clean up metagrammar handling of drop and question-mark
[sbp.git] / src / edu / berkeley / sbp / meta / GrammarBuilder.java
index 3651be3..e6e06ad 100644 (file)
@@ -264,7 +264,7 @@ public class GrammarBuilder {
     public class NonTerminalNode extends UnionNode {
         public boolean alwaysDrop;
         public String  name = null;
-        public boolean drop() { return alwaysDrop; }
+        public boolean drop(Context cx) { return alwaysDrop; }
         public NonTerminalNode(String name, Seq[][] sequences, boolean rep, String sep, boolean alwaysDrop) {
             super(sequences, rep, sep==null?null:(prefix + sep));
             this.name = prefix + name;
@@ -275,7 +275,7 @@ public class GrammarBuilder {
 
     public class Seq {
         public boolean alwaysDrop = false;
-        public boolean drop() { return alwaysDrop; }
+        public boolean drop(Context cx) { return alwaysDrop; }
         HashSet<Seq> and = new HashSet<Seq>();
         HashSet<Seq> not = new HashSet<Seq>();
         ElementNode[] elements;
@@ -326,13 +326,10 @@ public class GrammarBuilder {
         public Sequence build0(Context cx, NonTerminalNode cnt, boolean dropall) {
             boolean[] drops = new boolean[elements.length];
             Element[] els = new Element[elements.length];
-            dropall |= drop();
+            dropall |= drop(cx);
             for(int i=0; i<elements.length; i++) {
                 if (dropall) drops[i] = true;
-                else         drops[i] = elements[i].drop();
-                if (elements[i] instanceof ReferenceNode)
-                    if (((ReferenceNode)elements[i]).resolve(cx).drop())
-                        drops[i] = true;
+                else         drops[i] = elements[i].drop(cx);
                 if (elements[i].getOwnerTag() != null)
                     tag = elements[i].getOwnerTag();
             }
@@ -374,6 +371,7 @@ public class GrammarBuilder {
         public NonTerminalNode resolve(Context cx) { return cx.grammar.get(nonTerminal); }
         public ReferenceNode(String nonTerminal) { this.nonTerminal = prefix + nonTerminal; }
         public Atom toAtom(Context cx) { return cx.grammar.get(nonTerminal).toAtom(cx); }
+        public boolean drop(Context cx) { return resolve(cx).drop(cx); }
         public Element build(Context cx, NonTerminalNode cnt, boolean dropall) {
             if (!this.nonTerminal.startsWith(prefix)) nonTerminal = prefix + nonTerminal;
             Element ret = cx.get(nonTerminal);
@@ -393,7 +391,7 @@ public class GrammarBuilder {
         }
         public String getOwnerTag() { return caret ? thePrefix+string : super.getOwnerTag(); }
         public String toString() { return "\""+string+"\""; }
-        public boolean drop() { return true; }
+        public boolean drop(Context cx) { return true; }
         public Atom toAtom(Context cx) {
             if (string.length()!=1) return super.toAtom(cx);
             edu.berkeley.sbp.util.Range.Set set = new edu.berkeley.sbp.util.Range.Set();
@@ -423,16 +421,23 @@ public class GrammarBuilder {
 
     public class RepeatNode extends ElementNode {
         public ElementNode e, sep;
-        public boolean zero, many, max;
+        public final boolean zero, many, max;
         public RepeatNode(ElementNode e, ElementNode sep, boolean zero, boolean many, boolean max) {
-            this.e = e; this.sep = sep; this.zero = zero; this.many = many; this.max = max;}
+            this.e = e; this.sep = sep; this.zero = zero; this.many = many; this.max = max;
+        }
         public Atom toAtom(Context cx) { return sep==null ? e.toAtom(cx) : super.toAtom(cx); }
+        public boolean drop(Context cx) { return e.drop(cx); }
         public Element build(Context cx, NonTerminalNode cnt, boolean dropall) {
-            if (!dropall && !drop() && !e.drop())
-                throw new Error("you need a tag on this repetition: " + build(cx, cnt, dropall, ""));
-            return build(cx, cnt, dropall, illegalTag);
+            Element ret = build(cx, cnt, dropall, illegalTag);
+            String must = "must be tagged unless they appear within a dropped expression or their contents are dropped: ";
+            if (!dropall && !drop(cx) && !e.drop(cx))
+                if (!many)      throw new RuntimeException("options (?) " + must + ret);
+                else if (zero)  throw new RuntimeException("zero-or-more repetitions (*) " + must + ret);
+                else            throw new RuntimeException("one-or-more repetitions (+) " + must + ret);
+            return ret;
         }
         public Element build(Context cx, NonTerminalNode cnt, boolean dropall, Object repeatTag) {
+            if (!many) System.out.println("tag is: " + repeatTag);
             return (!max)
                 ? Repeat.repeat(e.build(cx, null, dropall), zero, many, sep==null ? null : sep.build(cx, null, dropall), repeatTag)
                 : sep==null
@@ -443,7 +448,7 @@ public class GrammarBuilder {
 
     public abstract class ElementNode {
         public String getOwnerTag() { return null; }
-        public boolean drop() { return false; }
+        public boolean drop(Context cx) { return false; }
         public Atom toAtom(Context cx) { throw new Error("can't convert a " + this.getClass().getName() + " to an atom: " + this); }
         public abstract Element build(Context cx, NonTerminalNode cnt, boolean dropall);
     }
@@ -452,7 +457,7 @@ public class GrammarBuilder {
         protected ElementNode _e;
         public ElementNodeWrapper(ElementNode e) { this._e = e; }
         public String getOwnerTag() { return _e.getOwnerTag(); }
-        public boolean drop() { return _e.drop(); }
+        public boolean drop(Context cx) { return _e.drop(cx); }
         public Atom toAtom(Context cx) { return _e.toAtom(cx); }
         public Element build(Context cx, NonTerminalNode cnt, boolean dropall) { return _e.build(cx, cnt, dropall); }
     }
@@ -465,7 +470,7 @@ public class GrammarBuilder {
 
     public class DropNode extends ElementNodeWrapper {
         public DropNode(ElementNode e) { super(e); }
-        public boolean drop() { return true; }
+        public boolean drop(Context cx) { return true; }
     }
 
     public    Seq  and2(Seq s,        Seq a)   { a.alwaysDrop = true;  return s.and(a); }
@@ -482,7 +487,7 @@ public class GrammarBuilder {
     public    ElementNode star(final ElementNode e)                            { return new RepeatNode(e, null, true,  true, false); }
     public  ElementNode starmaxfollow(final ElementNode e, final ElementNode sep)     { return new RepeatNode(e, sep,  true,  true, true); }
     public   ElementNode starfollow(final ElementNode e, final ElementNode sep)        { return new RepeatNode(e, sep,  true,  true, false); }
-    public    ElementNode question(final ElementNode e)                        { return new RepeatNode(e, null, true,  true, false); }
+    public    ElementNode question(final ElementNode e)                        { return new RepeatNode(e, null, true,  false, false); }
 
     //////////////////////////////////////////////////////////////////////////////
 
@@ -511,7 +516,7 @@ public class GrammarBuilder {
             } else {
                 ret = new Union(name, false);
                 map.put(name, ret);
-                nt.buildIntoPreallocatedUnion(this, nt, nt.drop(), ret);
+                nt.buildIntoPreallocatedUnion(this, nt, nt.drop(this), ret);
             }
             return ret;
         }