2003/05/12 05:10:30
[org.ibex.core.git] / src / org / mozilla / javascript / Node.java
1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
2  *\r
3  * The contents of this file are subject to the Netscape Public\r
4  * License Version 1.1 (the "License"); you may not use this file\r
5  * except in compliance with the License. You may obtain a copy of\r
6  * the License at http://www.mozilla.org/NPL/\r
7  *\r
8  * Software distributed under the License is distributed on an "AS\r
9  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
10  * implied. See the License for the specific language governing\r
11  * rights and limitations under the License.\r
12  *\r
13  * The Original Code is Rhino code, released\r
14  * May 6, 1999.\r
15  *\r
16  * The Initial Developer of the Original Code is Netscape\r
17  * Communications Corporation.  Portions created by Netscape are\r
18  * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
19  * Rights Reserved.\r
20  *\r
21  * Contributor(s): \r
22  * Norris Boyd\r
23  * Roger Lawrence\r
24  * Mike McCabe\r
25  *\r
26  * Alternatively, the contents of this file may be used under the\r
27  * terms of the GNU Public License (the "GPL"), in which case the\r
28  * provisions of the GPL are applicable instead of those above.\r
29  * If you wish to allow use of your version of this file only\r
30  * under the terms of the GPL and not to allow others to use your\r
31  * version of this file under the NPL, indicate your decision by\r
32  * deleting the provisions above and replace them with the notice\r
33  * and other provisions required by the GPL.  If you do not delete\r
34  * the provisions above, a recipient may use your version of this\r
35  * file under either the NPL or the GPL.\r
36  */\r
37 \r
38 package org.mozilla.javascript;\r
39 \r
40 /**\r
41  * This class implements the root of the intermediate representation.\r
42  *\r
43  * @author Norris Boyd\r
44  * @author Mike McCabe\r
45  */\r
46 \r
47 public class Node implements Cloneable {\r
48 \r
49     public Node(int nodeType) {\r
50         type = nodeType;\r
51     }\r
52 \r
53     public Node(int nodeType, Node child) {\r
54         type = nodeType;\r
55         first = last = child;\r
56         child.next = null;\r
57     }\r
58 \r
59     public Node(int nodeType, Node left, Node right) {\r
60         type = nodeType;\r
61         first = left;\r
62         last = right;\r
63         left.next = right;\r
64         right.next = null;\r
65     }\r
66 \r
67     public Node(int nodeType, Node left, Node mid, Node right) {\r
68         type = nodeType;\r
69         first = left;\r
70         last = right;\r
71         left.next = mid;\r
72         mid.next = right;\r
73         right.next = null;\r
74     }\r
75 \r
76     public Node(int nodeType, Object datum) {\r
77         type = nodeType;\r
78         this.datum = datum;\r
79     }\r
80 \r
81     public Node(int nodeType, Node child, Object datum) {\r
82         this(nodeType, child);\r
83         this.datum = datum;\r
84     }\r
85 \r
86     public Node(int nodeType, Node left, Node right, Object datum) {\r
87         this(nodeType, left, right);\r
88         this.datum = datum;\r
89     }\r
90 \r
91     public int getType() {\r
92         return type;\r
93     }\r
94 \r
95     public void setType(int type) {\r
96         this.type = type;\r
97     }\r
98 \r
99     public boolean hasChildren() {\r
100         return first != null;\r
101     }\r
102 \r
103     public Node getFirstChild() {\r
104         return first;\r
105     }\r
106 \r
107     public Node getLastChild() {\r
108         return last;\r
109     }\r
110 \r
111     public Node getNextSibling() {\r
112         return next;\r
113     }\r
114 \r
115     public Node getChildBefore(Node child) {\r
116         if (child == first)\r
117             return null;\r
118         Node n = first;\r
119         while (n.next != child) {\r
120             n = n.next;\r
121             if (n == null)\r
122                 throw new RuntimeException("node is not a child");\r
123         }\r
124         return n;\r
125     }\r
126 \r
127     public Node getLastSibling() {\r
128         Node n = this;\r
129         while (n.next != null) {\r
130             n = n.next;\r
131         }\r
132         return n;\r
133     }\r
134 \r
135     public ShallowNodeIterator getChildIterator() {\r
136         return new ShallowNodeIterator(first);\r
137     }\r
138 \r
139     public PreorderNodeIterator getPreorderIterator() {\r
140         return new PreorderNodeIterator(this);\r
141     }\r
142 \r
143     public void addChildToFront(Node child) {\r
144         child.next = first;\r
145         first = child;\r
146         if (last == null) {\r
147             last = child;\r
148         }\r
149     }\r
150 \r
151     public void addChildToBack(Node child) {\r
152         child.next = null;\r
153         if (last == null) {\r
154             first = last = child;\r
155             return;\r
156         }\r
157         last.next = child;\r
158         last = child;\r
159     }\r
160 \r
161     public void addChildrenToFront(Node children) {\r
162         Node lastSib = children.getLastSibling();\r
163         lastSib.next = first;\r
164         first = children;\r
165         if (last == null) {\r
166             last = lastSib;\r
167         }\r
168     }\r
169 \r
170     public void addChildrenToBack(Node children) {\r
171         if (last != null) {\r
172             last.next = children;\r
173         }\r
174         last = children.getLastSibling();\r
175         if (first == null) {\r
176             first = children;\r
177         }\r
178     }\r
179 \r
180     /**\r
181      * Add 'child' before 'node'.\r
182      */\r
183     public void addChildBefore(Node newChild, Node node) {\r
184         if (newChild.next != null)\r
185             throw new RuntimeException(\r
186                       "newChild had siblings in addChildBefore");\r
187         if (first == node) {\r
188             newChild.next = first;\r
189             first = newChild;\r
190             return;\r
191         }\r
192         Node prev = getChildBefore(node);\r
193         addChildAfter(newChild, prev);\r
194     }\r
195 \r
196     /**\r
197      * Add 'child' after 'node'.\r
198      */\r
199     public void addChildAfter(Node newChild, Node node) {\r
200         if (newChild.next != null)\r
201             throw new RuntimeException(\r
202                       "newChild had siblings in addChildAfter");\r
203         newChild.next = node.next;\r
204         node.next = newChild;\r
205         if (last == node)\r
206             last = newChild;\r
207     }\r
208 \r
209     public void removeChild(Node child) {\r
210         Node prev = getChildBefore(child);\r
211         if (prev == null)\r
212             first = first.next;\r
213         else\r
214             prev.next = child.next;\r
215         if (child == last) last = prev;\r
216         child.next = null;\r
217     }\r
218 \r
219     public void replaceChild(Node child, Node newChild) {\r
220         newChild.next = child.next;\r
221         if (child == first) {\r
222             first = newChild;\r
223         } else {\r
224             Node prev = getChildBefore(child);\r
225             prev.next = newChild;\r
226         }\r
227         if (child == last)\r
228             last = newChild;\r
229         child.next = null;\r
230     }\r
231 \r
232     public static final int\r
233         TARGET_PROP       =  1,\r
234         BREAK_PROP        =  2,\r
235         CONTINUE_PROP     =  3,\r
236         ENUM_PROP         =  4,\r
237         FUNCTION_PROP     =  5,\r
238         TEMP_PROP         =  6,\r
239         LOCAL_PROP        =  7,\r
240         CODEOFFSET_PROP   =  8,\r
241         FIXUPS_PROP       =  9,\r
242         VARS_PROP         = 10,\r
243         USES_PROP         = 11,\r
244         REGEXP_PROP       = 12,\r
245         CASES_PROP        = 13,\r
246         DEFAULT_PROP      = 14,\r
247         CASEARRAY_PROP    = 15,\r
248         SOURCENAME_PROP   = 16,\r
249         SOURCE_PROP       = 17,\r
250         TYPE_PROP         = 18,\r
251         SPECIAL_PROP_PROP = 19,\r
252         LABEL_PROP        = 20,\r
253         FINALLY_PROP      = 21,\r
254         LOCALCOUNT_PROP   = 22,\r
255     /*\r
256         the following properties are defined and manipulated by the\r
257         optimizer -\r
258         TARGETBLOCK_PROP - the block referenced by a branch node\r
259         VARIABLE_PROP - the variable referenced by a BIND or NAME node\r
260         LASTUSE_PROP - that variable node is the last reference before\r
261                         a new def or the end of the block\r
262         ISNUMBER_PROP - this node generates code on Number children and\r
263                         delivers a Number result (as opposed to Objects)\r
264         DIRECTCALL_PROP - this call node should emit code to test the function\r
265                           object against the known class and call diret if it\r
266                           matches.\r
267     */\r
268 \r
269         TARGETBLOCK_PROP  = 23,\r
270         VARIABLE_PROP     = 24,\r
271         LASTUSE_PROP      = 25,\r
272         ISNUMBER_PROP     = 26,\r
273         DIRECTCALL_PROP   = 27,\r
274 \r
275         BASE_LINENO_PROP  = 28,\r
276         END_LINENO_PROP   = 29,\r
277         SPECIALCALL_PROP  = 30,\r
278         DEBUGSOURCE_PROP  = 31;\r
279 \r
280     public static final int    // this value of the ISNUMBER_PROP specifies\r
281         BOTH = 0,               // which of the children are Number types\r
282         LEFT = 1,\r
283         RIGHT = 2;\r
284 \r
285     private static String propNames[];\r
286     \r
287     private static final String propToString(int propType) {\r
288         if (Context.printTrees && propNames == null) {\r
289             // If Context.printTrees is false, the compiler\r
290             // can remove all these strings.\r
291             String[] a = {\r
292                 "target",\r
293                 "break",\r
294                 "continue",\r
295                 "enum",\r
296                 "function",\r
297                 "temp",\r
298                 "local",\r
299                 "codeoffset",\r
300                 "fixups",\r
301                 "vars",\r
302                 "uses",\r
303                 "regexp",\r
304                 "cases",\r
305                 "default",\r
306                 "casearray",\r
307                 "sourcename",\r
308                 "source",\r
309                 "type",\r
310                 "special_prop",\r
311                 "label",\r
312                 "finally",\r
313                 "localcount",\r
314                 "targetblock",\r
315                 "variable",\r
316                 "lastuse",\r
317                 "isnumber",\r
318                 "directcall",\r
319                 "base_lineno",\r
320                 "end_lineno",\r
321                 "specialcall"\r
322             };\r
323             propNames = a;\r
324         }\r
325         return propNames[propType-1];\r
326     }\r
327 \r
328     public Object getProp(int propType) {\r
329         if (props == null)\r
330             return null;\r
331         return props.getObject(propType);\r
332     }\r
333 \r
334     public int getIntProp(int propType, int defaultValue) {\r
335         if (props == null)\r
336             return defaultValue;\r
337         return props.getInt(propType, defaultValue);\r
338     }\r
339 \r
340     public int getExistingIntProp(int propType) {\r
341         return props.getExistingInt(propType);\r
342     }\r
343 \r
344     public void putProp(int propType, Object prop) {\r
345         if (props == null)\r
346             props = new UintMap(2);\r
347         if (prop == null)\r
348             props.remove(propType);\r
349         else\r
350             props.put(propType, prop);\r
351     }\r
352 \r
353     public void putIntProp(int propType, int prop) {\r
354         if (props == null)\r
355             props = new UintMap(2);\r
356         props.put(propType, prop);\r
357     }\r
358 \r
359     public Object getDatum() {\r
360         return datum;\r
361     }\r
362 \r
363     public void setDatum(Object datum) {\r
364         this.datum = datum;\r
365     }\r
366 \r
367     public int getInt() {\r
368         return ((Number) datum).intValue();\r
369     }\r
370 \r
371     public double getDouble() {\r
372         return ((Number) datum).doubleValue();\r
373     }\r
374 \r
375     public long getLong() {\r
376         return ((Number) datum).longValue();\r
377     }\r
378 \r
379     public String getString() {\r
380         return (String) datum;\r
381     }\r
382 \r
383     public Node cloneNode() {\r
384         Node result;\r
385         try {\r
386             result = (Node) super.clone();\r
387             result.next = null;\r
388             result.first = null;\r
389             result.last = null;\r
390         }\r
391         catch (CloneNotSupportedException e) {\r
392             throw new RuntimeException(e.getMessage());\r
393         }\r
394         return result;\r
395     }\r
396     public String toString() {\r
397         return super.toString();\r
398     }\r
399     /*\r
400     public String toString() {\r
401         if (Context.printTrees) {\r
402             StringBuffer sb = new StringBuffer(TokenStream.tokenToName(type));\r
403             if (type == TokenStream.TARGET) {\r
404                 sb.append(' ');\r
405                 sb.append(hashCode());\r
406             }\r
407             if (datum != null) {\r
408                 sb.append(' ');\r
409                 sb.append(datum.toString());\r
410             }\r
411             if (props == null)\r
412                 return sb.toString();\r
413 \r
414             int[] keys = props.getKeys();\r
415             for (int i = 0; i != keys.length; ++i) {\r
416                 int key = keys[i];\r
417                 sb.append(" [");\r
418                 sb.append(propToString(key));\r
419                 sb.append(": ");\r
420                 switch (key) {\r
421                     case FIXUPS_PROP :      // can't add this as it recurses\r
422                         sb.append("fixups property");\r
423                         break;\r
424                     case SOURCE_PROP :      // can't add this as it has unprintables\r
425                         sb.append("source property");\r
426                         break;\r
427                     case TARGETBLOCK_PROP : // can't add this as it recurses\r
428                         sb.append("target block property");\r
429                         break;\r
430                     case LASTUSE_PROP :     // can't add this as it is dull\r
431                         sb.append("last use property");\r
432                         break;\r
433                     default :\r
434                         if (props.isObjectType(key)) {\r
435                             sb.append(props.getObject(key).toString());\r
436                         }\r
437                         else {\r
438                             sb.append(props.getExistingInt(key));\r
439                         }\r
440                         break;\r
441                 }\r
442                 sb.append(']');\r
443             }\r
444             return sb.toString();\r
445         }\r
446         return null;\r
447     }\r
448     */\r
449     public String toStringTree() {\r
450         return toStringTreeHelper(0);\r
451     }\r
452     \r
453 \r
454     private String toStringTreeHelper(int level) {\r
455         if (Context.printTrees) {\r
456             StringBuffer s = new StringBuffer();\r
457             for (int i=0; i < level; i++) {\r
458                 s.append("    ");\r
459             }\r
460             s.append(toString());\r
461             s.append('\n');\r
462             ShallowNodeIterator iterator = getChildIterator();\r
463             if (iterator != null) {\r
464                 while (iterator.hasMoreElements()) {\r
465                     Node n = (Node) iterator.nextElement();\r
466                     if (n.getType() == TokenStream.FUNCTION) {\r
467                         Node p = (Node) n.getProp(Node.FUNCTION_PROP);\r
468                         if (p != null)\r
469                             n = p;\r
470                     }\r
471                     s.append(n.toStringTreeHelper(level+1));\r
472                 }\r
473             }\r
474             return s.toString();\r
475         }\r
476         return "";\r
477     }\r
478 \r
479     public Node getFirst()  { return first; }\r
480     public Node getNext()   { return next; }\r
481 \r
482     protected int type;         // type of the node; TokenStream.NAME for example\r
483     protected Node next;        // next sibling\r
484     protected Node first;       // first element of a linked list of children\r
485     protected Node last;        // last element of a linked list of children\r
486     protected UintMap props;\r
487     protected Object datum;     // encapsulated data; depends on type\r
488 }\r
489 \r