34 @Immutable
35 public final class ForNode extends LoopNode {
36 private static final long serialVersionUID = 1L;
37
38 /** Initialize expression for an ordinary for statement, or the LHS expression receiving iterated-over values in a
39 * for-in statement. */
40 private final Expression init;
41
42 /** Modify expression for an ordinary statement, or the source of the iterator in the for-in statement. */
43 private final JoinPredecessorExpression modify;
44
45 /** Iterator symbol. */
46 private final Symbol iterator;
47
48 /** Is this a normal for in loop? */
49 public static final int IS_FOR_IN = 1 << 0;
50
51 /** Is this a normal for each in loop? */
52 public static final int IS_FOR_EACH = 1 << 1;
53
54 /** Does this loop need a per-iteration scope because its init contain a LET declaration? */
55 public static final int PER_ITERATION_SCOPE = 1 << 2;
56
57 private final int flags;
58
59 /**
60 * Constructs a ForNode
61 *
62 * @param lineNumber The line number of header
63 * @param token The for token
64 * @param finish The last character of the for node
65 * @param body The body of the for node
66 * @param flags The flags
67 */
68 public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags){
69 this(lineNumber, token, finish, body, flags, null, null, null);
70 }
71
72 /**
73 * Constructor
74 *
75 * @param lineNumber The line number of header
110 if (visitor.enterForNode(this)) {
111 return visitor.leaveForNode(
112 setInit(lc, init == null ? null : (Expression)init.accept(visitor)).
113 setTest(lc, test == null ? null : (JoinPredecessorExpression)test.accept(visitor)).
114 setModify(lc, modify == null ? null : (JoinPredecessorExpression)modify.accept(visitor)).
115 setBody(lc, (Block)body.accept(visitor)));
116 }
117
118 return this;
119 }
120
121 @Override
122 public void toString(final StringBuilder sb, final boolean printTypes) {
123 sb.append("for");
124 LocalVariableConversion.toString(conversion, sb).append(' ');
125
126 if (isForIn()) {
127 init.toString(sb, printTypes);
128 sb.append(" in ");
129 modify.toString(sb, printTypes);
130 } else {
131 if (init != null) {
132 init.toString(sb, printTypes);
133 }
134 sb.append("; ");
135 if (test != null) {
136 test.toString(sb, printTypes);
137 }
138 sb.append("; ");
139 if (modify != null) {
140 modify.toString(sb, printTypes);
141 }
142 }
143
144 sb.append(')');
145 }
146
147 @Override
148 public boolean hasGoto() {
149 return !isForIn() && test == null;
150 }
151
152 @Override
153 public boolean mustEnter() {
154 if (isForIn()) {
155 return false; //may be an empty set to iterate over, then we skip the loop
156 }
157 return test == null;
158 }
159
160 /**
161 * Get the initialization expression for this for loop
162 * @return the initialization expression
163 */
164 public Expression getInit() {
165 return init;
166 }
167
168 /**
169 * Reset the initialization expression for this for loop
170 * @param lc lexical context
171 * @param init new initialization expression
172 * @return new for node if changed or existing if not
173 */
174 public ForNode setInit(final LexicalContext lc, final Expression init) {
175 if (this.init == init) {
176 return this;
177 }
178 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
179 }
180
181 /**
182 * Is this a for in construct rather than a standard init;condition;modification one
183 * @return true if this is a for in constructor
184 */
185 public boolean isForIn() {
186 return (flags & IS_FOR_IN) != 0;
187 }
188 /**
189 * Is this a for each construct, known from e.g. Rhino. This will be a for of construct
190 * in ECMAScript 6
191 * @return true if this is a for each construct
192 */
193 public boolean isForEach() {
194 return (flags & IS_FOR_EACH) != 0;
195 }
196
197 /**
198 * If this is a for in or for each construct, there is an iterator symbol
199 * @return the symbol for the iterator to be used, or null if none exists
200 */
201 public Symbol getIterator() {
202 return iterator;
203 }
204
205 /**
206 * Assign an iterator symbol to this ForNode. Used for for in and for each constructs
207 * @param lc the current lexical context
266 }
267
268 @Override
269 JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
270 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
271 }
272
273 @Override
274 public boolean hasPerIterationScope() {
275 return (flags & PER_ITERATION_SCOPE) != 0;
276 }
277
278 /**
279 * Returns true if this for-node needs the scope creator of its containing block to create
280 * per-iteration scope. This is only true for for-in loops with lexical declarations.
281 *
282 * @see Block#providesScopeCreator()
283 * @return true if the containing block's scope object creator is required in codegen
284 */
285 public boolean needsScopeCreator() {
286 return isForIn() && hasPerIterationScope();
287 }
288 }
|
34 @Immutable
35 public final class ForNode extends LoopNode {
36 private static final long serialVersionUID = 1L;
37
38 /** Initialize expression for an ordinary for statement, or the LHS expression receiving iterated-over values in a
39 * for-in statement. */
40 private final Expression init;
41
42 /** Modify expression for an ordinary statement, or the source of the iterator in the for-in statement. */
43 private final JoinPredecessorExpression modify;
44
45 /** Iterator symbol. */
46 private final Symbol iterator;
47
48 /** Is this a normal for in loop? */
49 public static final int IS_FOR_IN = 1 << 0;
50
51 /** Is this a normal for each in loop? */
52 public static final int IS_FOR_EACH = 1 << 1;
53
54 /** Is this a ES6 for-of loop? */
55 public static final int IS_FOR_OF = 1 << 2;
56
57 /** Does this loop need a per-iteration scope because its init contain a LET declaration? */
58 public static final int PER_ITERATION_SCOPE = 1 << 3;
59
60 private final int flags;
61
62 /**
63 * Constructs a ForNode
64 *
65 * @param lineNumber The line number of header
66 * @param token The for token
67 * @param finish The last character of the for node
68 * @param body The body of the for node
69 * @param flags The flags
70 */
71 public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags){
72 this(lineNumber, token, finish, body, flags, null, null, null);
73 }
74
75 /**
76 * Constructor
77 *
78 * @param lineNumber The line number of header
113 if (visitor.enterForNode(this)) {
114 return visitor.leaveForNode(
115 setInit(lc, init == null ? null : (Expression)init.accept(visitor)).
116 setTest(lc, test == null ? null : (JoinPredecessorExpression)test.accept(visitor)).
117 setModify(lc, modify == null ? null : (JoinPredecessorExpression)modify.accept(visitor)).
118 setBody(lc, (Block)body.accept(visitor)));
119 }
120
121 return this;
122 }
123
124 @Override
125 public void toString(final StringBuilder sb, final boolean printTypes) {
126 sb.append("for");
127 LocalVariableConversion.toString(conversion, sb).append(' ');
128
129 if (isForIn()) {
130 init.toString(sb, printTypes);
131 sb.append(" in ");
132 modify.toString(sb, printTypes);
133 } else if (isForOf()) {
134 init.toString(sb, printTypes);
135 sb.append(" of ");
136 modify.toString(sb, printTypes);
137 } else {
138 if (init != null) {
139 init.toString(sb, printTypes);
140 }
141 sb.append("; ");
142 if (test != null) {
143 test.toString(sb, printTypes);
144 }
145 sb.append("; ");
146 if (modify != null) {
147 modify.toString(sb, printTypes);
148 }
149 }
150
151 sb.append(')');
152 }
153
154 @Override
155 public boolean hasGoto() {
156 return !isForInOrOf() && test == null;
157 }
158
159 @Override
160 public boolean mustEnter() {
161 if (isForInOrOf()) {
162 return false; //may be an empty set to iterate over, then we skip the loop
163 }
164 return test == null;
165 }
166
167 /**
168 * Get the initialization expression for this for loop
169 * @return the initialization expression
170 */
171 public Expression getInit() {
172 return init;
173 }
174
175 /**
176 * Reset the initialization expression for this for loop
177 * @param lc lexical context
178 * @param init new initialization expression
179 * @return new for node if changed or existing if not
180 */
181 public ForNode setInit(final LexicalContext lc, final Expression init) {
182 if (this.init == init) {
183 return this;
184 }
185 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
186 }
187
188 /**
189 * Is this a for in construct rather than a standard init;condition;modification one
190 * @return true if this is a for in constructor
191 */
192 public boolean isForIn() {
193 return (flags & IS_FOR_IN) != 0;
194 }
195
196 /**
197 * Is this a for-of loop?
198 * @return true if this is a for-of loop
199 */
200 public boolean isForOf() {
201 return (flags & IS_FOR_OF) != 0;
202 }
203
204 /**
205 * Is this a for-in or for-of statement?
206 * @return true if this is a for-in or for-of loop
207 */
208 public boolean isForInOrOf() {
209 return isForIn() || isForOf();
210 }
211
212 /**
213 * Is this a for each construct, known from e.g. Rhino. This will be a for of construct
214 * in ECMAScript 6
215 * @return true if this is a for each construct
216 */
217 public boolean isForEach() {
218 return (flags & IS_FOR_EACH) != 0;
219 }
220
221 /**
222 * If this is a for in or for each construct, there is an iterator symbol
223 * @return the symbol for the iterator to be used, or null if none exists
224 */
225 public Symbol getIterator() {
226 return iterator;
227 }
228
229 /**
230 * Assign an iterator symbol to this ForNode. Used for for in and for each constructs
231 * @param lc the current lexical context
290 }
291
292 @Override
293 JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
294 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
295 }
296
297 @Override
298 public boolean hasPerIterationScope() {
299 return (flags & PER_ITERATION_SCOPE) != 0;
300 }
301
302 /**
303 * Returns true if this for-node needs the scope creator of its containing block to create
304 * per-iteration scope. This is only true for for-in loops with lexical declarations.
305 *
306 * @see Block#providesScopeCreator()
307 * @return true if the containing block's scope object creator is required in codegen
308 */
309 public boolean needsScopeCreator() {
310 return isForInOrOf() && hasPerIterationScope();
311 }
312 }
|