bc099294e2c99c00012123e30758f22460663a36
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / UnaryExpression.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.codegen.Label;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
17 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
18 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
21
22 public class UnaryExpression extends OperatorExpression {
23         
24         public Expression expression;
25         public Constant optimizedBooleanConstant;
26
27         public UnaryExpression(Expression expression, int operator) {
28                 this.expression = expression;
29                 this.bits |= operator << OperatorSHIFT; // encode operator
30         }
31
32         public FlowInfo analyseCode(
33                 BlockScope currentScope,
34                 FlowContext flowContext,
35                 FlowInfo flowInfo) {
36                 if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
37                         return expression
38                                 .analyseCode(currentScope, flowContext, flowInfo)
39                                 .asNegatedCondition();
40                 } else {
41                         return expression.analyseCode(currentScope, flowContext, flowInfo);
42                 }
43         }
44
45         public Constant conditionalConstant() {
46                 return optimizedBooleanConstant == null ? constant : optimizedBooleanConstant;
47         }
48
49         /**
50          * Code generation for an unary operation
51          *
52          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
53          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
54          * @param valueRequired boolean
55          */
56         public void generateCode(
57                 BlockScope currentScope,
58                 CodeStream codeStream,
59                 boolean valueRequired) {
60                 int pc = codeStream.position;
61                 Label falseLabel, endifLabel;
62                 if (constant != Constant.NotAConstant) {
63                         // inlined value
64                         if (valueRequired) {
65                                 codeStream.generateConstant(constant, implicitConversion);
66                         }
67                         codeStream.recordPositionsFrom(pc, this.sourceStart);
68                         return;
69                 }
70                 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
71                         case NOT :
72                                 switch (expression.implicitConversion >> 4) /* runtime type */ {
73                                         case T_boolean :
74                                                 // ! <boolean>
75                                                 // Generate code for the condition
76                                                 expression.generateOptimizedBoolean(
77                                                         currentScope,
78                                                         codeStream,
79                                                         null,
80                                                         (falseLabel = new Label(codeStream)),
81                                                         valueRequired);
82                                                 if (valueRequired) {
83                                                         codeStream.iconst_0();
84                                                         if (falseLabel.hasForwardReferences()) {
85                                                                 codeStream.goto_(endifLabel = new Label(codeStream));
86                                                                 codeStream.decrStackSize(1);
87                                                                 falseLabel.place();
88                                                                 codeStream.iconst_1();
89                                                                 endifLabel.place();
90                                                         }
91                                                 } else { // 6596: if (!(a && b)){} - must still place falseLabel
92                                                         falseLabel.place();
93                                                 }                                               
94                                                 break;
95                                 }
96                                 break;
97                         case TWIDDLE :
98                                 switch (expression.implicitConversion >> 4 /* runtime */
99                                         ) {
100                                         case T_int :
101                                                 // ~int
102                                                 expression.generateCode(currentScope, codeStream, valueRequired);
103                                                 if (valueRequired) {
104                                                         codeStream.iconst_m1();
105                                                         codeStream.ixor();
106                                                 }
107                                                 break;
108                                         case T_long :
109                                                 expression.generateCode(currentScope, codeStream, valueRequired);
110                                                 if (valueRequired) {
111                                                         codeStream.ldc2_w(-1L);
112                                                         codeStream.lxor();
113                                                 }
114                                 }
115                                 break;
116                         case MINUS :
117                                 // - <num>
118                                 if (constant != NotAConstant) {
119                                         if (valueRequired) {
120                                                 switch (expression.implicitConversion >> 4 /* runtime */
121                                                         ) {
122                                                         case T_int :
123                                                                 codeStream.generateInlinedValue(constant.intValue() * -1);
124                                                                 break;
125                                                         case T_float :
126                                                                 codeStream.generateInlinedValue(constant.floatValue() * -1.0f);
127                                                                 break;
128                                                         case T_long :
129                                                                 codeStream.generateInlinedValue(constant.longValue() * -1L);
130                                                                 break;
131                                                         case T_double :
132                                                                 codeStream.generateInlinedValue(constant.doubleValue() * -1.0);
133                                                 }
134                                         }
135                                 } else {
136                                         expression.generateCode(currentScope, codeStream, valueRequired);
137                                         if (valueRequired) {
138                                                 switch (expression.implicitConversion >> 4 /* runtime type */
139                                                         ) {
140                                                         case T_int :
141                                                                 codeStream.ineg();
142                                                                 break;
143                                                         case T_float :
144                                                                 codeStream.fneg();
145                                                                 break;
146                                                         case T_long :
147                                                                 codeStream.lneg();
148                                                                 break;
149                                                         case T_double :
150                                                                 codeStream.dneg();
151                                                 }
152                                         }
153                                 }
154                                 break;
155                         case PLUS :
156                                 expression.generateCode(currentScope, codeStream, valueRequired);
157                 }
158                 if (valueRequired) {
159                         codeStream.generateImplicitConversion(implicitConversion);
160                 }
161                 codeStream.recordPositionsFrom(pc, this.sourceStart);
162         }
163
164         /**
165          * Boolean operator code generation
166          *      Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^
167          */
168         public void generateOptimizedBoolean(
169                 BlockScope currentScope,
170                 CodeStream codeStream,
171                 Label trueLabel,
172                 Label falseLabel,
173                 boolean valueRequired) {
174
175                 if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
176                         super.generateOptimizedBoolean(
177                                 currentScope,
178                                 codeStream,
179                                 trueLabel,
180                                 falseLabel,
181                                 valueRequired);
182                         return;
183                 }
184                 if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
185                         expression.generateOptimizedBoolean(
186                                 currentScope,
187                                 codeStream,
188                                 falseLabel,
189                                 trueLabel,
190                                 valueRequired);
191                 } else {
192                         super.generateOptimizedBoolean(
193                                 currentScope,
194                                 codeStream,
195                                 trueLabel,
196                                 falseLabel,
197                                 valueRequired);
198                 }
199         }
200
201         public TypeBinding resolveType(BlockScope scope) {
202                 TypeBinding expressionTb = expression.resolveType(scope);
203                 if (expressionTb == null) {
204                         constant = NotAConstant;
205                         return null;
206                 }
207                 int expressionId = expressionTb.id;
208                 if (expressionId > 15) {
209                         constant = NotAConstant;
210                         scope.problemReporter().invalidOperator(this, expressionTb);
211                         return null;
212                 }
213
214                 int tableId;
215                 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
216                         case NOT :
217                                 tableId = AND_AND;
218                                 break;
219                         case TWIDDLE :
220                                 tableId = LEFT_SHIFT;
221                                 break;
222                         default :
223                                 tableId = MINUS;
224                 } //+ and - cases
225
226                 // the code is an int
227                 // (cast)  left   Op (cast)  rigth --> result
228                 //  0000   0000       0000   0000      0000
229                 //  <<16   <<12       <<8    <<4       <<0
230                 int result = ResolveTypeTables[tableId][(expressionId << 4) + expressionId];
231                 expression.implicitConversion = result >>> 12;
232                 bits |= result & 0xF;
233                 switch (result & 0xF) { // only switch on possible result type.....
234                         case T_boolean :
235                                 this.typeBinding = BooleanBinding;
236                                 break;
237                         case T_byte :
238                                 this.typeBinding = ByteBinding;
239                                 break;
240                         case T_char :
241                                 this.typeBinding = CharBinding;
242                                 break;
243                         case T_double :
244                                 this.typeBinding = DoubleBinding;
245                                 break;
246                         case T_float :
247                                 this.typeBinding = FloatBinding;
248                                 break;
249                         case T_int :
250                                 this.typeBinding = IntBinding;
251                                 break;
252                         case T_long :
253                                 this.typeBinding = LongBinding;
254                                 break;
255                         default : //error........
256                                 constant = Constant.NotAConstant;
257                                 if (expressionId != T_undefined)
258                                         scope.problemReporter().invalidOperator(this, expressionTb);
259                                 return null;
260                 }
261                 // compute the constant when valid
262                 if (expression.constant != Constant.NotAConstant) {
263                         constant =
264                                 Constant.computeConstantOperation(
265                                         expression.constant,
266                                         expressionId,
267                                         (bits & OperatorMASK) >> OperatorSHIFT);
268                 } else {
269                         constant = Constant.NotAConstant;
270                         if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
271                                 Constant cst = expression.conditionalConstant();
272                                 if (cst.typeID() == T_boolean)
273                                         optimizedBooleanConstant = Constant.fromValue(!cst.booleanValue());
274                         }
275                 }
276                 return this.typeBinding;
277         }
278
279         public String toStringExpressionNoParenthesis() {
280                 return operatorToString() + " " + expression.toStringExpression(); //$NON-NLS-1$
281         } 
282         
283         public void traverse(
284                 IAbstractSyntaxTreeVisitor visitor,
285                 BlockScope blockScope) {
286                 if (visitor.visit(this, blockScope)) {
287                         expression.traverse(visitor, blockScope);
288                 }
289                 visitor.endVisit(this, blockScope);
290         }
291 }