blob: 8f3df734453105dff303c12be633b4084ec6c9d8 [file] [log] [blame]
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 CompoundAssignment extends Assignment implements OperatorIds {
public int operator;
public int assignmentImplicitConversion;
// var op exp is equivalent to var = (varType) var op exp
// assignmentImplicitConversion stores the cast needed for the assignment
public CompoundAssignment(Expression lhs, Expression expression,int operator) {
//lhs is always a reference by construction ,
//but is build as an expression ==> the checkcast cannot fail
super(lhs, expression);
this.operator = operator ;
}
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
// record setting a variable: various scenarii are possible, setting an array reference,
// a field reference, a blank final field reference, a field of an enclosing instance or
// just a local variable.
return lhs.analyseAssignment(currentScope, flowContext, flowInfo, this, true).unconditionalInits();
}
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
// various scenarii are possible, setting an array reference,
// a field reference, a blank final field reference, a field of an enclosing instance or
// just a local variable.
int pc = codeStream.position;
lhs.generateCompoundAssignment(currentScope, codeStream, expression, operator, assignmentImplicitConversion, valueRequired);
if (valueRequired) {
codeStream.generateImplicitConversion(implicitConversion);
}
codeStream.recordPositionsFrom(pc, this);
}
public String operatorToString() {
switch (operator) {
case PLUS :
return "+="/*nonNLS*/;
case MINUS :
return "-="/*nonNLS*/;
case MULTIPLY :
return "*="/*nonNLS*/;
case DIVIDE :
return "/="/*nonNLS*/;
case AND :
return "&="/*nonNLS*/;
case OR :
return "|="/*nonNLS*/;
case XOR :
return "^="/*nonNLS*/;
case REMAINDER :
return "%="/*nonNLS*/;
case LEFT_SHIFT :
return "<<="/*nonNLS*/;
case RIGHT_SHIFT :
return ">>="/*nonNLS*/;
case UNSIGNED_RIGHT_SHIFT :
return ">>>="/*nonNLS*/;
};
return "unknown operator"/*nonNLS*/;
}
public TypeBinding resolveType(BlockScope scope) {
constant = NotAConstant;
TypeBinding lhsTb = lhs.resolveType(scope);
TypeBinding expressionTb = expression.resolveType(scope);
if (lhsTb == null || expressionTb == null)
return null;
int lhsId = lhsTb.id;
int expressionId = expressionTb.id;
if (restrainUsageToNumericTypes() && !lhsTb.isNumericType()) {
scope.problemReporter().operatorOnlyValidOnNumericType(this, lhsTb, expressionTb);
return null;
}
if (lhsId > 15 || expressionId > 15) {
if (lhsId != T_String) { // String += Object is valid wheraas Object -= String is not
scope.problemReporter().invalidOperator(this, lhsTb, expressionTb);
return null;
}
expressionId = T_Object; // use the Object has tag table
}
// the code is an int
// (cast) left Op (cast) rigth --> result
// 0000 0000 0000 0000 0000
// <<16 <<12 <<8 <<4 <<0
// the conversion is stored INTO the reference (info needed for the code gen)
int result = OperatorExpression.ResolveTypeTables[operator][ (lhsId << 4) + expressionId];
if (result == T_undefined) {
scope.problemReporter().invalidOperator(this, lhsTb, expressionTb);
return null;
}
if (operator == PLUS && scope.isJavaLangObject(lhsTb)) {
// Object o = "hello";
// o += " world" // <--illegal
scope.problemReporter().invalidOperator(this, lhsTb, expressionTb);
return null;
}
lhs.implicitConversion = result >>> 12;
expression.implicitConversion = (result >>> 4) & 0x000FF;
assignmentImplicitConversion = (lhsId << 4) + (result & 0x0000F);
return lhsTb;
}
public boolean restrainUsageToNumericTypes(){
return false ;}
public String toStringExpressionNoParenthesis() {
return lhs.toStringExpression() + " "/*nonNLS*/ +
operatorToString() + " "/*nonNLS*/ +
expression.toStringExpression() ; }
public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
if (visitor.visit(this, scope)) {
lhs.traverse(visitor, scope);
expression.traverse(visitor, scope);
}
visitor.endVisit(this, scope);
}
}