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
265 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
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 * @return true if the containing block's scope object creator is required in codegen
283 */
284 public boolean needsScopeCreator() {
285 return isForIn() && hasPerIterationScope();
286 }
287 }
|
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 !isForIn() && !isForOf() && test == null;
157 }
158
159 @Override
160 public boolean mustEnter() {
161 if (isForIn() || isForOf()) {
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 each construct, known from e.g. Rhino. This will be a for of construct
206 * in ECMAScript 6
207 * @return true if this is a for each construct
208 */
209 public boolean isForEach() {
210 return (flags & IS_FOR_EACH) != 0;
211 }
212
213 /**
214 * If this is a for in or for each construct, there is an iterator symbol
215 * @return the symbol for the iterator to be used, or null if none exists
216 */
217 public Symbol getIterator() {
218 return iterator;
219 }
220
221 /**
222 * Assign an iterator symbol to this ForNode. Used for for in and for each constructs
223 * @param lc the current lexical context
281 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
282 }
283
284 @Override
285 JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
286 return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
287 }
288
289 @Override
290 public boolean hasPerIterationScope() {
291 return (flags & PER_ITERATION_SCOPE) != 0;
292 }
293
294 /**
295 * Returns true if this for-node needs the scope creator of its containing block to create
296 * per-iteration scope. This is only true for for-in loops with lexical declarations.
297 *
298 * @return true if the containing block's scope object creator is required in codegen
299 */
300 public boolean needsScopeCreator() {
301 return (isForIn() || isForOf()) && hasPerIterationScope();
302 }
303 }
|