MAJOR: huge revamp of Sequence, Result, Reduction, Parser, Node, GSS
[sbp.git] / src / edu / berkeley / sbp / meta / MetaGrammarBindings.java
index 8f322a5..927cd62 100644 (file)
@@ -1,3 +1,5 @@
+// Copyright 2006 all rights reserved; see LICENSE file for BSD-style license
+
 package edu.berkeley.sbp.meta;
 import edu.berkeley.sbp.util.*;
 import edu.berkeley.sbp.*;
@@ -64,23 +66,26 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
 
     public abstract static class UnionNode extends ElementNode {
         public Seq[][] sequences;
+        public Atom toAtom(Context cx) {
+            Atom ret = null;
+            for(Seq[] ss : sequences)
+                for(Seq s : ss)
+                    ret = ret==null ? s.toAtom(cx) : (Atom)ret.union(s.toAtom(cx));
+            return ret;
+        }
         public void build(Context cx, Union u, NonTerminalNode cnt) {
             HashSet<Sequence> bad2 = new HashSet<Sequence>();
             for(int i=0; i<sequences.length; i++) {
                 Seq[] group = sequences[i];
-                Union u2 = new Union();
+                Union u2 = new Union(null, false);
                 if (sequences.length==1) u2 = u;
-                for(int j=0; j<group.length; j++) {
-                    group[j].build(cx, u2, false, cnt);
-                }
+                for(int j=0; j<group.length; j++)
+                    group[j].build(cx, u2, cnt);
                 if (sequences.length==1) break;
-                Sequence seq = Sequence.singleton(u2);
-                for(Sequence s : bad2) {
-                    s.lame = true;
-                    seq = seq.not(s);
-                }
+                Sequence seq = Sequence.create(u2);
+                for(Sequence s : bad2) seq = seq.andnot(s);
                 u.add(seq);
-                bad2.add(Sequence.singleton(u2));
+                bad2.add(Sequence.create(u2));
             }
         }
     }
@@ -123,33 +128,31 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
             if (!rep) { super.build(cx, u, this); return; }
             HashSet<Sequence> bad2 = new HashSet<Sequence>();
 
-            Union urep = new Union();
-            urep.add(Sequence.empty);
+            Union urep = new Union(null, false);
+            urep.add(Sequence.create());
             if (sep != null)
-                urep.add(Sequence.singleton(new Element[] { cx.get(sep), u }, 1));
+                urep.add(Sequence.create(new Element[] { cx.get(sep), u }, 1));
             else
-                urep.add(Sequence.singleton(new Element[] { u }, 0));
+                urep.add(Sequence.create(new Element[] { u }, 0));
 
             for(int i=0; i<sequences.length; i++) {
                 Seq[] group = sequences[i];
-                Union u2 = new Union();
+                Union u2 = new Union(null, false);
                 if (sequences.length==1) u2 = u;
                 for(int j=0; j<group.length; j++) {
-                    Union u3 = new Union();
-                    group[j].build(cx, u3, false, this);
-                    Sequence s = Sequence.unwrap(new Element[] { u3, urep },
-                                                 cx.rm.repeatTag(),
-                                                 new boolean[] { false, false });
+                    Union u3 = new Union(null, false);
+                    group[j].build(cx, u3, this);
+                    Sequence s = Sequence.create(cx.rm.repeatTag(),
+                                                 new Element[] { u3, urep },
+                                                 new boolean[] { false, false },
+                                                 true);
                     u2.add(s);
                 }
                 if (sequences.length==1) break;
-                Sequence seq = Sequence.singleton(u2);
-                for(Sequence s : bad2) {
-                    s.lame = true;
-                    seq = seq.not(s);
-                }
+                Sequence seq = Sequence.create(u2);
+                for(Sequence s : bad2) seq = seq.andnot(s);
                 u.add(seq);
-                bad2.add(Sequence.singleton(u2));
+                bad2.add(Sequence.create(u2));
             }
         }
     }
@@ -164,7 +167,7 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
             this.sequences = sequences;
         }
         public Element build(Context cx, NonTerminalNode cnt) {
-            Union ret = new Union();
+            Union ret = new Union(null, false);
             build(cx, ret, cnt);
             return ret;
         }
@@ -183,7 +186,6 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
         ElementNode[] elements;
         ElementNode follow;
         String tag = null;
-        boolean lame;
         public void append(ElementNode e) {
             ElementNode[] elements = new ElementNode[this.elements.length+1];
             System.arraycopy(this.elements, 0, elements, 0, this.elements.length);
@@ -192,8 +194,15 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
         }
         public Seq(ElementNode e) { this(new ElementNode[] { e }); }
         public Seq(ElementNode[] elements) { this.elements = elements; }
