/* * * 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.flex.compiler.internal.tree.as; import static org.apache.flex.compiler.internal.parsing.as.ASTokenTypes.*; import antlr.Token; import org.apache.flex.compiler.constants.IASLanguageConstants.BuiltinType; import org.apache.flex.compiler.definitions.ITypeDefinition; import org.apache.flex.compiler.parsing.IASToken; import org.apache.flex.compiler.projects.ICompilerProject; import org.apache.flex.compiler.tree.as.IASNode; import org.apache.flex.compiler.tree.as.IDynamicAccessNode; import org.apache.flex.compiler.tree.as.IBinaryOperatorNode; import org.apache.flex.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); 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); } }