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