/* * * 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 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.IExpressionNode; import org.apache.flex.compiler.tree.as.IOperatorNode; import org.apache.flex.compiler.tree.as.IUnaryOperatorNode; /** * Abstract base class for all unary operator nodes. */ public abstract class UnaryOperatorNodeBase extends OperatorNodeBase implements IUnaryOperatorNode { /** * Length of post-fix operators: {@code ++} and {@code --}. */ private static final int POSTFIX_OPERATOR_LENGTH = 2; /** * Factory method for various kinds of unary prefix operator nodes. */ public static UnaryOperatorNodeBase createPrefix(IASToken operatorToken, ExpressionNodeBase operand) { switch (operatorToken.getType()) { case TOKEN_OPERATOR_PLUS: return new UnaryOperatorPlusNode(operatorToken, operand); case TOKEN_OPERATOR_MINUS: return new UnaryOperatorMinusNode(operatorToken, operand); case TOKEN_OPERATOR_INCREMENT: return new UnaryOperatorPreIncrementNode(operatorToken, operand); case TOKEN_OPERATOR_DECREMENT: return new UnaryOperatorPreDecrementNode(operatorToken, operand); case TOKEN_OPERATOR_LOGICAL_NOT: return new UnaryOperatorLogicalNotNode(operatorToken, operand); case TOKEN_OPERATOR_BITWISE_NOT: return new UnaryOperatorBitwiseNotNode(operatorToken, operand); case TOKEN_OPERATOR_ATSIGN: return new UnaryOperatorAtNode(operatorToken, operand); case TOKEN_KEYWORD_DELETE: return new UnaryOperatorDeleteNode(operatorToken, operand); case TOKEN_KEYWORD_TYPEOF: return new UnaryOperatorTypeOfNode(operatorToken, operand); case TOKEN_KEYWORD_VOID: return new UnaryOperatorVoidNode(operatorToken, operand); } assert false : "Token '" + operatorToken.getText() + "' unexpected in UnaryOperatorNodeBase.createPrefix()"; return null; } /** * Factory method for various kinds of unary prefix operator nodes. */ public static UnaryOperatorNodeBase createPostfix(IASToken operatorToken, ExpressionNodeBase operand) { switch (operatorToken.getType()) { case TOKEN_OPERATOR_INCREMENT: return new UnaryOperatorPostIncrementNode(operatorToken, operand); case TOKEN_OPERATOR_DECREMENT: return new UnaryOperatorPostDecrementNode(operatorToken, operand); } assert false : "Token '" + operatorToken.getText() + "' unexpected in UnaryOperatorNodeBase.createPostfix()"; return null; } /** * Constructor. * * @param operatorToken The token representing the unary operator. * @param operandNode The expresson node representing the operand. */ public UnaryOperatorNodeBase(IASToken operatorToken, ExpressionNodeBase operandNode) { super(operatorToken); this.operandNode = operandNode; } /** * Copy constructor. * * @param other The node to copy. */ protected UnaryOperatorNodeBase(UnaryOperatorNodeBase other) { super(other); this.operandNode = other.operandNode != null ? other.operandNode.copy() : null; } private ExpressionNodeBase operandNode; // // NodeBase overrides // @Override public int getChildCount() { return operandNode != null ? 1 : 0; } @Override public IASNode getChild(int i) { return i == 0 ? operandNode : null; } @Override protected void setChildren(boolean fillInOffsets) { if (operandNode != null) operandNode.setParent(this); } @Override protected void fillInOffsets() { if (operandNode == 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); } @Override public boolean isDynamicExpression(ICompilerProject project) { return false; } /** * Determine if e is part of an attribue expression (@name). * * @param e the expression to test * @return true if e if the sub-expr of the unary expression, and the * operator is '@' */ @Override boolean isAttributeExpr(ExpressionNodeBase e) { return this.getOperator() == IOperatorNode.OperatorType.AT && e == this.getOperandNode(); } /* * Get the ExpressionNodeBase representing the Base of the operand of an @ * operator. This would be the Node for 'a' in the expression 'a.@b', * assuming you asked for the base of 'b'. * * @param e The ExpressionNodeBase representing b. * @return The ExpressionNodeBase representing the base expression of e, or null * if there is no base */ @Override ExpressionNodeBase getBaseForMemberRef(ExpressionNodeBase e) { if (isAttributeExpr(e)) { ExpressionNodeBase p = getParentExpression(); if (p != null) return p.getBaseForMemberRef(this); } return null; } // // OperatorNodeBase overrides // @Override public ExpressionType getExpressionType() { // Most unary operators are prefix. // The two that aren't (a++ and a--) override this method to return POSTFIX. return ExpressionType.PREFIX; } // // IUnaryOperatorNode implementations // @Override public IExpressionNode getOperandNode() { return operandNode; } // // Other methods // public void setExpression(ExpressionNodeBase operandNode) { this.operandNode = operandNode; } /** * Utility method called by {@link #resolveType(ICompilerProject)} in subclasses * for the <code>++</code> and <code>--</code> operators. */ protected ITypeDefinition resolveIncrementOrDecrementType(ICompilerProject project) { ITypeDefinition exprType = operandNode.resolveType(project); if (exprType != null) { ITypeDefinition intType = project.getBuiltinType(BuiltinType.INT); ITypeDefinition uintType = project.getBuiltinType(BuiltinType.UINT); if (exprType.equals(intType)) return intType; else if (exprType.equals(uintType)) return uintType; } return project.getBuiltinType(BuiltinType.NUMBER); } }