X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/BinaryExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/BinaryExpression.java index ff93371..4f8e580 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/BinaryExpression.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/BinaryExpression.java @@ -1,25 +1,1767 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ package net.sourceforge.phpdt.internal.compiler.ast; -/** - * @author Matthieu Casanova - */ +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols.TokenName; +import net.sourceforge.phpdt.internal.compiler.ASTVisitor; +import net.sourceforge.phpdt.internal.compiler.flow.FlowContext; +import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; +import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + public class BinaryExpression extends OperatorExpression { - /** The two expressions. */ - public Expression left,right; - - public BinaryExpression(Expression left, - Expression right, - int operator) { - super(operator, left.sourceStart, right.sourceEnd); - this.left = left; - this.right = right; - } - - public String toStringExpressionNoParenthesis() { - final StringBuffer buff = new StringBuffer(left.toStringExpression()); - buff.append(operatorToString()); - buff.append(right.toStringExpression()); - return buff.toString(); - } + public Expression left, right; + + public Constant optimizedBooleanConstant; + + public BinaryExpression(Expression left, Expression right, int operator) { + this.left = left; + this.right = right; + this.bits |= operator << OperatorSHIFT; // encode operator + this.sourceStart = left.sourceStart; + this.sourceEnd = right.sourceEnd; + } + + public FlowInfo analyseCode(BlockScope currentScope, + FlowContext flowContext, FlowInfo flowInfo) { + + return right.analyseCode( + currentScope, + flowContext, + left.analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits()).unconditionalInits(); + } + + public void computeConstant(BlockScope scope, int leftId, int rightId) { + + // compute the constant when valid + if ((this.left.constant != Constant.NotAConstant) + && (this.right.constant != Constant.NotAConstant)) { + try { + this.constant = Constant.computeConstantOperation( + this.left.constant, leftId, + (this.bits & OperatorMASK) >> OperatorSHIFT, + this.right.constant, rightId); + } catch (ArithmeticException e) { + this.constant = Constant.NotAConstant; + // 1.2 no longer throws an exception at compile-time + // scope.problemReporter().compileTimeConstantThrowsArithmeticException(this); + } + } else { + this.constant = Constant.NotAConstant; + // add some work for the boolean operators & | + // this.optimizedBooleanConstant( + // leftId, + // (this.bits & OperatorMASK) >> OperatorSHIFT, + // rightId); + } + } + + public Constant optimizedBooleanConstant() { + + return this.optimizedBooleanConstant == null ? this.constant + : this.optimizedBooleanConstant; + } + + /** + * Code generation for a binary operation + */ + // public void generateCode( + // BlockScope currentScope, + // CodeStream codeStream, + // boolean valueRequired) { + // + // int pc = codeStream.position; + // Label falseLabel, endLabel; + // if (constant != Constant.NotAConstant) { + // if (valueRequired) + // codeStream.generateConstant(constant, implicitConversion); + // codeStream.recordPositionsFrom(pc, this.sourceStart); + // return; + // } + // bits |= OnlyValueRequiredMASK; + // switch ((bits & OperatorMASK) >> OperatorSHIFT) { + // case PLUS : + // switch (bits & ReturnTypeIDMASK) { + // case T_String : + // codeStream.generateStringAppend(currentScope, left, right); + // if (!valueRequired) + // codeStream.pop(); + // break; + // case T_int : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.iadd(); + // break; + // case T_long : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.ladd(); + // break; + // case T_double : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.dadd(); + // break; + // case T_float : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.fadd(); + // break; + // } + // break; + // case MINUS : + // switch (bits & ReturnTypeIDMASK) { + // case T_int : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.isub(); + // break; + // case T_long : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.lsub(); + // break; + // case T_double : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.dsub(); + // break; + // case T_float : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.fsub(); + // break; + // } + // break; + // case MULTIPLY : + // switch (bits & ReturnTypeIDMASK) { + // case T_int : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.imul(); + // break; + // case T_long : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.lmul(); + // break; + // case T_double : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.dmul(); + // break; + // case T_float : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.fmul(); + // break; + // } + // break; + // case DIVIDE : + // switch (bits & ReturnTypeIDMASK) { + // case T_int : + // left.generateCode(currentScope, codeStream, true); + // right.generateCode(currentScope, codeStream, true); + // codeStream.idiv(); + // if (!valueRequired) + // codeStream.pop(); + // break; + // case T_long : + // left.generateCode(currentScope, codeStream, true); + // right.generateCode(currentScope, codeStream, true); + // codeStream.ldiv(); + // if (!valueRequired) + // codeStream.pop2(); + // break; + // case T_double : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.ddiv(); + // break; + // case T_float : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.fdiv(); + // break; + // } + // break; + // case REMAINDER : + // switch (bits & ReturnTypeIDMASK) { + // case T_int : + // left.generateCode(currentScope, codeStream, true); + // right.generateCode(currentScope, codeStream, true); + // codeStream.irem(); + // if (!valueRequired) + // codeStream.pop(); + // break; + // case T_long : + // left.generateCode(currentScope, codeStream, true); + // right.generateCode(currentScope, codeStream, true); + // codeStream.lrem(); + // if (!valueRequired) + // codeStream.pop2(); + // break; + // case T_double : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.drem(); + // break; + // case T_float : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.frem(); + // break; + // } + // break; + // case AND : + // switch (bits & ReturnTypeIDMASK) { + // case T_int : + // // 0 & x + // if ((left.constant != Constant.NotAConstant) + // && (left.constant.typeID() == T_int) + // && (left.constant.intValue() == 0)) { + // right.generateCode(currentScope, codeStream, false); + // if (valueRequired) + // codeStream.iconst_0(); + // } else { + // // x & 0 + // if ((right.constant != Constant.NotAConstant) + // && (right.constant.typeID() == T_int) + // && (right.constant.intValue() == 0)) { + // left.generateCode(currentScope, codeStream, false); + // if (valueRequired) + // codeStream.iconst_0(); + // } else { + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.iand(); + // } + // } + // break; + // case T_long : + // // 0 & x + // if ((left.constant != Constant.NotAConstant) + // && (left.constant.typeID() == T_long) + // && (left.constant.longValue() == 0L)) { + // right.generateCode(currentScope, codeStream, false); + // if (valueRequired) + // codeStream.lconst_0(); + // } else { + // // x & 0 + // if ((right.constant != Constant.NotAConstant) + // && (right.constant.typeID() == T_long) + // && (right.constant.longValue() == 0L)) { + // left.generateCode(currentScope, codeStream, false); + // if (valueRequired) + // codeStream.lconst_0(); + // } else { + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.land(); + // } + // } + // break; + // case T_boolean : // logical and + // generateOptimizedLogicalAnd( + // currentScope, + // codeStream, + // null, + // (falseLabel = new Label(codeStream)), + // valueRequired); + // /* improving code gen for such a case: boolean b = i < 0 && false; + // * since the label has never been used, we have the inlined value on the + // stack. */ + // if (falseLabel.hasForwardReferences()) { + // if (valueRequired) { + // codeStream.iconst_1(); + // if ((bits & ValueForReturnMASK) != 0) { + // codeStream.ireturn(); + // falseLabel.place(); + // codeStream.iconst_0(); + // } else { + // codeStream.goto_(endLabel = new Label(codeStream)); + // codeStream.decrStackSize(1); + // falseLabel.place(); + // codeStream.iconst_0(); + // endLabel.place(); + // } + // } else { + // falseLabel.place(); + // } + // } + // } + // break; + // case OR : + // switch (bits & ReturnTypeIDMASK) { + // case T_int : + // // 0 | x + // if ((left.constant != Constant.NotAConstant) + // && (left.constant.typeID() == T_int) + // && (left.constant.intValue() == 0)) { + // right.generateCode(currentScope, codeStream, valueRequired); + // } else { + // // x | 0 + // if ((right.constant != Constant.NotAConstant) + // && (right.constant.typeID() == T_int) + // && (right.constant.intValue() == 0)) { + // left.generateCode(currentScope, codeStream, valueRequired); + // } else { + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.ior(); + // } + // } + // break; + // case T_long : + // // 0 | x + // if ((left.constant != Constant.NotAConstant) + // && (left.constant.typeID() == T_long) + // && (left.constant.longValue() == 0L)) { + // right.generateCode(currentScope, codeStream, valueRequired); + // } else { + // // x | 0 + // if ((right.constant != Constant.NotAConstant) + // && (right.constant.typeID() == T_long) + // && (right.constant.longValue() == 0L)) { + // left.generateCode(currentScope, codeStream, valueRequired); + // } else { + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.lor(); + // } + // } + // break; + // case T_boolean : // logical or + // generateOptimizedLogicalOr( + // currentScope, + // codeStream, + // null, + // (falseLabel = new Label(codeStream)), + // valueRequired); + // /* improving code gen for such a case: boolean b = i < 0 || true; + // * since the label has never been used, we have the inlined value on the + // stack. */ + // if (falseLabel.hasForwardReferences()) { + // if (valueRequired) { + // codeStream.iconst_1(); + // if ((bits & ValueForReturnMASK) != 0) { + // codeStream.ireturn(); + // falseLabel.place(); + // codeStream.iconst_0(); + // } else { + // codeStream.goto_(endLabel = new Label(codeStream)); + // codeStream.decrStackSize(1); + // falseLabel.place(); + // codeStream.iconst_0(); + // endLabel.place(); + // } + // } else { + // falseLabel.place(); + // } + // } + // } + // break; + // case XOR : + // switch (bits & ReturnTypeIDMASK) { + // case T_int : + // // 0 ^ x + // if ((left.constant != Constant.NotAConstant) + // && (left.constant.typeID() == T_int) + // && (left.constant.intValue() == 0)) { + // right.generateCode(currentScope, codeStream, valueRequired); + // } else { + // // x ^ 0 + // if ((right.constant != Constant.NotAConstant) + // && (right.constant.typeID() == T_int) + // && (right.constant.intValue() == 0)) { + // left.generateCode(currentScope, codeStream, valueRequired); + // } else { + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.ixor(); + // } + // } + // break; + // case T_long : + // // 0 ^ x + // if ((left.constant != Constant.NotAConstant) + // && (left.constant.typeID() == T_long) + // && (left.constant.longValue() == 0L)) { + // right.generateCode(currentScope, codeStream, valueRequired); + // } else { + // // x ^ 0 + // if ((right.constant != Constant.NotAConstant) + // && (right.constant.typeID() == T_long) + // && (right.constant.longValue() == 0L)) { + // left.generateCode(currentScope, codeStream, valueRequired); + // } else { + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.lxor(); + // } + // } + // break; + // case T_boolean : + // generateOptimizedLogicalXor( + // currentScope, + // codeStream, + // null, + // (falseLabel = new Label(codeStream)), + // valueRequired); + // /* improving code gen for such a case: boolean b = i < 0 ^ bool; + // * since the label has never been used, we have the inlined value on the + // stack. */ + // if (falseLabel.hasForwardReferences()) { + // if (valueRequired) { + // codeStream.iconst_1(); + // if ((bits & ValueForReturnMASK) != 0) { + // codeStream.ireturn(); + // falseLabel.place(); + // codeStream.iconst_0(); + // } else { + // codeStream.goto_(endLabel = new Label(codeStream)); + // codeStream.decrStackSize(1); + // falseLabel.place(); + // codeStream.iconst_0(); + // endLabel.place(); + // } + // } else { + // falseLabel.place(); + // } + // } + // } + // break; + // case LEFT_SHIFT : + // switch (bits & ReturnTypeIDMASK) { + // case T_int : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.ishl(); + // break; + // case T_long : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.lshl(); + // } + // break; + // case RIGHT_SHIFT : + // switch (bits & ReturnTypeIDMASK) { + // case T_int : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.ishr(); + // break; + // case T_long : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.lshr(); + // } + // break; + // case UNSIGNED_RIGHT_SHIFT : + // switch (bits & ReturnTypeIDMASK) { + // case T_int : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.iushr(); + // break; + // case T_long : + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) + // codeStream.lushr(); + // } + // break; + // case GREATER : + // generateOptimizedGreaterThan( + // currentScope, + // codeStream, + // null, + // (falseLabel = new Label(codeStream)), + // valueRequired); + // if (valueRequired) { + // codeStream.iconst_1(); + // if ((bits & ValueForReturnMASK) != 0) { + // codeStream.ireturn(); + // falseLabel.place(); + // codeStream.iconst_0(); + // } else { + // codeStream.goto_(endLabel = new Label(codeStream)); + // codeStream.decrStackSize(1); + // falseLabel.place(); + // codeStream.iconst_0(); + // endLabel.place(); + // } + // } + // break; + // case GREATER_EQUAL : + // generateOptimizedGreaterThanOrEqual( + // currentScope, + // codeStream, + // null, + // (falseLabel = new Label(codeStream)), + // valueRequired); + // if (valueRequired) { + // codeStream.iconst_1(); + // if ((bits & ValueForReturnMASK) != 0) { + // codeStream.ireturn(); + // falseLabel.place(); + // codeStream.iconst_0(); + // } else { + // codeStream.goto_(endLabel = new Label(codeStream)); + // codeStream.decrStackSize(1); + // falseLabel.place(); + // codeStream.iconst_0(); + // endLabel.place(); + // } + // } + // break; + // case LESS : + // generateOptimizedLessThan( + // currentScope, + // codeStream, + // null, + // (falseLabel = new Label(codeStream)), + // valueRequired); + // if (valueRequired) { + // codeStream.iconst_1(); + // if ((bits & ValueForReturnMASK) != 0) { + // codeStream.ireturn(); + // falseLabel.place(); + // codeStream.iconst_0(); + // } else { + // codeStream.goto_(endLabel = new Label(codeStream)); + // codeStream.decrStackSize(1); + // falseLabel.place(); + // codeStream.iconst_0(); + // endLabel.place(); + // } + // } + // break; + // case LESS_EQUAL : + // generateOptimizedLessThanOrEqual( + // currentScope, + // codeStream, + // null, + // (falseLabel = new Label(codeStream)), + // valueRequired); + // if (valueRequired) { + // codeStream.iconst_1(); + // if ((bits & ValueForReturnMASK) != 0) { + // codeStream.ireturn(); + // falseLabel.place(); + // codeStream.iconst_0(); + // } else { + // codeStream.goto_(endLabel = new Label(codeStream)); + // codeStream.decrStackSize(1); + // falseLabel.place(); + // codeStream.iconst_0(); + // endLabel.place(); + // } + // } + // } + // if (valueRequired) { + // codeStream.generateImplicitConversion(implicitConversion); + // } + // codeStream.recordPositionsFrom(pc, this.sourceStart); + // } + /** + * Boolean operator code generation Optimized operations are: <, <=, >, >=, &, |, ^ + */ + // public void generateOptimizedBoolean( + // BlockScope currentScope, + // CodeStream codeStream, + // Label trueLabel, + // Label falseLabel, + // boolean valueRequired) { + // + // if ((constant != Constant.NotAConstant) && (constant.typeID() == + // T_boolean)) { + // super.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // return; + // } + // switch ((bits & OperatorMASK) >> OperatorSHIFT) { + // case LESS : + // generateOptimizedLessThan( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // return; + // case LESS_EQUAL : + // generateOptimizedLessThanOrEqual( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // return; + // case GREATER : + // generateOptimizedGreaterThan( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // return; + // case GREATER_EQUAL : + // generateOptimizedGreaterThanOrEqual( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // return; + // case AND : + // generateOptimizedLogicalAnd( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // return; + // case OR : + // generateOptimizedLogicalOr( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // return; + // case XOR : + // generateOptimizedLogicalXor( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // return; + // } + // super.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // } + // + // /** + // * Boolean generation for > + // */ + // public void generateOptimizedGreaterThan( + // BlockScope currentScope, + // CodeStream codeStream, + // Label trueLabel, + // Label falseLabel, + // boolean valueRequired) { + // + // int promotedTypeID = left.implicitConversion >> 4; + // // both sides got promoted in the same way + // if (promotedTypeID == T_int) { + // // 0 > x + // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicitly falling through the FALSE case + // codeStream.iflt(trueLabel); + // } + // } else { + // if (trueLabel == null) { + // // implicitly falling through the TRUE case + // codeStream.ifge(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // // x > 0 + // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) + // { + // left.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicitly falling through the FALSE case + // codeStream.ifgt(trueLabel); + // } + // } else { + // if (trueLabel == null) { + // // implicitly falling through the TRUE case + // codeStream.ifle(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // } + // // default comparison + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicit falling through the FALSE case + // switch (promotedTypeID) { + // case T_int : + // codeStream.if_icmpgt(trueLabel); + // break; + // case T_float : + // codeStream.fcmpl(); + // codeStream.ifgt(trueLabel); + // break; + // case T_long : + // codeStream.lcmp(); + // codeStream.ifgt(trueLabel); + // break; + // case T_double : + // codeStream.dcmpl(); + // codeStream.ifgt(trueLabel); + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // } else { + // if (trueLabel == null) { + // // implicit falling through the TRUE case + // switch (promotedTypeID) { + // case T_int : + // codeStream.if_icmple(falseLabel); + // break; + // case T_float : + // codeStream.fcmpl(); + // codeStream.ifle(falseLabel); + // break; + // case T_long : + // codeStream.lcmp(); + // codeStream.ifle(falseLabel); + // break; + // case T_double : + // codeStream.dcmpl(); + // codeStream.ifle(falseLabel); + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // } + /** + * Boolean generation for >= + */ + // public void generateOptimizedGreaterThanOrEqual( + // BlockScope currentScope, + // CodeStream codeStream, + // Label trueLabel, + // Label falseLabel, + // boolean valueRequired) { + // + // int promotedTypeID = left.implicitConversion >> 4; + // // both sides got promoted in the same way + // if (promotedTypeID == T_int) { + // // 0 >= x + // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicitly falling through the FALSE case + // codeStream.ifle(trueLabel); + // } + // } else { + // if (trueLabel == null) { + // // implicitly falling through the TRUE case + // codeStream.ifgt(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // // x >= 0 + // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) + // { + // left.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicitly falling through the FALSE case + // codeStream.ifge(trueLabel); + // } + // } else { + // if (trueLabel == null) { + // // implicitly falling through the TRUE case + // codeStream.iflt(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // } + // // default comparison + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicit falling through the FALSE case + // switch (promotedTypeID) { + // case T_int : + // codeStream.if_icmpge(trueLabel); + // break; + // case T_float : + // codeStream.fcmpl(); + // codeStream.ifge(trueLabel); + // break; + // case T_long : + // codeStream.lcmp(); + // codeStream.ifge(trueLabel); + // break; + // case T_double : + // codeStream.dcmpl(); + // codeStream.ifge(trueLabel); + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // } else { + // if (trueLabel == null) { + // // implicit falling through the TRUE case + // switch (promotedTypeID) { + // case T_int : + // codeStream.if_icmplt(falseLabel); + // break; + // case T_float : + // codeStream.fcmpl(); + // codeStream.iflt(falseLabel); + // break; + // case T_long : + // codeStream.lcmp(); + // codeStream.iflt(falseLabel); + // break; + // case T_double : + // codeStream.dcmpl(); + // codeStream.iflt(falseLabel); + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // } + // + // /** + // * Boolean generation for < + // */ + // public void generateOptimizedLessThan( + // BlockScope currentScope, + // CodeStream codeStream, + // Label trueLabel, + // Label falseLabel, + // boolean valueRequired) { + // + // int promotedTypeID = left.implicitConversion >> 4; + // // both sides got promoted in the same way + // if (promotedTypeID == T_int) { + // // 0 < x + // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicitly falling through the FALSE case + // codeStream.ifgt(trueLabel); + // } + // } else { + // if (trueLabel == null) { + // // implicitly falling through the TRUE case + // codeStream.ifle(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // // x < 0 + // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) + // { + // left.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicitly falling through the FALSE case + // codeStream.iflt(trueLabel); + // } + // } else { + // if (trueLabel == null) { + // // implicitly falling through the TRUE case + // codeStream.ifge(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // } + // // default comparison + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicit falling through the FALSE case + // switch (promotedTypeID) { + // case T_int : + // codeStream.if_icmplt(trueLabel); + // break; + // case T_float : + // codeStream.fcmpg(); + // codeStream.iflt(trueLabel); + // break; + // case T_long : + // codeStream.lcmp(); + // codeStream.iflt(trueLabel); + // break; + // case T_double : + // codeStream.dcmpg(); + // codeStream.iflt(trueLabel); + // } + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // } else { + // if (trueLabel == null) { + // // implicit falling through the TRUE case + // switch (promotedTypeID) { + // case T_int : + // codeStream.if_icmpge(falseLabel); + // break; + // case T_float : + // codeStream.fcmpg(); + // codeStream.ifge(falseLabel); + // break; + // case T_long : + // codeStream.lcmp(); + // codeStream.ifge(falseLabel); + // break; + // case T_double : + // codeStream.dcmpg(); + // codeStream.ifge(falseLabel); + // } + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // } + // + // /** + // * Boolean generation for <= + // */ + // public void generateOptimizedLessThanOrEqual( + // BlockScope currentScope, + // CodeStream codeStream, + // Label trueLabel, + // Label falseLabel, + // boolean valueRequired) { + // + // int promotedTypeID = left.implicitConversion >> 4; + // // both sides got promoted in the same way + // if (promotedTypeID == T_int) { + // // 0 <= x + // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicitly falling through the FALSE case + // codeStream.ifge(trueLabel); + // } + // } else { + // if (trueLabel == null) { + // // implicitly falling through the TRUE case + // codeStream.iflt(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // // x <= 0 + // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) + // { + // left.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicitly falling through the FALSE case + // codeStream.ifle(trueLabel); + // } + // } else { + // if (trueLabel == null) { + // // implicitly falling through the TRUE case + // codeStream.ifgt(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // } + // // default comparison + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicit falling through the FALSE case + // switch (promotedTypeID) { + // case T_int : + // codeStream.if_icmple(trueLabel); + // break; + // case T_float : + // codeStream.fcmpg(); + // codeStream.ifle(trueLabel); + // break; + // case T_long : + // codeStream.lcmp(); + // codeStream.ifle(trueLabel); + // break; + // case T_double : + // codeStream.dcmpg(); + // codeStream.ifle(trueLabel); + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } + // } else { + // if (trueLabel == null) { + // // implicit falling through the TRUE case + // switch (promotedTypeID) { + // case T_int : + // codeStream.if_icmpgt(falseLabel); + // break; + // case T_float : + // codeStream.fcmpg(); + // codeStream.ifgt(falseLabel); + // break; + // case T_long : + // codeStream.lcmp(); + // codeStream.ifgt(falseLabel); + // break; + // case T_double : + // codeStream.dcmpg(); + // codeStream.ifgt(falseLabel); + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // return; + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // } + // + // /** + // * Boolean generation for & + // */ + // public void generateOptimizedLogicalAnd( + // BlockScope currentScope, + // CodeStream codeStream, + // Label trueLabel, + // Label falseLabel, + // boolean valueRequired) { + // + // Constant condConst; + // if ((left.implicitConversion & 0xF) == T_boolean) { + // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) { + // if (condConst.booleanValue() == true) { + // // & x + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // if ((bits & OnlyValueRequiredMASK) != 0) { + // right.generateCode(currentScope, codeStream, valueRequired); + // } else { + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // } + // } else { + // // & x + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // if (valueRequired) { + // if ((bits & OnlyValueRequiredMASK) != 0) { + // codeStream.iconst_0(); + // } else { + // if (falseLabel != null) { + // // implicit falling through the TRUE case + // codeStream.goto_(falseLabel); + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // } + // return; + // } + // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) { + // if (condConst.booleanValue() == true) { + // // x & + // if ((bits & OnlyValueRequiredMASK) != 0) { + // left.generateCode(currentScope, codeStream, valueRequired); + // } else { + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // } + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // } else { + // // x & + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // if (valueRequired) { + // if ((bits & OnlyValueRequiredMASK) != 0) { + // codeStream.iconst_0(); + // } else { + // if (falseLabel != null) { + // // implicit falling through the TRUE case + // codeStream.goto_(falseLabel); + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // } + // return; + // } + // } + // // default case + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // codeStream.iand(); + // if ((bits & OnlyValueRequiredMASK) == 0) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicit falling through the FALSE case + // codeStream.ifne(trueLabel); + // } + // } else { + // // implicit falling through the TRUE case + // if (trueLabel == null) { + // codeStream.ifeq(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // } + // + // /** + // * Boolean generation for | + // */ + // public void generateOptimizedLogicalOr( + // BlockScope currentScope, + // CodeStream codeStream, + // Label trueLabel, + // Label falseLabel, + // boolean valueRequired) { + // + // Constant condConst; + // if ((left.implicitConversion & 0xF) == T_boolean) { + // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) { + // if (condConst.booleanValue() == true) { + // // | x + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // if (valueRequired) { + // if ((bits & OnlyValueRequiredMASK) != 0) { + // codeStream.iconst_1(); + // } else { + // if (trueLabel != null) { + // codeStream.goto_(trueLabel); + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // } else { + // // | x + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // if ((bits & OnlyValueRequiredMASK) != 0) { + // right.generateCode(currentScope, codeStream, valueRequired); + // } else { + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // } + // } + // return; + // } + // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) { + // if (condConst.booleanValue() == true) { + // // x | + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // if (valueRequired) { + // if ((bits & OnlyValueRequiredMASK) != 0) { + // codeStream.iconst_1(); + // } else { + // if (trueLabel != null) { + // codeStream.goto_(trueLabel); + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // } else { + // // x | + // if ((bits & OnlyValueRequiredMASK) != 0) { + // left.generateCode(currentScope, codeStream, valueRequired); + // } else { + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // } + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // } + // return; + // } + // } + // // default case + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // codeStream.ior(); + // if ((bits & OnlyValueRequiredMASK) == 0) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicit falling through the FALSE case + // codeStream.ifne(trueLabel); + // } + // } else { + // // implicit falling through the TRUE case + // if (trueLabel == null) { + // codeStream.ifeq(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // } + // + // /** + // * Boolean generation for ^ + // */ + // public void generateOptimizedLogicalXor( + // BlockScope currentScope, + // CodeStream codeStream, + // Label trueLabel, + // Label falseLabel, + // boolean valueRequired) { + // + // Constant condConst; + // if ((left.implicitConversion & 0xF) == T_boolean) { + // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) { + // if (condConst.booleanValue() == true) { + // // ^ x + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // falseLabel, + // trueLabel, + // valueRequired); + // } else { + // // ^ x + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // if ((bits & OnlyValueRequiredMASK) != 0) { + // right.generateCode(currentScope, codeStream, valueRequired); + // } else { + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // } + // } + // return; + // } + // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) { + // if (condConst.booleanValue() == true) { + // // x ^ + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // falseLabel, + // trueLabel, + // valueRequired); + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // } else { + // // x ^ + // if ((bits & OnlyValueRequiredMASK) != 0) { + // left.generateCode(currentScope, codeStream, valueRequired); + // } else { + // left.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // valueRequired); + // } + // right.generateOptimizedBoolean( + // currentScope, + // codeStream, + // trueLabel, + // falseLabel, + // false); + // } + // return; + // } + // } + // // default case + // left.generateCode(currentScope, codeStream, valueRequired); + // right.generateCode(currentScope, codeStream, valueRequired); + // if (valueRequired) { + // codeStream.ixor(); + // if ((bits & OnlyValueRequiredMASK) == 0) { + // if (falseLabel == null) { + // if (trueLabel != null) { + // // implicit falling through the FALSE case + // codeStream.ifne(trueLabel); + // } + // } else { + // // implicit falling through the TRUE case + // if (trueLabel == null) { + // codeStream.ifeq(falseLabel); + // } else { + // // no implicit fall through TRUE/FALSE --> should never occur + // } + // } + // } + // } + // // reposition the endPC + // codeStream.updateLastRecordedEndPC(codeStream.position); + // } + // + // public void generateOptimizedStringBuffer( + // BlockScope blockScope, + // CodeStream codeStream, + // int typeID) { + // + // /* In the case trying to make a string concatenation, there is no need to + // create a new + // * string buffer, thus use a lower-level API for code generation involving + // only the + // * appending of arguments to the existing StringBuffer + // */ + // + // if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) + // && ((bits & ReturnTypeIDMASK) == T_String)) { + // if (constant != NotAConstant) { + // codeStream.generateConstant(constant, implicitConversion); + // codeStream.invokeStringBufferAppendForType(implicitConversion & 0xF); + // } else { + // int pc = codeStream.position; + // left.generateOptimizedStringBuffer( + // blockScope, + // codeStream, + // left.implicitConversion & 0xF); + // codeStream.recordPositionsFrom(pc, left.sourceStart); + // pc = codeStream.position; + // right.generateOptimizedStringBuffer( + // blockScope, + // codeStream, + // right.implicitConversion & 0xF); + // codeStream.recordPositionsFrom(pc, right.sourceStart); + // } + // } else { + // super.generateOptimizedStringBuffer(blockScope, codeStream, typeID); + // } + // } + // + // public void generateOptimizedStringBufferCreation( + // BlockScope blockScope, + // CodeStream codeStream, + // int typeID) { + // + // /* In the case trying to make a string concatenation, there is no need to + // create a new + // * string buffer, thus use a lower-level API for code generation involving + // only the + // * appending of arguments to the existing StringBuffer + // */ + // + // if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) + // && ((bits & ReturnTypeIDMASK) == T_String)) { + // if (constant != NotAConstant) { + // codeStream.newStringBuffer(); // new: java.lang.StringBuffer + // codeStream.dup(); + // codeStream.ldc(constant.stringValue()); + // codeStream.invokeStringBufferStringConstructor(); + // // invokespecial: java.lang.StringBuffer.(Ljava.lang.String;)V + // } else { + // int pc = codeStream.position; + // left.generateOptimizedStringBufferCreation( + // blockScope, + // codeStream, + // left.implicitConversion & 0xF); + // codeStream.recordPositionsFrom(pc, left.sourceStart); + // pc = codeStream.position; + // right.generateOptimizedStringBuffer( + // blockScope, + // codeStream, + // right.implicitConversion & 0xF); + // codeStream.recordPositionsFrom(pc, right.sourceStart); + // } + // } else { + // super.generateOptimizedStringBufferCreation(blockScope, codeStream, + // typeID); + // } + // } + // + // public boolean isCompactableOperation() { + // + // return true; + // } + // + // public void optimizedBooleanConstant(int leftId, int operator, int + // rightId) { + // + // switch (operator) { + // case AND : + // if ((leftId != T_boolean) || (rightId != T_boolean)) + // return; + // case AND_AND : + // Constant cst; + // if ((cst = left.optimizedBooleanConstant()) != NotAConstant) { + // if (cst.booleanValue() == false) { // left is equivalent to false + // optimizedBooleanConstant = cst; // constant(false) + // return; + // } else { //left is equivalent to true + // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { + // optimizedBooleanConstant = cst; + // // the conditional result is equivalent to the right conditional value + // } + // return; + // } + // } + // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { + // if (cst.booleanValue() == false) { // right is equivalent to false + // optimizedBooleanConstant = cst; // constant(false) + // } + // } + // return; + // case OR : + // if ((leftId != T_boolean) || (rightId != T_boolean)) + // return; + // case OR_OR : + // if ((cst = left.optimizedBooleanConstant()) != NotAConstant) { + // if (cst.booleanValue() == true) { // left is equivalent to true + // optimizedBooleanConstant = cst; // constant(true) + // return; + // } else { //left is equivalent to false + // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { + // optimizedBooleanConstant = cst; + // } + // return; + // } + // } + // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { + // if (cst.booleanValue() == true) { // right is equivalent to true + // optimizedBooleanConstant = cst; // constant(true) + // } + // } + // } + // } + public StringBuffer printExpressionNoParenthesis(int indent, + StringBuffer output) { + + left.printExpression(indent, output).append(' ').append( + operatorToString()).append(' '); + return right.printExpression(0, output); + } + + public TypeBinding resolveType(BlockScope scope) { + + // use the id of the type to navigate into the table + TypeBinding leftTb = left.resolveType(scope); + TypeBinding rightTb = right.resolveType(scope); + if (leftTb == null || rightTb == null) { + constant = Constant.NotAConstant; + return null; + } + int leftId = leftTb.id; + int rightId = rightTb.id; + if (leftId > 15 || rightId > 15) { // must convert String + Object || + // Object + String + if (leftId == T_String) { + rightId = T_Object; + } else if (rightId == T_String) { + leftId = T_Object; + } else { + constant = Constant.NotAConstant; + scope.problemReporter().invalidOperator(this, leftTb, rightTb); + return null; + } + } + if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) { + if (leftId == T_String + && rightTb.isArrayType() + && ((ArrayBinding) rightTb).elementsType(scope) == CharBinding) + scope + .problemReporter() + .signalNoImplicitStringConversionForCharArrayExpression( + right); + else if (rightId == T_String + && leftTb.isArrayType() + && ((ArrayBinding) leftTb).elementsType(scope) == CharBinding) + scope + .problemReporter() + .signalNoImplicitStringConversionForCharArrayExpression( + left); + } + + // the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 <<0 + + // Don't test for result = 0. If it is zero, some more work is done. + // On the one hand when it is not zero (correct code) we avoid doing the + // test + int result = ResolveTypeTables[(bits & OperatorMASK) >> OperatorSHIFT][(leftId << 4) + + rightId]; + left.implicitConversion = result >>> 12; + right.implicitConversion = (result >>> 4) & 0x000FF; + + bits |= result & 0xF; + switch (result & 0xF) { // record the current ReturnTypeID + // only switch on possible result type..... + case T_boolean: + this.resolvedType = BooleanBinding; + break; + case T_byte: + this.resolvedType = ByteBinding; + break; + case T_char: + this.resolvedType = CharBinding; + break; + case T_double: + this.resolvedType = DoubleBinding; + break; + case T_float: + this.resolvedType = FloatBinding; + break; + case T_int: + this.resolvedType = IntBinding; + break; + case T_long: + this.resolvedType = LongBinding; + break; + case T_String: + this.resolvedType = scope.getJavaLangString(); + break; + default: // error........ + constant = Constant.NotAConstant; + scope.problemReporter().invalidOperator(this, leftTb, rightTb); + return null; + } + + // compute the constant when valid + computeConstant(scope, leftId, rightId); + return this.resolvedType; + } + + public String toStringExpressionNoParenthesis() { + + return left.toStringExpression() + " " + //$NON-NLS-1$ + operatorToString() + " " + //$NON-NLS-1$ + right.toStringExpression(); + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + left.traverse(visitor, scope); + right.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } }