blob: 03dae65b00dcd9ef7a25a95095bf04d70815027e [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.royale.compiler.internal.tree.as;
import static org.apache.royale.compiler.internal.parsing.as.ASTokenTypes.*;
import antlr.Token;
import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.parsing.IASToken;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
/**
* Abstract base class for all binary operator nodes.
*/
public abstract class BinaryOperatorNodeBase extends OperatorNodeBase implements IBinaryOperatorNode
{
/**
* Factory method for various kinds of binary operator nodes.
*/
public static BinaryOperatorNodeBase create(IASToken operatorToken, ExpressionNodeBase leftOperand, ExpressionNodeBase rightOperand)
{
switch (operatorToken.getType())
{
// simple assignment
case TOKEN_OPERATOR_ASSIGNMENT:
return new BinaryOperatorAssignmentNode(operatorToken, leftOperand, rightOperand);
// arithmetic
case TOKEN_OPERATOR_PLUS:
return new BinaryOperatorPlusNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_PLUS_ASSIGNMENT:
return new BinaryOperatorPlusAssignmentNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_MINUS:
return new BinaryOperatorMinusNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_MINUS_ASSIGNMENT:
return new BinaryOperatorMinusAssignmentNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_STAR:
return new BinaryOperatorMultiplicationNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_MULTIPLICATION_ASSIGNMENT:
return new BinaryOperatorMultiplicationAssignmentNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_DIVISION:
return new BinaryOperatorDivisionNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_DIVISION_ASSIGNMENT:
return new BinaryOperatorDivisionAssignmentNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_MODULO:
return new BinaryOperatorModuloNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_MODULO_ASSIGNMENT:
return new BinaryOperatorModuloAssignmentNode(operatorToken, leftOperand, rightOperand);
// equality
case TOKEN_OPERATOR_EQUAL:
return new BinaryOperatorEqualNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_NOT_EQUAL:
return new BinaryOperatorNotEqualNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_STRICT_EQUAL:
return new BinaryOperatorStrictEqualNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_STRICT_NOT_EQUAL:
return new BinaryOperatorStrictNotEqualNode(operatorToken, leftOperand, rightOperand);
// comparison
case TOKEN_OPERATOR_LESS_THAN:
return new BinaryOperatorLessThanNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_LESS_THAN_EQUALS:
return new BinaryOperatorLessThanEqualsNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_GREATER_THAN:
return new BinaryOperatorGreaterThanNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_GREATER_THAN_EQUALS:
return new BinaryOperatorGreaterThanEqualsNode(operatorToken, leftOperand, rightOperand);
// logical
case TOKEN_OPERATOR_LOGICAL_AND:
return new BinaryOperatorLogicalAndNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_LOGICAL_AND_ASSIGNMENT:
return new BinaryOperatorLogicalAndAssignmentNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_LOGICAL_OR:
return new BinaryOperatorLogicalOrNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_LOGICAL_OR_ASSIGNMENT:
return new BinaryOperatorLogicalOrAssignmentNode(operatorToken, leftOperand, rightOperand);
// bitwise logical
case TOKEN_OPERATOR_BITWISE_AND:
return new BinaryOperatorBitwiseAndNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_BITWISE_AND_ASSIGNMENT:
return new BinaryOperatorBitwiseAndAssignmentNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_BITWISE_OR:
return new BinaryOperatorBitwiseOrNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_BITWISE_OR_ASSIGNMENT:
return new BinaryOperatorBitwiseOrAssignmentNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_BITWISE_XOR:
return new BinaryOperatorBitwiseXorNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_BITWISE_XOR_ASSIGNMENT:
return new BinaryOperatorBitwiseXorAssignmentNode(operatorToken, leftOperand, rightOperand);
// shift
case TOKEN_OPERATOR_BITWISE_LEFT_SHIFT:
return new BinaryOperatorBitwiseLeftShiftNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_BITWISE_LEFT_SHIFT_ASSIGNMENT:
return new BinaryOperatorBitwiseLeftShiftAssignmentNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_BITWISE_RIGHT_SHIFT:
return new BinaryOperatorBitwiseRightShiftNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_BITWISE_RIGHT_SHIFT_ASSIGNMENT:
return new BinaryOperatorBitwiseRightShiftAssignmentNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_BITWISE_UNSIGNED_RIGHT_SHIFT:
return new BinaryOperatorBitwiseUnsignedRightShiftNode(operatorToken, leftOperand, rightOperand);
case TOKEN_OPERATOR_BITWISE_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
return new BinaryOperatorBitwiseUnsignedRightShiftAssignmentNode(operatorToken, leftOperand, rightOperand);
// other
case TOKEN_KEYWORD_AS:
return new BinaryOperatorAsNode(operatorToken, leftOperand, rightOperand);
case TOKEN_COMMA:
return new BinaryOperatorCommaNode(operatorToken, leftOperand, rightOperand);
case TOKEN_KEYWORD_IN:
return new BinaryOperatorInNode(operatorToken, leftOperand, rightOperand);
case TOKEN_KEYWORD_INSTANCEOF:
return new BinaryOperatorInstanceOfNode(operatorToken, leftOperand, rightOperand);
case TOKEN_KEYWORD_IS:
return new BinaryOperatorIsNode(operatorToken, leftOperand, rightOperand);
}
assert false : "Token '" + operatorToken.getText() + "' unexpected in BinaryOperatorNodeBase.create()";
return null;
}
/**
* Constructor.
* <p>
* Creates a {@code BinaryOperatorNode} from an operator and both operands.
* If either operand is {@code null}, we will synthesize
* empty {@link IdentifierNode} to repair the tree.
*
* @param op operator token
* @param left first operand
* @param right second operand
*/
public BinaryOperatorNodeBase(IASToken op, ExpressionNodeBase left, ExpressionNodeBase right)
{
super(op);
// Synthesize an empty ID node if either operand is null. (Fix for CMP-883)
if (left == null)
leftOperandNode = IdentifierNode.createEmptyIdentifierNodeAfterToken((Token)op);
else
leftOperandNode = left;
if (right == null)
rightOperandNode = IdentifierNode.createEmptyIdentifierNodeAfterToken((Token)op);
else
rightOperandNode = right;
span(leftOperandNode, rightOperandNode);
}
/**
* Copy constructor.
*
* @param other The node to copy.
*/
protected BinaryOperatorNodeBase(BinaryOperatorNodeBase other)
{
super(other);
this.leftOperandNode = other.leftOperandNode != null ? other.leftOperandNode.copy() : null;
this.rightOperandNode = other.rightOperandNode != null ? other.rightOperandNode.copy() : null;
}
/**
* The expression to the left of the operator
*/
protected ExpressionNodeBase leftOperandNode;
/**
* The expression to the right of the operator
*/
protected ExpressionNodeBase rightOperandNode;
//
// NodeBase overrides
//
@Override
public int getChildCount()
{
int count = 0;
if (leftOperandNode != null)
count++;
if (rightOperandNode != null)
count++;
return count;
}
@Override
public IASNode getChild(int i)
{
if (i == 0)
return leftOperandNode != null ? leftOperandNode : rightOperandNode;
else if (i == 1)
return rightOperandNode;
return null;
}
@Override
protected void setChildren(boolean fillInOffsets)
{
if (leftOperandNode != null)
leftOperandNode.setParent(this);
if (rightOperandNode != null)
rightOperandNode.setParent(this);
}
@Override
protected void fillInOffsets()
{
if (rightOperandNode == null && leftOperandNode == null && operatorStart != -1)
span(operatorStart, operatorStart + 1, -1, -1, -1, -1);
else
super.fillInOffsets();
}
//
// ExpressionNodeBase overrides
//
@Override
public ITypeDefinition resolveType(ICompilerProject project)
{
// Various subclasses override this default behavior.
return project.getBuiltinType(BuiltinType.ANY_TYPE);
}
//
// OperatorNodeBase overrides
//
@Override
public ExpressionType getExpressionType()
{
return ExpressionType.BINARY;
}
//
// IBinaryOperatorNode implementations
//
@Override
public IExpressionNode getLeftOperandNode()
{
return leftOperandNode;
}
@Override
public IExpressionNode getRightOperandNode()
{
return rightOperandNode;
}
//
// Other methods
//
/**
* Sets the left-hand side of the expression.
*
* @param leftOperandNode Left-hand side expression.
*/
public void setLeftOperandNode(ExpressionNodeBase leftOperandNode)
{
this.leftOperandNode = leftOperandNode;
}
/**
* Sets the right side of the expression
*
* @param rightOperandNode ExpressionNodeBase to the right of the operator
*/
public void setRightOperandNode(ExpressionNodeBase rightOperandNode)
{
this.rightOperandNode = rightOperandNode;
}
public boolean isOperatingOnArray()
{
if (leftOperandNode instanceof IDynamicAccessNode || rightOperandNode instanceof IDynamicAccessNode)
return true;
if (leftOperandNode instanceof IBinaryOperatorNode)
{
boolean onArray = ((BinaryOperatorNodeBase)leftOperandNode).isOperatingOnArray();
if (onArray)
return true;
}
if (rightOperandNode instanceof IBinaryOperatorNode)
return ((BinaryOperatorNodeBase)rightOperandNode).isOperatingOnArray();
return false;
}
/**
* Utility method called by {@link #resolveType(ICompilerProject)}
* in subclasses for assignment operators.
*/
protected ITypeDefinition resolveAssignmentType(ICompilerProject project)
{
// The type of any assignment expression is the type
// of what we are assigning to.
return getLeftOperandNode().resolveType(project);
}
/**
* Utility method called by {@link #resolveType(ICompilerProject)}
* in subclasses for the <code>&&</code> and <code>||</code> operators.
*/
protected ITypeDefinition resolveLogicalType(ICompilerProject project)
{
// The old compiler says the type of && or || is one of the operand types,
// but only checks if the types are equivalent.
// TODO: Could probably be smarter - calculate common base class and use that as the type?
ITypeDefinition leftType = getLeftOperandNode().resolveType(project);
ITypeDefinition rightType = getRightOperandNode().resolveType(project);
if (leftType != null && leftType.equals(rightType))
return leftType;
return project.getBuiltinType(BuiltinType.ANY_TYPE);
}
}