added -J option to preserve unmodified files in preexisting jarfile
[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 & IMPLICIT_CONVERSION_MASK) >> 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 & IMPLICIT_CONVERSION_MASK) >> 4 /* runtime */) {
101                                         case T_int :
102                                                 // ~int
103                                                 this.expression.generateCode(currentScope, codeStream, valueRequired);
104                                                 if (valueRequired) {
105                                                         codeStream.iconst_m1();
106                                                         codeStream.ixor();
107                                                 }
108                                                 break;
109                                         case T_long :
110                                                 this.expression.generateCode(currentScope, codeStream, valueRequired);
111                                                 if (valueRequired) {
112                                                         codeStream.ldc2_w(-1L);
113                                                         codeStream.lxor();
114                                                 }
115                                 }
116                                 break;
117                         case MINUS :
118                                 // - <num>
119                                 if (this.constant != NotAConstant) {
120                                         if (valueRequired) {
121                                                 switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4){ /* runtime */
122                                                         case T_int :
123                                                                 codeStream.generateInlinedValue(this.constant.intValue() * -1);
124                                                                 break;
125                                                         case T_float :
126                                                                 codeStream.generateInlinedValue(this.constant.floatValue() * -1.0f);
127                                                                 break;
128                                                         case T_long :
129                                                                 codeStream.generateInlinedValue(this.constant.longValue() * -1L);
130                                                                 break;
131                                                         case T_double :
132                                                                 codeStream.generateInlinedValue(this.constant.doubleValue() * -1.0);
133                                                 }
134                                         }
135                                 } else {
136                                         this.expression.generateCode(currentScope, codeStream, valueRequired);
137                                         if (valueRequired) {
138                                                 switch ((expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4){ /* runtime type */
139                                                         case T_int :
140                                                                 codeStream.ineg();
141                                                                 break;
142                                                         case T_float :
143                                                                 codeStream.fneg();
144                                                                 break;
145                                                         case T_long :
146                                                                 codeStream.lneg();
147                                                                 break;
148                                                         case T_double :
149                                                                 codeStream.dneg();
150                                                 }
151                                         }
152                                 }
153                                 break;
154                         case PLUS :
155                                 this.expression.generateCode(currentScope, codeStream, valueRequired);
156                 }
157                 if (valueRequired) {
158                         codeStream.generateImplicitConversion(this.implicitConversion);
159                 }
160                 codeStream.recordPositionsFrom(pc, this.sourceStart);
161         }
162
163         /**
164          * Boolean operator code generation
165          *      Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^
166          */
167         public void generateOptimizedBoolean(
168                 BlockScope currentScope,
169                 CodeStream codeStream,
170                 Label trueLabel,
171                 Label falseLabel,
172                 boolean valueRequired) {
173
174                 if ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == T_boolean)) {
175                         super.generateOptimizedBoolean(
176                                 currentScope,
177                                 codeStream,
178                                 trueLabel,
179                                 falseLabel,
180                                 valueRequired);
181                         return;
182                 }
183                 if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
184                         this.expression.generateOptimizedBoolean(
185                                 currentScope,
186                                 codeStream,
187                                 falseLabel,
188                                 trueLabel,
189                                 valueRequired);
190                 } else {
191                         super.generateOptimizedBoolean(
192                                 currentScope,
193                                 codeStream,
194                                 trueLabel,
195                                 falseLabel,
196                                 valueRequired);
197                 }
198         }
199
200         public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
201                 
202                 output.append(operatorToString()).append(' ');
203                 return this.expression.printExpression(0, output);
204         } 
205         
206         public TypeBinding resolveType(BlockScope scope) {
207                 
208                 boolean expressionIsCast;
209                 if ((expressionIsCast = this.expression instanceof CastExpression) == true) this.expression.bits |= IgnoreNeedForCastCheckMASK; // will check later on
210                 TypeBinding expressionType = this.expression.resolveType(scope);
211                 if (expressionType == null) {
212                         this.constant = NotAConstant;
213                         return null;
214                 }
215                 int expressionTypeID = expressionType.id;
216                 // autoboxing support
217                 LookupEnvironment env = scope.environment();
218                 boolean use15specifics = env.options.sourceLevel >= JDK1_5;
219                 if (use15specifics) {
220                         if (!expressionType.isBaseType()) {
221                                 expressionTypeID = env.computeBoxingType(expressionType).id;
222                         }
223                 }               
224                 if (expressionTypeID > 15) {
225                         this.constant = NotAConstant;
226                         scope.problemReporter().invalidOperator(this, expressionType);
227                         return null;
228                 }
229         
230                 int tableId;
231                 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
232                         case NOT :
233                                 tableId = AND_AND;
234                                 break;
235                         case TWIDDLE :
236                                 tableId = LEFT_SHIFT;
237                                 break;
238                         default :
239                                 tableId = MINUS;
240                 } //+ and - cases
241         
242                 // the code is an int
243                 // (cast)  left   Op (cast)  rigth --> result
244                 //  0000   0000       0000   0000      0000
245                 //  <<16   <<12       <<8    <<4       <<0
246                 int operatorSignature = OperatorSignatures[tableId][(expressionTypeID << 4) + expressionTypeID];
247                 this.expression.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), expressionType);
248                 this.bits |= operatorSignature & 0xF;
249                 switch (operatorSignature & 0xF) { // only switch on possible result type.....
250                         case T_boolean :
251                                 this.resolvedType = BooleanBinding;
252                                 break;
253                         case T_byte :
254                                 this.resolvedType = ByteBinding;
255                                 break;
256                         case T_char :
257                                 this.resolvedType = CharBinding;
258                                 break;
259                         case T_double :
260                                 this.resolvedType = DoubleBinding;
261                                 break;
262                         case T_float :
263                                 this.resolvedType = FloatBinding;
264                                 break;
265                         case T_int :
266                                 this.resolvedType = IntBinding;
267                                 break;
268                         case T_long :
269                                 this.resolvedType = LongBinding;
270                                 break;
271                         default : //error........
272                                 this.constant = Constant.NotAConstant;
273                                 if (expressionTypeID != T_undefined)
274                                         scope.problemReporter().invalidOperator(this, expressionType);
275                                 return null;
276                 }
277                 // compute the constant when valid
278                 if (this.expression.constant != Constant.NotAConstant) {
279                         this.constant =
280                                 Constant.computeConstantOperation(
281                                         this.expression.constant,
282                                         expressionTypeID,
283                                         (bits & OperatorMASK) >> OperatorSHIFT);
284                 } else {
285                         this.constant = Constant.NotAConstant;
286                         if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
287                                 Constant cst = expression.optimizedBooleanConstant();
288                                 if (cst != Constant.NotAConstant) 
289                                         this.optimizedBooleanConstant = Constant.fromValue(!cst.booleanValue());
290                         }
291                 }
292                 if (expressionIsCast) {
293                 // check need for operand cast
294                         CastExpression.checkNeedForArgumentCast(scope, tableId, operatorSignature, this.expression, expressionTypeID);
295                 }
296                 return this.resolvedType;
297         }
298
299         public void traverse(
300                 ASTVisitor visitor,
301                 BlockScope blockScope) {
302                         
303                 if (visitor.visit(this, blockScope)) {
304                         this.expression.traverse(visitor, blockScope);
305                 }
306                 visitor.endVisit(this, blockScope);
307         }
308 }