in compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java [60:665]
public void emit(IBinaryOperatorNode node)
{
// TODO (mschmalle) will remove this cast as more things get abstracted
JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter();
String op = node.getOperator().getOperatorText();
boolean isAssignment = op.contains("=")
&& !op.contains("==")
&& !(op.startsWith("<") || op.startsWith(">") || op
.startsWith("!"));
ASTNodeID id = node.getNodeID();
/*
if (id == ASTNodeID.Op_InID
|| id == ASTNodeID.Op_LogicalAndAssignID
|| id == ASTNodeID.Op_LogicalOrAssignID)
{
super.emitBinaryOperator(node);
}
else */if (id == ASTNodeID.Op_IsID || id == ASTNodeID.Op_AsID)
{
fjs.emitIsAs(node, node.getLeftOperandNode(), node.getRightOperandNode(),
id, false);
}
else if (id == ASTNodeID.Op_InstanceOfID)
{
if (ASNodeUtils.hasParenOpen(node)) {
write(ASEmitterTokens.PAREN_OPEN);
}
getWalker().walk(node.getLeftOperandNode());
startMapping(node, node.getLeftOperandNode());
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.INSTANCEOF);
endMapping(node);
IDefinition dnode = (node.getRightOperandNode())
.resolve(getProject());
if (dnode != null)
{
String dnodeQname = dnode.getQualifiedName();
boolean isPackageOrFileMember = false;
if (dnode instanceof IVariableDefinition)
{
IVariableDefinition variable = (IVariableDefinition) dnode;
VariableClassification classification = variable.getVariableClassification();
if (classification == VariableClassification.PACKAGE_MEMBER ||
classification == VariableClassification.FILE_MEMBER)
{
isPackageOrFileMember = true;
}
}
else if (dnode instanceof IFunctionDefinition)
{
IFunctionDefinition func = (IFunctionDefinition) dnode;
FunctionClassification classification = func.getFunctionClassification();
if (classification == FunctionClassification.PACKAGE_MEMBER ||
classification == FunctionClassification.FILE_MEMBER)
{
isPackageOrFileMember = true;
}
}
else if(dnode instanceof ITypeDefinition)
{
isPackageOrFileMember = true;
}
if(isPackageOrFileMember)
{
dnodeQname = getEmitter().formatQualifiedName(dnodeQname);
}
write(dnodeQname);
}
else
{
getWalker().walk(node.getRightOperandNode());
}
if (ASNodeUtils.hasParenClose(node)) {
write(ASEmitterTokens.PAREN_CLOSE);
}
}
else
{
IExpressionNode leftSide = node.getLeftOperandNode();
IDefinition leftDef = leftSide.resolveType(getWalker().getProject());
if (leftSide.getNodeID() == ASTNodeID.MemberAccessExpressionID)
{
IASNode lnode = leftSide.getChild(0);
IASNode rnode = leftSide.getChild(1);
IDefinition rnodeDef = (rnode instanceof IIdentifierNode) ?
((IIdentifierNode) rnode).resolve(getWalker().getProject()) :
null;
boolean isDynamicAccess = rnode instanceof DynamicAccessNode;
if (lnode.getNodeID() == ASTNodeID.SuperID
&& rnodeDef instanceof AccessorDefinition)
{
if (isAssignment)
{
boolean propagateAssignedValue = !(node.getParent() instanceof IBlockNode);
if (propagateAssignedValue)
{
write(ASEmitterTokens.PAREN_OPEN);
write(ASEmitterTokens.FUNCTION);
write(ASEmitterTokens.PAREN_OPEN);
write("$value");
write(ASEmitterTokens.PAREN_CLOSE);
write(ASEmitterTokens.BLOCK_OPEN);
}
IClassNode cnode = (IClassNode) node
.getAncestorOfType(IClassNode.class);
if (cnode != null)
write(getEmitter().formatQualifiedName(
cnode.getQualifiedName()));
else
write(getEmitter().formatQualifiedName(
getModel().getCurrentClass().getQualifiedName()));
write(ASEmitterTokens.MEMBER_ACCESS);
write(JSGoogEmitterTokens.SUPERCLASS);
write(ASEmitterTokens.MEMBER_ACCESS);
write(fjs.formatSetter(rnodeDef.getBaseName()));
write(ASEmitterTokens.MEMBER_ACCESS);
write(JSEmitterTokens.APPLY);
write(ASEmitterTokens.PAREN_OPEN);
write(ASEmitterTokens.THIS);
writeToken(ASEmitterTokens.COMMA);
write(ASEmitterTokens.SQUARE_OPEN);
if (op.length() > 1) // += and things like that
{
write(getEmitter().formatQualifiedName(
cnode.getQualifiedName()));
write(ASEmitterTokens.MEMBER_ACCESS);
write(JSGoogEmitterTokens.SUPERCLASS);
write(ASEmitterTokens.MEMBER_ACCESS);
write(fjs.formatGetter(rnodeDef.getBaseName()));
write(ASEmitterTokens.MEMBER_ACCESS);
write(JSEmitterTokens.APPLY);
write(ASEmitterTokens.PAREN_OPEN);
write(ASEmitterTokens.THIS);
write(ASEmitterTokens.PAREN_CLOSE);
write(op.substring(0, 1));
}
if (propagateAssignedValue)
{
write("$value");
write(ASEmitterTokens.SQUARE_CLOSE);
write(ASEmitterTokens.PAREN_CLOSE);
write(ASEmitterTokens.SEMICOLON);
// returning the original $value ensures that
// chained assignments work properly
// the getter should NOT be called!
// x = super.y = z;
writeToken(ASEmitterTokens.RETURN);
write("$value");
write(ASEmitterTokens.SEMICOLON);
write(ASEmitterTokens.BLOCK_CLOSE);
write(ASEmitterTokens.PAREN_CLOSE);
write(ASEmitterTokens.MEMBER_ACCESS);
write(JSEmitterTokens.APPLY);
write(ASEmitterTokens.PAREN_OPEN);
write(ASEmitterTokens.THIS);
writeToken(ASEmitterTokens.COMMA);
write(ASEmitterTokens.SQUARE_OPEN);
}
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.SQUARE_CLOSE);
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
}
else if (((JSRoyaleEmitter)getEmitter()).isXMLList((IMemberAccessExpressionNode)leftSide))
{
MemberAccessExpressionNode xmlNode = (MemberAccessExpressionNode)leftSide;
if (node.getNodeID() == ASTNodeID.Op_AssignId)
{
boolean wrapQuotes = true;
getWalker().walk(xmlNode.getLeftOperandNode());
IExpressionNode rightSide = xmlNode.getRightOperandNode();
if (rightSide instanceof UnaryOperatorAtNode)
{
write(".setAttribute('");
getWalker().walk(rightSide.getChild(0));
}
else if (rightSide instanceof IDynamicAccessNode && ((IDynamicAccessNode) rightSide).getLeftOperandNode().getNodeID() == ASTNodeID.Op_AtID) {
write(".setAttribute(");
wrapQuotes = false;
getWalker().walk(((IDynamicAccessNode)rightSide).getRightOperandNode());
}
else if (rightSide instanceof INamespaceAccessExpressionNode) {
write(".setChild(");
write("new QName(");
getWalker().walk(((INamespaceAccessExpressionNode) rightSide).getLeftOperandNode());
write(",'");
getWalker().walk(((INamespaceAccessExpressionNode) rightSide).getRightOperandNode());
write("')");
wrapQuotes = false;
}
else
{
write(".setChild('");
getWalker().walk(rightSide);
}
if (wrapQuotes) write("'");
write(", ");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
else if (node.getNodeID() == ASTNodeID.Op_AddAssignID)
{
getWalker().walk(xmlNode.getLeftOperandNode());
IExpressionNode rightSide = xmlNode.getRightOperandNode();
if (rightSide instanceof UnaryOperatorAtNode)
{
write(".setAttribute('");
getWalker().walk(((UnaryOperatorAtNode)rightSide).getChild(0));
}
else
{
write(".setChild('");
getWalker().walk(rightSide);
}
write("', ");
getWalker().walk(node.getLeftOperandNode());
write(".plus(");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
else if (node.getNodeID() == ASTNodeID.Op_AddID)
{
getWalker().walk(xmlNode);
write(".plus(");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
}
else if (isDynamicAccess && ((JSRoyaleEmitter)getEmitter()).isXMLish((IExpressionNode)lnode))
{
DynamicAccessNode dyn = (DynamicAccessNode)rnode;
ITypeDefinition type = dyn.getRightOperandNode().resolveType(getProject());
if (type.isInstanceOf("String", getProject()) || type.isInstanceOf("Object", getProject())
|| type == getProject().getBuiltinType(BuiltinType.ANY_TYPE))
{
String field;
if (node.getNodeID() == ASTNodeID.Op_AssignId)
{
getWalker().walk(lnode);
IExpressionNode dynLeft = dyn.getLeftOperandNode();
IExpressionNode dynRight = dyn.getRightOperandNode();
if (dynLeft instanceof UnaryOperatorAtNode)
{
write(".setAttribute(");
field = fjs.stringifyNode(dyn.getRightOperandNode());
}
else if (dynRight instanceof UnaryOperatorAtNode)
{
write(".setAttribute(");
field = fjs.stringifyNode(dynRight.getChild(0));
}
else
{
write(".setChild(");
field = fjs.stringifyNode(dynLeft);
}
write(field + ", ");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
else if (node.getNodeID() == ASTNodeID.Op_AddAssignID)
{
getWalker().walk(lnode);
IExpressionNode rightSide = dyn.getRightOperandNode();
if (rightSide instanceof UnaryOperatorAtNode)
{
write(".setAttribute('");
field = fjs.stringifyNode(((UnaryOperatorAtNode)rightSide).getChild(0));
field = field.replace("\"", ""); // remove wrapping double-quotes
}
else
{
write(".setChild('");
field = fjs.stringifyNode(rightSide);
field = field.replace("\"", ""); // remove wrapping double-quotes
}
write(field + "', ");
getWalker().walk(node.getLeftOperandNode());
write(".plus(");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
else if (node.getNodeID() == ASTNodeID.Op_AddID)
{
getWalker().walk(dyn);
write(".plus(");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
}
}
else if (((JSRoyaleEmitter)getEmitter()).isProxy(((MemberAccessExpressionNode)leftSide).getLeftOperandNode()) && leftDef == null)
{
MemberAccessExpressionNode proxyNode = (MemberAccessExpressionNode)leftSide;
if (node.getNodeID() == ASTNodeID.Op_AssignId)
{
getWalker().walk(proxyNode.getLeftOperandNode());
IExpressionNode rightSide = proxyNode.getRightOperandNode();
write(".setProperty('");
getWalker().walk(rightSide);
write("', ");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
else if (node.getNodeID() == ASTNodeID.Op_AddAssignID)
{
IExpressionNode rightSide = proxyNode.getRightOperandNode();
getWalker().walk(proxyNode.getLeftOperandNode());
write(".setProperty('");
getWalker().walk(rightSide);
write("', ");
getWalker().walk(proxyNode.getLeftOperandNode());
write(".getProperty(");
write(ASEmitterTokens.SINGLE_QUOTE);
getWalker().walk(rightSide);
write(ASEmitterTokens.SINGLE_QUOTE);
write(ASEmitterTokens.PAREN_CLOSE);
write(" + ");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
}
else if (((JSRoyaleEmitter)getEmitter()).isDateProperty((MemberAccessExpressionNode)leftSide, true))
{
specialCaseDate(node, (MemberAccessExpressionNode)leftSide);
return;
}
}
else if (leftSide.getNodeID() == ASTNodeID.IdentifierID)
{
if ((leftDef != null)
&& SemanticUtils.isXMLish(leftDef, getWalker().getProject()))
{
if (node.getNodeID() == ASTNodeID.Op_AddAssignID)
{
getWalker().walk(leftSide);
write(" = ");
getWalker().walk(leftSide);
write(".plus(");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
}
}
else if (leftSide.getNodeID() == ASTNodeID.ArrayIndexExpressionID) // dynamic access
{
DynamicAccessNode dyn = (DynamicAccessNode)leftSide;
IExpressionNode dynLeft = dyn.getLeftOperandNode();
ITypeDefinition type = dyn.getRightOperandNode().resolveType(getProject());
if (((JSRoyaleEmitter)getEmitter()).isXMLish(dynLeft)/* && !SemanticUtils.isNumericType(type, getProject())*/) //type.isInstanceOf("String", getProject())
{
String field;
if (node.getNodeID() == ASTNodeID.Op_AssignId)
{
getWalker().walk(dynLeft);
IExpressionNode rightSide = dyn.getRightOperandNode();
if (rightSide instanceof UnaryOperatorAtNode)
{
write(".setAttribute(");
field = fjs.stringifyNode((rightSide).getChild(0));
}
else
{
write(".setChild(");
field = fjs.stringifyNode(rightSide);
}
if (field.startsWith("\"") && field.endsWith("\"")) {
// remove wrapping double-quotes and swap to single quotes
field = "'" + field.substring(1, field.length() - 1) + "'";
}
write(field + ", ");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
else if (node.getNodeID() == ASTNodeID.Op_AddAssignID)
{
getWalker().walk(dynLeft);
IExpressionNode rightSide = dyn.getRightOperandNode();
if (rightSide instanceof UnaryOperatorAtNode)
{
write(".setAttribute('");
field = fjs.stringifyNode(((UnaryOperatorAtNode)rightSide).getChild(0));
field = field.replace("\"", ""); // remove wrapping double-quotes
}
else
{
write(".setChild('");
field = fjs.stringifyNode(rightSide);
field = field.replace("\"", ""); // remove wrapping double-quotes
}
write(field + "', ");
getWalker().walk(node.getLeftOperandNode());
write(".plus(");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
else if (node.getNodeID() == ASTNodeID.Op_AddID)
{
getWalker().walk(dyn);
write(".plus(");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
return;
}
}
else if (((JSRoyaleEmitter)getEmitter()).isProxy(dynLeft))
{
if (isAssignment)
{
getWalker().walk(dynLeft);
IExpressionNode rightSide = dyn.getRightOperandNode();
write(".setProperty(");
getWalker().walk(rightSide);
write(", ");
getWalker().walk(node.getRightOperandNode());
write(ASEmitterTokens.PAREN_CLOSE);
}
else
{
getWalker().walk(dynLeft);
IExpressionNode rightSide = dyn.getRightOperandNode();
write(".getProperty(");
getWalker().walk(rightSide);
write(ASEmitterTokens.PAREN_CLOSE);
write(ASEmitterTokens.SPACE);
writeToken(op);
getWalker().walk(node.getRightOperandNode());
}
return;
}
}
if (id == ASTNodeID.Op_EqualID || id ==ASTNodeID.Op_NotEqualID) {
//QName == QName
if (leftDef != null && leftDef.getQualifiedName().equals("QName")) {
IDefinition rightDef = node.getRightOperandNode().resolveType(getProject());
if (rightDef != null && rightDef.getQualifiedName().equals("QName")) {
//handle non-strict equality/inequality a little differently via QName.equality method
if (id == ASTNodeID.Op_NotEqualID) write("!");
write("QName.equality(");
getWalker().walk(node.getLeftOperandNode());
write(",");
getWalker().walk(node.getRightOperandNode());
write(")");
return;
}
} else {
IASNode codeContext = node.getAncestorOfType(IClassNode.class);
boolean isFrameworkXML = false;
if (codeContext instanceof IClassNode) {
if (((IClassNode) codeContext).getQualifiedName().equals("XML") || ((IClassNode) codeContext).getQualifiedName().equals("XMLList")) {
//we will ignore the internal code of the emulation support classes for these cases
isFrameworkXML = true;
}
}
if (!isFrameworkXML) {
boolean leftIsAny = (leftDef == null || getProject().getBuiltinType(BuiltinType.ANY_TYPE).equals(leftDef));
IDefinition rightDef = node.getRightOperandNode().resolveType(getProject());
boolean rightIsAny = (rightDef == null || getProject().getBuiltinType(BuiltinType.ANY_TYPE).equals(rightDef));
boolean leftIsXMLish = (leftIsAny && SemanticUtils.isXMLish(node.getLeftOperandNode(), getProject())) || SemanticUtils.isXMLish(leftDef, getProject());
boolean rightIsXMLish = (rightIsAny && SemanticUtils.isXMLish(node.getRightOperandNode(), getProject())) || SemanticUtils.isXMLish(rightDef, getProject());
if (leftIsXMLish && rightIsXMLish) {
startMapping(node, node.getLeftOperandNode());
//handle non-strict equality/inequality for XMLish comparisons a little differently
if (id == ASTNodeID.Op_NotEqualID) write("!");
write("XML.equality(");
endMapping(node);
getWalker().walk(node.getLeftOperandNode());
startMapping(node, node.getLeftOperandNode());
write(",");
endMapping(node);
getWalker().walk(node.getRightOperandNode());
startMapping(node, node.getLeftOperandNode());
write(")");
endMapping(node);
return;
} else {
if (leftIsXMLish || rightIsXMLish) {
IDefinition otherDef = leftIsXMLish ? rightDef : leftDef;
boolean otherIsBoolean = getProject().getBuiltinType(BuiltinType.BOOLEAN).equals(otherDef);
if (otherIsBoolean || (leftIsAny && rightIsXMLish) || (rightIsAny && leftIsXMLish)) {
if (otherIsBoolean) {
//cover xmlish ==/!= boolean and boolean ==/!= xmlish variations by converting the boolean value to string (xmlishBooleanEqualityOperand):
if (leftIsXMLish) getWalker().walk(node.getLeftOperandNode());
else xmlishBooleanEqualityOperand(node.getLeftOperandNode());
write(" " + node.getOperator().getOperatorText() + " ");
if (leftIsXMLish) xmlishBooleanEqualityOperand(node.getRightOperandNode());
else getWalker().walk(node.getRightOperandNode());
return;
} else {
//cover xmlish ==/!= * (typed) and * (typed) ==/!= xmlish variations:
IExpressionNode lhs = leftIsXMLish ? node.getLeftOperandNode() : node.getRightOperandNode();
IExpressionNode rhs = leftIsXMLish ? node.getRightOperandNode() : node.getLeftOperandNode();
//@todo check the source-mapping to the equality/inequality operator, this could probably be improved:
startMapping(node, node.getLeftOperandNode());
//handle non-strict equality/inequality for XMLish comparisons a little differently via XML.mixedEquality method
if (id == ASTNodeID.Op_NotEqualID) write("!");
write("XML.mixedEquality(");
endMapping(node);
getWalker().walk(lhs);
startMapping(node, node.getLeftOperandNode());
write(",");
endMapping(node);
getWalker().walk(rhs);
startMapping(node, node.getLeftOperandNode());
write(")");
endMapping(node);
return;
}
}
}
}
}
}
} else if (id == ASTNodeID.Op_AddID) {
IDefinition rightDef = node.getRightOperandNode().resolveType(getProject());
boolean leftIsXMLish = (SemanticUtils.isXMLish(node.getLeftOperandNode(), getProject())) || SemanticUtils.isXMLish(leftDef, getProject());
boolean rightIsXMLish = (SemanticUtils.isXMLish(node.getRightOperandNode(), getProject())) || SemanticUtils.isXMLish(rightDef, getProject());
boolean process;
if (leftIsXMLish) {
process = !rightIsXMLish;
} else {
process = rightIsXMLish;
}
if (process) {
IASNode codeContext = node.getAncestorOfType(IClassNode.class);
boolean isFrameworkXML = false;
if (codeContext instanceof IClassNode) {
if (((IClassNode) codeContext).getQualifiedName().equals("XML") || ((IClassNode) codeContext).getQualifiedName().equals("XMLList")) {
//we will ignore the internal code of the emulation support classes for these cases
isFrameworkXML = true;
}
}
if (!isFrameworkXML) {
IExpressionNode leftOperand = node.getLeftOperandNode();
IExpressionNode rightOperand = node.getRightOperandNode();
FunctionCallNode functionCallNode;
if (leftIsXMLish) {
//wrap in string coercion
if (EmitterUtils.xmlRequiresNullCheck((NodeBase) leftOperand, getProject())) {
//if it is a simple identifier, then it could be a null reference so use the XMLList.coerce_string method, which retains null
functionCallNode = EmitterUtils.wrapXMLListStringCoercion((NodeBase) leftOperand);
} else {
//if it is a member access expression or something else then assume we don't have to check for null
functionCallNode = EmitterUtils.wrapSimpleStringCoercion((NodeBase) leftOperand);
}
functionCallNode.setParent((NodeBase) node);
leftOperand = functionCallNode;
} else {
//wrap in string coercion
if (EmitterUtils.xmlRequiresNullCheck((NodeBase) rightOperand, getProject())) {
//if it is a simple identifier, then it could be a null reference so use the XMLList.coerce_string method, which retains null
functionCallNode = EmitterUtils.wrapXMLListStringCoercion((NodeBase) rightOperand);
} else {
//if it is a member access expression or something else then assume we don't have to check for null
functionCallNode = EmitterUtils.wrapSimpleStringCoercion((NodeBase) rightOperand);
}
functionCallNode.setParent((NodeBase) node);
rightOperand = functionCallNode;
}
getWalker().walk(leftOperand);
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.PLUS);
write(ASEmitterTokens.SPACE);
getWalker().walk(rightOperand);
return;
}
}
}
super_emitBinaryOperator(node, isAssignment);
}
}