/*******************************************************************************
- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v0.5
+ * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v05.html
+ * http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
- ******************************************************************************/
+ *******************************************************************************/
package net.sourceforge.phpdt.internal.compiler.ast;
-import net.sourceforge.phpdt.internal.compiler.impl.*;
-import net.sourceforge.phpdt.internal.compiler.codegen.*;
-import net.sourceforge.phpdt.internal.compiler.flow.*;
-import net.sourceforge.phpdt.internal.compiler.lookup.*;
-import net.sourceforge.phpdt.internal.compiler.problem.*;
-import net.sourceforge.phpdt.internal.compiler.util.Util;
+import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
+import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
+import net.sourceforge.phpdt.internal.compiler.impl.Constant;
+import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
+import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
-public abstract class Expression extends Statement {
+public class Expression extends Statement {
//some expression may not be used - from a java semantic point
//of view only - as statements. Other may. In order to avoid the creation
//Expression is a subclass of Statement. See the message isValidJavaStatement()
public int implicitConversion;
-
+ public TypeBinding resolvedType;
+
public Constant constant;
public Expression() {
super();
}
- public FlowInfo analyseCode(
- BlockScope currentScope,
- FlowContext flowContext,
- FlowInfo flowInfo,
- boolean valueRequired) {
+ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
- return analyseCode(currentScope, flowContext, flowInfo);
+ return flowInfo;
}
- public Constant conditionalConstant() {
+ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
+
+ return analyseCode(currentScope, flowContext, flowInfo);
+ }
- return constant;
+ /**
+ * Constant usable for bytecode pattern optimizations, but cannot be inlined
+ * since it is not strictly equivalent to the definition of constant expressions.
+ * In particular, some side-effects may be required to occur (only the end value
+ * is known).
+ * Constant is known to be of boolean type
+ */
+ public Constant optimizedBooleanConstant() {
+
+ return this.constant;
}
public static final boolean isConstantValueRepresentable(
* Expression statements are plain expressions, however they generate like
* normal expressions with no value required.
*
- * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
- * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
+ * @param codeStream net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
*/
- public void generateCode(BlockScope currentScope, CodeStream codeStream) {
-
- if ((bits & IsReachableMASK) == 0) {
- return;
- }
- generateCode(currentScope, codeStream, false);
- }
+// public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+//
+// if ((bits & IsReachableMASK) == 0) {
+// return;
+// }
+// generateCode(currentScope, codeStream, false);
+// }
/**
* Every expression is responsible for generating its implicit conversion when necessary.
*
- * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
- * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
+ * @param codeStream net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
* @param valueRequired boolean
*/
- public void generateCode(
- BlockScope currentScope,
- CodeStream codeStream,
- boolean valueRequired) {
-
- if (constant != NotAConstant) {
- // generate a constant expression
- int pc = codeStream.position;
- codeStream.generateConstant(constant, implicitConversion);
- codeStream.recordPositionsFrom(pc, this.sourceStart);
- } else {
- // actual non-constant code generation
- throw new ShouldNotImplement(Util.bind("ast.missingCode")); //$NON-NLS-1$
- }
- }
+// public void generateCode(
+// BlockScope currentScope,
+// CodeStream codeStream,
+// boolean valueRequired) {
+//
+// if (constant != NotAConstant) {
+// // generate a constant expression
+// int pc = codeStream.position;
+// codeStream.generateConstant(constant, implicitConversion);
+// codeStream.recordPositionsFrom(pc, this.sourceStart);
+// } else {
+// // actual non-constant code generation
+// throw new ShouldNotImplement(ProjectPrefUtil.bind("ast.missingCode")); //$NON-NLS-1$
+// }
+// }
/**
* Default generation of a boolean value
*/
- public void generateOptimizedBoolean(
- BlockScope currentScope,
- CodeStream codeStream,
- Label trueLabel,
- Label falseLabel,
- boolean valueRequired) {
-
- // a label valued to nil means: by default we fall through the case...
- // both nil means we leave the value on the stack
-
- if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
- int pc = codeStream.position;
- if (constant.booleanValue() == true) {
- // constant == true
- if (valueRequired) {
- if (falseLabel == null) {
- // implicit falling through the FALSE case
- if (trueLabel != null) {
- codeStream.goto_(trueLabel);
- }
- }
- }
- } else {
- if (valueRequired) {
- if (falseLabel != null) {
- // implicit falling through the TRUE case
- if (trueLabel == null) {
- codeStream.goto_(falseLabel);
- }
- }
- }
- }
- codeStream.recordPositionsFrom(pc, this.sourceStart);
- return;
- }
- generateCode(currentScope, codeStream, valueRequired);
- // branching
- int position = codeStream.position;
- if (valueRequired) {
- if (falseLabel == null) {
- if (trueLabel != null) {
- // Implicit falling through the FALSE case
- codeStream.ifne(trueLabel);
- }
- } else {
- if (trueLabel == null) {
- // Implicit falling through the TRUE case
- codeStream.ifeq(falseLabel);
- } else {
- // No implicit fall through TRUE/FALSE --> should never occur
- }
- }
- }
- // reposition the endPC
- codeStream.updateLastRecordedEndPC(position);
- }
+// public void generateOptimizedBoolean(
+// BlockScope currentScope,
+// CodeStream codeStream,
+// Label trueLabel,
+// Label falseLabel,
+// boolean valueRequired) {
+//
+// // a label valued to nil means: by default we fall through the case...
+// // both nil means we leave the value on the stack
+//
+// if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
+// int pc = codeStream.position;
+// if (constant.booleanValue() == true) {
+// // constant == true
+// if (valueRequired) {
+// if (falseLabel == null) {
+// // implicit falling through the FALSE case
+// if (trueLabel != null) {
+// codeStream.goto_(trueLabel);
+// }
+// }
+// }
+// } else {
+// if (valueRequired) {
+// if (falseLabel != null) {
+// // implicit falling through the TRUE case
+// if (trueLabel == null) {
+// codeStream.goto_(falseLabel);
+// }
+// }
+// }
+// }
+// codeStream.recordPositionsFrom(pc, this.sourceStart);
+// return;
+// }
+// generateCode(currentScope, codeStream, valueRequired);
+// // branching
+// int position = codeStream.position;
+// if (valueRequired) {
+// if (falseLabel == null) {
+// if (trueLabel != null) {
+// // Implicit falling through the FALSE case
+// codeStream.ifne(trueLabel);
+// }
+// } else {
+// if (trueLabel == null) {
+// // Implicit falling through the TRUE case
+// codeStream.ifeq(falseLabel);
+// } else {
+// // No implicit fall through TRUE/FALSE --> should never occur
+// }
+// }
+// }
+// // reposition the endPC
+// codeStream.updateLastRecordedEndPC(position);
+// }
+//
+// /* Optimized (java) code generation for string concatenations that involve StringBuffer
+// * creation: going through this path means that there is no need for a new StringBuffer
+// * creation, further operands should rather be only appended to the current one.
+// * By default: no optimization.
+// */
+// public void generateOptimizedStringBuffer(
+// BlockScope blockScope,
+// net.sourceforge.phpdt.internal.compiler.codegen.CodeStream codeStream,
+// int typeID) {
+//
+// generateCode(blockScope, codeStream, true);
+// codeStream.invokeStringBufferAppendForType(typeID);
+// }
/* Optimized (java) code generation for string concatenations that involve StringBuffer
* creation: going through this path means that there is no need for a new StringBuffer
* creation, further operands should rather be only appended to the current one.
- * By default: no optimization.
*/
- public void generateOptimizedStringBuffer(
- BlockScope blockScope,
- net.sourceforge.phpdt.internal.compiler.codegen.CodeStream codeStream,
- int typeID) {
-
- generateCode(blockScope, codeStream, true);
- codeStream.invokeStringBufferAppendForType(typeID);
- }
-
- /* Optimized (java) code generation for string concatenations that involve StringBuffer
- * creation: going through this path means that there is no need for a new StringBuffer
- * creation, further operands should rather be only appended to the current one.
- */
- public void generateOptimizedStringBufferCreation(
- BlockScope blockScope,
- CodeStream codeStream,
- int typeID) {
-
- // Optimization only for integers and strings
- if (typeID == T_Object) {
- // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object)
- // append(Object) returns append(valueOf(Object)), which means that the null case is handled by append(String).
- codeStream.newStringBuffer();
- codeStream.dup();
- codeStream.invokeStringBufferDefaultConstructor();
- generateCode(blockScope, codeStream, true);
- codeStream.invokeStringBufferAppendForType(T_Object);
- return;
- }
- codeStream.newStringBuffer();
- codeStream.dup();
- if ((typeID == T_String) || (typeID == T_null)) {
- if (constant != NotAConstant) {
- codeStream.ldc(constant.stringValue());
- } else {
- generateCode(blockScope, codeStream, true);
- codeStream.invokeStringValueOf(T_Object);
- }
- } else {
- generateCode(blockScope, codeStream, true);
- codeStream.invokeStringValueOf(typeID);
- }
- codeStream.invokeStringBufferStringConstructor();
- }
+// public void generateOptimizedStringBufferCreation(
+// BlockScope blockScope,
+// CodeStream codeStream,
+// int typeID) {
+//
+// // Optimization only for integers and strings
+// if (typeID == T_Object) {
+// // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object)
+// // append(Object) returns append(valueOf(Object)), which means that the null case is handled by append(String).
+// codeStream.newStringBuffer();
+// codeStream.dup();
+// codeStream.invokeStringBufferDefaultConstructor();
+// generateCode(blockScope, codeStream, true);
+// codeStream.invokeStringBufferAppendForType(T_Object);
+// return;
+// }
+// codeStream.newStringBuffer();
+// codeStream.dup();
+// if (typeID == T_String || typeID == T_null) {
+// if (constant != NotAConstant) {
+// codeStream.ldc(constant.stringValue());
+// } else {
+// generateCode(blockScope, codeStream, true);
+// codeStream.invokeStringValueOf(T_Object);
+// }
+// } else {
+// generateCode(blockScope, codeStream, true);
+// codeStream.invokeStringValueOf(typeID);
+// }
+// codeStream.invokeStringBufferStringConstructor();
+// }
// Base types need that the widening is explicitly done by the compiler using some bytecode like i2f
public void implicitWidening(
if (runtimeTimeType == null || compileTimeType == null)
return;
- if (compileTimeType.id == T_null) {
- // this case is possible only for constant null
- // The type of runtime is a reference type
- // The code gen use the constant id thus any value
- // for the runtime id (akak the <<4) could be used.
- // T_Object is used as some general T_reference
- implicitConversion = (T_Object << 4) + T_null;
- return;
- }
+// if (compileTimeType.id == T_null) {
+// // this case is possible only for constant null
+// // The type of runtime is a reference type
+// // The code gen use the constant id thus any value
+// // for the runtime id (akak the <<4) could be used.
+// // T_Object is used as some general T_reference
+// implicitConversion = (T_Object << 4) + T_null;
+// return;
+// }
switch (runtimeTimeType.id) {
case T_byte :
public boolean isTypeReference() {
return false;
}
+ public StringBuffer print(int indent, StringBuffer output) {
+ printIndent(indent, output);
+ return printExpression(indent, output);
+ }
+ public StringBuffer printExpression(int indent, StringBuffer output) {
+ output.append(super.toString(0));
+ return output;
+ }
+
+ public StringBuffer printStatement(int indent, StringBuffer output) {
+ return print(indent, output).append(";"); //$NON-NLS-1$
+ }
public void resolve(BlockScope scope) {
// drops the returning expression's type whatever the type is.
public TypeBinding resolveTypeExpecting(
BlockScope scope,
- TypeBinding expectedTb) {
-
- TypeBinding thisTb = this.resolveType(scope);
- if (thisTb == null)
- return null;
- if (!scope.areTypesCompatible(thisTb, expectedTb)) {
- scope.problemReporter().typeMismatchError(thisTb, expectedTb, this);
+ TypeBinding expectedType) {
+
+ TypeBinding expressionType = this.resolveType(scope);
+ if (expressionType == null) return null;
+ if (expressionType == expectedType) return expressionType;
+
+ if (!expressionType.isCompatibleWith(expectedType)) {
+ scope.problemReporter().typeMismatchError(expressionType, expectedType, this);
return null;
}
- return thisTb;
+ return expressionType;
}
public String toString(int tab) {
return this;
}
-}
\ No newline at end of file
+}