d3d8d8a136d124dfdca130cd15ad651e9f146aa0
[sbp.git] / src / edu / berkeley / sbp / Sequence.java
1 // Copyright 2006 all rights reserved; see LICENSE file for BSD-style license
2
3 package edu.berkeley.sbp;
4 import edu.berkeley.sbp.util.*;
5 import edu.berkeley.sbp.*;
6 import edu.berkeley.sbp.*;
7 import java.io.*;
8 import java.util.*;
9 import java.lang.reflect.*;
10 import java.lang.ref.*;
11
12 /** <font color=green>juxtaposition; zero or more adjacent Elements; can specify a rewriting</font> */
13 public abstract class Sequence implements Iterable<Element>, SequenceOrElement {
14
15     protected final Element[] elements;
16
17     public boolean needed_or_hated = false;
18
19     final HashSet<Sequence> hated  = new HashSet<Sequence>();
20
21     final HashSet<Sequence> needs  = new HashSet<Sequence>();
22     final HashSet<Sequence> hates  = new HashSet<Sequence>();
23
24     final Position          firstp;
25
26     Atom follow = null;
27
28     // Static Constructors //////////////////////////////////////////////////////////////////////////////
29
30     abstract Sequence _clone();
31     Sequence dup() {
32         Sequence ret = _clone();
33         for(Sequence s : needs) { ret.needs.add(s); }
34         for(Sequence s : hates) { ret.hates.add(s); s.hated.add(ret); }
35         ret.follow = follow;
36         return ret;
37     }
38
39     /** create an empty sequence (matches the empty string) */
40     public static Sequence create() { return new Sequence.Constant.Empty(); }
41
42     /** create a sequence of one element */
43     public static Sequence create(Element e) { return create(new Element[] { e }, 0); }
44
45     /** create a sequence which drops the result of all but one of its element */
46     public static Sequence create(Element[] e, int which) { return new Singleton(e, which); }
47
48     /** create a sequence which always evaluates to a constant result  */
49     public static Sequence create(Element[] e, Object result) { return new Constant(e, result); }
50
51     /**
52      *  create a sequence (general form)
53      *  @param head   the head of the output tree
54      *  @param e      the elements to match
55      *  @param drop   only elements of <tt>e</tt> whose corresponding <tt>boolean</tt> in <tt>drops</tt>
56      *                is <i>false</i> will be included in the output tree
57      *  @param foster if true, all children of the last child (ie
58      *                grandchildren) are promoted to children of this
59      *                node; this is very useful for matching repetitions
60      **/
61     public static Sequence create(Object head, Element[] e, boolean[] drop, boolean foster) {
62         return foster
63             ? new Unwrap(e, head, drop)
64             : new RewritingSequence(head, e, drop);
65     }
66
67     ////////////////////////////////////////////////////////////////////////////////
68
69     /** return a new sequence identical to this one, but with a positive conjunct <tt>s</tt> */
70     public Sequence and(Sequence s) { Sequence ret = dup(); ret.needs.add(s); s.needed_or_hated=true; return ret; }
71
72     /** return a new sequence identical to this one, but with a negative conjunct <tt>s</tt> */
73     public Sequence andnot(Sequence s) { Sequence ret = dup(); ret.hates.add(s); s.hated.add(ret); s.needed_or_hated=true; return ret; }
74
75     /** return a new sequence identical to this one, but with a follow-set restricted to <tt>a</tt> */
76     public Sequence followedBy(Atom a) { Sequence ret = dup(); ret.follow = a; return ret; }
77
78     boolean hatesAny(Iterable<Sequence> it) {
79         if (hates.isEmpty()) return false;
80         for(Sequence s : it) if (hates.contains(s)) return true;
81         return false;
82     }
83
84     Iterable<Sequence> needs() { return needs; }
85     Iterable<Sequence> hates() { return hates; }
86
87     Position firstp() { return firstp; }
88
89     public Iterator<Element> iterator()    { return new ArrayIterator<Element>(elements); }
90     protected Sequence(Element[] elements) {
91         this.elements = elements;
92         this.firstp = new Position(0);
93     }
94
95     // DO NOT MESS WITH THE FOLLOWING LINE!!!
96     private Forest.Many epsilonForm = null;
97     Forest epsilonForm(Input.Region loc) {
98         if (epsilonForm!=null) return epsilonForm;
99         epsilonForm = new Forest.Many();
100         epsilonForm.merge(firstp().rewrite(loc, false));
101         return epsilonForm;
102     }
103
104     protected abstract <T> Forest<T> postReduce(Input.Region loc, Forest<T>[] args, Position p);
105
106
107     // Position //////////////////////////////////////////////////////////////////////////////
108
109     /** the imaginary position before or after an element of a sequence; corresponds to an "LR item" */
110     class Position implements IntegerMappable {
111
112         private Forest zero = null;
113         public Forest zero(Input.Region reg) {
114             if (zero != null) return zero;
115             if (pos > 0) throw new Error();
116             return zero = rewrite(reg);
117         }
118
119
120                 final int      pos;
121         private final Position next;
122                 final Forest[] holder;
123         
124         private Position(int pos) {
125             this.pos      = pos;
126             this.next     = pos==elements.length ? null : new Position(pos+1);
127             this.holder   = new Forest[elements.length];
128         }
129
130         boolean isFirst() { return pos==0; }
131
132         /** the element immediately after this Position, or null if this is the last Position */
133         public Element  element() { return pos>=elements.length ? null : elements[pos]; }
134
135         /** the element which produces the sequence to which this Position belongs */
136         public Sequence owner() { return Sequence.this; }
137
138         /** the next Position (the Position after <tt>this.element()</tt>) */
139         public Position next() { return next; }
140
141         /** true iff this Position is the last one in the sequence */
142         public boolean isLast() { return next()==null; }
143
144         // Position /////////////////////////////////////////////////////////////////////////////////
145
146         final <T> Forest<T> rewrite(Input.Region loc) { return rewrite(loc, true); }
147         private final <T> Forest<T> rewrite(Input.Region loc, boolean epsilonCheck) {
148             if (epsilonCheck && this==firstp()) return epsilonForm(loc);
149             for(int i=0; i<pos; i++) if (holder[i]==null) throw new Error("realbad " + i);
150             for(int i=pos; i<elements.length; i++) {
151                 if (holder[i]==null) holder[i] = elements[i].epsilonForm(loc);
152                 if (holder[i]==null) throw new Error("bad " + i);
153             }
154             Forest<T> ret = Sequence.this.postReduce(loc, holder, this);
155             //for(int k=0; k<pos; k++) holder[k] = null; // to help GC
156             return ret;
157         }
158
159         public String   toString() {
160             StringBuffer ret = new StringBuffer();
161             ret.append("<{");
162             for(Position p = Sequence.this.firstp(); p != null; p = p.next()) {
163                 ret.append(' ');
164                 if (p==this) ret.append(" | ");
165                 if (p.element()!=null) ret.append(p.element());
166                 else                   ret.append(' ');
167             }
168             ret.append("}>");
169             return ret.toString();
170         }
171         private final int idx = master_position_idx++;
172         public int toInt() { return idx; }
173     }
174     private static int master_position_idx = 0;
175
176     // toString //////////////////////////////////////////////////////////////////////////////
177
178     public String toString() { return toString(new StringBuffer(), false).toString(); }
179     StringBuffer toString(StringBuffer sb) { return toString(sb, true); }
180     StringBuffer toString(StringBuffer sb, boolean spacing) {
181         for(int i=0; i<elements.length; i++) {
182             sb.append(elements[i].toString());
183             sb.append(' ');
184         }
185         if (follow != null) {
186             sb.append("-> ");
187             sb.append(follow);
188         }
189         for(Sequence s : needs) {
190             sb.append("& ");
191             sb.append(s);
192         }
193         for(Sequence s : hates) {
194             sb.append("&~ ");
195             sb.append(s);
196         }
197         return sb;
198     }
199
200
201     // Specialized Subclasses //////////////////////////////////////////////////////////////////////////////
202
203     static class Constant extends Sequence {
204         private final Object result;
205         public Constant(Element[] e, Object result) { super(e); this.result = result; }
206         Sequence _clone() { return new Constant(elements, result); }
207         public <T> Forest<T> postReduce(Input.Region loc, Forest<T>[] args, Position p) {
208             return (Forest<T>)Forest.create(loc, result, null, false);
209         }
210         static class Drop extends Constant {
211             Sequence _clone() { return new Drop(elements); }
212             public Drop(Element[] e) { super(e, null); }
213         }
214         static class Empty extends Sequence.Constant.Drop {
215             Sequence _clone() { return new Empty(); }
216             public Empty() { super(new Element[] { }); } }
217     }
218
219     static class Singleton extends Sequence {
220         private final int idx;
221         public Singleton(Element e) { this(new Element[] { e }, 0); }
222         public Singleton(Element[] e, int idx) { super(e); this.idx = idx; }
223         public <T> Forest<T> postReduce(Input.Region loc, Forest<T>[] args, Position p) { return args[idx]; }
224         Sequence _clone() { return new Singleton(elements,idx); }
225     }
226
227     static class Unwrap extends Sequence {
228         private boolean[] drops;
229         private final Object tag;
230         public Unwrap(Element[] e, Object tag)                  { super(e); this.drops = null; this.tag = tag; }
231         public Unwrap(Element[] e, Object tag, boolean[] drops) { super(e); this.drops = drops; this.tag = tag; }
232         Sequence _clone() { return new Unwrap(elements, tag, drops); }
233         public <T> Forest<T> postReduce(Input.Region loc, Forest<T>[] args, Position p) {
234             for(int i=0; i<args.length; i++) if (args[i]==null) throw new Error();
235             if (drops==null) return Forest.create(loc, (T)tag, args, true);
236             int count = 0;
237             for(int i=0; i<drops.length; i++) if (!drops[i]) count++;
238             Forest<T>[] args2 = new Forest[count];
239             int j = 0;
240             for(int i=0; i<args.length; i++) if (!drops[i]) args2[j++] = args[i];
241             return Forest.create(loc, (T)tag, args2, true);
242         }
243     }
244
245
246
247     static class RegionRewritingSequence extends RewritingSequence {
248         private Functor<Input.Region, Object> tagf;
249         public RegionRewritingSequence(Functor<Input.Region,Object> tagfunctor, Element[] e, boolean[] drops) {
250             super(null, e, drops);
251             this.tagf = tagfunctor;
252         }
253         public <T> Forest<T> postReduce(Input.Region loc, Forest<T>[] args, Position p) {
254             this.tag = tagf.invoke(loc);
255             Forest<T> ret = super.postReduce(loc, args, p);
256             this.tag = null;
257             return ret;
258         }
259     }
260
261     static class RewritingSequence extends Sequence {
262         /*private*/public /*final*/ Object tag;
263         private final boolean[] drops;
264         private int count = 0;
265         Sequence _clone() { return new RewritingSequence(tag, elements, drops); }
266         public RewritingSequence(Object tag, Element[] e) { this(tag, e, null); }
267         public RewritingSequence(Object tag, Element[] e, boolean[] drops) {
268             super(e);
269             this.tag = tag;
270             this.drops = drops == null ? new boolean[e.length] : drops;
271             for(int i=0; i<this.drops.length; i++) if (!this.drops[i]) count++;
272         }
273         public <T> Forest<T> postReduce(Input.Region loc, Forest<T>[] args, Position p) {
274             Forest<T>[] args2 = new Forest[count];
275             int j = 0;
276             for(int i=0; i<args.length; i++) if (!drops[i]) args2[j++] = args[i];
277             //System.out.println("reduce \""+tag+"\"");
278             return Forest.create(loc, (T)tag, args2, false);
279         }
280         public StringBuffer toString(StringBuffer sb, boolean spacing) {
281             int len = sb.length();
282             if (tag != null)
283                 sb.append("\""+StringUtil.escapify(tag.toString(),"\"\r\n")+"\":: ");
284             super.toString(sb, spacing);
285             len = sb.length()-len;
286             if (spacing) for(int i=0; i<50-len; i++) sb.append(' ');
287             return sb;
288         }
289     }
290
291 }