Makefile fixup
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / ast / Expression.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.impl.*;
14 import org.eclipse.jdt.internal.compiler.codegen.*;
15 import org.eclipse.jdt.internal.compiler.flow.*;
16 import org.eclipse.jdt.internal.compiler.lookup.*;
17 import org.eclipse.jdt.internal.compiler.problem.*;
18 import org.eclipse.jdt.internal.compiler.util.Util;
19
20 public abstract class Expression extends Statement {
21         
22         //Some expression may not be used - from a java semantic point
23         //of view only - as statements. Other may. In order to avoid the creation
24         //of wrappers around expression in order to tune them as expression
25         //Expression is a subclass of Statement. See the message isValidJavaStatement()
26
27         public int implicitConversion;
28         public TypeBinding resolvedType;
29         
30         public Constant constant;
31
32         public Expression() {
33                 super();
34         }
35
36         public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
37
38                 return flowInfo;
39         }
40
41         public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
42
43                 return analyseCode(currentScope, flowContext, flowInfo);
44         }
45
46         /**
47          * Constant usable for bytecode pattern optimizations, but cannot be inlined
48          * since it is not strictly equivalent to the definition of constant expressions.
49          * In particular, some side-effects may be required to occur (only the end value
50          * is known).
51          * @return Constant known to be of boolean type
52          */ 
53         public Constant optimizedBooleanConstant() {
54                 return this.constant;
55         }
56
57         public static final boolean isConstantValueRepresentable(
58                 Constant constant,
59                 int constantTypeID,
60                 int targetTypeID) {
61
62                 //true if there is no loss of precision while casting.
63                 // constantTypeID == constant.typeID
64                 if (targetTypeID == constantTypeID)
65                         return true;
66                 switch (targetTypeID) {
67                         case T_char :
68                                 switch (constantTypeID) {
69                                         case T_char :
70                                                 return true;
71                                         case T_double :
72                                                 return constant.doubleValue() == constant.charValue();
73                                         case T_float :
74                                                 return constant.floatValue() == constant.charValue();
75                                         case T_int :
76                                                 return constant.intValue() == constant.charValue();
77                                         case T_short :
78                                                 return constant.shortValue() == constant.charValue();
79                                         case T_byte :
80                                                 return constant.byteValue() == constant.charValue();
81                                         case T_long :
82                                                 return constant.longValue() == constant.charValue();
83                                         default :
84                                                 return false;//boolean
85                                 } 
86
87                         case T_float :
88                                 switch (constantTypeID) {
89                                         case T_char :
90                                                 return constant.charValue() == constant.floatValue();
91                                         case T_double :
92                                                 return constant.doubleValue() == constant.floatValue();
93                                         case T_float :
94                                                 return true;
95                                         case T_int :
96                                                 return constant.intValue() == constant.floatValue();
97                                         case T_short :
98                                                 return constant.shortValue() == constant.floatValue();
99                                         case T_byte :
100                                                 return constant.byteValue() == constant.floatValue();
101                                         case T_long :
102                                                 return constant.longValue() == constant.floatValue();
103                                         default :
104                                                 return false;//boolean
105                                 } 
106                                 
107                         case T_double :
108                                 switch (constantTypeID) {
109                                         case T_char :
110                                                 return constant.charValue() == constant.doubleValue();
111                                         case T_double :
112                                                 return true;
113                                         case T_float :
114                                                 return constant.floatValue() == constant.doubleValue();
115                                         case T_int :
116                                                 return constant.intValue() == constant.doubleValue();
117                                         case T_short :
118                                                 return constant.shortValue() == constant.doubleValue();
119                                         case T_byte :
120                                                 return constant.byteValue() == constant.doubleValue();
121                                         case T_long :
122                                                 return constant.longValue() == constant.doubleValue();
123                                         default :
124                                                 return false; //boolean
125                                 } 
126                                 
127                         case T_byte :
128                                 switch (constantTypeID) {
129                                         case T_char :
130                                                 return constant.charValue() == constant.byteValue();
131                                         case T_double :
132                                                 return constant.doubleValue() == constant.byteValue();
133                                         case T_float :
134                                                 return constant.floatValue() == constant.byteValue();
135                                         case T_int :
136                                                 return constant.intValue() == constant.byteValue();
137                                         case T_short :
138                                                 return constant.shortValue() == constant.byteValue();
139                                         case T_byte :
140                                                 return true;
141                                         case T_long :
142                                                 return constant.longValue() == constant.byteValue();
143                                         default :
144                                                 return false; //boolean
145                                 } 
146                                 
147                         case T_short :
148                                 switch (constantTypeID) {
149                                         case T_char :
150                                                 return constant.charValue() == constant.shortValue();
151                                         case T_double :
152                                                 return constant.doubleValue() == constant.shortValue();
153                                         case T_float :
154                                                 return constant.floatValue() == constant.shortValue();
155                                         case T_int :
156                                                 return constant.intValue() == constant.shortValue();
157                                         case T_short :
158                                                 return true;
159                                         case T_byte :
160                                                 return constant.byteValue() == constant.shortValue();
161                                         case T_long :
162                                                 return constant.longValue() == constant.shortValue();
163                                         default :
164                                                 return false; //boolean
165                                 } 
166                                 
167                         case T_int :
168                                 switch (constantTypeID) {
169                                         case T_char :
170                                                 return constant.charValue() == constant.intValue();
171                                         case T_double :
172                                                 return constant.doubleValue() == constant.intValue();
173                                         case T_float :
174                                                 return constant.floatValue() == constant.intValue();
175                                         case T_int :
176                                                 return true;
177                                         case T_short :
178                                                 return constant.shortValue() == constant.intValue();
179                                         case T_byte :
180                                                 return constant.byteValue() == constant.intValue();
181                                         case T_long :
182                                                 return constant.longValue() == constant.intValue();
183                                         default :
184                                                 return false; //boolean
185                                 } 
186                                 
187                         case T_long :
188                                 switch (constantTypeID) {
189                                         case T_char :
190                                                 return constant.charValue() == constant.longValue();
191                                         case T_double :
192                                                 return constant.doubleValue() == constant.longValue();
193                                         case T_float :
194                                                 return constant.floatValue() == constant.longValue();
195                                         case T_int :
196                                                 return constant.intValue() == constant.longValue();
197                                         case T_short :
198                                                 return constant.shortValue() == constant.longValue();
199                                         case T_byte :
200                                                 return constant.byteValue() == constant.longValue();
201                                         case T_long :
202                                                 return true;
203                                         default :
204                                                 return false; //boolean
205                                 } 
206                                 
207                         default :
208                                 return false; //boolean
209                 } 
210         }
211
212         /**
213          * Expression statements are plain expressions, however they generate like
214          * normal expressions with no value required.
215          *
216          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
217          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream 
218          */
219         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
220
221                 if ((bits & IsReachableMASK) == 0) {
222                         return;
223                 }
224                 generateCode(currentScope, codeStream, false);
225         }
226
227         /**
228          * Every expression is responsible for generating its implicit conversion when necessary.
229          *
230          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
231          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
232          * @param valueRequired boolean
233          */
234         public void generateCode(
235                 BlockScope currentScope,
236                 CodeStream codeStream,
237                 boolean valueRequired) {
238
239                 if (constant != NotAConstant) {
240                         // generate a constant expression
241                         int pc = codeStream.position;
242                         codeStream.generateConstant(constant, implicitConversion);
243                         codeStream.recordPositionsFrom(pc, this.sourceStart);
244                 } else {
245                         // actual non-constant code generation
246                         throw new ShouldNotImplement(Util.bind("ast.missingCode")); //$NON-NLS-1$
247                 }
248         }
249
250         /**
251          * Default generation of a boolean value
252          * @param currentScope
253          * @param codeStream
254          * @param trueLabel
255          * @param falseLabel
256          * @param valueRequired
257          */
258         public void generateOptimizedBoolean(
259                 BlockScope currentScope,
260                 CodeStream codeStream,
261                 Label trueLabel,
262                 Label falseLabel,
263                 boolean valueRequired) {
264
265                 // a label valued to nil means: by default we fall through the case... 
266                 // both nil means we leave the value on the stack
267
268                 if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
269                         int pc = codeStream.position;
270                         if (constant.booleanValue() == true) {
271                                 // constant == true
272                                 if (valueRequired) {
273                                         if (falseLabel == null) {
274                                                 // implicit falling through the FALSE case
275                                                 if (trueLabel != null) {
276                                                         codeStream.goto_(trueLabel);
277                                                 }
278                                         }
279                                 }
280                         } else {
281                                 if (valueRequired) {
282                                         if (falseLabel != null) {
283                                                 // implicit falling through the TRUE case
284                                                 if (trueLabel == null) {
285                                                         codeStream.goto_(falseLabel);
286                                                 }
287                                         }
288                                 }
289                         }
290                         codeStream.recordPositionsFrom(pc, this.sourceStart);
291                         return;
292                 }
293                 generateCode(currentScope, codeStream, valueRequired);
294                 // branching
295                 int position = codeStream.position;
296                 if (valueRequired) {
297                         if (falseLabel == null) {
298                                 if (trueLabel != null) {
299                                         // Implicit falling through the FALSE case
300                                         codeStream.ifne(trueLabel);
301                                 }
302                         } else {
303                                 if (trueLabel == null) {
304                                         // Implicit falling through the TRUE case
305                                         codeStream.ifeq(falseLabel);
306                                 } else {
307                                         // No implicit fall through TRUE/FALSE --> should never occur
308                                 }
309                         }
310                 }
311                 // reposition the endPC
312                 codeStream.updateLastRecordedEndPC(position);
313         }
314
315         /* Optimized (java) code generation for string concatenations that involve StringBuffer
316          * creation: going through this path means that there is no need for a new StringBuffer
317          * creation, further operands should rather be only appended to the current one.
318          * By default: no optimization.
319          */
320         public void generateOptimizedStringBuffer(
321                 BlockScope blockScope,
322                 org.eclipse.jdt.internal.compiler.codegen.CodeStream codeStream,
323                 int typeID) {
324
325                 if (typeID == T_String && this.constant != NotAConstant && this.constant.stringValue().length() == 0) {
326                         return; // optimize str + ""
327                 }
328                 generateCode(blockScope, codeStream, true);
329                 codeStream.invokeStringBufferAppendForType(typeID);
330         }
331
332         /* Optimized (java) code generation for string concatenations that involve StringBuffer
333          * creation: going through this path means that there is no need for a new StringBuffer
334          * creation, further operands should rather be only appended to the current one.
335          */
336         public void generateOptimizedStringBufferCreation(
337                 BlockScope blockScope,
338                 CodeStream codeStream,
339                 int typeID) {
340
341                 // Optimization only for integers and strings
342                 if (typeID == T_Object) {
343                         // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object)
344                         // append(Object) returns append(valueOf(Object)), which means that the null case is handled by append(String).
345                         codeStream.newStringBuffer();
346                         codeStream.dup();
347                         codeStream.invokeStringBufferDefaultConstructor();
348                         generateCode(blockScope, codeStream, true);
349                         codeStream.invokeStringBufferAppendForType(T_Object);
350                         return;
351                 }
352                 codeStream.newStringBuffer();
353                 codeStream.dup();
354                 if (typeID == T_String || typeID == T_null) {
355                         if (constant != NotAConstant) {
356                                 String stringValue = constant.stringValue();
357                                 if (stringValue.length() == 0) {  // optimize ""+<str> 
358                                         codeStream.invokeStringBufferDefaultConstructor();
359                                         return;
360                                 }
361                                 codeStream.ldc(stringValue);
362                         } else {
363                                 generateCode(blockScope, codeStream, true);
364                                 codeStream.invokeStringValueOf(T_Object);
365                         }
366                 } else {
367                         generateCode(blockScope, codeStream, true);
368                         codeStream.invokeStringValueOf(typeID);
369                 }
370                 codeStream.invokeStringBufferStringConstructor();
371         }
372
373         // Base types need that the widening is explicitly done by the compiler using some bytecode like i2f
374         public void implicitWidening(
375                 TypeBinding runtimeTimeType,
376                 TypeBinding compileTimeType) {
377
378                 if (runtimeTimeType == null || compileTimeType == null)
379                         return;
380
381 //              if (compileTimeType.id == T_null) {
382 //                      // this case is possible only for constant null
383 //                      // The type of runtime is a reference type
384 //                      // The code gen use the constant id thus any value
385 //                      // for the runtime id (akak the <<4) could be used.
386 //                      // T_Object is used as some general T_reference
387 //                      implicitConversion = (T_Object << 4) + T_null;
388 //                      return;
389 //              }
390
391                 switch (runtimeTimeType.id) {
392                         case T_byte :
393                         case T_short :
394                         case T_char :
395                                 implicitConversion = (T_int << 4) + compileTimeType.id;
396                                 break;
397                         case T_String :
398                         case T_float :
399                         case T_boolean :
400                         case T_double :
401                         case T_int : //implicitConversion may result in i2i which will result in NO code gen
402                         case T_long :
403                                 implicitConversion = (runtimeTimeType.id << 4) + compileTimeType.id;
404                                 break;
405                         default : //nothing on regular object ref
406                 }
407         }
408
409         public boolean isCompactableOperation() {
410
411                 return false;
412         }
413
414         //Return true if the conversion is done AUTOMATICALLY by the vm
415         //while the javaVM is an int based-machine, thus for example pushing
416         //a byte onto the stack , will automatically creates a int on the stack
417         //(this request some work d be done by the VM on signed numbers)
418         public boolean isConstantValueOfTypeAssignableToType(
419                 TypeBinding constantType,
420                 TypeBinding targetType) {
421
422                 if (constant == Constant.NotAConstant)
423                         return false;
424                 if (constantType == targetType)
425                         return true;
426                 if (constantType.isBaseType() && targetType.isBaseType()) {
427                         //No free assignment conversion from anything but to integral ones.
428                         if ((constantType == IntBinding
429                                 || BaseTypeBinding.isWidening(T_int, constantType.id))
430                                 && (BaseTypeBinding.isNarrowing(targetType.id, T_int))) {
431                                 //use current explicit conversion in order to get some new value to compare with current one
432                                 return isConstantValueRepresentable(constant, constantType.id, targetType.id);
433                         }
434                 }
435                 return false;
436         }
437
438         public boolean isTypeReference() {
439                 return false;
440         }
441
442         public void resolve(BlockScope scope) {
443                 // drops the returning expression's type whatever the type is.
444
445                 this.resolveType(scope);
446                 return;
447         }
448
449         public TypeBinding resolveType(BlockScope scope) {
450                 // by default... subclasses should implement a better TC if required.
451
452                 return null;
453         }
454
455         public TypeBinding resolveType(ClassScope classScope) {
456                 // by default... subclasses should implement a better TB if required.
457                 return null;
458         }
459
460         public TypeBinding resolveTypeExpecting(
461                 BlockScope scope,
462                 TypeBinding expectedType) {
463
464                 TypeBinding expressionType = this.resolveType(scope);
465                 if (expressionType == null) return null;
466                 if (expressionType == expectedType) return expressionType;
467                 
468                 if (!expressionType.isCompatibleWith(expectedType)) {
469                         scope.problemReporter().typeMismatchError(expressionType, expectedType, this);
470                         return null;
471                 }
472                 return expressionType;
473         }
474
475         public StringBuffer print(int indent, StringBuffer output) {
476                 printIndent(indent, output);
477                 return printExpression(indent, output);
478         }
479
480         public abstract StringBuffer printExpression(int indent, StringBuffer output);
481         
482         public StringBuffer printStatement(int indent, StringBuffer output) {
483                 return print(indent, output).append(";"); //$NON-NLS-1$
484         }
485
486         public Expression toTypeReference() {
487                 //by default undefined
488
489                 //this method is meanly used by the parser in order to transform
490                 //an expression that is used as a type reference in a cast ....
491                 //--appreciate the fact that castExpression and ExpressionWithParenthesis
492                 //--starts with the same pattern.....
493
494                 return this;
495         }
496 }