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.phpdt.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
15 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
16 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
17 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
20 public 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
26 // isValidJavaStatement()
28 public int implicitConversion;
30 public TypeBinding resolvedType;
32 public Constant constant;
38 public FlowInfo analyseCode(BlockScope currentScope,
39 FlowContext flowContext, FlowInfo flowInfo) {
44 public FlowInfo analyseCode(BlockScope currentScope,
45 FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
47 return analyseCode(currentScope, flowContext, flowInfo);
51 * Constant usable for bytecode pattern optimizations, but cannot be inlined
52 * since it is not strictly equivalent to the definition of constant
53 * expressions. In particular, some side-effects may be required to occur
54 * (only the end value is known). Constant is known to be of boolean type
56 public Constant optimizedBooleanConstant() {
61 public static final boolean isConstantValueRepresentable(Constant constant,
62 int constantTypeID, int targetTypeID) {
64 // true if there is no loss of precision while casting.
65 // constantTypeID == constant.typeID
66 if (targetTypeID == constantTypeID)
68 switch (targetTypeID) {
70 switch (constantTypeID) {
74 return constant.doubleValue() == constant.charValue();
76 return constant.floatValue() == constant.charValue();
78 return constant.intValue() == constant.charValue();
80 return constant.shortValue() == constant.charValue();
82 return constant.byteValue() == constant.charValue();
84 return constant.longValue() == constant.charValue();
86 return false;// boolean
90 switch (constantTypeID) {
92 return constant.charValue() == constant.floatValue();
94 return constant.doubleValue() == constant.floatValue();
98 return constant.intValue() == constant.floatValue();
100 return constant.shortValue() == constant.floatValue();
102 return constant.byteValue() == constant.floatValue();
104 return constant.longValue() == constant.floatValue();
106 return false;// boolean
110 switch (constantTypeID) {
112 return constant.charValue() == constant.doubleValue();
116 return constant.floatValue() == constant.doubleValue();
118 return constant.intValue() == constant.doubleValue();
120 return constant.shortValue() == constant.doubleValue();
122 return constant.byteValue() == constant.doubleValue();
124 return constant.longValue() == constant.doubleValue();
126 return false; // boolean
130 switch (constantTypeID) {
132 return constant.charValue() == constant.byteValue();
134 return constant.doubleValue() == constant.byteValue();
136 return constant.floatValue() == constant.byteValue();
138 return constant.intValue() == constant.byteValue();
140 return constant.shortValue() == constant.byteValue();
144 return constant.longValue() == constant.byteValue();
146 return false; // boolean
150 switch (constantTypeID) {
152 return constant.charValue() == constant.shortValue();
154 return constant.doubleValue() == constant.shortValue();
156 return constant.floatValue() == constant.shortValue();
158 return constant.intValue() == constant.shortValue();
162 return constant.byteValue() == constant.shortValue();
164 return constant.longValue() == constant.shortValue();
166 return false; // boolean
170 switch (constantTypeID) {
172 return constant.charValue() == constant.intValue();
174 return constant.doubleValue() == constant.intValue();
176 return constant.floatValue() == constant.intValue();
180 return constant.shortValue() == constant.intValue();
182 return constant.byteValue() == constant.intValue();
184 return constant.longValue() == constant.intValue();
186 return false; // boolean
190 switch (constantTypeID) {
192 return constant.charValue() == constant.longValue();
194 return constant.doubleValue() == constant.longValue();
196 return constant.floatValue() == constant.longValue();
198 return constant.intValue() == constant.longValue();
200 return constant.shortValue() == constant.longValue();
202 return constant.byteValue() == constant.longValue();
206 return false; // boolean
210 return false; // boolean
215 * Expression statements are plain expressions, however they generate like
216 * normal expressions with no value required.
218 * @param currentScope
219 * net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
221 * net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
223 // public void generateCode(BlockScope currentScope, CodeStream codeStream)
226 // if ((bits & IsReachableMASK) == 0) {
229 // generateCode(currentScope, codeStream, false);
232 * Every expression is responsible for generating its implicit conversion
235 * @param currentScope
236 * net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
238 * net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
239 * @param valueRequired
242 // public void generateCode(
243 // BlockScope currentScope,
244 // CodeStream codeStream,
245 // boolean valueRequired) {
247 // if (constant != NotAConstant) {
248 // // generate a constant expression
249 // int pc = codeStream.position;
250 // codeStream.generateConstant(constant, implicitConversion);
251 // codeStream.recordPositionsFrom(pc, this.sourceStart);
253 // // actual non-constant code generation
254 // throw new ShouldNotImplement(ProjectPrefUtil.bind("ast.missingCode"));
259 * Default generation of a boolean value
261 // public void generateOptimizedBoolean(
262 // BlockScope currentScope,
263 // CodeStream codeStream,
266 // boolean valueRequired) {
268 // // a label valued to nil means: by default we fall through the case...
269 // // both nil means we leave the value on the stack
271 // if ((constant != Constant.NotAConstant) && (constant.typeID() ==
273 // int pc = codeStream.position;
274 // if (constant.booleanValue() == true) {
275 // // constant == true
276 // if (valueRequired) {
277 // if (falseLabel == null) {
278 // // implicit falling through the FALSE case
279 // if (trueLabel != null) {
280 // codeStream.goto_(trueLabel);
285 // if (valueRequired) {
286 // if (falseLabel != null) {
287 // // implicit falling through the TRUE case
288 // if (trueLabel == null) {
289 // codeStream.goto_(falseLabel);
294 // codeStream.recordPositionsFrom(pc, this.sourceStart);
297 // generateCode(currentScope, codeStream, valueRequired);
299 // int position = codeStream.position;
300 // if (valueRequired) {
301 // if (falseLabel == null) {
302 // if (trueLabel != null) {
303 // // Implicit falling through the FALSE case
304 // codeStream.ifne(trueLabel);
307 // if (trueLabel == null) {
308 // // Implicit falling through the TRUE case
309 // codeStream.ifeq(falseLabel);
311 // // No implicit fall through TRUE/FALSE --> should never occur
315 // // reposition the endPC
316 // codeStream.updateLastRecordedEndPC(position);
319 // /* Optimized (java) code generation for string concatenations that
320 // involve StringBuffer
321 // * creation: going through this path means that there is no need for a new
323 // * creation, further operands should rather be only appended to the
325 // * By default: no optimization.
327 // public void generateOptimizedStringBuffer(
328 // BlockScope blockScope,
329 // net.sourceforge.phpdt.internal.compiler.codegen.CodeStream codeStream,
332 // generateCode(blockScope, codeStream, true);
333 // codeStream.invokeStringBufferAppendForType(typeID);
336 * Optimized (java) code generation for string concatenations that involve
337 * StringBuffer creation: going through this path means that there is no
338 * need for a new StringBuffer creation, further operands should rather be
339 * only appended to the current one.
341 // public void generateOptimizedStringBufferCreation(
342 // BlockScope blockScope,
343 // CodeStream codeStream,
346 // // Optimization only for integers and strings
347 // if (typeID == T_Object) {
348 // // in the case the runtime value of valueOf(Object) returns null, we have
349 // to use append(Object) instead of directly valueOf(Object)
350 // // append(Object) returns append(valueOf(Object)), which means that the
351 // null case is handled by append(String).
352 // codeStream.newStringBuffer();
354 // codeStream.invokeStringBufferDefaultConstructor();
355 // generateCode(blockScope, codeStream, true);
356 // codeStream.invokeStringBufferAppendForType(T_Object);
359 // codeStream.newStringBuffer();
361 // if (typeID == T_String || typeID == T_null) {
362 // if (constant != NotAConstant) {
363 // codeStream.ldc(constant.stringValue());
365 // generateCode(blockScope, codeStream, true);
366 // codeStream.invokeStringValueOf(T_Object);
369 // generateCode(blockScope, codeStream, true);
370 // codeStream.invokeStringValueOf(typeID);
372 // codeStream.invokeStringBufferStringConstructor();
374 // Base types need that the widening is explicitly done by the compiler
375 // using some bytecode like i2f
376 public void implicitWidening(TypeBinding runtimeTimeType,
377 TypeBinding compileTimeType) {
379 if (runtimeTimeType == null || compileTimeType == null)
382 // if (compileTimeType.id == T_null) {
383 // // this case is possible only for constant null
384 // // The type of runtime is a reference type
385 // // The code gen use the constant id thus any value
386 // // for the runtime id (akak the <<4) could be used.
387 // // T_Object is used as some general T_reference
388 // implicitConversion = (T_Object << 4) + T_null;
392 switch (runtimeTimeType.id) {
396 implicitConversion = (T_int << 4) + compileTimeType.id;
402 case T_int: // implicitConversion may result in i2i which will result in
405 implicitConversion = (runtimeTimeType.id << 4) + compileTimeType.id;
407 default: // nothing on regular object ref
411 public boolean isCompactableOperation() {
416 // Return true if the conversion is done AUTOMATICALLY by the vm
417 // while the javaVM is an int based-machine, thus for example pushing
418 // a byte onto the stack , will automatically creates a int on the stack
419 // (this request some work d be done by the VM on signed numbers)
420 public boolean isConstantValueOfTypeAssignableToType(
421 TypeBinding constantType, TypeBinding targetType) {
423 if (constant == Constant.NotAConstant)
425 if (constantType == targetType)
427 if (constantType.isBaseType() && targetType.isBaseType()) {
428 // No free assignment conversion from anything but to integral ones.
429 if ((constantType == IntBinding || BaseTypeBinding.isWidening(
430 T_int, constantType.id))
431 && (BaseTypeBinding.isNarrowing(targetType.id, T_int))) {
432 // use current explicit conversion in order to get some new
433 // value to compare with current one
434 return isConstantValueRepresentable(constant, constantType.id,
441 public boolean isTypeReference() {
445 public StringBuffer print(int indent, StringBuffer output) {
446 printIndent(indent, output);
447 return printExpression(indent, output);
450 public StringBuffer printExpression(int indent, StringBuffer output) {
451 output.append(super.toString(0));
455 public StringBuffer printStatement(int indent, StringBuffer output) {
456 return print(indent, output).append(";"); //$NON-NLS-1$
459 public void resolve(BlockScope scope) {
460 // drops the returning expression's type whatever the type is.
462 this.resolveType(scope);
466 public TypeBinding resolveType(BlockScope scope) {
467 // by default... subclasses should implement a better TC if required.
472 public TypeBinding resolveTypeExpecting(BlockScope scope,
473 TypeBinding expectedType) {
475 TypeBinding expressionType = this.resolveType(scope);
476 if (expressionType == null)
478 if (expressionType == expectedType)
479 return expressionType;
481 if (!expressionType.isCompatibleWith(expectedType)) {
482 scope.problemReporter().typeMismatchError(expressionType,
486 return expressionType;
489 public String toString(int tab) {
491 // Subclass re-define toStringExpression
492 String s = tabString(tab);
493 if (constant != null)
494 // before TC has runned
495 if (constant != NotAConstant)
496 // after the TC has runned
497 s += " /*cst:" + constant.toString() + "*/ "; //$NON-NLS-1$ //$NON-NLS-2$
498 return s + toStringExpression(tab);
501 // Subclass re-define toStringExpression
502 // This method is abstract and should never be called
503 // but we provide some code that is running.....just in case
504 // of developpement time (while every thing is not built)
505 public String toStringExpression() {
507 return super.toString(0);
510 public String toStringExpression(int tab) {
511 // default is regular toString expression (qualified allocation
512 // expressions redifine this method)
513 return this.toStringExpression();
516 public Expression toTypeReference() {
517 // by default undefined
519 // this method is meanly used by the parser in order to transform
520 // an expression that is used as a type reference in a cast ....
521 // --appreciate the fact that castExpression and
522 // ExpressionWithParenthesis
523 // --starts with the same pattern.....