in compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ForEachEmitter.java [51:297]
public void emit(IForLoopNode node)
{
IContainerNode cnode = node.getConditionalsContainerNode();
IBinaryOperatorNode bnode = (IBinaryOperatorNode) cnode.getChild(0);
IExpressionNode childNode = bnode.getLeftOperandNode();
IExpressionNode rnode = bnode.getRightOperandNode();
final String iterName = getModel().getCurrentForeachName();
getModel().incForeachLoopCount();
final String targetName = iterName + "_target";
startMapping(rnode);
write(ASEmitterTokens.VAR);
write(ASEmitterTokens.SPACE);
write(targetName);
write(ASEmitterTokens.SPACE);
write(ASEmitterTokens.EQUAL);
write(ASEmitterTokens.SPACE);
endMapping(rnode);
IASNode obj = bnode.getChild(1);
getWalker().walk(obj);
startMapping(rnode);
write(ASEmitterTokens.SEMICOLON);
endMapping(rnode);
writeNewline();
if (node.getParent().getNodeID() == ASTNodeID.BlockID &&
node.getParent().getParent().getNodeID() == ASTNodeID.LabledStatementID)
{
// emit label here
LabeledStatementNode labelNode = (LabeledStatementNode)node.getParent().getParent();
writeToken(labelNode.getLabel());
writeToken(ASEmitterTokens.COLON);
}
startMapping(node);
write(ASEmitterTokens.FOR);
write(ASEmitterTokens.SPACE);
write(ASEmitterTokens.PAREN_OPEN);
endMapping(node);
startMapping(rnode);
write(ASEmitterTokens.VAR);
write(ASEmitterTokens.SPACE);
write(iterName);
endMapping(rnode);
startMapping(bnode, childNode);
write(ASEmitterTokens.SPACE);
write(ASEmitterTokens.IN);
write(ASEmitterTokens.SPACE);
endMapping(bnode);
startMapping(rnode);
write(targetName);
boolean isXML = false;
boolean isProxy = false;
if (obj.getNodeID() == ASTNodeID.IdentifierID)
{
if (((JSRoyaleEmitter)getEmitter()).isXMLish((IdentifierNode)obj))
{
write(".elementNames()");
isXML = true;
}
if (((JSRoyaleEmitter)getEmitter()).isProxy((IdentifierNode)obj))
{
emitNullSafeProxyTarget(targetName);
isProxy = true;
}
}
else if (obj.getNodeID() == ASTNodeID.Op_DescendantsID)
{
//it should always be XMLList... but check anyway
if (((JSRoyaleEmitter)getEmitter()).isXMLList((IMemberAccessExpressionNode)obj))
{
write(".elementNames()");
isXML = true;
}
}
else if (obj.getNodeID() == ASTNodeID.MemberAccessExpressionID)
{
if (((JSRoyaleEmitter)getEmitter()).isXMLList((IMemberAccessExpressionNode)obj))
{
write(".elementNames()");
isXML = true;
}
if (((JSRoyaleEmitter)getEmitter()).isProxy((IMemberAccessExpressionNode)obj))
{
emitNullSafeProxyTarget(targetName);
isProxy = true;
}
}
else if (obj.getNodeID() == ASTNodeID.Op_AsID)
{
IASNode asChild = obj.getChild(1);
if (asChild.getNodeID() == ASTNodeID.IdentifierID)
{
String asName = ((IdentifierNode)asChild).getName();
if (asName.equals(IASLanguageConstants.XML) || asName.equals(IASLanguageConstants.XMLList))
{
write(".elementNames()");
isXML = true;
} else {
IClassDefinition asTarget = (IClassDefinition) ((IdentifierNode) asChild).resolve(getProject());
if (asTarget != null) {
//check ancestry for proxy
RoyaleProject project = (RoyaleProject) getProject();
if (asTarget.isInstanceOf(project.getProxyBaseClass(), project)){
emitNullSafeProxyTarget(targetName);
isProxy = true;
}
}
}
}
}
else if (obj.getNodeID() == ASTNodeID.FunctionCallID)
{
FunctionCallNode func = (FunctionCallNode)obj;
IExpressionNode funcName = func.getNameNode();
if (funcName.getNodeID() == ASTNodeID.IdentifierID)
{
String asName = ((IdentifierNode)funcName).getName();
if (asName.equals(IASLanguageConstants.XML) || asName.equals(IASLanguageConstants.XMLList))
{
write(".elementNames()");
isXML = true;
} else {
IDefinition funcNameDef = funcName.resolve(getProject());
//if it is IClassDefinition, then it is a type cast, otherwise...
if (funcNameDef instanceof IFunctionDefinition) {
//then it is a regular function call, so check the return type, and use that for the IClassDefinition type check:
funcNameDef = ((IFunctionDefinition)funcNameDef).resolveReturnType(getProject());
}
if (funcNameDef instanceof IClassDefinition) {
//this is a a hard cast
//check ancestry for proxy
RoyaleProject project = (RoyaleProject) getProject();
if (((IClassDefinition) funcNameDef).isInstanceOf(project.getProxyBaseClass(), project)){
emitNullSafeProxyTarget(targetName);
isProxy = true;
}
}
}
} else if (funcName instanceof IMemberAccessExpressionNode) {
IFunctionDefinition funcDef = (IFunctionDefinition) ((IMemberAccessExpressionNode) funcName).getRightOperandNode().resolve(getProject());
if (funcDef == null) {
//we need to check the LHS for XMLishness, and then resolve the method name against the determined XMLish definition (XML or XMLList),
// and then check its return type once we find the public FunctionDefinition for the method name
// (because although it is a member of something XMLish, it may not return something that is also XMLish, such as a QName, a String, a uint, or a Namespace etc)
IDefinitionSet matchingDefinitions = null;
if (EmitterUtils.isLeftNodeXML(((IMemberAccessExpressionNode) funcName).getLeftOperandNode(), getProject())) {
if (((IMemberAccessExpressionNode) funcName).getRightOperandNode().getNodeID() == ASTNodeID.IdentifierID) {
matchingDefinitions = getProject().getBuiltinType(IASLanguageConstants.BuiltinType.XML).getContainedScope().getLocalDefinitionSetByName(((IIdentifierNode)((IMemberAccessExpressionNode) funcName).getRightOperandNode()).getName());
}
} else if (EmitterUtils.isLeftNodeXMLList(((IMemberAccessExpressionNode) funcName).getLeftOperandNode(), getProject())) {
if (((IMemberAccessExpressionNode) funcName).getRightOperandNode().getNodeID() == ASTNodeID.IdentifierID) {
matchingDefinitions = getProject().getBuiltinType(IASLanguageConstants.BuiltinType.XMLLIST).getContainedScope().getLocalDefinitionSetByName(((IIdentifierNode)((IMemberAccessExpressionNode) funcName).getRightOperandNode()).getName());
}
}
if (matchingDefinitions != null) {
for (int i = 0; i< matchingDefinitions.getSize(); i++) {
IDefinition functionDefinition = matchingDefinitions.getDefinition(i);
if (functionDefinition instanceof IFunctionDefinition) {
if (functionDefinition.isPublic()) {
isXML = SemanticUtils.isXMLish((((IFunctionDefinition) functionDefinition).resolveReturnType(getProject())), getProject());
break;
}
}
}
}
//@todo should we emit a warning here if wasXMLish (from either of the first 2 checks) && !isXML (from the matchingDefinitions check)?
// results will not be consistent in this case.
// e.g. looping over a QName or Namespace instance
// It is probably rare and ill-advised, but it definitely won't work well in javascript currently for those classes, for example.
} else {
IClassDefinition returnType = (IClassDefinition) funcDef.resolveReturnType(getProject());
isXML = SemanticUtils.isXMLish(returnType, getProject());
if (!isXML) {
//check for Proxy
RoyaleProject project = (RoyaleProject) getProject();
if (returnType.isInstanceOf(project.getProxyBaseClass(), project)){
emitNullSafeProxyTarget(targetName);
isProxy = true;
}
}
}
if (isXML) {
write(".elementNames()");
}
} //@todo what about dynamic access node for function call? e.g. myXML[string_Value_Here]() ... not so easy really, would likely need a runtime helper/wrapper.
}
endMapping(rnode);
startMapping(node, cnode);
writeToken(ASEmitterTokens.PAREN_CLOSE);
endMapping(node);
writeNewline();
write(ASEmitterTokens.BLOCK_OPEN);
writeNewline();
if (childNode instanceof IVariableExpressionNode)
{
startMapping(childNode);
write(ASEmitterTokens.VAR);
write(ASEmitterTokens.SPACE);
write(((IVariableNode) childNode.getChild(0)).getName()); //it's always a local var
//putting this in here instead of common code following the 2 blocks to keep sourcemap tests passing
write(ASEmitterTokens.SPACE);
write(ASEmitterTokens.EQUAL);
write(ASEmitterTokens.SPACE);
endMapping(childNode);
}
else { //IdentifierNode
getWalker().walk(childNode); //we need to walk here, to deal with non-local var identifiers
startMapping(childNode);
write(ASEmitterTokens.SPACE);
write(ASEmitterTokens.EQUAL);
write(ASEmitterTokens.SPACE);
endMapping(childNode);
}
startMapping(rnode);
write(targetName);
if (isXML)
{
write("[");
write(iterName);
write("]");
}
else if (isProxy)
{
write(".getProperty(");
write(iterName);
write(")");
}
else
{
write(ASEmitterTokens.SQUARE_OPEN);
write(iterName);
write(ASEmitterTokens.SQUARE_CLOSE);
}
write(ASEmitterTokens.SEMICOLON);
endMapping(rnode);
writeNewline();
getWalker().walk(node.getStatementContentsNode());
write(ASEmitterTokens.BLOCK_CLOSE);
writeNewline();
}