Makefile fixup
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / CompoundAssignment.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
12
13 import org.eclipse.jdt.internal.compiler.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.codegen.*;
15 import org.eclipse.jdt.internal.compiler.flow.*;
16 import org.eclipse.jdt.internal.compiler.lookup.*;
17
18 public class CompoundAssignment extends Assignment implements OperatorIds {
19         public int operator;
20         public int assignmentImplicitConversion;
21
22         //  var op exp is equivalent to var = (varType) var op exp
23         // assignmentImplicitConversion stores the cast needed for the assignment
24
25         public CompoundAssignment(Expression lhs, Expression expression,int operator, int sourceEnd) {
26                 //lhs is always a reference by construction ,
27                 //but is build as an expression ==> the checkcast cannot fail
28         
29                 super(lhs, expression, sourceEnd);
30                 lhs.bits &= ~IsStrictlyAssignedMASK; // tag lhs as NON assigned - it is also a read access
31                 lhs.bits |= IsCompoundAssignedMASK; // tag lhs as assigned by compound
32                 this.operator = operator ;
33         }
34         
35         public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
36                 // record setting a variable: various scenarii are possible, setting an array reference, 
37                 // a field reference, a blank final field reference, a field of an enclosing instance or 
38                 // just a local variable.
39         
40                 return  ((Reference) lhs).analyseAssignment(currentScope, flowContext, flowInfo, this, true).unconditionalInits();
41         }
42         
43         public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
44         
45                 // various scenarii are possible, setting an array reference, 
46                 // a field reference, a blank final field reference, a field of an enclosing instance or 
47                 // just a local variable.
48         
49                 int pc = codeStream.position;
50                  ((Reference) lhs).generateCompoundAssignment(currentScope, codeStream, expression, operator, assignmentImplicitConversion, valueRequired);
51                 if (valueRequired) {
52                         codeStream.generateImplicitConversion(implicitConversion);
53                 }
54                 codeStream.recordPositionsFrom(pc, this.sourceStart);
55         }
56         
57         public String operatorToString() {
58                 switch (operator) {
59                         case PLUS :
60                                 return "+="; //$NON-NLS-1$
61                         case MINUS :
62                                 return "-="; //$NON-NLS-1$
63                         case MULTIPLY :
64                                 return "*="; //$NON-NLS-1$
65                         case DIVIDE :
66                                 return "/="; //$NON-NLS-1$
67                         case AND :
68                                 return "&="; //$NON-NLS-1$
69                         case OR :
70                                 return "|="; //$NON-NLS-1$
71                         case XOR :
72                                 return "^="; //$NON-NLS-1$
73                         case REMAINDER :
74                                 return "%="; //$NON-NLS-1$
75                         case LEFT_SHIFT :
76                                 return "<<="; //$NON-NLS-1$
77                         case RIGHT_SHIFT :
78                                 return ">>="; //$NON-NLS-1$
79                         case UNSIGNED_RIGHT_SHIFT :
80                                 return ">>>="; //$NON-NLS-1$
81                 }
82                 return "unknown operator"; //$NON-NLS-1$
83         }
84         
85         public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
86         
87                 lhs.printExpression(indent, output).append(' ').append(operatorToString()).append(' ');
88                 return expression.printExpression(0, output) ; 
89         }
90         
91         public TypeBinding resolveType(BlockScope scope) {
92                 constant = NotAConstant;
93                 if (!(this.lhs instanceof Reference) || this.lhs.isThis()) {
94                         scope.problemReporter().expressionShouldBeAVariable(this.lhs);
95                         return null;
96                 }
97                 TypeBinding lhsType = lhs.resolveType(scope);
98                 TypeBinding expressionType = expression.resolveType(scope);
99                 if (lhsType == null || expressionType == null)
100                         return null;
101         
102                 int lhsId = lhsType.id;
103                 int expressionId = expressionType.id;
104                 if (restrainUsageToNumericTypes() && !lhsType.isNumericType()) {
105                         scope.problemReporter().operatorOnlyValidOnNumericType(this, lhsType, expressionType);
106                         return null;
107                 }
108                 if (lhsId > 15 || expressionId > 15) {
109                         if (lhsId != T_String) { // String += Thread is valid whereas Thread += String  is not
110                                 scope.problemReporter().invalidOperator(this, lhsType, expressionType);
111                                 return null;
112                         }
113                         expressionId = T_Object; // use the Object has tag table
114                 }
115         
116                 // the code is an int
117                 // (cast)  left   Op (cast)  rigth --> result 
118                 //  0000   0000       0000   0000      0000
119                 //  <<16   <<12       <<8     <<4        <<0
120         
121                 // the conversion is stored INTO the reference (info needed for the code gen)
122                 int result = OperatorExpression.OperatorSignatures[operator][ (lhsId << 4) + expressionId];
123                 if (result == T_undefined) {
124                         scope.problemReporter().invalidOperator(this, lhsType, expressionType);
125                         return null;
126                 }
127                 if (operator == PLUS){
128                         if(lhsId == T_JavaLangObject) {
129                                 // <Object> += <String> is illegal (39248)
130                                 scope.problemReporter().invalidOperator(this, lhsType, expressionType);
131                                 return null;
132                         } else {
133                                 // <int | boolean> += <String> is illegal
134                                 if ((lhsType.isNumericType() || lhsId == T_boolean) && !expressionType.isNumericType()){
135                                         scope.problemReporter().invalidOperator(this, lhsType, expressionType);
136                                         return null;
137                                 }
138                         }
139                 }
140                 lhs.implicitConversion = result >>> 12;
141                 expression.implicitConversion = (result >>> 4) & 0x000FF;
142                 assignmentImplicitConversion = (lhsId << 4) + (result & 0x0000F);
143                 return this.resolvedType = lhsType;
144         }
145         
146         public boolean restrainUsageToNumericTypes(){
147                 return false ;
148         }
149         
150         public void traverse(ASTVisitor visitor, BlockScope scope) {
151                 if (visitor.visit(this, scope)) {
152                         lhs.traverse(visitor, scope);
153                         expression.traverse(visitor, scope);
154                 }
155                 visitor.endVisit(this, scope);
156         }
157 }