Thu, 11 Jul 2013 18:33:33 +0200
8013925: Remove symbol fields from nodes that don't need them
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.annotations.Immutable;
29 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
31 /**
32 * IR representing a FOR statement.
33 */
34 @Immutable
35 public final class ForNode extends LoopNode {
36 /** Initialize expression. */
37 private final Expression init;
39 /** Test expression. */
40 private final Expression modify;
42 /** Iterator symbol. */
43 private Symbol iterator;
45 /** Is this a normal for loop? */
46 public static final int IS_FOR = 1 << 0;
48 /** Is this a normal for in loop? */
49 public static final int IS_FOR_IN = 1 << 1;
51 /** Is this a normal for each in loop? */
52 public static final int IS_FOR_EACH = 1 << 2;
54 private final int flags;
56 /**
57 * Constructor
58 *
59 * @param lineNumber line number
60 * @param token token
61 * @param finish finish
62 * @param init initialization expression
63 * @param test test
64 * @param body body
65 * @param modify modify
66 * @param flags flags
67 */
68 public ForNode(final int lineNumber, final long token, final int finish, final Expression init, final Expression test, final Block body, final Expression modify, final int flags) {
69 super(lineNumber, token, finish, test, body, false);
70 this.init = init;
71 this.modify = modify;
72 this.flags = flags;
73 }
75 private ForNode(final ForNode forNode, final Expression init, final Expression test, final Block body, final Expression modify, final int flags, final boolean controlFlowEscapes) {
76 super(forNode, test, body, controlFlowEscapes);
77 this.init = init;
78 this.modify = modify;
79 this.flags = flags;
80 this.iterator = forNode.iterator; //TODO is this acceptable? symbols are never cloned, just copied as references
81 }
83 @Override
84 public Node ensureUniqueLabels(LexicalContext lc) {
85 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
86 }
88 @Override
89 public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
90 if (visitor.enterForNode(this)) {
91 return visitor.leaveForNode(
92 setInit(lc, init == null ? null : (Expression)init.accept(visitor)).
93 setTest(lc, test == null ? null : (Expression)test.accept(visitor)).
94 setModify(lc, modify == null ? null : (Expression)modify.accept(visitor)).
95 setBody(lc, (Block)body.accept(visitor)));
96 }
98 return this;
99 }
101 @Override
102 public void toString(final StringBuilder sb) {
103 sb.append("for (");
105 if (isForIn()) {
106 init.toString(sb);
107 sb.append(" in ");
108 modify.toString(sb);
109 } else {
110 if (init != null) {
111 init.toString(sb);
112 }
113 sb.append("; ");
114 if (test != null) {
115 test.toString(sb);
116 }
117 sb.append("; ");
118 if (modify != null) {
119 modify.toString(sb);
120 }
121 }
123 sb.append(')');
124 }
126 @Override
127 public boolean hasGoto() {
128 return !isForIn() && test == null;
129 }
131 @Override
132 public boolean mustEnter() {
133 if (isForIn()) {
134 return false; //may be an empty set to iterate over, then we skip the loop
135 }
136 return test == null;
137 }
139 /**
140 * Get the initialization expression for this for loop
141 * @return the initialization expression
142 */
143 public Expression getInit() {
144 return init;
145 }
147 /**
148 * Reset the initialization expression for this for loop
149 * @param lc lexical context
150 * @param init new initialization expression
151 * @return new for node if changed or existing if not
152 */
153 public ForNode setInit(final LexicalContext lc, final Expression init) {
154 if (this.init == init) {
155 return this;
156 }
157 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
158 }
160 /**
161 * Is this a for in construct rather than a standard init;condition;modification one
162 * @return true if this is a for in constructor
163 */
164 public boolean isForIn() {
165 return (flags & IS_FOR_IN) != 0;
166 }
168 /**
169 * Flag this to be a for in construct
170 * @param lc lexical context
171 * @return new for node if changed or existing if not
172 */
173 public ForNode setIsForIn(final LexicalContext lc) {
174 return setFlags(lc, flags | IS_FOR_IN);
175 }
177 /**
178 * Is this a for each construct, known from e.g. Rhino. This will be a for of construct
179 * in ECMAScript 6
180 * @return true if this is a for each construct
181 */
182 public boolean isForEach() {
183 return (flags & IS_FOR_EACH) != 0;
184 }
186 /**
187 * Flag this to be a for each construct
188 * @param lc lexical context
189 * @return new for node if changed or existing if not
190 */
191 public ForNode setIsForEach(final LexicalContext lc) {
192 return setFlags(lc, flags | IS_FOR_EACH);
193 }
195 /**
196 * If this is a for in or for each construct, there is an iterator symbol
197 * @return the symbol for the iterator to be used, or null if none exists
198 */
199 public Symbol getIterator() {
200 return iterator;
201 }
203 /**
204 * Assign an iterator symbol to this ForNode. Used for for in and for each constructs
205 * @param iterator the iterator symbol
206 */
207 public void setIterator(final Symbol iterator) {
208 this.iterator = iterator;
209 }
211 /**
212 * Get the modification expression for this ForNode
213 * @return the modification expression
214 */
215 public Expression getModify() {
216 return modify;
217 }
219 /**
220 * Reset the modification expression for this ForNode
221 * @param lc lexical context
222 * @param modify new modification expression
223 * @return new for node if changed or existing if not
224 */
225 public ForNode setModify(final LexicalContext lc, final Expression modify) {
226 if (this.modify == modify) {
227 return this;
228 }
229 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
230 }
232 @Override
233 public Expression getTest() {
234 return test;
235 }
237 @Override
238 public ForNode setTest(final LexicalContext lc, final Expression test) {
239 if (this.test == test) {
240 return this;
241 }
242 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
243 }
245 @Override
246 public Block getBody() {
247 return body;
248 }
250 @Override
251 public ForNode setBody(final LexicalContext lc, final Block body) {
252 if (this.body == body) {
253 return this;
254 }
255 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
256 }
258 @Override
259 public ForNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes) {
260 if (this.controlFlowEscapes == controlFlowEscapes) {
261 return this;
262 }
263 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
264 }
266 private ForNode setFlags(final LexicalContext lc, final int flags) {
267 if (this.flags == flags) {
268 return this;
269 }
270 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
271 }
273 }