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