| Index: frog/leg/ssa/builder.dart
|
| diff --git a/frog/leg/ssa/builder.dart b/frog/leg/ssa/builder.dart
|
| index 2131c4e95e01269afa5c157f5f1e2250b6c74ca4..f6245ed588ad526ad01f99dcacd3810ad0d419f2 100644
|
| --- a/frog/leg/ssa/builder.dart
|
| +++ b/frog/leg/ssa/builder.dart
|
| @@ -1290,7 +1290,67 @@ class SsaBuilder implements Visitor {
|
| }
|
|
|
| visitForInStatement(ForInStatement node) {
|
| - compiler.unimplemented('SsaBuilder.visitForInStatement', node: node);
|
| + // Generate a structure equivalent to:
|
| + // Iterator<E> $iter = <iterable>.iterator()
|
| + // while ($iter.hasNext()) {
|
| + // E <declaredIdentifier> = $iter.next();
|
| + // <body>
|
| + // }
|
| + SourceString iteratorName = const SourceString("iterator");
|
| +
|
| + Element interceptor = interceptors.getStaticInterceptor(iteratorName, 0);
|
| + assert(interceptor != null);
|
| + HStatic target = new HStatic(interceptor);
|
| + add(target);
|
| + visit(node.expression);
|
| + List<HInstruction> inputs = <HInstruction>[target, pop()];
|
| + HInstruction iterator = new HInvokeInterceptor("iterator", false, inputs);
|
| + add(iterator);
|
| +
|
| + Map initializerDefinitions = startLoop();
|
| + HBasicBlock conditionBlock = current;
|
| +
|
| + // The condition.
|
| + String jsHasNextName =
|
| + compiler.namer.instanceName(new SourceString("hasNext"));
|
| + push(new HInvokeDynamicMethod(jsHasNextName, [iterator]));
|
| + HBasicBlock conditionExitBlock = close(new HLoopBranch(popBoolified()));
|
| +
|
| + Map conditionDefinitions =
|
| + new Map<Element, HInstruction>.from(definitions);
|
| +
|
| + // The body.
|
| + HBasicBlock bodyBlock = addNewBlock();
|
| + conditionExitBlock.addSuccessor(bodyBlock);
|
| + open(bodyBlock);
|
| +
|
| + VariableDefinitions definition = node.declaredIdentifier;
|
| + Identifier identifier = definition.definitions.nodes.head;
|
| + Element variable = elements[identifier];
|
| + String jsNextName =
|
| + compiler.namer.instanceName(new SourceString("next"));
|
| + push(new HInvokeDynamicMethod(jsNextName, [iterator]));
|
| + definitions[variable] = pop();
|
| +
|
| + visit(node.body);
|
| + if (isAborted()) {
|
| + compiler.unimplemented("SsaBuilder for loop with aborting body");
|
| + }
|
| + bodyBlock = close(new HGoto());
|
| +
|
| + // Update.
|
| + // We create an update block, even when we are in a while loop. There the
|
| + // update block is the jump-target for continue statements. We could avoid
|
| + // the creation if there is no continue, but for now we always create it.
|
| + HBasicBlock updateBlock = addNewBlock();
|
| + bodyBlock.addSuccessor(updateBlock);
|
| + open(updateBlock);
|
| + updateBlock = close(new HGoto());
|
| + // The back-edge completing the cycle.
|
| + updateBlock.addSuccessor(conditionBlock);
|
| + conditionBlock.postProcessLoopHeader();
|
| +
|
| + endLoop(conditionBlock, conditionExitBlock, false, conditionDefinitions);
|
| }
|
|
|
| visitLabelledStatement(LabelledStatement node) {
|
|
|