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