1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
\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
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
13 * The Original Code is Rhino code, released
\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
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
38 package org.mozilla.javascript;
\r
41 * This class implements the root of the intermediate representation.
\r
43 * @author Norris Boyd
\r
44 * @author Mike McCabe
\r
47 public class Node implements Cloneable {
\r
49 public Node(int nodeType) {
\r
53 public Node(int nodeType, Node child) {
\r
55 first = last = child;
\r
59 public Node(int nodeType, Node left, Node right) {
\r
67 public Node(int nodeType, Node left, Node mid, Node right) {
\r
76 public Node(int nodeType, Object datum) {
\r
81 public Node(int nodeType, Node child, Object datum) {
\r
82 this(nodeType, child);
\r
86 public Node(int nodeType, Node left, Node right, Object datum) {
\r
87 this(nodeType, left, right);
\r
91 public int getType() {
\r
95 public void setType(int type) {
\r
99 public boolean hasChildren() {
\r
100 return first != null;
\r
103 public Node getFirstChild() {
\r
107 public Node getLastChild() {
\r
111 public Node getNextSibling() {
\r
115 public Node getChildBefore(Node child) {
\r
116 if (child == first)
\r
119 while (n.next != child) {
\r
122 throw new RuntimeException("node is not a child");
\r
127 public Node getLastSibling() {
\r
129 while (n.next != null) {
\r
135 public ShallowNodeIterator getChildIterator() {
\r
136 return new ShallowNodeIterator(first);
\r
139 public PreorderNodeIterator getPreorderIterator() {
\r
140 return new PreorderNodeIterator(this);
\r
143 public void addChildToFront(Node child) {
\r
144 child.next = first;
\r
146 if (last == null) {
\r
151 public void addChildToBack(Node child) {
\r
153 if (last == null) {
\r
154 first = last = child;
\r
161 public void addChildrenToFront(Node children) {
\r
162 Node lastSib = children.getLastSibling();
\r
163 lastSib.next = first;
\r
165 if (last == null) {
\r
170 public void addChildrenToBack(Node children) {
\r
171 if (last != null) {
\r
172 last.next = children;
\r
174 last = children.getLastSibling();
\r
175 if (first == null) {
\r
181 * Add 'child' before 'node'.
\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
192 Node prev = getChildBefore(node);
\r
193 addChildAfter(newChild, prev);
\r
197 * Add 'child' after 'node'.
\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
209 public void removeChild(Node child) {
\r
210 Node prev = getChildBefore(child);
\r
212 first = first.next;
\r
214 prev.next = child.next;
\r
215 if (child == last) last = prev;
\r
219 public void replaceChild(Node child, Node newChild) {
\r
220 newChild.next = child.next;
\r
221 if (child == first) {
\r
224 Node prev = getChildBefore(child);
\r
225 prev.next = newChild;
\r
232 public static final int
\r
240 CODEOFFSET_PROP = 8,
\r
247 CASEARRAY_PROP = 15,
\r
248 SOURCENAME_PROP = 16,
\r
251 SPECIAL_PROP_PROP = 19,
\r
254 LOCALCOUNT_PROP = 22,
\r
256 the following properties are defined and manipulated by the
\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
269 TARGETBLOCK_PROP = 23,
\r
270 VARIABLE_PROP = 24,
\r
272 ISNUMBER_PROP = 26,
\r
273 DIRECTCALL_PROP = 27,
\r
275 BASE_LINENO_PROP = 28,
\r
276 END_LINENO_PROP = 29,
\r
277 SPECIALCALL_PROP = 30,
\r
278 DEBUGSOURCE_PROP = 31;
\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
285 private static String propNames[];
\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
325 return propNames[propType-1];
\r
328 public Object getProp(int propType) {
\r
331 return props.getObject(propType);
\r
334 public int getIntProp(int propType, int defaultValue) {
\r
336 return defaultValue;
\r
337 return props.getInt(propType, defaultValue);
\r
340 public int getExistingIntProp(int propType) {
\r
341 return props.getExistingInt(propType);
\r
344 public void putProp(int propType, Object prop) {
\r
346 props = new UintMap(2);
\r
348 props.remove(propType);
\r
350 props.put(propType, prop);
\r
353 public void putIntProp(int propType, int prop) {
\r
355 props = new UintMap(2);
\r
356 props.put(propType, prop);
\r
359 public Object getDatum() {
\r
363 public void setDatum(Object datum) {
\r
364 this.datum = datum;
\r
367 public int getInt() {
\r
368 return ((Number) datum).intValue();
\r
371 public double getDouble() {
\r
372 return ((Number) datum).doubleValue();
\r
375 public long getLong() {
\r
376 return ((Number) datum).longValue();
\r
379 public String getString() {
\r
380 return (String) datum;
\r
383 public Node cloneNode() {
\r
386 result = (Node) super.clone();
\r
387 result.next = null;
\r
388 result.first = null;
\r
389 result.last = null;
\r
391 catch (CloneNotSupportedException e) {
\r
392 throw new RuntimeException(e.getMessage());
\r
396 public String toString() {
\r
397 return super.toString();
\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
405 sb.append(hashCode());
\r
407 if (datum != null) {
\r
409 sb.append(datum.toString());
\r
412 return sb.toString();
\r
414 int[] keys = props.getKeys();
\r
415 for (int i = 0; i != keys.length; ++i) {
\r
418 sb.append(propToString(key));
\r
421 case FIXUPS_PROP : // can't add this as it recurses
\r
422 sb.append("fixups property");
\r
424 case SOURCE_PROP : // can't add this as it has unprintables
\r
425 sb.append("source property");
\r
427 case TARGETBLOCK_PROP : // can't add this as it recurses
\r
428 sb.append("target block property");
\r
430 case LASTUSE_PROP : // can't add this as it is dull
\r
431 sb.append("last use property");
\r
434 if (props.isObjectType(key)) {
\r
435 sb.append(props.getObject(key).toString());
\r
438 sb.append(props.getExistingInt(key));
\r
444 return sb.toString();
\r
449 public String toStringTree() {
\r
450 return toStringTreeHelper(0);
\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
460 s.append(toString());
\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
471 s.append(n.toStringTreeHelper(level+1));
\r
474 return s.toString();
\r
479 public Node getFirst() { return first; }
\r
480 public Node getNext() { return next; }
\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