misc updates
[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
75         void addTo(FastSet<Body> h) {
76             if (!singleton) h.add(this, true);
77             else for(Body b : (IterableForest<T>)tokens[0]) b.addTo(h);
78         }
79
80         public String toString() {
81             StringBuffer ret = new StringBuffer();
82             for(int i=0; i<tokens.length; i++) {
83                 String q = tokens[i]==null ? "null" : tokens[i].toString();
84                 if (q.length() > 0) {
85                     ret.append(q);
86                     ret.append(" ");
87                 }
88             }
89             String tail = ret.toString().trim();
90             String head = (tag!=null && !tag.toString().equals("")) ? (tail.length() > 0 ? tag+":" : tag+"") : "";
91             if (tail.length() > 0) tail = "{" + tail + "}";
92             return head + tail;
93         }
94     }
95
96
97     // Ref //////////////////////////////////////////////////////////////////////////////
98
99     private static abstract class IterableForest<T> extends Forest<T> implements Iterable<Forest.Body<T>> {
100         public abstract Iterator<Forest.Body<T>> iterator();
101     }
102
103     /**
104      *  This class represents a partially complete collection of
105      *  forests to be viewed as a forest at some later date; once
106      *  viewed, it becomes immutable
107      */
108     static class Ref<T> extends IterableForest<T> {
109         private FastSet<Forest> hp = new FastSet<Forest>();
110         private Forest res = null;
111         public Ref() { }
112         public void merge(Forest p) {
113             if (res != null) throw new Error("already resolved!");
114             if (p==null) throw new Error();
115             if (p!=this) hp.add(p, true);
116         }
117         public Iterator<Body<T>> iterator() { return ((IterableForest<T>)resolve()).iterator(); }
118         public HashSet<Tree<T>> expand(boolean toss) { return resolve().expand(toss); }
119         public String toString() { return resolve().toString(); }
120         public Forest resolve() {
121             if (hp==null) return res;
122             FastSet<Body> nh      = new FastSet<Body>();
123             for(Forest<?> p : hp)
124                 for(Body<?> b : (IterableForest<?>)p)
125                     b.addTo(nh);
126             res = new MultiForest(nh);
127             hp = null;
128             return res;
129         }
130     }
131
132     // Implementations //////////////////////////////////////////////////////////////////////////////
133
134     private static class MultiForest<T> extends IterableForest<T> {
135         private final FastSet<Body<T>> results;
136         private MultiForest(FastSet<Body<T>> results) { this.results = results; }
137         public MultiForest(Token.Location loc, T tag, Forest<T>[] tokens, boolean unwrap, boolean singleton) {
138             this.results = new FastSet<Body<T>>(new Body(loc, tag, tokens, unwrap, singleton));
139         }
140         public Iterator<Body<T>> iterator() { return results.iterator(); }
141
142         public HashSet<Tree<T>> expand(boolean toss) {
143             HashSet<Tree<T>> ret = new HashSet<Tree<T>>();
144             for(Body<T> b : results)
145                 ret.addAll(b.expand(toss, new ArrayList<Tree<T>>(), 0, new HashSet<Tree<T>>()));
146             if (toss && ret.size() > 1) throw new Parser.Ambiguous(this);
147             return ret;
148         }
149         
150         // Display //////////////////////////////////////////////////////////////////////////////
151         
152         private String toString = null;
153         public String toString() {
154             if (toString != null) return toString;
155             StringBuffer ret = new StringBuffer();
156             if (results.size()==1) {
157                 for(Forest.Body<T> r : results)
158                     ret.append(r);
159                 return toString = ret.toString();
160             }
161             ret.append("<?");
162             boolean first = true;
163             for(Forest.Body<T> r : results) {
164                 if (!first) ret.append(' ');
165                 first = false;
166                 ret.append(r);
167             }
168             ret.append("?>");
169             return toString = ret.toString();
170         }
171     }
172
173     // Statics //////////////////////////////////////////////////////////////////////////////
174
175     private static Tree[] tree_hint = new Tree[0];
176     private static final Forest[] emptyForestArray = new Forest[0];
177 }