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.....