Chromium Code Reviews| 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(); |
|
ngeoffray
2012/01/11 10:09:22
Maybe mark E as optional in this statement? Someth
Lasse Reichstein
2012/01/11 10:26:00
I should make it optional in Iterator<E> too then.
|
| + // <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")); |
|
ngeoffray
2012/01/11 10:09:22
new SourceString -> const SourceString
|
| + 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")); |
|
ngeoffray
2012/01/11 10:09:22
new -> const
|
| + push(new HInvokeDynamicMethod(jsNextName, [iterator])); |
| + definitions[variable] = pop(); |
| + |
| + visit(node.body); |
| + if (isAborted()) { |
| + compiler.unimplemented("SsaBuilder for loop with aborting body"); |
|
ngeoffray
2012/01/11 10:09:22
add:
node: node
|
| + } |
| + bodyBlock = close(new HGoto()); |
| + |
| + // Update. |
| + // We create an update block, even when we are in a while loop. There the |
|
ngeoffray
2012/01/11 10:09:22
when -> if.
ngeoffray
2012/01/11 10:09:22
Remove 'There'
|
| + // 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) { |