Sat, 23 Mar 2013 00:58:39 +0100
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
Reviewed-by: jlaskey, lagergren
1 /*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package jdk.nashorn.internal.ir;
28 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
29 import jdk.nashorn.internal.runtime.Source;
31 /**
32 * Node represents a var/let declaration.
33 */
34 public class VarNode extends Node implements Assignment<IdentNode> {
35 /** Var name. */
36 private IdentNode name;
38 /** Initialization expression. */
39 private Node init;
41 /** Is this a var statement (as opposed to a "var" in a for loop statement) */
42 private final boolean isStatement;
44 /**
45 * Constructor
46 *
47 * @param source the source
48 * @param token token
49 * @param finish finish
50 * @param name name of variable
51 * @param init init node or null if just a declaration
52 */
53 public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) {
54 this(source, token, finish, name, init, true);
55 }
57 /**
58 * Constructor
59 *
60 * @param source the source
61 * @param token token
62 * @param finish finish
63 * @param name name of variable
64 * @param init init node or null if just a declaration
65 * @param isStatement if this is a var statement (true), or a for-loop initializer (false)
66 */
67 public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, boolean isStatement) {
68 super(source, token, finish);
70 this.name = init == null ? name : name.setIsInitializedHere();
71 this.init = init;
72 this.isStatement = isStatement;
73 }
76 private VarNode(final VarNode varNode, final CopyState cs) {
77 super(varNode);
79 this.name = (IdentNode)cs.existingOrCopy(varNode.name);
80 this.init = cs.existingOrCopy(varNode.init);
81 this.isStatement = varNode.isStatement;
82 }
84 @Override
85 protected Node copy(final CopyState cs) {
86 return new VarNode(this, cs);
87 }
89 @Override
90 public boolean isAssignment() {
91 return hasInit();
92 }
94 @Override
95 public IdentNode getAssignmentDest() {
96 return isAssignment() ? name : null;
97 }
99 @Override
100 public Node setAssignmentDest(IdentNode n) {
101 return setName(n);
102 }
104 @Override
105 public Node getAssignmentSource() {
106 return isAssignment() ? getInit() : null;
107 }
109 /**
110 * Does this variable declaration have an init value
111 * @return true if an init exists, false otherwise
112 */
113 public boolean hasInit() {
114 return init != null;
115 }
117 /**
118 * Test to see if two VarNodes are the same.
119 * @param other Other VarNode.
120 * @return True if the VarNodes are the same.
121 */
122 @Override
123 public boolean equals(final Object other) {
124 if (other instanceof VarNode) {
125 final VarNode otherNode = (VarNode)other;
126 final boolean nameMatches = name.equals(otherNode.name);
127 if (hasInit() != otherNode.hasInit()) {
128 return false;
129 } else if (init == null) {
130 return nameMatches;
131 } else {
132 return nameMatches && init.equals(otherNode.init);
133 }
134 }
135 return false;
136 }
138 @Override
139 public int hashCode() {
140 return name.hashCode() ^ (init == null ? 0 : init.hashCode());
141 }
143 /**
144 * Assist in IR navigation.
145 * @param visitor IR navigating visitor.
146 */
147 @Override
148 public Node accept(final NodeVisitor visitor) {
149 if (visitor.enterVarNode(this) != null) {
150 final IdentNode newName = (IdentNode)name.accept(visitor);
151 final Node newInit = init == null ? null : init.accept(visitor);
152 final VarNode newThis;
153 if(name != newName || init != newInit) {
154 newThis = (VarNode)clone();
155 newThis.init = newInit;
156 newThis.name = newInit == null ? newName : newName.setIsInitializedHere();
157 } else {
158 newThis = this;
159 }
160 return visitor.leaveVarNode(newThis);
161 }
162 return this;
163 }
165 @Override
166 public void toString(final StringBuilder sb) {
167 sb.append("var ");
168 name.toString(sb);
170 if (init != null) {
171 sb.append(" = ");
172 init.toString(sb);
173 }
174 }
176 /**
177 * If this is an assignment of the form {@code var x = init;}, get the init part.
178 * @return the expression to initialize the variable to, null if just a declaration
179 */
180 public Node getInit() {
181 return init;
182 }
184 /**
185 * Reset the initialization expression
186 * @param init new initialization expression
187 * @return a node equivalent to this one except for the requested change.
188 */
189 public VarNode setInit(final Node init) {
190 if(this.init == init) return this;
191 final VarNode n = (VarNode)clone();
192 n.init = init;
193 return n;
194 }
196 /**
197 * Get the identifier for the variable
198 * @return IdentNode representing the variable being set or declared
199 */
200 public IdentNode getName() {
201 return name;
202 }
204 /**
205 * Reset the identifier for this VarNode
206 * @param name new IdentNode representing the variable being set or declared
207 */
208 private VarNode setName(final IdentNode name) {
209 if(this.name == name) return this;
210 final VarNode n = (VarNode)clone();
211 n.name = name;
212 return n;
213 }
215 /**
216 * Returns true if this is a var statement (as opposed to a var initializer in a for loop).
217 * @return true if this is a var statement (as opposed to a var initializer in a for loop).
218 */
219 public boolean isStatement() {
220 return isStatement;
221 }
223 /**
224 * Returns true if this is a function declaration.
225 * @return true if this is a function declaration.
226 */
227 public boolean isFunctionDeclaration() {
228 return init instanceof FunctionNode && ((FunctionNode)init).isDeclared();
229 }
230 }