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);
}
}
