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