checkpoint
[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> extends PrintableTree<Forest.Body<T>> implements Iterable<Forest.Body<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 Ambiguous, ParseFailed {
14         Iterator<Tree<T>> it = expand(true).iterator();
15         if (!it.hasNext()) throw new ParseFailed();
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(Input.Location loc)                       { return create(loc, null, new Forest[] { }, false, true); }
23     static        <T> Forest<T> singleton(Input.Location loc, Forest<T> body)       { return create(loc, null, new Forest[] { body },  false, true); }
24     static        <T> Forest<T> leaf(Input.Location loc, T tag) { return create(loc, tag, null, false, false); }
25     public static <T> Forest<T> create(Input.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> extends PrintableTree<Forest<T>> implements Iterable<Forest<T>> {
32
33         private final Input.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(Input.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 : 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 : 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 : tokens[0]) b.addTo(h);
78         }
79
80         protected String  headToString()         { return null; }
81         protected String  headToJava()           { return null; }
82         protected String  left()                 { return "{"; }
83         protected String  right()                { return "}"; }
84         protected boolean ignoreSingleton()      { return false; }
85         public    Iterator<Forest<T>> iterator() { return new ArrayIterator<Forest<T>>(tokens); }
86     }
87
88
89     // Ref //////////////////////////////////////////////////////////////////////////////
90
91     /**
92      *  This class represents a partially complete collection of
93      *  forests to be viewed as a forest at some later date; once
94      *  viewed, it becomes immutable
95      */
96     static class Ref<T> extends Forest<T> {
97         private FastSet<Forest> hp = new FastSet<Forest>();
98         private Forest res = null;
99         public Ref() { }
100         public void merge(Forest p) {
101             if (res != null) throw new Error("already resolved!");
102             if (p==null) throw new Error();
103             if (p!=this) hp.add(p, true);
104         }
105         public Iterator<Body<T>> iterator() { return ((Forest<T>)resolve()).iterator(); }
106         public HashSet<Tree<T>> expand(boolean toss) { return resolve().expand(toss); }
107         public Forest resolve() {
108             if (hp==null) return res;
109             FastSet<Body> nh      = new FastSet<Body>();
110             for(Forest<?> p : hp)
111                 for(Body<?> b : (Forest<?>)p)
112                     b.addTo(nh);
113             res = new MultiForest(nh);
114             hp = null;
115             return res;
116         }
117     }
118
119     // Implementations //////////////////////////////////////////////////////////////////////////////
120
121     private static class MultiForest<T> extends Forest<T> {
122         private final FastSet<Body<T>> results;
123         private MultiForest(FastSet<Body<T>> results) { this.results = results; }
124         public MultiForest(Input.Location loc, T tag, Forest<T>[] tokens, boolean unwrap, boolean singleton) {
125             this.results = new FastSet<Body<T>>(new Body(loc, tag, tokens, unwrap, singleton));
126         }
127         public Iterator<Body<T>> iterator() { return results.iterator(); }
128         public HashSet<Tree<T>> expand(boolean toss) {
129             HashSet<Tree<T>> ret = new HashSet<Tree<T>>();
130             for(Body<T> b : results)
131                 ret.addAll(b.expand(toss, new ArrayList<Tree<T>>(), 0, new HashSet<Tree<T>>()));
132             if (toss && ret.size() > 1) throw new Ambiguous(this);
133             return ret;
134         }
135     }
136
137     // Statics //////////////////////////////////////////////////////////////////////////////
138
139     private static Tree[] tree_hint = new Tree[0];
140     private static final Forest[] emptyForestArray = new Forest[0];
141
142     protected String  headToString()    { return null; }
143     protected String  headToJava()      { return null; }
144     protected String  left()            { return "<?"; }
145     protected String  right()           { return "?>"; }
146     protected boolean ignoreSingleton() { return true; }
147 }