+        public Atom toAtom(Context cx) {
+            if (elements.length != 1) throw new Error("you attempted to use ->, **, ++, or a similar character-class operator on a [potentially] multicharacter production");
+            return elements[0].toAtom(cx);
+        }
         public Seq tag(String tag) { this.tag = prefix+tag; return this; }
-        public Seq follow(ElementNode follow) { this.follow = follow; return this; }
+        public Seq follow(ElementNode follow) {
+            this.follow = follow;
+            return this;
+       }
         public Seq dup() {
             Seq ret = new Seq(elements);
             ret.and.addAll(and);
@@ -202,8 +211,8 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
             ret.tag = prefix+tag;
             return ret;
         }
-        public Seq and(Seq s) { and.add(s); s.lame = true; return this; }
-        public Seq andnot(Seq s) { not.add(s); s.lame = true; return this; }
+        public Seq and(Seq s) { and.add(s); return this; }
+        public Seq andnot(Seq s) { not.add(s); return this; }
         public Seq separate(ElementNode sep) {
             ElementNode[] elements = new ElementNode[this.elements.length * 2 - 1];
             for(int i=0; i<this.elements.length; i++) {
@@ -214,17 +223,14 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
             this.elements = elements;
             return this;
         }
-        public Sequence build(Context cx, Union u, boolean lame, NonTerminalNode cnt) {
-            Sequence ret = build0(cx, lame || this.lame, cnt);
-            for(Seq s : and) { Sequence dork = s.build(cx, u, true, cnt); ret = ret.and(dork); }
-            for(Seq s : not) { Sequence dork = s.build(cx, u, true, cnt); ret = ret.not(dork); }
-            u.add(ret);
-            ret.lame = lame;
+        public Sequence build(Context cx, Union u, NonTerminalNode cnt) {
+            Sequence ret = build0(cx, cnt);
+            for(Seq s : and) { Sequence dork = s.build(cx, null, cnt); ret = ret.and(dork); }
+            for(Seq s : not) { Sequence dork = s.build(cx, null, cnt); ret = ret.andnot(dork); }
+            if (u!=null) u.add(ret);
             return ret;
         }
-        public Sequence build0(Context cx, boolean lame, NonTerminalNode cnt) {
-            boolean dropAll = lame;
-            if (tag!=null && tag.endsWith("()")) dropAll = true;
+        public Sequence build0(Context cx, NonTerminalNode cnt) {
             boolean[] drops = new boolean[elements.length];
             Element[] els = new Element[elements.length];
             for(int i=0; i<elements.length; i++) {
@@ -234,38 +240,37 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
                     tag = elements[i].getOwnerTag();
             }
             Sequence ret = null;
-            if (dropAll)     ret = Sequence.drop(els, false);
-            else {
-                Production prod = new Production(tag, (cnt==null?null:cnt.name), els, drops);
-                ret = cx.rm.createSequence(prod);
-                if (ret == null) {
-                    int idx = -1;
-                    for(int i=0; i<els.length; i++)
-                        if (!drops[i])
-                            if (idx==-1) idx = i;
-                            else throw new Error("multiple non-dropped elements in sequence: " + Sequence.drop(els,false));
-                    if (idx != -1) ret = Sequence.singleton(els, idx);
-                    else           ret = Sequence.drop(els, false);
-                }
+            Production prod = new Production(tag, (cnt==null?null:cnt.name), els, drops);
+            ret = cx.rm.createSequence(prod);
+            if (ret == null) {
+                int idx = -1;
+                for(int i=0; i<els.length; i++)
+                    if (!drops[i])
+                        if (idx==-1) idx = i;
+                        else throw new Error("multiple non-dropped elements in sequence: " + Sequence.create(els, null));
+                if (idx != -1) ret = Sequence.create(els, idx);
+                else           ret = Sequence.create(els, null);
             }
             if (this.follow != null)
-                ret.follow = infer(this.follow.build(cx, null));
-            ret.lame = this.lame;
+                ret = ret.followedBy(this.follow.toAtom(cx));
             return ret;
         }
     }
-    public static @bind.as("&")   Seq  and2(Seq s,        Seq a) { return s.and(a); }
-    public static @bind.as("&~")  Seq  andnot2(Seq s,     Seq a) { return s.andnot(a); }
-    public static @bind.as("->")  Seq  arrow(Seq s, ElementNode e)                { return s.follow(e); }
-    public static @bind.as("::")  Seq  tag(String tagname, Seq s)        { return s.tag(tagname); }
-    public static @bind.as("/")   Seq  slash(Seq s, ElementNode e)                { return s.separate(e); }
+    public static @bind.as("&")   Seq  and2(Seq s,        Seq a)   { return s.and(a); }
+    public static @bind.as("&~")  Seq  andnot2(Seq s,     Seq a)   { return s.andnot(a); }
+    public static @bind.as("->")  Seq  arrow(Seq s, ElementNode e) { return s.follow(e); }
+    public static @bind.as("::")  Seq  tag(String tagname, Seq s)  { return s.tag(tagname); }
+    public static @bind.as("/")   Seq  slash(Seq s, ElementNode e) { return s.separate(e); }
 
     public static Seq  seq(ElementNode[] elements)               { return new Seq(elements); }
     public static @bind.as("Elements")  Seq  seq2(ElementNode[] elements)               { return new Seq(elements); }
     public static @bind.as        Seq  psx(Seq s)                        { return s; }
     public static @bind.as(":")   ElementNode   colon(String s, ElementNode e)             { return new Label(s, e); }
     public static @bind.as(")")   void close(String foo)                 { throw new Error("not supported"); }
-    public static @bind.as("()")  ElementNode   epsilon()                         { return new Constant(Union.epsilon); }
+    public static @bind.as("()")  ElementNode   epsilon()                         { return new Constant(epsilon); }
+
+    private static Union epsilon = new Union("()");
+    static { epsilon.add(Sequence.create()); }
 
     public static class NonTerminalReferenceNode extends ElementNode {
         public String nonTerminal;
@@ -273,6 +278,9 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
         public @bind.as("NonTerminalReference") NonTerminalReferenceNode(String nonTerminal) {
             this.nonTerminal = prefix + nonTerminal;
         }
+        public Atom toAtom(Context cx) {
+            return cx.grammar.get(nonTerminal).toAtom(cx);
+        }
         public Element build(Context cx, NonTerminalNode cnt) {
             if (!this.nonTerminal.startsWith(prefix)) nonTerminal = prefix + nonTerminal;
             Element ret = cx.get(nonTerminal);
@@ -282,33 +290,54 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
     }
 
     public static class Literal extends Constant {
-        public @bind Literal(@bind.arg String string) { super(CharRange.string(string)); }
+        private String string;
+        public @bind Literal(@bind.arg String string) {
+            super(CharAtom.string(string));
+            this.string = string;
+        }
         public boolean drop() { 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();
+            set.add(string.charAt(0), string.charAt(0));
+            return CharAtom.set(set);
+        }
     }
 
     public static                     class CharClass            extends ElementNode {
         Range[] ranges;
         public @bind.as("[") CharClass(Range[] ranges) { this.ranges = ranges; }
+        public Atom toAtom(Context cx) {
+            edu.berkeley.sbp.util.Range.Set set = new edu.berkeley.sbp.util.Range.Set();
+            for(Range r : ranges)
+                set.add(r.first, r.last);
+            return CharAtom.set(set);
+        }
         public Element build(Context cx, NonTerminalNode cnt) {
             edu.berkeley.sbp.util.Range.Set set = new edu.berkeley.sbp.util.Range.Set();
             for(Range r : ranges)
                 set.add(r.first, r.last);
-            return CharRange.set(set);
+            return CharAtom.set(set);
         }
     }
 
+    public static @bind.as("\\{") ElementNode   leftBrace() {
+        return new Drop(new CharClass(new Range[] { new Range(CharAtom.left, CharAtom.left) })); }
+    public static @bind.as("\\}") ElementNode   rightBrace() {
+        return new Drop(new CharClass(new Range[] { new Range(CharAtom.right, CharAtom.right) })); }
+
     public static @bind.as("{")           class XTree                 extends ElementNode {
         public @bind.arg Seq body;
         public Element build(Context cx, NonTerminalNode cnt) {
-            Union u = new Union();
-            Sequence s = body.build(cx, u, false, null);
-            Union u2 = new Union();
-            u2.add(Sequence.singleton(new Element[] {
-                CharRange.leftBrace,
+            Union u = new Union(null, false);
+            Sequence s = body.build(cx, u, null);
+            Union u2 = new Union(null, false);
+            u2.add(Sequence.create(new Element[] {
+                CharAtom.leftBrace,
                 cx.get("ws"),
                 u,
                 cx.get("ws"),
-                CharRange.rightBrace
+                CharAtom.rightBrace
             }, 2));
             return u2;
         }
@@ -319,12 +348,16 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
         public boolean zero, many, max;
         public Rep(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;}
+        public Atom toAtom(Context cx) {
+            if (sep != null) return super.toAtom(cx);
+            return e.toAtom(cx);
+        }
         public Element build(Context cx, NonTerminalNode cnt) {
             return (!max)
-                ? Sequence.repeat(e.build(cx, null), zero, many, sep==null ? null : sep.build(cx, null), cx.rm.repeatTag())
+                ? Repeat.repeat(e.build(cx, null), zero, many, sep==null ? null : sep.build(cx, null), cx.rm.repeatTag())
                 : sep==null
-                ? Sequence.repeatMaximal(infer(e.build(cx, null)), zero, many, cx.rm.repeatTag())
-                : Sequence.repeatMaximal(e.build(cx, null), zero, many, infer(sep.build(cx, null)), cx.rm.repeatTag());
+                ? Repeat.repeatMaximal(e.toAtom(cx), zero, many, cx.rm.repeatTag())
+                : Repeat.repeatMaximal(e.build(cx, null), zero, many, sep.toAtom(cx), cx.rm.repeatTag());
         }
     }
 
@@ -352,27 +385,34 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
 
     public static @bind.as("^")   ElementNode caret(final String s) {
         final String thePrefix = prefix;
-        return new Constant(CharRange.string(s)) {
+        return new Constant(CharAtom.string(s)) {
                 public String getOwnerTag() { return thePrefix+s; }
                 public boolean drop() { return true; }
             };
     }
 
     public static @bind.as("~")   ElementNode tilde(final ElementNode e) {
-        return new PostProcess(e) {
-                public Element postProcess(Element e) {
-                    return infer((Topology<Character>)Atom.toAtom(e).complement().minus(CharRange.braces));
+        return new ElementNodeWrapper(e) {
+                public Atom toAtom(Context cx) {
+                    return infer((Topology<Character>)e.toAtom(cx).complement()/*.minus(CharAtom.braces)*/);
+                }
+                public Element build(Context cx, NonTerminalNode cnt) {
+                    return infer((Topology<Character>)e.toAtom(cx).complement()/*.minus(CharAtom.braces)*/);
                 } }; }
 
     public static @bind.as("Word")        String word(String s) { return s; }
     public static @bind.as("Quoted")      String quoted(String s) { return s; }
-    public static @bind.as("escaped")     String c(char c) { return c+""; }
+    public static @bind.as("escaped")     String c(char c) {
+        if (c=='{') return CharAtom.left+"";
+        if (c=='}') return CharAtom.right+"";
+        return c+"";
+    }
     public static @bind.as("EmptyString") String emptystring() { return ""; }
     public static @bind.as("\n")          String retur() { return "\n"; }
     public static @bind.as("\r")          String lf() { return "\r"; }
 
-    static Atom infer(Element e)  { return infer((Topology<Character>)Atom.toAtom(e)); }
-    static Atom infer(Topology<Character> t) { return new CharRange(new CharTopology(t)); }
+    //static Atom infer(Element e)  { return infer((Topology<Character>)Atom.toAtom(e)); }
+    static Atom infer(Object t) { return (Atom)t; }
 
     public static class Context {
         public HashMap<String,Union> map = new HashMap<String,Union>();
@@ -422,6 +462,7 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
         public String getLabel() { return null; }
         public String getOwnerTag() { return null; }
         public boolean drop() { return false; }
+        public Atom toAtom(Context cx) { throw new Error("can't convert a " + this.getClass().getName() + " to an atom"); }
         public abstract Element build(Context cx, NonTerminalNode cnt);
     }
 
@@ -431,6 +472,7 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
         public String getLabel() { return _e.getLabel(); }
         public String getOwnerTag() { return _e.getOwnerTag(); }
         public boolean drop() { return _e.drop(); }
+        public Atom toAtom(Context cx) { return _e.toAtom(cx); }
         public Element build(Context cx, NonTerminalNode cnt) { return _e.build(cx, cnt); }
     }
 
@@ -438,10 +480,13 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
         Element constant;
         public Constant(Element constant) { this.constant = constant; }
         public Element build(Context cx, NonTerminalNode cnt) { return constant; }
+        public Atom toAtom(Context cx) {
+            if (constant instanceof Atom) return ((Atom)constant);
+            return super.toAtom(cx);
+        }
     }
 
     public abstract static class PostProcess extends ElementNodeWrapper {
-        ElementNode e;
         public PostProcess(ElementNode e) { super(e); }
         public Element build(Context cx, NonTerminalNode cnt) { return postProcess(_e.build(cx, cnt)); }
         public abstract Element postProcess(Element e);
@@ -457,4 +502,13 @@ public class MetaGrammarBindings extends AnnotationGrammarBindings {
         public Label(String label, ElementNode e) { super(e); this.label = label; }
         public String getLabel() { return label; }
     }
+
+    /*
+    static class Invert extends Atom {
+        private final Atom a;
+        public Invert(Atom a) { this.a = a; }
+        public Topology top() { return a.complement(); }
+        public String toString() { return "~"+a; }
+    }
+    */
 }