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