package org.eclipse.jdt.internal.compiler.ast; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor; | |
import org.eclipse.jdt.internal.compiler.impl.*; | |
import org.eclipse.jdt.internal.compiler.codegen.*; | |
import org.eclipse.jdt.internal.compiler.flow.*; | |
import org.eclipse.jdt.internal.compiler.lookup.*; | |
public class BinaryExpression extends OperatorExpression { | |
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 ((left.constant != Constant.NotAConstant) && (right.constant != Constant.NotAConstant)) { | |
try { | |
constant = Constant.computeConstantOperation(left.constant, leftId, (bits & OperatorMASK) >> OperatorSHIFT, right.constant, rightId); | |
} catch (ArithmeticException e) { | |
constant = Constant.NotAConstant; | |
// 1.2 no longer throws an exception at compile-time | |
//scope.problemReporter().compileTimeConstantThrowsArithmeticException(this); | |
} | |
} else { | |
constant = Constant.NotAConstant; | |
//add some work for the boolean operators & | | |
optimizedBooleanConstant(leftId, (bits & OperatorMASK) >> OperatorSHIFT, rightId); | |
} | |
} | |
public Constant conditionalConstant() { | |
return optimizedBooleanConstant == null ? constant : 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); | |
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); | |
} | |
/** | |
* 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)) { | |
int pc = codeStream.position; | |
if (constant.booleanValue() == true) { | |
// constant == true | |
if (valueRequired) { | |
if (falseLabel == null) { | |
// implicit falling through the FALSE case | |
if (trueLabel != null) { | |
codeStream.goto_(trueLabel); | |
} | |
} | |
} | |
} else { | |
if (valueRequired) { | |
if (falseLabel != null) { | |
// implicit falling through the TRUE case | |
if (trueLabel == null) { | |
codeStream.goto_(falseLabel); | |
} | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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 pc = codeStream.position; | |
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 | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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 | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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); | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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); | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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 pc = codeStream.position; | |
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 | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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 | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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); | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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); | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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 pc = codeStream.position; | |
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.recordPositionsFrom(pc, this); | |
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.recordPositionsFrom(pc, this); | |
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.recordPositionsFrom(pc, this); | |
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.recordPositionsFrom(pc, this); | |
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 pc = codeStream.position; | |
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 | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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 | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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); | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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); | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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) { | |
int pc = codeStream.position; | |
Constant condConst; | |
if ((left.implicitConversion & 0xF) == T_boolean) { | |
if ((condConst = left.conditionalConstant()) != NotAConstant) { | |
if (condConst.booleanValue() == true) { | |
// <something equivalent to 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 { | |
// <something equivalent to false> & 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); | |
} | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
return; | |
} | |
if ((condConst = right.conditionalConstant()) != NotAConstant) { | |
if (condConst.booleanValue() == true) { | |
// x & <something equivalent to true> | |
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 & <something equivalent to false> | |
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); | |
} | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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 | |
} | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
} | |
/** | |
* Boolean generation for | | |
*/ | |
public void generateOptimizedLogicalOr(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { | |
int pc = codeStream.position; | |
Constant condConst; | |
if ((left.implicitConversion & 0xF) == T_boolean) { | |
if ((condConst = left.conditionalConstant()) != NotAConstant) { | |
if (condConst.booleanValue() == true) { | |
// <something equivalent to 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); | |
} | |
} | |
} | |
} else { | |
// <something equivalent to false> | 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); | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
return; | |
} | |
if ((condConst = right.conditionalConstant()) != NotAConstant) { | |
if (condConst.booleanValue() == true) { | |
// x | <something equivalent to true> | |
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); | |
} | |
} | |
} | |
} else { | |
// x | <something equivalent to false> | |
if ((bits & OnlyValueRequiredMASK) != 0) { | |
left.generateCode(currentScope, codeStream, valueRequired); | |
} else { | |
left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); | |
} | |
right.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, false); | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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 | |
} | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
} | |
/** | |
* Boolean generation for ^ | |
*/ | |
public void generateOptimizedLogicalXor(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { | |
int pc = codeStream.position; | |
Constant condConst; | |
if ((left.implicitConversion & 0xF) == T_boolean) { | |
if ((condConst = left.conditionalConstant()) != NotAConstant) { | |
if (condConst.booleanValue() == true) { | |
// <something equivalent to true> ^ x | |
left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, false); | |
right.generateOptimizedBoolean(currentScope, codeStream, falseLabel, trueLabel, valueRequired); | |
} else { | |
// <something equivalent to false> ^ 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); | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
return; | |
} | |
if ((condConst = right.conditionalConstant()) != NotAConstant) { | |
if (condConst.booleanValue() == true) { | |
// x ^ <something equivalent to true> | |
left.generateOptimizedBoolean(currentScope, codeStream, falseLabel, trueLabel, valueRequired); | |
right.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, false); | |
} else { | |
// x ^ <something equivalent to false> | |
if ((bits & OnlyValueRequiredMASK) != 0) { | |
left.generateCode(currentScope, codeStream, valueRequired); | |
} else { | |
left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); | |
} | |
right.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, false); | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
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 | |
} | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
} | |
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); | |
pc = codeStream.position; | |
right.generateOptimizedStringBuffer(blockScope, codeStream, right.implicitConversion & 0xF); | |
codeStream.recordPositionsFrom(pc, right); | |
} | |
} 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.<init>(Ljava.lang.String;)V | |
} else { | |
int pc = codeStream.position; | |
left.generateOptimizedStringBufferCreation(blockScope, codeStream, left.implicitConversion & 0xF); | |
codeStream.recordPositionsFrom(pc, left); | |
pc = codeStream.position; | |
right.generateOptimizedStringBuffer(blockScope, codeStream, right.implicitConversion & 0xF); | |
codeStream.recordPositionsFrom(pc, right); | |
} | |
} 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.conditionalConstant()) != NotAConstant) { | |
if (cst.booleanValue() == false) { // left is equivalent to false | |
optimizedBooleanConstant = cst; // constant(false) | |
return; | |
} else { //left is equivalent to true | |
if ((cst = right.conditionalConstant()) != NotAConstant) { | |
optimizedBooleanConstant = cst; // the conditional result is equivalent to the right conditional value | |
} | |
return; | |
} | |
} | |
if ((cst = right.conditionalConstant()) != 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.conditionalConstant()) != NotAConstant) { | |
if (cst.booleanValue() == true) { // left is equivalent to true | |
optimizedBooleanConstant = cst; // constant(true) | |
return; | |
} else { //left is equivalent to false | |
if ((cst = right.conditionalConstant()) != NotAConstant) { | |
optimizedBooleanConstant = Constant.fromValue(!cst.booleanValue()); // the conditional result is equivalent to the opposite of the right conditional value | |
} | |
return; | |
} | |
} | |
if ((cst = right.conditionalConstant()) != NotAConstant) { | |
if (cst.booleanValue() == true) { // right is equivalent to true | |
optimizedBooleanConstant = cst; // constant(true) | |
} | |
} | |
} | |
} | |
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; | |
TypeBinding type; | |
bits |= result & 0xF; | |
switch (result & 0xF) {// record the current ReturnTypeID | |
// only switch on possible result type..... | |
case T_boolean : | |
type = BooleanBinding; | |
break; | |
case T_byte : | |
type = ByteBinding; | |
break; | |
case T_char : | |
type = CharBinding; | |
break; | |
case T_double : | |
type = DoubleBinding; | |
break; | |
case T_float : | |
type = FloatBinding; | |
break; | |
case T_int : | |
type = IntBinding; | |
break; | |
case T_long : | |
type = LongBinding; | |
break; | |
case T_String : | |
type = 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 type; | |
} | |
public String toStringExpressionNoParenthesis(){ | |
/* slow code*/ | |
return left.toStringExpression() + " " + //$NON-NLS-1$ | |
operatorToString() + " " + //$NON-NLS-1$ | |
right.toStringExpression() ; } | |
public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { | |
if (visitor.visit(this, scope)) { | |
left.traverse(visitor, scope); | |
right.traverse(visitor, scope); | |
} | |
visitor.endVisit(this, scope); | |
} | |
} |