KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > js > rhino > Node


1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * The contents of this file are subject to the Netscape Public
4  * License Version 1.1 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of
6  * the License at http://www.mozilla.org/NPL/
7  *
8  * Software distributed under the License is distributed on an "AS
9  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10  * implied. See the License for the specific language governing
11  * rights and limitations under the License.
12  *
13  * The Original Code is Rhino code, released
14  * May 6, 1999.
15  *
16  * The Initial Developer of the Original Code is Netscape
17  * Communications Corporation. Portions created by Netscape are
18  * Copyright (C) 1997-1999 Netscape Communications Corporation. All
19  * Rights Reserved.
20  *
21  * Contributor(s):
22  * Norris Boyd
23  * Roger Lawrence
24  * Mike McCabe
25  *
26  * Alternatively, the contents of this file may be used under the
27  * terms of the GNU Public License (the "GPL"), in which case the
28  * provisions of the GPL are applicable instead of those above.
29  * If you wish to allow use of your version of this file only
30  * under the terms of the GPL and not to allow others to use your
31  * version of this file under the NPL, indicate your decision by
32  * deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL. If you do not delete
34  * the provisions above, a recipient may use your version of this
35  * file under either the NPL or the GPL.
36  */

37 // Modified by Google
38

39 package com.google.gwt.dev.js.rhino;
40
41 /**
42  * This class implements the root of the intermediate representation.
43  *
44  * @author Norris Boyd
45  * @author Mike McCabe
46  */

47
48 public class Node implements Cloneable JavaDoc {
49
50     private static class NumberNode extends Node {
51
52         NumberNode(double number) {
53             super(TokenStream.NUMBER);
54             this.number = number;
55         }
56
57         public double getDouble() {
58           return this.number;
59         }
60
61         public boolean equals(Object JavaDoc o) {
62             return o instanceof NumberNode
63                 && getDouble() == ((NumberNode) o).getDouble();
64         }
65
66         private double number;
67     }
68
69     private static class StringNode extends Node {
70
71         StringNode(int type, String JavaDoc str) {
72             super(type);
73             if (null == str) {
74                 throw new IllegalArgumentException JavaDoc("StringNode: str is null");
75             }
76             this.str = str;
77         }
78
79         /** returns the string content.
80           * @return non null.
81           */

82         public String JavaDoc getString() {
83             return this.str;
84         }
85
86         /** sets the string content.
87           * @param str the new value. Non null.
88           */

89         public void setString(String JavaDoc str) {
90             if (null == str) {
91                 throw new IllegalArgumentException JavaDoc("StringNode: str is null");
92             }
93             this.str = str;
94         }
95
96         public boolean equals(Object JavaDoc o) {
97             if (!(o instanceof StringNode)) { return false; }
98             return o instanceof StringNode
99                 && this.str.equals(((StringNode) o).str);
100         }
101
102         private String JavaDoc str;
103     }
104
105     public Node(int nodeType) {
106         type = nodeType;
107     }
108
109     public Node(int nodeType, Node child) {
110         type = nodeType;
111         first = last = child;
112         child.next = null;
113     }
114
115     public Node(int nodeType, Node left, Node right) {
116         type = nodeType;
117         first = left;
118         last = right;
119         left.next = right;
120         right.next = null;
121     }
122
123     public Node(int nodeType, Node left, Node mid, Node right) {
124         type = nodeType;
125         first = left;
126         last = right;
127         left.next = mid;
128         mid.next = right;
129         right.next = null;
130     }
131
132     public Node(int nodeType, Node left, Node mid, Node mid2, Node right) {
133         type = nodeType;
134         first = left;
135         last = right;
136         left.next = mid;
137         mid.next = mid2;
138         mid2.next = right;
139         right.next = null;
140     }
141
142     public Node(int nodeType, Node[] children) {
143         this.type = nodeType;
144         if (children.length != 0) {
145             this.first = children[0];
146             this.last = children[children.length - 1];
147
148             for (int i = 1; i < children.length; i++) {
149                 if (null != children[i - 1].next) {
150                     // fail early on loops. implies same node in array twice
151
throw new IllegalArgumentException JavaDoc("duplicate child");
152                 }
153                 children[i - 1].next = children[i];
154             }
155             if (null != this.last.next) {
156                 // fail early on loops. implies same node in array twice
157
throw new IllegalArgumentException JavaDoc("duplicate child");
158             }
159         }
160     }
161
162     public Node(int nodeType, int value) {
163         type = nodeType;
164         intDatum = value;
165     }
166
167     public Node(int nodeType, Node child, int value) {
168         this(nodeType, child);
169         intDatum = value;
170     }
171
172     public Node(int nodeType, Node left, Node right, int value) {
173         this(nodeType, left, right);
174         intDatum = value;
175     }
176
177     public Node(int nodeType, Node left, Node mid, Node right, int value) {
178         this(nodeType, left, mid, right);
179         intDatum = value;
180     }
181
182     public static Node newNumber(double number) {
183         return new NumberNode(number);
184     }
185
186     public static Node newString(String JavaDoc str) {
187         return new StringNode(TokenStream.STRING, str);
188     }
189
190     public static Node newString(int type, String JavaDoc str) {
191         return new StringNode(type, str);
192     }
193
194     public int getType() {
195         return type;
196     }
197
198     public void setType(int type) {
199         this.type = type;
200     }
201
202     public int getIntDatum() {
203         return this.intDatum;
204     }
205
206     public boolean hasChildren() {
207         return first != null;
208     }
209
210     public Node getFirstChild() {
211         return first;
212     }
213
214     public Node getLastChild() {
215         return last;
216     }
217
218     public Node getNext() {
219         return next;
220     }
221
222     public int getChildCount() {
223         int c = 0;
224         for (Node n = first; n != null; n = n.next)
225             c++;
226
227         return c;
228     }
229
230
231     public Node getChildBefore(Node child) {
232         if (child == first)
233             return null;
234         Node n = first;
235         while (n.next != child) {
236             n = n.next;
237             if (n == null)
238                 throw new RuntimeException JavaDoc("node is not a child");
239         }
240         return n;
241     }
242
243     public Node getLastSibling() {
244         Node n = this;
245         while (n.next != null) {
246             n = n.next;
247         }
248         return n;
249     }
250
251     public void addChildToFront(Node child) {
252         child.next = first;
253         first = child;
254         if (last == null) {
255             last = child;
256         }
257     }
258
259     public void addChildToBack(Node child) {
260         child.next = null;
261         if (last == null) {
262             first = last = child;
263             return;
264         }
265         last.next = child;
266         last = child;
267     }
268
269     public void addChildrenToFront(Node children) {
270         Node lastSib = children.getLastSibling();
271         lastSib.next = first;
272         first = children;
273         if (last == null) {
274             last = lastSib;
275         }
276     }
277
278     public void addChildrenToBack(Node children) {
279         if (last != null) {
280             last.next = children;
281         }
282         last = children.getLastSibling();
283         if (first == null) {
284             first = children;
285         }
286     }
287
288     /**
289      * Add 'child' before 'node'.
290      */

291     public void addChildBefore(Node newChild, Node node) {
292         if (newChild.next != null)
293             throw new RuntimeException JavaDoc(
294                       "newChild had siblings in addChildBefore");
295         if (first == node) {
296             newChild.next = first;
297             first = newChild;
298             return;
299         }
300         Node prev = getChildBefore(node);
301         addChildAfter(newChild, prev);
302     }
303
304     /**
305      * Add 'child' after 'node'.
306      */

307     public void addChildAfter(Node newChild, Node node) {
308         if (newChild.next != null)
309             throw new RuntimeException JavaDoc(
310                       "newChild had siblings in addChildAfter");
311         newChild.next = node.next;
312         node.next = newChild;
313         if (last == node)
314             last = newChild;
315     }
316
317     public void removeChild(Node child) {
318         Node prev = getChildBefore(child);
319         if (prev == null)
320             first = first.next;
321         else
322             prev.next = child.next;
323         if (child == last) last = prev;
324         child.next = null;
325     }
326
327     public void replaceChild(Node child, Node newChild) {
328         newChild.next = child.next;
329         if (child == first) {
330             first = newChild;
331         } else {
332             Node prev = getChildBefore(child);
333             prev.next = newChild;
334         }
335         if (child == last)
336             last = newChild;
337         child.next = null;
338     }
339
340     public void replaceChildAfter(Node prevChild, Node newChild) {
341         Node child = prevChild.next;
342         newChild.next = child.next;
343         prevChild.next = newChild;
344         if (child == last)
345             last = newChild;
346         child.next = null;
347     }
348
349     public static final int
350         TARGET_PROP = 1,
351         BREAK_PROP = 2,
352         CONTINUE_PROP = 3,
353         ENUM_PROP = 4,
354         FUNCTION_PROP = 5,
355         TEMP_PROP = 6,
356         LOCAL_PROP = 7,
357         CODEOFFSET_PROP = 8,
358         FIXUPS_PROP = 9,
359         VARS_PROP = 10,
360         USES_PROP = 11,
361         REGEXP_PROP = 12,
362         CASES_PROP = 13,
363         DEFAULT_PROP = 14,
364         CASEARRAY_PROP = 15,
365         SOURCENAME_PROP = 16,
366         SOURCE_PROP = 17,
367         TYPE_PROP = 18,
368         SPECIAL_PROP_PROP = 19,
369         LABEL_PROP = 20,
370         FINALLY_PROP = 21,
371         LOCALCOUNT_PROP = 22,
372     /*
373         the following properties are defined and manipulated by the
374         optimizer -
375         TARGETBLOCK_PROP - the block referenced by a branch node
376         VARIABLE_PROP - the variable referenced by a BIND or NAME node
377         LASTUSE_PROP - that variable node is the last reference before
378                         a new def or the end of the block
379         ISNUMBER_PROP - this node generates code on Number children and
380                         delivers a Number result (as opposed to Objects)
381         DIRECTCALL_PROP - this call node should emit code to test the function
382                           object against the known class and call diret if it
383                           matches.
384     */

385
386         TARGETBLOCK_PROP = 23,
387         VARIABLE_PROP = 24,
388         LASTUSE_PROP = 25,
389         ISNUMBER_PROP = 26,
390         DIRECTCALL_PROP = 27,
391
392         BASE_LINENO_PROP = 28,
393         END_LINENO_PROP = 29,
394         SPECIALCALL_PROP = 30,
395         DEBUGSOURCE_PROP = 31;
396
397     public static final int // this value of the ISNUMBER_PROP specifies
398
BOTH = 0, // which of the children are Number types
399
LEFT = 1,
400         RIGHT = 2;
401
402     private static final String JavaDoc propToString(int propType) {
403         switch (propType) {
404             case TARGET_PROP: return "target";
405             case BREAK_PROP: return "break";
406             case CONTINUE_PROP: return "continue";
407             case ENUM_PROP: return "enum";
408             case FUNCTION_PROP: return "function";
409             case TEMP_PROP: return "temp";
410             case LOCAL_PROP: return "local";
411             case CODEOFFSET_PROP: return "codeoffset";
412             case FIXUPS_PROP: return "fixups";
413             case VARS_PROP: return "vars";
414             case USES_PROP: return "uses";
415             case REGEXP_PROP: return "regexp";
416             case CASES_PROP: return "cases";
417             case DEFAULT_PROP: return "default";
418             case CASEARRAY_PROP: return "casearray";
419             case SOURCENAME_PROP: return "sourcename";
420             case SOURCE_PROP: return "source";
421             case TYPE_PROP: return "type";
422             case SPECIAL_PROP_PROP: return "special_prop";
423             case LABEL_PROP: return "label";
424             case FINALLY_PROP: return "finally";
425             case LOCALCOUNT_PROP: return "localcount";
426
427             case TARGETBLOCK_PROP: return "targetblock";
428             case VARIABLE_PROP: return "variable";
429             case LASTUSE_PROP: return "lastuse";
430             case ISNUMBER_PROP: return "isnumber";
431             case DIRECTCALL_PROP: return "directcall";
432
433             case BASE_LINENO_PROP: return "base_lineno";
434             case END_LINENO_PROP: return "end_lineno";
435             case SPECIALCALL_PROP: return "specialcall";
436             case DEBUGSOURCE_PROP: return "debugsource";
437
438             default: Context.codeBug();
439
440         }
441         return null;
442     }
443
444     public Object JavaDoc getProp(int propType) {
445         if (props == null)
446             return null;
447         return props.getObject(propType);
448     }
449
450     public int getIntProp(int propType, int defaultValue) {
451         if (props == null)
452             return defaultValue;
453         return props.getInt(propType, defaultValue);
454     }
455
456     public int getExistingIntProp(int propType) {
457         return props.getExistingInt(propType);
458     }
459
460     public void putProp(int propType, Object JavaDoc prop) {
461         if (prop == null) {
462             removeProp(propType);
463         }
464         else {
465             if (props == null) {
466                 props = new UintMap(2);
467             }
468             props.put(propType, prop);
469         }
470     }
471
472     public void putIntProp(int propType, int prop) {
473         if (props == null)
474             props = new UintMap(2);
475         props.put(propType, prop);
476     }
477
478     public void removeProp(int propType) {
479         if (props != null) {
480             props.remove(propType);
481         }
482     }
483
484     public int getOperation() {
485         switch (type) {
486             case TokenStream.EQOP:
487             case TokenStream.RELOP:
488             case TokenStream.UNARYOP:
489             case TokenStream.PRIMARY:
490                 return intDatum;
491         }
492         Context.codeBug();
493         return 0;
494     }
495
496     public int getLineno() {
497         if (hasLineno()) {
498             return intDatum;
499         }
500         return -1;
501     }
502
503     private boolean hasLineno() {
504         switch (type) {
505             case TokenStream.EXPRSTMT:
506             case TokenStream.BLOCK:
507             case TokenStream.VAR:
508             case TokenStream.WHILE:
509             case TokenStream.DO:
510             case TokenStream.SWITCH:
511             case TokenStream.CATCH:
512             case TokenStream.THROW:
513             case TokenStream.RETURN:
514             case TokenStream.BREAK:
515             case TokenStream.CONTINUE:
516             case TokenStream.WITH:
517                 return true;
518         }
519         return false;
520     }
521
522     /** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */
523     public double getDouble() throws UnsupportedOperationException JavaDoc {
524         throw new UnsupportedOperationException JavaDoc(this + " is not a number node");
525     }
526
527     /** Can only be called when node has String context. */
528     public String JavaDoc getString() throws UnsupportedOperationException JavaDoc {
529         throw new UnsupportedOperationException JavaDoc(this + " is not a string node");
530     }
531
532     /** Can only be called when node has String context. */
533     public void setString(String JavaDoc s) throws UnsupportedOperationException JavaDoc {
534         throw new UnsupportedOperationException JavaDoc(this + " is not a string node");
535     }
536
537     public boolean equals(Object JavaDoc o) {
538         if (!(o instanceof Node)) { return false; }
539         return hasLineno()
540             || this.getIntDatum() == ((Node) o).getIntDatum();
541     }
542
543     public Node cloneNode() {
544         Node result;
545         try {
546             result = (Node) super.clone();
547             result.next = null;
548             result.first = null;
549             result.last = null;
550         }
551         catch (CloneNotSupportedException JavaDoc e) {
552             throw new RuntimeException JavaDoc(e.getMessage());
553         }
554         return result;
555     }
556
557     public Node cloneTree() {
558         Node result = cloneNode();
559         for (Node n2 = getFirstChild(); n2 != null; n2 = n2.getNext()) {
560             Node n2clone = n2.cloneTree();
561             if (result.last != null) {
562                 result.last.next = n2clone;
563             }
564             if (result.first == null) {
565                 result.first = n2clone;
566             }
567             result.last = n2clone;
568         }
569         return result;
570     }
571
572
573
574     public String JavaDoc toString() {
575         if (Context.printTrees) {
576             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(TokenStream.tokenToName(type));
577             if (this instanceof StringNode) {
578                 sb.append(' ');
579                 sb.append(getString());
580             } else {
581                 switch (type) {
582                     case TokenStream.TARGET:
583                         sb.append(' ');
584                         sb.append(hashCode());
585                         break;
586                     case TokenStream.NUMBER:
587                         sb.append(' ');
588                         sb.append(getDouble());
589                         break;
590                     case TokenStream.FUNCTION:
591                         sb.append(' ');
592                         sb.append(first.getString());
593                         break;
594                 }
595             }
596             if (intDatum != -1) {
597                 sb.append(' ');
598                 sb.append(intDatum);
599             }
600             if (props == null)
601                 return sb.toString();
602
603             int[] keys = props.getKeys();
604             for (int i = 0; i != keys.length; ++i) {
605                 int key = keys[i];
606                 sb.append(" [");
607                 sb.append(propToString(key));
608                 sb.append(": ");
609                 switch (key) {
610                     case FIXUPS_PROP : // can't add this as it recurses
611
sb.append("fixups property");
612                         break;
613                     case SOURCE_PROP : // can't add this as it has unprintables
614
sb.append("source property");
615                         break;
616                     case TARGETBLOCK_PROP : // can't add this as it recurses
617
sb.append("target block property");
618                         break;
619                     case LASTUSE_PROP : // can't add this as it is dull
620
sb.append("last use property");
621                         break;
622                     default :
623                         Object JavaDoc obj = props.getObject(key);
624                         if (obj != null) {
625                             sb.append(obj.toString());
626                         } else {
627                             sb.append(props.getExistingInt(key));
628                         }
629                         break;
630                 }
631                 sb.append(']');
632             }
633             return sb.toString();
634         }
635         return null;
636     }
637
638     public String JavaDoc toStringTree() {
639         return toStringTreeHelper(0);
640     }
641
642
643     private String JavaDoc toStringTreeHelper(int level) {
644         if (Context.printTrees) {
645             StringBuffer JavaDoc s = new StringBuffer JavaDoc();
646             for (int i=0; i < level; i++) {
647                 s.append(" ");
648             }
649             s.append(toString());
650             s.append('\n');
651             for (Node cursor = getFirstChild(); cursor != null;
652                  cursor = cursor.getNext())
653             {
654                 Node n = cursor;
655                 s.append(n.toStringTreeHelper(level+1));
656             }
657             return s.toString();
658         }
659         return "";
660     }
661
662     /**
663      * Checks if the subtree under this node is the same as another subtree.
664      * Returns null if it's equal, or a message describing the differences.
665      */

666     public String JavaDoc checkTreeEquals(Node node2) {
667         boolean eq = false;
668
669         if (type == node2.getType() &&
670             getChildCount() == node2.getChildCount() &&
671             getClass() == node2.getClass()) {
672
673             eq = this.equals(node2);
674         }
675
676         if (!eq) {
677             return "Node tree inequality:\nTree1:\n" + toStringTreeHelper(1) +
678                 "\n\nTree2:\n" + node2.toStringTreeHelper(1);
679         }
680
681         String JavaDoc res = null;
682         Node n, n2;
683         for (n = first, n2 = node2.first;
684              res == null && n != null;
685              n = n.next, n2 = n2.next) {
686             res = n.checkTreeEquals(n2);
687             if (res != null) {
688                 return res;
689             }
690         }
691         return res;
692     }
693
694     public void setIsSyntheticBlock(boolean val) {
695         isSyntheticBlock = val;
696     }
697
698     public boolean isSyntheticBlock() {
699         return isSyntheticBlock;
700     }
701
702     int type; // type of the node; TokenStream.NAME for example
703
Node next; // next sibling
704
private Node first; // first element of a linked list of children
705
private Node last; // last element of a linked list of children
706
private int intDatum = -1; // encapsulated int data; depends on type
707
private UintMap props;
708     private boolean isSyntheticBlock = false;
709 }
710
Popular Tags