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