705208f672d5305446865bcb31d26ca8f632801a
[sbp.git] / src / edu / berkeley / sbp / Forest.java
1 package edu.berkeley.sbp;
2 import edu.berkeley.sbp.*;
3 import edu.berkeley.sbp.*;
4 import edu.berkeley.sbp.util.*;
5 import java.io.*;
6 import java.util.*;
7 import java.lang.reflect.*;
8
9 /** an efficient representation of a collection of trees (Tomita's shared packed parse forest) */
10 public abstract class Forest<T> {
11
12     /** assume that this forest contains exactly one tree and return it; otherwise throw an exception */
13     public final Tree<T> expand1() throws Parser.Ambiguous, Parser.Failed {
14         Iterator<Tree<T>> it = expand(true).iterator();
15         if (!it.hasNext()) throw new Parser.Failed();
16         return it.next();
17     }
18
19     /** expand this forest into a set of trees */
20     public abstract HashSet<Tree<T>>  expand(boolean toss);
21
22     static        <T> Forest<T> singleton(Token.Location loc)                       { return create(loc, null, new Forest[] { }, false, true); }
23     static        <T> Forest<T> singleton(Token.Location loc, Forest<T> body)       { return create(loc, null, new Forest[] { body },  false, true); }
24     static        <T> Forest<T> leaf(Token.Location loc, T tag) { return create(loc, tag, null, false, false); }
25     public static <T> Forest<T> create(Token.Location loc, T tag, Forest<T>[] tokens, boolean unwrap, boolean singleton) {
26         return new MultiForest<T>(loc, tag, tokens, unwrap, singleton);
27     }
28
29     // Body //////////////////////////////////////////////////////////////////////////////
30
31     protected static class Body<T> {
32
33         private final Token.Location    location;
34         private final T                 tag;
35         private final Forest<T>[]       tokens;
36         private final boolean           unwrap;
37         private final boolean           singleton;
38
39         private Body(Token.Location loc, T tag, Forest<T>[] tokens, boolean unwrap, boolean singleton) {
40             this.location = loc;
41             this.tag = tag;
42             this.tokens = tokens==null ? emptyForestArray : new Forest[tokens.length];
43             if (tokens != null) System.arraycopy(tokens, 0, this.tokens, 0, tokens.length);
44             if (tokens != null) for(int i=0; i<tokens.length; i++) if (tokens[i]==null) throw new Error(i+"");
45             this.unwrap = unwrap;
46             this.singleton = singleton;
47         }
48
49         private HashSet<Tree<T>> expand(boolean toss, ArrayList<Tree<T>> toks, int i, HashSet<Tree<T>> h) {
50             if (singleton) {
51                 for(Body<T> b : (IterableForest<T>)tokens[0]) b.expand(toss, toks, i, h);
52
53             } else if (i==tokens.length) {
54                 h.add(new Tree<T>(null, tag, toks.toArray(tree_hint)));
55
56             } else if (unwrap && i==tokens.length-1) {
57                 if (tokens[i] != null)
58                     for(Body b : (IterableForest<T>)tokens[i])
59                         b.expand(toss, toks, 0, h);
60
61             } else {
62                 boolean hit = false;
63                 for(Tree<T> r : tokens[i].expand(toss)) {
64                     hit = true;
65                     int old = toks.size();
66                     toks.add(r);
67                     expand(toss, toks, i+1, h);
68                     while(toks.size() > old) toks.remove(toks.size()-1);
69                 }
70                 //if (!hit) throw new Error();
71             }
72             return h;
73         }
74         void addTo(HashSet<Body> h) {
75             if (!singleton) h.add(this);
76             else for(Body b : (IterableForest<T>)tokens[0]) b.addTo(h);
77         }
78         void addTo(FastSet<Body> h) {
79             if (!singleton) h.add(this, true);
80             else for(Body b : (IterableForest<T>)tokens[0]) b.addTo(h);
81         }
82
83
84         private boolean rep = false;
85         public String toString() {
86             if (rep) return "***";
87             try {
88                 rep = true;
89                 StringBuffer ret = new StringBuffer();
90                 for(int i=0; i<tokens.length; i++) {
91                     String q = tokens[i]==null ? "null" : tokens[i].toString();
92                     if (q.length() > 0) {
93                         ret.append(q);
94                         ret.append(" ");
95                     }
96                 }
97                 String tail = ret.toString().trim();
98                 String head = (tag!=null && !tag.toString().equals("")) ? (tail.length() > 0 ? tag+":" : tag+"") : "";
99                 if (tail.length() > 0) tail = "{" + tail + "}";
100                 return head + tail;
101             } finally {
102                 rep = false;
103             }
104         }
105     }
106
107
108     // Ref //////////////////////////////////////////////////////////////////////////////
109
110     static abstract class IterableForest<T> extends Forest<T> implements Iterable<Forest.Body<T>> {
111         public abstract Iterator<Forest.Body<T>> iterator();
112     }
113
114     /**
115      *  This class represents a partially complete collection of
116      *  forests to be viewed as a forest at some later date; once
117      *  viewed, it becomes immutable
118      */
119     static class Ref<T> extends IterableForest<T> {
120         private FastSet<Forest> hp = new FastSet<Forest>();
121         private Forest res = null;
122         public Ref() { }
123         public void merge(Forest p) {
124             if (res != null) throw new Error("already resolved!");
125             if (p==null) throw new Error();
126             if (p!=this) hp.add(p, true);
127         }
128         public Iterator<Body<T>> iterator() { return ((IterableForest<T>)resolve()).iterator(); }
129         public HashSet<Tree<T>> expand(boolean toss) { return resolve().expand(toss); }
130         public String toString() { return resolve().toString(); }
131         public Forest resolve() {
132             if (hp==null) return res;
133             FastSet<Body> nh      = new FastSet<Body>();
134             for(Forest<?> p : hp)
135                 for(Body<?> b : (IterableForest<?>)p)
136                     b.addTo(nh);
137             res = new MultiForest(nh);
138             hp = null;
139             return res;
140         }
141     }
142
143     // Implementations //////////////////////////////////////////////////////////////////////////////
144
145     private static class MultiForest<T> extends IterableForest<T> {
146         private final FastSet<Body<T>> results;
147         private MultiForest(FastSet<Body<T>> results) { this.results = results; }
148         public MultiForest(Token.Location loc, T tag, Forest<T>[] tokens, boolean unwrap, boolean singleton) {
149             this.results = new FastSet<Body<T>>(new Body(loc, tag, tokens, unwrap, singleton));
150         }
151         public Iterator<Body<T>> iterator() { return results.iterator(); }
152
153         public HashSet<Tree<T>> expand(boolean toss) {
154             HashSet<Tree<T>> ret = new HashSet<Tree<T>>();
155             for(Body<T> b : results)
156                 ret.addAll(b.expand(toss, new ArrayList<Tree<T>>(), 0, new HashSet<Tree<T>>()));
157             if (toss && ret.size() > 1) throw new Parser.Ambiguous(this);
158             return ret;
159         }
160         
161         // Display //////////////////////////////////////////////////////////////////////////////
162         
163         private String toString = null;
164         public String toString() {
165             if (toString != null) return toString;
166             StringBuffer ret = new StringBuffer();
167             if (results.size()==1) {
168                 for(Forest.Body<T> r : results)
169                     ret.append(r);
170                 return toString = ret.toString();
171             }
172             ret.append("<?");
173             boolean first = true;
174             for(Forest.Body<T> r : results) {
175                 if (!first) ret.append(' ');
176                 first = false;
177                 ret.append(r);
178             }
179             ret.append("?>");
180             return toString = ret.toString();
181         }
182     }
183
184     // Statics //////////////////////////////////////////////////////////////////////////////
185
186     private static Tree[] tree_hint = new Tree[0];
187     private static Body[] body_hint = new Body[0];
188     private static final Forest[] emptyForestArray = new Forest[0];
189 }