create common superclass of ResultNode and StateNode
[sbp.git] / src / edu / berkeley / sbp / StateNode.java
1 // Copyright 2006-2007 all rights reserved; see LICENSE file for BSD-style license
2
3 package edu.berkeley.sbp;
4 import edu.berkeley.sbp.*;
5 import edu.berkeley.sbp.util.*;
6 import edu.berkeley.sbp.Parser.Table.*;
7 import edu.berkeley.sbp.Sequence.Pos;
8 import edu.berkeley.sbp.Sequence.Pos;
9 import java.io.*;
10 import java.util.*;
11 import java.lang.reflect.*;
12
13 /** a node in the GSS */
14 final class StateNode
15     extends Node
16     implements Invokable<Pos, ResultNode, Object>,
17                IntegerMappable,
18                GraphViz.ToGraphViz,
19                Iterable<ResultNode> {
20
21     /** which GSS.Phase this StateNode belongs to */
22     public GSS.Phase phase() { return phase; }
23     public Iterator<ResultNode> iterator() { return results.iterator(); }
24     public Parser.Table.State state() { return state; }
25
26     public int toInt() { return idx; }
27
28     boolean destroyed = false;
29
30     public void check() {
31         if (destroyed) return;
32         boolean dead = true;
33         // - all nodes must have a predecessor
34         // - non-doomed nodes must either:
35         //      - be on the frontier or
36         //      - have a non-doomed node closer to the frontier than themself
37         if (phase.isFrontier()) dead = false;
38         else for(ResultNode r : successors)
39                  if (state.doomed) { if (r.usedByAnyNode()) { dead = false; break; } }
40                  else              { if (r.usedByNonDoomedNode()) { dead = false; break; } }
41         dead |= results.size()==0;
42         if (!dead) return;
43         destroyed = true;
44         if (phase() != null && phase().hash != null)
45             phase().hash.remove(state, predPhase);
46         while(successors.size()>0)
47             for(ResultNode r : successors) {
48                 successors.remove(r);
49                 r.removePred(this);
50                 break;
51             }
52         while(results.size()>0)
53             for(ResultNode r : results) {
54                 results.remove(r);
55                 r.removeSucc(this);
56                 break;
57             }
58         results = null;
59         successors = null;
60     }
61
62     //////////////////////////////////////////////////////////////////////
63
64     private static int node_idx = 0;
65     private final int idx = node_idx++;
66
67     private final GSS.Phase phase;
68     private final GSS.Phase predPhase;
69     private final Parser.Table.State state;
70     private  boolean fromEmptyReduction;
71     private       FastSet<ResultNode> results = new FastSet<ResultNode>();
72     private       FastSet<ResultNode> successors = new FastSet<ResultNode>();
73     //private       HashSet<ResultNode> results = new HashSet<ResultNode>();
74     //private       HashSet<ResultNode> successors = new HashSet<ResultNode>();
75
76     public final void invoke(Pos r, ResultNode only, Object o) {
77         boolean emptyProductions = only==null;
78         if (emptyProductions != (r.numPops()==0)) return;
79         if (r.numPops()!=0)  reduce(r, r.numPops()-1, phase(), only);
80         else {
81             Input.Region region = phase().getLocation().createRegion(phase().getLocation());
82             phase().newNodeFromReduction(r.rewrite(region), r, this);
83         }
84     }
85
86     private void reduce(Pos r, int pos, GSS.Phase target, ResultNode only) {
87         for(ResultNode res : results)
88             if (only == null || res == only)
89                 for(StateNode pred : res.getPreds())
90                     reduce2(r, pos, target, pred, res.getForest());
91     }
92
93     void reduce2(Pos r, int pos, GSS.Phase target, StateNode pred, Forest f) {
94         Forest[] holder = r.holder;
95         Forest old = pos >= holder.length ? null : holder[pos];
96         if (pos < holder.length) holder[pos] = f;
97         if (pos>0)  pred.reduce(r, pos-1, target, null);
98         else {
99             Input.Region region = pred.phase().getLocation().createRegion(target.getLocation());
100             new Reduction(pred, r, r.rewrite(region), target);
101         }
102         if (pos < holder.length) holder[pos] = old;
103     }
104
105     StateNode(GSS.Phase phase, Forest f, Pos reduction, StateNode pred, State state, boolean fromEmptyReduction) {
106         this(phase, new ResultNode(f, reduction, pred), state, fromEmptyReduction);
107     }
108     StateNode(GSS.Phase phase, ResultNode pred, State state, boolean fromEmptyReduction) {
109         this.phase = phase;
110         this.state = state;
111         this.fromEmptyReduction = fromEmptyReduction;
112         if (phase.hash.get(state, pred.phase()) != null) throw new Error("severe problem!");
113         this.predPhase = pred.phase();
114         phase.hash.put(state, pred.phase(), this);
115
116         results.add(pred);
117         pred.addSucc(this);
118         if (!fromEmptyReduction)
119             state.invokeReductions(phase().getToken(), this, pred);
120
121         state.invokeEpsilonReductions(phase().token, this);
122     }
123
124     // Add/Remove Successors/Results //////////////////////////////////////////////////////////////////////////////
125
126     public void removeSucc(ResultNode succ)   {
127         successors.remove(succ);
128         check();
129     }
130     public void removeResult(ResultNode result) {
131         results.remove(result);
132         check();
133     }
134     public void addSucc(ResultNode succ)      {
135         successors.add(succ);
136     }
137     public void addResult(Forest f, Pos reduction, StateNode pred) {
138         for(ResultNode r : results)
139             if (r.predecessorsContains(pred)) {
140                 r.merge(f);
141                 return;
142             }
143         ResultNode result = new ResultNode(f, reduction, pred);
144         results.add(result);
145         result.addSucc(this);
146         if (!this.fromEmptyReduction) state.invokeReductions(phase().getToken(), this, result);
147     }
148
149     // GraphViz //////////////////////////////////////////////////////////////////////////////
150
151     public GraphViz.StateNode toGraphViz(GraphViz gv) {
152         if (results.size()==0) return null;
153         if (gv.hasNode(this)) return gv.createNode(this);
154         GraphViz.StateNode n = gv.createNode(this);
155         n.label = "state["+state.toInt()+"]";
156         n.shape = "rectangle";
157         boolean haspreds = false;
158         for(ResultNode r : results) n.edge(r, "");
159         n.color = state.doomed ? "red" : "green";
160         ((GraphViz.Group)phase().toGraphViz(gv)).add(n);
161         return n;
162     }
163     public boolean isTransparent() { return false; }
164     public boolean isHidden() { return false; }
165
166 }