| /******************************************************************************* |
| * Copyright (c) 2004, 2015 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * John Camelon (IBM) - Initial API and implementation |
| * Mike Kucera (IBM) |
| * Markus Schorn (Wind River Systems) |
| * Sergey Prigogin (Google) |
| *******************************************************************************/ |
| package org.eclipse.cdt.internal.core.dom.parser.cpp; |
| |
| import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE; |
| |
| import org.eclipse.cdt.core.dom.ast.ASTVisitor; |
| import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTImplicitDestructorName; |
| import org.eclipse.cdt.core.dom.ast.IASTImplicitName; |
| import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; |
| import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; |
| import org.eclipse.cdt.core.dom.ast.IASTNode; |
| import org.eclipse.cdt.core.dom.ast.IType; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; |
| import org.eclipse.cdt.internal.core.dom.parser.ASTNode; |
| import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPEvaluation; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.DestructorCallCollector; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalBinary; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed; |
| |
| |
| public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpression, IASTAmbiguityParent { |
| private int fOperator; |
| private ICPPASTExpression fOperand1; |
| private ICPPASTInitializerClause fOperand2; |
| |
| private ICPPEvaluation fEvaluation; |
| private IASTImplicitName[] fImplicitNames; |
| private IASTImplicitDestructorName[] fImplicitDestructorNames; |
| |
| public CPPASTBinaryExpression() { |
| } |
| |
| public CPPASTBinaryExpression(int op, IASTExpression operand1, IASTInitializerClause operand2) { |
| this.fOperator = op; |
| setOperand1(operand1); |
| setInitOperand2(operand2); |
| } |
| |
| @Override |
| public CPPASTBinaryExpression copy() { |
| return copy(CopyStyle.withoutLocations); |
| } |
| |
| @Override |
| public CPPASTBinaryExpression copy(CopyStyle style) { |
| CPPASTBinaryExpression copy = new CPPASTBinaryExpression(fOperator, |
| fOperand1 == null ? null : fOperand1.copy(style), |
| fOperand2 == null ? null : fOperand2.copy(style)); |
| return copy(copy, style); |
| } |
| |
| @Override |
| public int getOperator() { |
| return fOperator; |
| } |
| |
| @Override |
| public IASTExpression getOperand1() { |
| return fOperand1; |
| } |
| |
| @Override |
| public IASTInitializerClause getInitOperand2() { |
| return fOperand2; |
| } |
| |
| @Override |
| public IASTExpression getOperand2() { |
| if (fOperand2 instanceof IASTExpression) |
| return (IASTExpression) fOperand2; |
| return null; |
| } |
| |
| @Override |
| public void setOperator(int op) { |
| assertNotFrozen(); |
| this.fOperator = op; |
| } |
| |
| @Override |
| public void setOperand1(IASTExpression expression) { |
| assertNotFrozen(); |
| if (expression != null) { |
| if (!(expression instanceof ICPPASTExpression)) |
| throw new IllegalArgumentException(expression.getClass().getName()); |
| |
| expression.setParent(this); |
| expression.setPropertyInParent(OPERAND_ONE); |
| } |
| fOperand1 = (ICPPASTExpression) expression; |
| } |
| |
| public void setInitOperand2(IASTInitializerClause operand) { |
| assertNotFrozen(); |
| if (operand != null) { |
| if (!(operand instanceof ICPPASTInitializerClause)) |
| throw new IllegalArgumentException(operand.getClass().getName()); |
| operand.setParent(this); |
| operand.setPropertyInParent(OPERAND_TWO); |
| } |
| fOperand2 = (ICPPASTInitializerClause) operand; |
| } |
| |
| @Override |
| public void setOperand2(IASTExpression expression) { |
| setInitOperand2(expression); |
| } |
| |
| @Override |
| public IASTImplicitName[] getImplicitNames() { |
| if (fImplicitNames == null) { |
| ICPPFunction overload = getOverload(); |
| if (overload == null || (overload instanceof CPPImplicitFunction && !(overload instanceof ICPPMethod))) { |
| fImplicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; |
| } else { |
| CPPASTImplicitName operatorName = new CPPASTImplicitName(overload.getNameCharArray(), this); |
| operatorName.setBinding(overload); |
| operatorName.setOperator(true); |
| operatorName.computeOperatorOffsets(fOperand1, true); |
| fImplicitNames = new IASTImplicitName[] { operatorName }; |
| } |
| } |
| |
| return fImplicitNames; |
| } |
| |
| @Override |
| public IASTImplicitDestructorName[] getImplicitDestructorNames() { |
| if (fImplicitDestructorNames == null) { |
| fImplicitDestructorNames = DestructorCallCollector.getTemporariesDestructorCalls(this); |
| } |
| |
| return fImplicitDestructorNames; |
| } |
| |
| @Override |
| public boolean accept(ASTVisitor action) { |
| if (fOperand1 instanceof IASTBinaryExpression || fOperand2 instanceof IASTBinaryExpression) { |
| return acceptWithoutRecursion(this, action); |
| } |
| |
| if (action.shouldVisitExpressions) { |
| switch (action.visit(this)) { |
| case ASTVisitor.PROCESS_ABORT: return false; |
| case ASTVisitor.PROCESS_SKIP: return true; |
| default: break; |
| } |
| } |
| |
| if (fOperand1 != null && !fOperand1.accept(action)) |
| return false; |
| |
| if (action.shouldVisitImplicitNames && !acceptByNodes(getImplicitNames(), action)) |
| return false; |
| |
| if (fOperand2 != null && !fOperand2.accept(action)) |
| return false; |
| |
| if (action.shouldVisitImplicitDestructorNames && !acceptByNodes(getImplicitDestructorNames(), action)) |
| return false; |
| |
| if (action.shouldVisitExpressions && action.leave(this) == ASTVisitor.PROCESS_ABORT) |
| return false; |
| |
| return true; |
| } |
| |
| private static class N { |
| final IASTBinaryExpression fExpression; |
| int fState; |
| N fNext; |
| |
| N(IASTBinaryExpression expr) { |
| fExpression = expr; |
| } |
| } |
| |
| private static boolean acceptWithoutRecursion(IASTBinaryExpression bexpr, ASTVisitor action) { |
| N stack= new N(bexpr); |
| while (stack != null) { |
| IASTBinaryExpression expr= stack.fExpression; |
| if (stack.fState == 0) { |
| if (action.shouldVisitExpressions) { |
| switch (action.visit(expr)) { |
| case ASTVisitor.PROCESS_ABORT: |
| return false; |
| case ASTVisitor.PROCESS_SKIP: |
| stack= stack.fNext; |
| continue; |
| } |
| } |
| stack.fState= 1; |
| IASTExpression op1 = expr.getOperand1(); |
| if (op1 instanceof IASTBinaryExpression) { |
| N n= new N((IASTBinaryExpression) op1); |
| n.fNext= stack; |
| stack= n; |
| continue; |
| } |
| if (op1 != null && !op1.accept(action)) |
| return false; |
| } |
| if (stack.fState == 1) { |
| if (action.shouldVisitImplicitNames && |
| !acceptByNodes(((IASTImplicitNameOwner) expr).getImplicitNames(), action)) { |
| return false; |
| } |
| stack.fState= 2; |
| |
| IASTInitializerClause op2 = expr.getInitOperand2(); |
| if (op2 instanceof IASTBinaryExpression) { |
| N n= new N((IASTBinaryExpression) op2); |
| n.fNext= stack; |
| stack= n; |
| continue; |
| } |
| if (op2 != null && !op2.accept(action)) |
| return false; |
| } |
| |
| if (action.shouldVisitExpressions && action.leave(expr) == ASTVisitor.PROCESS_ABORT) |
| return false; |
| |
| stack= stack.fNext; |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public void replace(IASTNode child, IASTNode other) { |
| if (child == fOperand1) { |
| other.setPropertyInParent(child.getPropertyInParent()); |
| other.setParent(child.getParent()); |
| fOperand1 = (ICPPASTExpression) other; |
| } |
| if (child == fOperand2) { |
| other.setPropertyInParent(child.getPropertyInParent()); |
| other.setParent(child.getParent()); |
| fOperand2 = (ICPPASTInitializerClause) other; |
| } |
| } |
| |
| |
| @Override |
| public ICPPFunction getOverload() { |
| ICPPEvaluation eval = getEvaluation(); |
| if (eval instanceof EvalBinary) { |
| CPPSemantics.pushLookupPoint(this); |
| try { |
| return ((EvalBinary) eval).getOverload(); |
| } finally { |
| CPPSemantics.popLookupPoint(); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public ICPPEvaluation getEvaluation() { |
| if (fEvaluation == null) |
| fEvaluation= computeEvaluation(); |
| |
| return fEvaluation; |
| } |
| |
| private ICPPEvaluation computeEvaluation() { |
| if (fOperand1 == null || fOperand2 == null) |
| return EvalFixed.INCOMPLETE; |
| |
| ICPPEvaluation eval1 = fOperand1.getEvaluation(); |
| ICPPEvaluation eval2 = fOperand2.getEvaluation(); |
| return new EvalBinary(fOperator, eval1, eval2, this); |
| } |
| |
| @Override |
| public IType getExpressionType() { |
| return CPPEvaluation.getType(this); |
| } |
| |
| @Override |
| public ValueCategory getValueCategory() { |
| return CPPEvaluation.getValueCategory(this); |
| } |
| |
| @Override |
| public boolean isLValue() { |
| return getValueCategory() == LVALUE; |
| } |
| } |