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
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
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;
24 public abstract class Expression extends Statement {
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()
31 public int implicitConversion;
33 public Constant constant;
39 public FlowInfo analyseCode(
40 BlockScope currentScope,
41 FlowContext flowContext,
43 boolean valueRequired) {
45 return analyseCode(currentScope, flowContext, flowInfo);
48 public Constant conditionalConstant() {
53 public static final boolean isConstantValueRepresentable(
58 //true if there is no loss of precision while casting.
59 // constantTypeID == constant.typeID
60 if (targetTypeID == constantTypeID)
62 switch (targetTypeID) {
64 switch (constantTypeID) {
68 return constant.doubleValue() == constant.charValue();
70 return constant.floatValue() == constant.charValue();
72 return constant.intValue() == constant.charValue();
74 return constant.shortValue() == constant.charValue();
76 return constant.byteValue() == constant.charValue();
78 return constant.longValue() == constant.charValue();
80 return false;//boolean
84 switch (constantTypeID) {
86 return constant.charValue() == constant.floatValue();
88 return constant.doubleValue() == constant.floatValue();
92 return constant.intValue() == constant.floatValue();
94 return constant.shortValue() == constant.floatValue();
96 return constant.byteValue() == constant.floatValue();
98 return constant.longValue() == constant.floatValue();
100 return false;//boolean
104 switch (constantTypeID) {
106 return constant.charValue() == constant.doubleValue();
110 return constant.floatValue() == constant.doubleValue();
112 return constant.intValue() == constant.doubleValue();
114 return constant.shortValue() == constant.doubleValue();
116 return constant.byteValue() == constant.doubleValue();
118 return constant.longValue() == constant.doubleValue();
120 return false; //boolean
124 switch (constantTypeID) {
126 return constant.charValue() == constant.byteValue();
128 return constant.doubleValue() == constant.byteValue();
130 return constant.floatValue() == constant.byteValue();
132 return constant.intValue() == constant.byteValue();
134 return constant.shortValue() == constant.byteValue();
138 return constant.longValue() == constant.byteValue();
140 return false; //boolean
144 switch (constantTypeID) {
146 return constant.charValue() == constant.shortValue();
148 return constant.doubleValue() == constant.shortValue();
150 return constant.floatValue() == constant.shortValue();
152 return constant.intValue() == constant.shortValue();
156 return constant.byteValue() == constant.shortValue();
158 return constant.longValue() == constant.shortValue();
160 return false; //boolean
164 switch (constantTypeID) {
166 return constant.charValue() == constant.intValue();
168 return constant.doubleValue() == constant.intValue();
170 return constant.floatValue() == constant.intValue();
174 return constant.shortValue() == constant.intValue();
176 return constant.byteValue() == constant.intValue();
178 return constant.longValue() == constant.intValue();
180 return false; //boolean
184 switch (constantTypeID) {
186 return constant.charValue() == constant.longValue();
188 return constant.doubleValue() == constant.longValue();
190 return constant.floatValue() == constant.longValue();
192 return constant.intValue() == constant.longValue();
194 return constant.shortValue() == constant.longValue();
196 return constant.byteValue() == constant.longValue();
200 return false; //boolean
204 return false; //boolean
209 * Expression statements are plain expressions, however they generate like
210 * normal expressions with no value required.
212 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
213 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
215 public void generateCode(BlockScope currentScope, CodeStream codeStream) {
217 if ((bits & IsReachableMASK) == 0) {
220 generateCode(currentScope, codeStream, false);
224 * Every expression is responsible for generating its implicit conversion when necessary.
226 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
227 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
228 * @param valueRequired boolean
230 public void generateCode(
231 BlockScope currentScope,
232 CodeStream codeStream,
233 boolean valueRequired) {
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);
241 // actual non-constant code generation
242 throw new ShouldNotImplement(Util.bind("ast.missingCode")); //$NON-NLS-1$
247 * Default generation of a boolean value
249 public void generateOptimizedBoolean(
250 BlockScope currentScope,
251 CodeStream codeStream,
254 boolean valueRequired) {
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
259 if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
260 int pc = codeStream.position;
261 if (constant.booleanValue() == true) {
264 if (falseLabel == null) {
265 // implicit falling through the FALSE case
266 if (trueLabel != null) {
267 codeStream.goto_(trueLabel);
273 if (falseLabel != null) {
274 // implicit falling through the TRUE case
275 if (trueLabel == null) {
276 codeStream.goto_(falseLabel);
281 codeStream.recordPositionsFrom(pc, this.sourceStart);
284 generateCode(currentScope, codeStream, valueRequired);
286 int position = codeStream.position;
288 if (falseLabel == null) {
289 if (trueLabel != null) {
290 // Implicit falling through the FALSE case
291 codeStream.ifne(trueLabel);
294 if (trueLabel == null) {
295 // Implicit falling through the TRUE case
296 codeStream.ifeq(falseLabel);
298 // No implicit fall through TRUE/FALSE --> should never occur
302 // reposition the endPC
303 codeStream.updateLastRecordedEndPC(position);
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.
311 public void generateOptimizedStringBuffer(
312 BlockScope blockScope,
313 net.sourceforge.phpdt.internal.compiler.codegen.CodeStream codeStream,
316 generateCode(blockScope, codeStream, true);
317 codeStream.invokeStringBufferAppendForType(typeID);
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.
324 public void generateOptimizedStringBufferCreation(
325 BlockScope blockScope,
326 CodeStream codeStream,
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();
335 codeStream.invokeStringBufferDefaultConstructor();
336 generateCode(blockScope, codeStream, true);
337 codeStream.invokeStringBufferAppendForType(T_Object);
340 codeStream.newStringBuffer();
342 if ((typeID == T_String) || (typeID == T_null)) {
343 if (constant != NotAConstant) {
344 codeStream.ldc(constant.stringValue());
346 generateCode(blockScope, codeStream, true);
347 codeStream.invokeStringValueOf(T_Object);
350 generateCode(blockScope, codeStream, true);
351 codeStream.invokeStringValueOf(typeID);
353 codeStream.invokeStringBufferStringConstructor();
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) {
361 if (runtimeTimeType == null || compileTimeType == null)
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;
374 switch (runtimeTimeType.id) {
378 implicitConversion = (T_int << 4) + compileTimeType.id;
384 case T_int : //implicitConversion may result in i2i which will result in NO code gen
386 implicitConversion = (runtimeTimeType.id << 4) + compileTimeType.id;
388 default : //nothing on regular object ref
392 public boolean isCompactableOperation() {
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) {
405 if (constant == Constant.NotAConstant)
407 if (constantType == targetType)
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);
421 public boolean isTypeReference() {
425 public void resolve(BlockScope scope) {
426 // drops the returning expression's type whatever the type is.
428 this.resolveType(scope);
432 public TypeBinding resolveType(BlockScope scope) {
433 // by default... subclasses should implement a better TC if required.
438 public TypeBinding resolveTypeExpecting(
440 TypeBinding expectedTb) {
442 TypeBinding thisTb = this.resolveType(scope);
445 if (!BlockScope.areTypesCompatible(thisTb, expectedTb)) {
446 scope.problemReporter().typeMismatchError(thisTb, expectedTb, this);
452 public String toString(int tab) {
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);
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() {
470 return super.toString(0);
473 public String toStringExpression(int tab) {
474 // default is regular toString expression (qualified allocation expressions redifine this method)
475 return this.toStringExpression();
478 public Expression toTypeReference() {
479 //by default undefined
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.....