final Naming.SyntheticName iterVar,
Naming.SyntheticName itemVar) {
final Tree.ForComprehensionClause fcl = clause;
Tree.SpecifierExpression specexpr = fcl.getForIterator().getSpecifierExpression();
ProducedType iterType = specexpr.getExpression().getTypeModel();
JCExpression iterTypeExpr = makeJavaType(typeFact().getIteratorType(
typeFact().getIteratedType(iterType)));
ProducedType iterableType = iterType.getSupertype(typeFact().getIterableDeclaration());
JCExpression iterableExpr = transformExpression(specexpr.getExpression(), BoxingStrategy.BOXED, iterableType);
if (clause == comp.getInitialComprehensionClause()) {
//The first iterator can be initialized as a field
fields.add(make().VarDef(make().Modifiers(Flags.PRIVATE | Flags.FINAL), iterVar.asName(), iterTypeExpr,
null));
fieldNames.add(iterVar.getName());
initIterator = make().Exec(make().Assign(iterVar.makeIdent(), make().Apply(null, makeSelect(iterableExpr, "iterator"),
List.<JCExpression>nil())));
} else {
//The subsequent iterators need to be inside a method,
//in case they depend on the current element of the previous iterator
fields.add(make().VarDef(make().Modifiers(Flags.PRIVATE), iterVar.asName(), iterTypeExpr, null));
fieldNames.add(iterVar.getName());
List<JCStatement> block = List.<JCStatement>nil();
if (lastIteratorCtxtName != null) {
block = block.append(make().If(lastIteratorCtxtName.suffixedBy(Suffix.$exhausted$).makeIdent(),
make().Return(makeBoolean(false)),
null));
}
block = block.appendList(List.<JCStatement>of(
make().If(make().Binary(JCTree.NE, iterVar.makeIdent(), makeNull()),
make().Return(makeBoolean(true)),
null),
make().If(make().Unary(JCTree.NOT, make().Apply(null, ctxtName.makeIdentWithThis(), List.<JCExpression>nil())),
make().Return(makeBoolean(false)),
null),
make().Exec(make().Assign(iterVar.makeIdent(),
make().Apply(null,
makeSelect(iterableExpr, "iterator"),
List.<JCExpression>nil()))),
make().Return(makeBoolean(true))
));
JCBlock body = make().Block(0l, block);
fields.add(make().MethodDef(make().Modifiers(Flags.PRIVATE | Flags.FINAL),
iterVar.asName(), makeJavaType(typeFact().getBooleanDeclaration().getType()),
List.<JCTree.JCTypeParameter>nil(),
List.<JCTree.JCVariableDecl>nil(), List.<JCExpression>nil(), body, null));
}
if (fcl.getForIterator() instanceof Tree.ValueIterator) {
//Add the item variable as a field in the iterator
Value item = ((Tree.ValueIterator)fcl.getForIterator()).getVariable().getDeclarationModel();
itemVar = naming.synthetic(item);
valueCaptures.append(makeVar(Flags.FINAL, itemVar,
makeJavaType(item.getType(),JT_NO_PRIMITIVES), itemVar.makeIdentWithThis()));
fields.add(make().VarDef(make().Modifiers(Flags.PRIVATE), itemVar.asName(),
makeJavaType(item.getType(),JT_NO_PRIMITIVES), null));
fieldNames.add(itemVar.getName());
} else if (fcl.getForIterator() instanceof Tree.KeyValueIterator) {
//Add the key and value variables as fields in the iterator
Tree.KeyValueIterator kviter = (Tree.KeyValueIterator)fcl.getForIterator();
Value kdec = kviter.getKeyVariable().getDeclarationModel();
Value vdec = kviter.getValueVariable().getDeclarationModel();
//But we'll use this as the name for the context function and base for the exhausted field
itemVar = naming.synthetic(Prefix.$kv$, kdec.getName(), vdec.getName());
fields.add(make().VarDef(make().Modifiers(Flags.PRIVATE), names().fromString(kdec.getName()),
makeJavaType(kdec.getType(), JT_NO_PRIMITIVES), null));
fields.add(make().VarDef(make().Modifiers(Flags.PRIVATE), names().fromString(vdec.getName()),
makeJavaType(vdec.getType(), JT_NO_PRIMITIVES), null));
fieldNames.add(kdec.getName());
fieldNames.add(vdec.getName());
} else {
error = makeErroneous(fcl, "compiler bug: iterators of type " + fcl.getForIterator().getNodeType() + " not yet supported");
return null;
}
fields.add(make().VarDef(make().Modifiers(Flags.PRIVATE), itemVar.suffixedBy(Suffix.$exhausted$).asName(),
makeJavaType(typeFact().getBooleanDeclaration().getType()), null));
//Now the context for this iterator
ListBuffer<JCStatement> contextBody = new ListBuffer<JCStatement>();
//Assign the next item to an Object variable
Naming.SyntheticName tmpItem = naming.temp("item");
contextBody.add(make().VarDef(make().Modifiers(Flags.FINAL), tmpItem.asName(),
makeJavaType(typeFact().getObjectDeclaration().getType()),
make().Apply(null, makeSelect(iterVar.makeIdent(), "next"),
List.<JCExpression>nil())));
//Then we check if it's exhausted
contextBody.add(make().Exec(make().Assign(itemVar.suffixedBy(Suffix.$exhausted$).makeIdent(),
make().Binary(JCTree.EQ, tmpItem.makeIdent(), makeFinished()))));
//Variables get assigned in the else block
ListBuffer<JCStatement> elseBody = new ListBuffer<JCStatement>();
if (fcl.getForIterator() instanceof Tree.ValueIterator) {
ProducedType itemType = ((Tree.ValueIterator)fcl.getForIterator()).getVariable().getDeclarationModel().getType();
elseBody.add(make().Exec(make().Assign(itemVar.makeIdent(),
make().TypeCast(makeJavaType(itemType,JT_NO_PRIMITIVES), tmpItem.makeIdent()))));
} else {
Tree.KeyValueIterator kviter = (Tree.KeyValueIterator)fcl.getForIterator();
Value key = kviter.getKeyVariable().getDeclarationModel();
Value item = kviter.getValueVariable().getDeclarationModel();
//Assign the key and item to the corresponding fields with the proper type casts
//equivalent to k=(KeyType)((Entry<KeyType,ItemType>)tmpItem).getKey()
JCExpression castEntryExprKey = make().TypeCast(
makeJavaType(typeFact().getIteratedType(iterType)),
tmpItem.makeIdent());
SyntheticName keyName = naming.synthetic(key);
SyntheticName itemName = naming.synthetic(item);
valueCaptures.append(makeVar(Flags.FINAL, keyName,
makeJavaType(key.getType(), JT_NO_PRIMITIVES),
keyName.makeIdentWithThis()));
valueCaptures.append(makeVar(Flags.FINAL, itemName,
makeJavaType(item.getType(), JT_NO_PRIMITIVES),
itemName.makeIdentWithThis()));
elseBody.add(make().Exec(make().Assign(keyName.makeIdent(),
make().TypeCast(makeJavaType(key.getType(), JT_NO_PRIMITIVES),
make().Apply(null, makeSelect(castEntryExprKey, "getKey"),
List.<JCExpression>nil())
))));
//equivalent to v=(ItemType)((Entry<KeyType,ItemType>)tmpItem).getItem()
JCExpression castEntryExprItem = make().TypeCast(
makeJavaType(typeFact().getIteratedType(iterType)),
tmpItem.makeIdent());
elseBody.add(make().Exec(make().Assign(itemName.makeIdent(),
make().TypeCast(makeJavaType(item.getType(), JT_NO_PRIMITIVES),
make().Apply(null, makeSelect(castEntryExprItem, "getItem"),