001    /*
002    @license.text@
003     */
004    package biz.hammurapi.antlr;
005    
006    import java.awt.event.WindowAdapter;
007    import java.awt.event.WindowEvent;
008    import java.io.PrintStream;
009    import java.util.LinkedHashMap;
010    
011    import antlr.CommonAST;
012    import biz.hammurapi.legacy.review.SourceMarker;
013    import biz.hammurapi.util.Attributable;
014    import biz.hammurapi.util.PoliteVisitor;
015    import biz.hammurapi.util.Visitable;
016    import biz.hammurapi.util.Visitor;
017    
018    
019    /** 
020     * Holds line and column numbers 
021     * @author Pavel Vlasov
022     * @version $Revision: 1.8 $
023     */
024    public class AST extends CommonAST implements SourceMarker, Visitable, Attributable {
025        /**
026             * Comment for <code>serialVersionUID</code>
027             */
028            private static final long serialVersionUID = -3283377943637002016L;
029            private int line;
030        private int column;
031        private boolean childrenQueried=false;
032        private AST parent;
033        private String id;
034        private Token token;
035        private boolean loaded=false;
036    //  private LanguageElement owner;
037        
038        private Token firstToken;
039        private Token lastToken;
040        
041        public void initialize(antlr.Token tok) {
042            super.initialize(tok);
043            line=tok.getLine();
044            column=tok.getColumn();
045            this.token=(Token) tok;
046            this.firstToken=this.token;
047            this.lastToken=this.token;
048        }
049        
050        public void initialize(antlr.collections.AST node) {
051            super.initialize(node);
052            if (node instanceof AST) {
053                line=((AST) node).getLine();
054                column=((AST) node).getColumn();
055            }
056        }
057        
058        public int getLine() {
059            queryChildren();
060            return line;        
061        }
062        
063        public int getColumn() {
064            queryChildren();
065            return column;
066        }
067        
068        public Token getToken() {
069            return token;
070        }
071        
072        /**
073         * Returns leftmost non-zero column among itself and all children
074         */
075        public int getLeftColumn() {
076            int ret=getColumn();
077            for (AST child=(AST) getFirstChild(); child!=null; child=(AST) child.getNextSibling()) {
078                int c=child.getLeftColumn();
079                if (c!=0 && c<ret) ret=c;
080            }
081            return ret;        
082        }
083        
084        public AST getParent() {
085            return parent;
086        }
087        
088        protected void setParent(AST parent) {
089            this.parent=parent;
090        }
091        
092        /**************************************************************************
093         * Parent calculation
094         *************************************************************************/
095        public void addChild(antlr.collections.AST node) {
096            super.addChild(node);
097            if (node instanceof AST) {
098                ((AST) node).parent=this;
099            }
100        }
101        
102        public void setFirstChild(antlr.collections.AST c) {
103            super.setFirstChild(c);
104            if (c instanceof AST) {
105                ((AST) c).parent=this;
106            }
107        }
108        
109        public void setNextSibling(antlr.collections.AST n) {
110                    antlr.collections.AST currentNextSibling=getNextSibling();
111            if (currentNextSibling instanceof AST) {
112                    ((AST) currentNextSibling).setPrevSibling(null);        
113            }
114            
115            super.setNextSibling(n);
116            
117            
118            if (n instanceof AST) {
119                ((AST) n).setParent(parent);
120                ((AST) n).setPrevSibling(this);
121            }
122        }
123        
124        private AST prevSibling;
125        
126        public AST getPrevSibling() {
127            return prevSibling;
128        }
129        
130        protected void setPrevSibling(AST prevSibling) {
131            this.prevSibling=prevSibling;
132        }
133        
134        /**
135         * Removes AST from tree
136         */
137        public void remove() {
138            if (parent!=null && parent.getFirstChild()==this) {
139                    parent.setFirstChild(getNextSibling());
140            }
141            
142            parent=null;
143            
144            if (prevSibling==null) {
145                    if (getNextSibling() instanceof AST) {
146                            ((AST) getNextSibling()).setPrevSibling(null);          
147                    }
148            } else {
149                    prevSibling.setNextSibling(getNextSibling());
150            }                               
151            
152            setPrevSibling(null);           
153        }
154        
155        /**
156         * Reads column and line from children if its own are 0
157         */
158        private void queryChildren() {
159            if (!childrenQueried) {
160                    childrenQueried=true;
161                    for (AST child = (AST) getFirstChild(); child != null ; child = (AST) child.getNextSibling()) {
162                        if (line==0 && column==0 && child.getLine()!=0) {
163                            line=child.getLine();
164                            column=child.getColumn();
165                        }
166                        
167                        Token cft=child.getFirstToken();
168                        if (cft!=null && (firstToken==null || cft.compareTo(firstToken)<0)) {
169                            firstToken=cft;
170                        }
171                        
172                        Token clt=child.getLastToken();
173                        if (clt!=null && (lastToken==null || clt.compareTo(lastToken)>0)) {
174                            lastToken=clt;
175                        }
176                    }
177            }
178        }
179        
180        private String sourceURL;
181    
182            public String getSourceURL() {
183                    return sourceURL;
184            }
185            
186            public void setSourceURL(String sourceURL) {
187                    this.sourceURL=sourceURL;
188            }
189            
190            /**
191             * Indicates that the node has been processed by superclass and can be ignored
192             * @return Returns the loaded.
193             */
194            boolean isLoaded() {
195                    return loaded;
196            }
197    
198            /**
199             * @param loaded The loaded to set.
200             */
201            void setLoaded(boolean loaded) {
202                    this.loaded = loaded;
203            }
204    
205            public boolean equals(Object obj) {
206                    if (obj==null) {
207                            return false;
208                    }
209                    
210                    if (obj==this) {
211                            return true;
212                    }
213                    
214                    if (getClass().equals(obj.getClass())) {
215                            return false;
216                    }
217                    
218                    AST ast=(AST) obj;
219                    
220                    if (super.equals(ast)) {
221                            
222                            if (ast.getNumberOfChildren()!=getNumberOfChildren()) {
223                                    return false;
224                            }
225                            
226                            for (AST child=(AST) getFirstChild(), otherChild=(AST) ast.getFirstChild(); child!=null && otherChild!=null; child=(AST) child.getNextSibling(), otherChild=(AST) otherChild.getNextSibling()) {
227                                    if (!child.equals(ast.getFirstChild())) {
228                                            return false;
229                                    }
230                            }
231                            return true;
232                    }
233                    
234                    return false;
235            }
236            
237            public int hashCode() {
238                    int ret=getType();
239                    ret^=getClass().getName().hashCode();
240                    
241                    if (getText()!=null) {
242                            ret^=getText().hashCode();
243                    }
244                    for (AST child=(AST) getFirstChild(); child!=null; child=(AST) child.getNextSibling()) {
245                            ret^=child.hashCode();
246                    }
247                    return ret;
248            }
249            
250            public int getSize() {
251                    int ret=1;
252                    for (AST child=(AST) getFirstChild(); child!=null; child=(AST) child.getNextSibling()) {
253                            ret+=child.getSize();
254                    }
255                    
256                    return ret;
257            }
258    
259            public Token getFirstToken() {
260                    queryChildren();
261                    return firstToken;
262            }
263    
264            public Token getLastToken() {
265                    queryChildren();
266                    return lastToken;
267            }
268            
269    //      protected LanguageElement getOwner() {
270    //              return owner;
271    //      }
272    
273    //      protected void setOwner(LanguageElement owner) {
274    //              this.owner = owner;
275    //      }
276    
277            public String getId() {
278                    return id;
279            }
280            
281            private void enumerateChildren() {
282                    int i=0;
283                    for (AST node=(AST) getFirstChild(); node!=null; node=(AST) node.getNextSibling(), i++) {
284                            node.id = id==null ? String.valueOf(i) : id+'.'+i;
285                            node.enumerateChildren();                       
286                    }
287            }
288            
289            public void enumerate() {
290                    int i=0;
291                    for (AST node=this; node!=null; node=(AST) node.getNextSibling(), i++) {
292                            node.id=String.valueOf(i);
293                            node.enumerateChildren();
294                    }
295            }
296    
297            public boolean accept(Visitor visitor) {
298                    if (visitor.visit(this)) {
299                            if (getFirstChild()!=null) {
300                                    ((Visitable) getFirstChild()).accept(visitor);
301                            }
302                            
303                            if (visitor instanceof PoliteVisitor) {
304                                    ((PoliteVisitor) visitor).leave(this);
305                            }
306                            
307                            if (getNextSibling()!=null) {
308                                    return ((Visitable) getNextSibling()).accept(visitor);
309                            }
310                            
311                            return true;                                            
312                    }
313                    
314                    return false;
315            }
316    
317            public Integer getSourceId() {
318                    return null;
319            }
320            
321            public void print(String[] tokenNames, boolean withSiblings) {          
322                    print(tokenNames, System.out, 0, withSiblings);
323            }
324            
325            public void print(String[] tokenNames, PrintStream out, int level, boolean withSiblings) {
326                    if (withSiblings) {
327                            visitAll(tokenNames, this, level, out);                 
328                    } else {
329                            visit(tokenNames, this, level, out);                    
330                    }
331            }
332    
333            protected void tabs(PrintStream out, int level) {
334                    for (int i = 0; i < level; i++) {
335                            out.print("   ");
336                    }
337            }
338            
339            protected void visit(String[] tokenNames, AST node, int level, PrintStream out) {
340                    tabs(out, level);        
341                    out.print(tokenNames[node.getType()]+" ");
342                    out.print(node.getText()==null ? "nil" : node.getText());
343                    out.println(" "+node.getLine()+(node.getColumn()==node.getLeftColumn() ? ":"+node.getColumn() : ":"+node.getColumn()+"("+node.getLeftColumn()+") "));
344                    visitAll(tokenNames, (AST) node.getFirstChild(), level+1, out);
345            }
346    
347            protected void visitAll(String[] tokenNames, AST node, int level, PrintStream out) {
348                    while (node!=null) {
349                            visit(tokenNames, node, level, out); 
350                            node = (AST) node.getNextSibling();
351                    }
352            }
353            
354            public void show(String[] tokenNames) {
355                    final ASTFrame frame = new ASTFrame("AST: "+getText(), this, tokenNames);
356                    frame.setVisible(true);
357                    frame.addWindowListener(new WindowAdapter() {
358                            public void windowClosing(WindowEvent e) {
359                                    frame.setVisible(false); // hide the Frame
360                                    frame.dispose();
361                            }
362                    });
363            }
364            
365            public void showWithSiblings(String title, String[] tokenNames) {
366                    AST root=new AST();
367                    root.setText(title);
368                    root.setFirstChild(this);
369                    final ASTFrame frame = new ASTFrame(title, root, tokenNames);
370                    frame.setVisible(true);
371                    frame.addWindowListener(new WindowAdapter() {
372                            public void windowClosing(WindowEvent e) {
373                                    frame.setVisible(false); // hide the Frame
374                                    frame.dispose();
375                            }
376                    });
377            }       
378            
379            private LinkedHashMap attributes = new LinkedHashMap();
380            
381            public void setAttribute(Object key, Object value) {
382                    attributes.put(key, value);
383            }
384    
385            public Object getAttribute(Object key) {
386                    return attributes.get(key);
387            }
388    
389            public Object removeAttribute(Object key) {
390                    return attributes.remove(key);
391            }
392            
393            /**
394             * Finds AST of given type in this AST and siblings.
395             * @param type
396             * @return
397             */
398            public AST find(int type) {
399                    if (type == getType()) {
400                            return this;
401                    }
402                    
403                    AST nextSibling = (AST) getNextSibling();
404                    return nextSibling == null ? null : nextSibling.find(type);
405            }
406    
407            /**
408             * Finds child of given type.
409             * @param type
410             */
411            public AST findChild(int type) {
412                    AST firstChild = (AST) getFirstChild();
413                    return firstChild == null ? null : firstChild.find(type);
414            }
415    }