removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / UnaryExpression.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.impl.*;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.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                         
34                 if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
35                         return this.expression
36                                 .analyseCode(currentScope, flowContext, flowInfo)
37                                 .asNegatedCondition();
38                 } else {
39                         return this.expression.analyseCode(currentScope, flowContext, flowInfo);
40                 }
41         }
42
43         public Constant optimizedBooleanConstant() {
44                 
45                 return this.optimizedBooleanConstant == null 
46                                 ? this.constant 
47                                 : this.optimizedBooleanConstant;
48         }
49
50         /**
51          * Code generation for an unary operation
52          *
53          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
54          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
55          * @param valueRequired boolean
56          */
57         public void generateCode(
58                 BlockScope currentScope,
59                 CodeStream codeStream,
60                 boolean valueRequired) {
61                         
62                 int pc = codeStream.position;
63                 Label falseLabel, endifLabel;
64                 if (this.constant != Constant.NotAConstant) {
65                         // inlined value
66                         if (valueRequired) {
67                                 codeStream.generateConstant(this.constant, this.implicitConversion);
68                         }
69                         codeStream.recordPositionsFrom(pc, this.sourceStart);
70                         return;
71                 }
72                 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
73                         case NOT :
74                                 switch (this.expression.implicitConversion >> 4) /* runtime type */ {
75                                         case T_boolean :
76                                                 // ! <boolean>
77                                                 // Generate code for the condition
78                                                 this.expression.generateOptimizedBoolean(
79                                                         currentScope,
80                                                         codeStream,
81                                                         null,
82                                                         (falseLabel = new Label(codeStream)),
83                                                         valueRequired);
84                                                 if (valueRequired) {
85                                                         codeStream.iconst_0();
86                                                         if (falseLabel.hasForwardReferences()) {
87                                                                 codeStream.goto_(endifLabel = new Label(codeStream));
88                                                                 codeStream.decrStackSize(1);
89                                                                 falseLabel.place();
90                                                                 codeStream.iconst_1();
91                                                                 endifLabel.place();
92                                                         }
93                                                 } else { // 6596: if (!(a && b)){} - must still place falseLabel
94                                                         falseLabel.place();
95                                                 }                                               
96                                                 break;
97                                 }
98                                 break;
99                         case TWIDDLE :
100                                 switch (this.expression.implicitConversion >> 4 /* runtime */
101                                         ) {
102                                         case T_int :
103                                                 // ~int
104                                                 this.expression.generateCode(currentScope, codeStream, valueRequired);
105                                                 if (valueRequired) {
106                                                         codeStream.iconst_m1();
107                                                         codeStream.ixor();
108                                                 }
109                                                 break;
110                                         case T_long :
111                                                 this.expression.generateCode(currentScope, codeStream, valueRequired);
112                                                 if (valueRequired) {
113                                                         codeStream.ldc2_w(-1L);
114                                                         codeStream.lxor();
115                                                 }
116                                 }
117                                 break;
118                         case MINUS :
119                                 // - <num>
120                                 if (this.constant != NotAConstant) {
121                                         if (valueRequired) {
122                                                 switch (this.expression.implicitConversion >> 4){ /* runtime */
123                                                         case T_int :
124                                                                 codeStream.generateInlinedValue(this.constant.intValue() * -1);
125                                                                 break;
126                                                         case T_float :
127                                                                 codeStream.generateInlinedValue(this.constant.floatValue() * -1.0f);
128                                                                 break;
129                                                         case T_long :
130                                                                 codeStream.generateInlinedValue(this.constant.longValue() * -1L);
131                                                                 break;
132                                                         case T_double :
133                                                                 codeStream.generateInlinedValue(this.constant.doubleValue() * -1.0);
134                                                 }
135                                         }
136                                 } else {
137                                         this.expression.generateCode(currentScope, codeStream, valueRequired);
138                                         if (valueRequired) {
139                                                 switch (expression.implicitConversion >> 4){ /* runtime type */
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                                 this.expression.generateCode(currentScope, codeStream, valueRequired);
157                 }
158                 if (valueRequired) {
159                         codeStream.generateImplicitConversion(this.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 ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == T_boolean)) {
176                         super.generateOptimizedBoolean(
177                                 currentScope,
178                                 codeStream,
179                                 trueLabel,
180                                 falseLabel,
181                                 valueRequired);
182                         return;
183                 }
184                 if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
185                         this.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 StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
202                 
203                 output.append(operatorToString()).append(' ');
204                 return this.expression.printExpression(0, output);
205         } 
206         
207         public TypeBinding resolveType(BlockScope scope) {
208                 
209                 boolean expressionIsCast;
210                 if ((expressionIsCast = this.expression instanceof CastExpression) == true) this.expression.bits |= IgnoreNeedForCastCheckMASK; // will check later on
211                 TypeBinding expressionType = this.expression.resolveType(scope);
212                 if (expressionType == null) {
213                         this.constant = NotAConstant;
214                         return null;
215                 }
216                 int expressionTypeId = expressionType.id;
217                 if (expressionTypeId > 15) {
218                         this.constant = NotAConstant;
219                         scope.problemReporter().invalidOperator(this, expressionType);
220                         return null;
221                 }
222         
223                 int tableId;
224                 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
225                         case NOT :
226                                 tableId = AND_AND;
227                                 break;
228                         case TWIDDLE :
229                                 tableId = LEFT_SHIFT;
230                                 break;
231                         default :
232                                 tableId = MINUS;
233                 } //+ and - cases
234         
235                 // the code is an int
236                 // (cast)  left   Op (cast)  rigth --> result
237                 //  0000   0000       0000   0000      0000
238                 //  <<16   <<12       <<8    <<4       <<0
239                 int operatorSignature = OperatorSignatures[tableId][(expressionTypeId << 4) + expressionTypeId];
240                 this.expression.implicitConversion = operatorSignature >>> 12;
241                 this.bits |= operatorSignature & 0xF;
242                 switch (operatorSignature & 0xF) { // only switch on possible result type.....
243                         case T_boolean :
244                                 this.resolvedType = BooleanBinding;
245                                 break;
246                         case T_byte :
247                                 this.resolvedType = ByteBinding;
248                                 break;
249                         case T_char :
250                                 this.resolvedType = CharBinding;
251                                 break;
252                         case T_double :
253                                 this.resolvedType = DoubleBinding;
254                                 break;
255                         case T_float :
256                                 this.resolvedType = FloatBinding;
257                                 break;
258                         case T_int :
259                                 this.resolvedType = IntBinding;
260                                 break;
261                         case T_long :
262                                 this.resolvedType = LongBinding;
263                                 break;
264                         default : //error........
265                                 this.constant = Constant.NotAConstant;
266                                 if (expressionTypeId != T_undefined)
267                                         scope.problemReporter().invalidOperator(this, expressionType);
268                                 return null;
269                 }
270                 // compute the constant when valid
271                 if (this.expression.constant != Constant.NotAConstant) {
272                         this.constant =
273                                 Constant.computeConstantOperation(
274                                         this.expression.constant,
275                                         expressionTypeId,
276                                         (bits & OperatorMASK) >> OperatorSHIFT);
277                 } else {
278                         this.constant = Constant.NotAConstant;
279                         if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
280                                 Constant cst = expression.optimizedBooleanConstant();
281                                 if (cst != Constant.NotAConstant) 
282                                         this.optimizedBooleanConstant = Constant.fromValue(!cst.booleanValue());
283                         }
284                 }
285                 if (expressionIsCast) {
286                 // check need for operand cast
287                         CastExpression.checkNeedForArgumentCast(scope, tableId, operatorSignature, this.expression, expressionTypeId);
288                 }
289                 return this.resolvedType;
290         }
291
292         public void traverse(
293                 ASTVisitor visitor,
294                 BlockScope blockScope) {
295                         
296                 if (visitor.visit(this, blockScope)) {
297                         this.expression.traverse(visitor, blockScope);
298                 }
299                 visitor.endVisit(this, blockScope);
300         }
301 }