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