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.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;
20 public abstract class Expression extends Statement {
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()
27 public int implicitConversion;
29 public Constant constant;
35 public FlowInfo analyseCode(
36 BlockScope currentScope,
37 FlowContext flowContext,
39 boolean valueRequired) {
41 return analyseCode(currentScope, flowContext, flowInfo);
44 public Constant conditionalConstant() {
49 public static final boolean isConstantValueRepresentable(
54 //true if there is no loss of precision while casting.
55 // constantTypeID == constant.typeID
56 if (targetTypeID == constantTypeID)
58 switch (targetTypeID) {
60 switch (constantTypeID) {
64 return constant.doubleValue() == constant.charValue();
66 return constant.floatValue() == constant.charValue();
68 return constant.intValue() == constant.charValue();
70 return constant.shortValue() == constant.charValue();
72 return constant.byteValue() == constant.charValue();
74 return constant.longValue() == constant.charValue();
76 return false;//boolean
80 switch (constantTypeID) {
82 return constant.charValue() == constant.floatValue();
84 return constant.doubleValue() == constant.floatValue();
88 return constant.intValue() == constant.floatValue();
90 return constant.shortValue() == constant.floatValue();
92 return constant.byteValue() == constant.floatValue();
94 return constant.longValue() == constant.floatValue();
96 return false;//boolean
100 switch (constantTypeID) {
102 return constant.charValue() == constant.doubleValue();
106 return constant.floatValue() == constant.doubleValue();
108 return constant.intValue() == constant.doubleValue();
110 return constant.shortValue() == constant.doubleValue();
112 return constant.byteValue() == constant.doubleValue();
114 return constant.longValue() == constant.doubleValue();
116 return false; //boolean
120 switch (constantTypeID) {
122 return constant.charValue() == constant.byteValue();
124 return constant.doubleValue() == constant.byteValue();
126 return constant.floatValue() == constant.byteValue();
128 return constant.intValue() == constant.byteValue();
130 return constant.shortValue() == constant.byteValue();
134 return constant.longValue() == constant.byteValue();
136 return false; //boolean
140 switch (constantTypeID) {
142 return constant.charValue() == constant.shortValue();
144 return constant.doubleValue() == constant.shortValue();
146 return constant.floatValue() == constant.shortValue();
148 return constant.intValue() == constant.shortValue();
152 return constant.byteValue() == constant.shortValue();
154 return constant.longValue() == constant.shortValue();
156 return false; //boolean
160 switch (constantTypeID) {
162 return constant.charValue() == constant.intValue();
164 return constant.doubleValue() == constant.intValue();
166 return constant.floatValue() == constant.intValue();
170 return constant.shortValue() == constant.intValue();
172 return constant.byteValue() == constant.intValue();
174 return constant.longValue() == constant.intValue();
176 return false; //boolean
180 switch (constantTypeID) {
182 return constant.charValue() == constant.longValue();
184 return constant.doubleValue() == constant.longValue();
186 return constant.floatValue() == constant.longValue();
188 return constant.intValue() == constant.longValue();
190 return constant.shortValue() == constant.longValue();
192 return constant.byteValue() == constant.longValue();
196 return false; //boolean
200 return false; //boolean
205 * Expression statements are plain expressions, however they generate like
206 * normal expressions with no value required.
208 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
209 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
211 public void generateCode(BlockScope currentScope, CodeStream codeStream) {
213 if ((bits & IsReachableMASK) == 0) {
216 generateCode(currentScope, codeStream, false);
220 * Every expression is responsible for generating its implicit conversion when necessary.
222 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
223 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
224 * @param valueRequired boolean
226 public void generateCode(
227 BlockScope currentScope,
228 CodeStream codeStream,
229 boolean valueRequired) {
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);
237 // actual non-constant code generation
238 throw new ShouldNotImplement(Util.bind("ast.missingCode")); //$NON-NLS-1$
243 * Default generation of a boolean value
245 public void generateOptimizedBoolean(
246 BlockScope currentScope,
247 CodeStream codeStream,
250 boolean valueRequired) {
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
255 if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
256 int pc = codeStream.position;
257 if (constant.booleanValue() == true) {
260 if (falseLabel == null) {
261 // implicit falling through the FALSE case
262 if (trueLabel != null) {
263 codeStream.goto_(trueLabel);
269 if (falseLabel != null) {
270 // implicit falling through the TRUE case
271 if (trueLabel == null) {
272 codeStream.goto_(falseLabel);
277 codeStream.recordPositionsFrom(pc, this.sourceStart);
280 generateCode(currentScope, codeStream, valueRequired);
282 int position = codeStream.position;
284 if (falseLabel == null) {
285 if (trueLabel != null) {
286 // Implicit falling through the FALSE case
287 codeStream.ifne(trueLabel);
290 if (trueLabel == null) {
291 // Implicit falling through the TRUE case
292 codeStream.ifeq(falseLabel);
294 // No implicit fall through TRUE/FALSE --> should never occur
298 // reposition the endPC
299 codeStream.updateLastRecordedEndPC(position);
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.
307 public void generateOptimizedStringBuffer(
308 BlockScope blockScope,
309 net.sourceforge.phpdt.internal.compiler.codegen.CodeStream codeStream,
312 generateCode(blockScope, codeStream, true);
313 codeStream.invokeStringBufferAppendForType(typeID);
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.
320 public void generateOptimizedStringBufferCreation(
321 BlockScope blockScope,
322 CodeStream codeStream,
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();
331 codeStream.invokeStringBufferDefaultConstructor();
332 generateCode(blockScope, codeStream, true);
333 codeStream.invokeStringBufferAppendForType(T_Object);
336 codeStream.newStringBuffer();
338 if ((typeID == T_String) || (typeID == T_null)) {
339 if (constant != NotAConstant) {
340 codeStream.ldc(constant.stringValue());
342 generateCode(blockScope, codeStream, true);
343 codeStream.invokeStringValueOf(T_Object);
346 generateCode(blockScope, codeStream, true);
347 codeStream.invokeStringValueOf(typeID);
349 codeStream.invokeStringBufferStringConstructor();
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) {
357 if (runtimeTimeType == null || compileTimeType == null)
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;
370 switch (runtimeTimeType.id) {
374 implicitConversion = (T_int << 4) + compileTimeType.id;
380 case T_int : //implicitConversion may result in i2i which will result in NO code gen
382 implicitConversion = (runtimeTimeType.id << 4) + compileTimeType.id;
384 default : //nothing on regular object ref
388 public boolean isCompactableOperation() {
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) {
401 if (constant == Constant.NotAConstant)
403 if (constantType == targetType)
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);
417 public boolean isTypeReference() {
421 public void resolve(BlockScope scope) {
422 // drops the returning expression's type whatever the type is.
424 this.resolveType(scope);
428 public TypeBinding resolveType(BlockScope scope) {
429 // by default... subclasses should implement a better TC if required.
434 public TypeBinding resolveTypeExpecting(
436 TypeBinding expectedTb) {
438 TypeBinding thisTb = this.resolveType(scope);
441 if (!scope.areTypesCompatible(thisTb, expectedTb)) {
442 scope.problemReporter().typeMismatchError(thisTb, expectedTb, this);
448 public String toString(int tab) {
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);
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() {
466 return super.toString(0);
469 public String toStringExpression(int tab) {
470 // default is regular toString expression (qualified allocation expressions redifine this method)
471 return this.toStringExpression();
474 public Expression toTypeReference() {
475 //by default undefined
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.....