first scanner /parser copied from the jdt java version
[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.*;
15 import net.sourceforge.phpdt.internal.compiler.flow.*;
16 import net.sourceforge.phpdt.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         this.operator = operator ;
31 }
32 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
33         // record setting a variable: various scenarii are possible, setting an array reference, 
34         // a field reference, a blank final field reference, a field of an enclosing instance or 
35         // just a local variable.
36
37         return lhs.analyseAssignment(currentScope, flowContext, flowInfo, this, true).unconditionalInits();
38 }
39 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
40
41         // various scenarii are possible, setting an array reference, 
42         // a field reference, a blank final field reference, a field of an enclosing instance or 
43         // just a local variable.
44
45         int pc = codeStream.position;
46         lhs.generateCompoundAssignment(currentScope, codeStream, expression, operator, assignmentImplicitConversion, valueRequired);
47         if (valueRequired) {
48                 codeStream.generateImplicitConversion(implicitConversion);
49         }
50         codeStream.recordPositionsFrom(pc, this.sourceStart);
51 }
52 public String operatorToString() {
53         switch (operator) {
54                 case PLUS :
55                         return "+="; //$NON-NLS-1$
56                 case MINUS :
57                         return "-="; //$NON-NLS-1$
58                 case MULTIPLY :
59                         return "*="; //$NON-NLS-1$
60                 case DIVIDE :
61                         return "/="; //$NON-NLS-1$
62                 case AND :
63                         return "&="; //$NON-NLS-1$
64                 case OR :
65                         return "|="; //$NON-NLS-1$
66                 case XOR :
67                         return "^="; //$NON-NLS-1$
68                 case REMAINDER :
69                         return "%="; //$NON-NLS-1$
70                 case LEFT_SHIFT :
71                         return "<<="; //$NON-NLS-1$
72                 case RIGHT_SHIFT :
73                         return ">>="; //$NON-NLS-1$
74                 case UNSIGNED_RIGHT_SHIFT :
75                         return ">>>="; //$NON-NLS-1$
76         };
77         return "unknown operator"; //$NON-NLS-1$
78 }
79 public TypeBinding resolveType(BlockScope scope) {
80         constant = NotAConstant;
81         TypeBinding lhsType = lhs.resolveType(scope);
82         TypeBinding expressionType = expression.resolveType(scope);
83         if (lhsType == null || expressionType == null)
84                 return null;
85
86         int lhsId = lhsType.id;
87         int expressionId = expressionType.id;
88         if (restrainUsageToNumericTypes() && !lhsType.isNumericType()) {
89                 scope.problemReporter().operatorOnlyValidOnNumericType(this, lhsType, expressionType);
90                 return null;
91         }
92         if (lhsId > 15 || expressionId > 15) {
93                 if (lhsId != T_String) { // String += Object is valid wheraas Object -= String is not
94                         scope.problemReporter().invalidOperator(this, lhsType, expressionType);
95                         return null;
96                 }
97                 expressionId = T_Object; // use the Object has tag table
98         }
99
100         // the code is an int
101         // (cast)  left   Op (cast)  rigth --> result 
102         //  0000   0000       0000   0000      0000
103         //  <<16   <<12       <<8     <<4        <<0
104
105         // the conversion is stored INTO the reference (info needed for the code gen)
106         int result = OperatorExpression.ResolveTypeTables[operator][ (lhsId << 4) + expressionId];
107         if (result == T_undefined) {
108                 scope.problemReporter().invalidOperator(this, lhsType, expressionType);
109                 return null;
110         }
111         if (operator == PLUS){
112                 if(scope.isJavaLangObject(lhsType)) {
113                         // <Object> += <String> is illegal
114                         scope.problemReporter().invalidOperator(this, lhsType, expressionType);
115                         return null;
116                 } else if ((lhsType.isNumericType() || lhsId == T_boolean) && !expressionType.isNumericType()){
117                         // <int | boolean> += <String> is illegal
118                         scope.problemReporter().invalidOperator(this, lhsType, expressionType);
119                         return null;
120                 }
121         }
122         lhs.implicitConversion = result >>> 12;
123         expression.implicitConversion = (result >>> 4) & 0x000FF;
124         assignmentImplicitConversion = (lhsId << 4) + (result & 0x0000F);
125         return lhsType;
126 }
127 public boolean restrainUsageToNumericTypes(){
128         return false ;}
129 public String toStringExpressionNoParenthesis() {
130
131         return  lhs.toStringExpression() + " " + //$NON-NLS-1$
132                         operatorToString() + " " + //$NON-NLS-1$
133                         expression.toStringExpression() ; }
134 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
135         if (visitor.visit(this, scope)) {
136                 lhs.traverse(visitor, scope);
137                 expression.traverse(visitor, scope);
138         }
139         visitor.endVisit(this, scope);
140 }
141 }