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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpeclipse.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.codegen.Label;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
17 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
18 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
19 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
20 import net.sourceforge.phpdt.internal.compiler.problem.ShouldNotImplement;
21 import net.sourceforge.phpdt.internal.compiler.util.Util;
23 public abstract class Expression extends Statement {
25 //some expression may not be used - from a java semantic point
26 //of view only - as statements. Other may. In order to avoid the creation
27 //of wrappers around expression in order to tune them as expression
28 //Expression is a subclass of Statement. See the message isValidJavaStatement()
30 public int implicitConversion;
31 public TypeBinding resolvedType;
33 public Constant constant;
39 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
44 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
46 return analyseCode(currentScope, flowContext, flowInfo);
50 * Constant usable for bytecode pattern optimizations, but cannot be inlined
51 * since it is not strictly equivalent to the definition of constant expressions.
52 * In particular, some side-effects may be required to occur (only the end value
54 * Constant is known to be of boolean type
56 public Constant optimizedBooleanConstant() {
61 public static final boolean isConstantValueRepresentable(
66 //true if there is no loss of precision while casting.
67 // constantTypeID == constant.typeID
68 if (targetTypeID == constantTypeID)
70 switch (targetTypeID) {
72 switch (constantTypeID) {
76 return constant.doubleValue() == constant.charValue();
78 return constant.floatValue() == constant.charValue();
80 return constant.intValue() == constant.charValue();
82 return constant.shortValue() == constant.charValue();
84 return constant.byteValue() == constant.charValue();
86 return constant.longValue() == constant.charValue();
88 return false;//boolean
92 switch (constantTypeID) {
94 return constant.charValue() == constant.floatValue();
96 return constant.doubleValue() == constant.floatValue();
100 return constant.intValue() == constant.floatValue();
102 return constant.shortValue() == constant.floatValue();
104 return constant.byteValue() == constant.floatValue();
106 return constant.longValue() == constant.floatValue();
108 return false;//boolean
112 switch (constantTypeID) {
114 return constant.charValue() == constant.doubleValue();
118 return constant.floatValue() == constant.doubleValue();
120 return constant.intValue() == constant.doubleValue();
122 return constant.shortValue() == constant.doubleValue();
124 return constant.byteValue() == constant.doubleValue();
126 return constant.longValue() == constant.doubleValue();
128 return false; //boolean
132 switch (constantTypeID) {
134 return constant.charValue() == constant.byteValue();
136 return constant.doubleValue() == constant.byteValue();
138 return constant.floatValue() == constant.byteValue();
140 return constant.intValue() == constant.byteValue();
142 return constant.shortValue() == constant.byteValue();
146 return constant.longValue() == constant.byteValue();
148 return false; //boolean
152 switch (constantTypeID) {
154 return constant.charValue() == constant.shortValue();
156 return constant.doubleValue() == constant.shortValue();
158 return constant.floatValue() == constant.shortValue();
160 return constant.intValue() == constant.shortValue();
164 return constant.byteValue() == constant.shortValue();
166 return constant.longValue() == constant.shortValue();
168 return false; //boolean
172 switch (constantTypeID) {
174 return constant.charValue() == constant.intValue();
176 return constant.doubleValue() == constant.intValue();
178 return constant.floatValue() == constant.intValue();
182 return constant.shortValue() == constant.intValue();
184 return constant.byteValue() == constant.intValue();
186 return constant.longValue() == constant.intValue();
188 return false; //boolean
192 switch (constantTypeID) {
194 return constant.charValue() == constant.longValue();
196 return constant.doubleValue() == constant.longValue();
198 return constant.floatValue() == constant.longValue();
200 return constant.intValue() == constant.longValue();
202 return constant.shortValue() == constant.longValue();
204 return constant.byteValue() == constant.longValue();
208 return false; //boolean
212 return false; //boolean
217 * Expression statements are plain expressions, however they generate like
218 * normal expressions with no value required.
220 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
221 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
223 // public void generateCode(BlockScope currentScope, CodeStream codeStream) {
225 // if ((bits & IsReachableMASK) == 0) {
228 // generateCode(currentScope, codeStream, false);
232 * Every expression is responsible for generating its implicit conversion when necessary.
234 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
235 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
236 * @param valueRequired boolean
238 // public void generateCode(
239 // BlockScope currentScope,
240 // CodeStream codeStream,
241 // boolean valueRequired) {
243 // if (constant != NotAConstant) {
244 // // generate a constant expression
245 // int pc = codeStream.position;
246 // codeStream.generateConstant(constant, implicitConversion);
247 // codeStream.recordPositionsFrom(pc, this.sourceStart);
249 // // actual non-constant code generation
250 // throw new ShouldNotImplement(Util.bind("ast.missingCode")); //$NON-NLS-1$
255 * Default generation of a boolean value
257 // public void generateOptimizedBoolean(
258 // BlockScope currentScope,
259 // CodeStream codeStream,
262 // boolean valueRequired) {
264 // // a label valued to nil means: by default we fall through the case...
265 // // both nil means we leave the value on the stack
267 // if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
268 // int pc = codeStream.position;
269 // if (constant.booleanValue() == true) {
270 // // constant == true
271 // if (valueRequired) {
272 // if (falseLabel == null) {
273 // // implicit falling through the FALSE case
274 // if (trueLabel != null) {
275 // codeStream.goto_(trueLabel);
280 // if (valueRequired) {
281 // if (falseLabel != null) {
282 // // implicit falling through the TRUE case
283 // if (trueLabel == null) {
284 // codeStream.goto_(falseLabel);
289 // codeStream.recordPositionsFrom(pc, this.sourceStart);
292 // generateCode(currentScope, codeStream, valueRequired);
294 // int position = codeStream.position;
295 // if (valueRequired) {
296 // if (falseLabel == null) {
297 // if (trueLabel != null) {
298 // // Implicit falling through the FALSE case
299 // codeStream.ifne(trueLabel);
302 // if (trueLabel == null) {
303 // // Implicit falling through the TRUE case
304 // codeStream.ifeq(falseLabel);
306 // // No implicit fall through TRUE/FALSE --> should never occur
310 // // reposition the endPC
311 // codeStream.updateLastRecordedEndPC(position);
314 // /* Optimized (java) code generation for string concatenations that involve StringBuffer
315 // * creation: going through this path means that there is no need for a new StringBuffer
316 // * creation, further operands should rather be only appended to the current one.
317 // * By default: no optimization.
319 // public void generateOptimizedStringBuffer(
320 // BlockScope blockScope,
321 // org.eclipse.jdt.internal.compiler.codegen.CodeStream codeStream,
324 // generateCode(blockScope, codeStream, true);
325 // codeStream.invokeStringBufferAppendForType(typeID);
328 /* Optimized (java) code generation for string concatenations that involve StringBuffer
329 * creation: going through this path means that there is no need for a new StringBuffer
330 * creation, further operands should rather be only appended to the current one.
332 // public void generateOptimizedStringBufferCreation(
333 // BlockScope blockScope,
334 // CodeStream codeStream,
337 // // Optimization only for integers and strings
338 // if (typeID == T_Object) {
339 // // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object)
340 // // append(Object) returns append(valueOf(Object)), which means that the null case is handled by append(String).
341 // codeStream.newStringBuffer();
343 // codeStream.invokeStringBufferDefaultConstructor();
344 // generateCode(blockScope, codeStream, true);
345 // codeStream.invokeStringBufferAppendForType(T_Object);
348 // codeStream.newStringBuffer();
350 // if (typeID == T_String || typeID == T_null) {
351 // if (constant != NotAConstant) {
352 // codeStream.ldc(constant.stringValue());
354 // generateCode(blockScope, codeStream, true);
355 // codeStream.invokeStringValueOf(T_Object);
358 // generateCode(blockScope, codeStream, true);
359 // codeStream.invokeStringValueOf(typeID);
361 // codeStream.invokeStringBufferStringConstructor();
364 // Base types need that the widening is explicitly done by the compiler using some bytecode like i2f
365 public void implicitWidening(
366 TypeBinding runtimeTimeType,
367 TypeBinding compileTimeType) {
369 if (runtimeTimeType == null || compileTimeType == null)
372 // if (compileTimeType.id == T_null) {
373 // // this case is possible only for constant null
374 // // The type of runtime is a reference type
375 // // The code gen use the constant id thus any value
376 // // for the runtime id (akak the <<4) could be used.
377 // // T_Object is used as some general T_reference
378 // implicitConversion = (T_Object << 4) + T_null;
382 switch (runtimeTimeType.id) {
386 implicitConversion = (T_int << 4) + compileTimeType.id;
392 case T_int : //implicitConversion may result in i2i which will result in NO code gen
394 implicitConversion = (runtimeTimeType.id << 4) + compileTimeType.id;
396 default : //nothing on regular object ref
400 public boolean isCompactableOperation() {
405 //Return true if the conversion is done AUTOMATICALLY by the vm
406 //while the javaVM is an int based-machine, thus for example pushing
407 //a byte onto the stack , will automatically creates a int on the stack
408 //(this request some work d be done by the VM on signed numbers)
409 public boolean isConstantValueOfTypeAssignableToType(
410 TypeBinding constantType,
411 TypeBinding targetType) {
413 if (constant == Constant.NotAConstant)
415 if (constantType == targetType)
417 if (constantType.isBaseType() && targetType.isBaseType()) {
418 //No free assignment conversion from anything but to integral ones.
419 if ((constantType == IntBinding
420 || BaseTypeBinding.isWidening(T_int, constantType.id))
421 && (BaseTypeBinding.isNarrowing(targetType.id, T_int))) {
422 //use current explicit conversion in order to get some new value to compare with current one
423 return isConstantValueRepresentable(constant, constantType.id, targetType.id);
429 public boolean isTypeReference() {
433 public void resolve(BlockScope scope) {
434 // drops the returning expression's type whatever the type is.
436 this.resolveType(scope);
440 public TypeBinding resolveType(BlockScope scope) {
441 // by default... subclasses should implement a better TC if required.
446 public TypeBinding resolveTypeExpecting(
448 TypeBinding expectedType) {
450 TypeBinding expressionType = this.resolveType(scope);
451 if (expressionType == null) return null;
452 if (expressionType == expectedType) return expressionType;
454 if (!expressionType.isCompatibleWith(expectedType)) {
455 scope.problemReporter().typeMismatchError(expressionType, expectedType, this);
458 return expressionType;
461 public String toString(int tab) {
463 //Subclass re-define toStringExpression
464 String s = tabString(tab);
465 if (constant != null)
466 //before TC has runned
467 if (constant != NotAConstant)
468 //after the TC has runned
469 s += " /*cst:" + constant.toString() + "*/ "; //$NON-NLS-1$ //$NON-NLS-2$
470 return s + toStringExpression(tab);
473 //Subclass re-define toStringExpression
474 //This method is abstract and should never be called
475 //but we provide some code that is running.....just in case
476 //of developpement time (while every thing is not built)
477 public String toStringExpression() {
479 return super.toString(0);
482 public String toStringExpression(int tab) {
483 // default is regular toString expression (qualified allocation expressions redifine this method)
484 return this.toStringExpression();
487 public Expression toTypeReference() {
488 //by default undefined
490 //this method is meanly used by the parser in order to transform
491 //an expression that is used as a type reference in a cast ....
492 //--appreciate the fact that castExpression and ExpressionWithParenthesis
493 //--starts with the same pattern.....