first scanner /parser copied from the jdt java version
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / CastExpression.java
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CastExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CastExpression.java
new file mode 100644 (file)
index 0000000..f295b80
--- /dev/null
@@ -0,0 +1,285 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v0.5 
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package net.sourceforge.phpdt.internal.compiler.ast;
+
+import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+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.*;
+
+public class CastExpression extends Expression {
+
+       public Expression expression;
+       public Expression type;
+       public boolean needRuntimeCheckcast;
+       public TypeBinding castTb;
+
+       //expression.implicitConversion holds the cast for baseType casting 
+       public CastExpression(Expression e, Expression t) {
+               expression = e;
+               type = t;
+
+               //due to the fact an expression may start with ( and that a cast also start with (
+               //the field is an expression....it can be a TypeReference OR a NameReference Or
+               //an expression <--this last one is invalid.......
+
+               // :-( .............
+
+               //if (type instanceof TypeReference )
+               //      flag = IsTypeReference ;
+               //else
+               //      if (type instanceof NameReference)
+               //              flag = IsNameReference ;
+               //      else
+               //              flag = IsExpression ;
+
+       }
+
+       public FlowInfo analyseCode(
+               BlockScope currentScope,
+               FlowContext flowContext,
+               FlowInfo flowInfo) {
+
+               return expression
+                       .analyseCode(currentScope, flowContext, flowInfo)
+                       .unconditionalInits();
+       }
+
+       public final void areTypesCastCompatible(
+               BlockScope scope,
+               TypeBinding castTb,
+               TypeBinding expressionTb) {
+
+               // see specifications p.68
+               // handle errors and process constant when needed
+
+               // if either one of the type is null ==>
+               // some error has been already reported some where ==>
+               // we then do not report an obvious-cascade-error.
+
+               needRuntimeCheckcast = false;
+               if (castTb == null || expressionTb == null)
+                       return;
+               if (castTb.isBaseType()) {
+                       if (expressionTb.isBaseType()) {
+                               if (expressionTb == castTb) {
+                                       constant = expression.constant; //use the same constant
+                                       return;
+                               }
+                               if (scope.areTypesCompatible(expressionTb, castTb)
+                                       || BaseTypeBinding.isNarrowing(castTb.id, expressionTb.id)) {
+                                       expression.implicitConversion = (castTb.id << 4) + expressionTb.id;
+                                       if (expression.constant != Constant.NotAConstant)
+                                               constant = expression.constant.castTo(expression.implicitConversion);
+                                       return;
+                               }
+                       }
+                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                       return;
+               }
+
+               //-----------cast to something which is NOT a base type--------------------------       
+               if (expressionTb == NullBinding)
+                       return; //null is compatible with every thing
+
+               if (expressionTb.isBaseType()) {
+                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                       return;
+               }
+
+               if (expressionTb.isArrayType()) {
+                       if (castTb.isArrayType()) {
+                               //------- (castTb.isArray) expressionTb.isArray -----------
+                               TypeBinding expressionEltTb = ((ArrayBinding) expressionTb).elementsType(scope);
+                               if (expressionEltTb.isBaseType()) {
+                                       // <---stop the recursion------- 
+                                       if (((ArrayBinding) castTb).elementsType(scope) == expressionEltTb)
+                                               needRuntimeCheckcast = true;
+                                       else
+                                               scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                                       return;
+                               }
+                               // recursively on the elements...
+                               areTypesCastCompatible(
+                                       scope,
+                                       ((ArrayBinding) castTb).elementsType(scope),
+                                       expressionEltTb);
+                               return;
+                       } else if (
+                               castTb.isClass()) {
+                               //------(castTb.isClass) expressionTb.isArray ---------------   
+                               if (scope.isJavaLangObject(castTb))
+                                       return;
+                       } else { //------- (castTb.isInterface) expressionTb.isArray -----------
+                               if (scope.isJavaLangCloneable(castTb) || scope.isJavaIoSerializable(castTb)) {
+                                       needRuntimeCheckcast = true;
+                                       return;
+                               }
+                       }
+                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                       return;
+               }
+
+               if (expressionTb.isClass()) {
+                       if (castTb.isArrayType()) {
+                               // ---- (castTb.isArray) expressionTb.isClass -------
+                               if (scope.isJavaLangObject(expressionTb)) { // potential runtime error
+                                       needRuntimeCheckcast = true;
+                                       return;
+                               }
+                       } else if (
+                               castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------
+                               if (scope.areTypesCompatible(expressionTb, castTb)) // no runtime error
+                                       return;
+                               if (scope.areTypesCompatible(castTb, expressionTb)) {
+                                       // potential runtime  error
+                                       needRuntimeCheckcast = true;
+                                       return;
+                               }
+                       } else { // ----- (castTb.isInterface) expressionTb.isClass -------  
+                               if (((ReferenceBinding) expressionTb).isFinal()) {
+                                       // no subclass for expressionTb, thus compile-time check is valid
+                                       if (scope.areTypesCompatible(expressionTb, castTb))
+                                               return;
+                               } else { // a subclass may implement the interface ==> no check at compile time
+                                       needRuntimeCheckcast = true;
+                                       return;
+                               }
+                       }
+                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                       return;
+               }
+
+               //      if (expressionTb.isInterface()) { cannot be anything else
+               if (castTb.isArrayType()) {
+                       // ----- (castTb.isArray) expressionTb.isInterface ------
+                       if (scope.isJavaLangCloneable(expressionTb)
+                               || scope.isJavaIoSerializable(expressionTb)) // potential runtime error
+                               needRuntimeCheckcast = true;
+                       else
+                               scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                       return;
+               } else if (
+                       castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isInterface --------
+                       if (scope.isJavaLangObject(castTb)) // no runtime error
+                               return;
+                       if (((ReferenceBinding) castTb).isFinal()) {
+                               // no subclass for castTb, thus compile-time check is valid
+                               if (!scope.areTypesCompatible(castTb, expressionTb)) {
+                                       // potential runtime error
+                                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                                       return;
+                               }
+                       }
+               } else { // ----- (castTb.isInterface) expressionTb.isInterface -------
+                       if (castTb != expressionTb
+                               && (Scope.compareTypes(castTb, expressionTb) == NotRelated)) {
+                               MethodBinding[] castTbMethods = ((ReferenceBinding) castTb).methods();
+                               MethodBinding[] expressionTbMethods =
+                                       ((ReferenceBinding) expressionTb).methods();
+                               int exprMethodsLength = expressionTbMethods.length;
+                               for (int i = 0, castMethodsLength = castTbMethods.length;
+                                       i < castMethodsLength;
+                                       i++)
+                                       for (int j = 0; j < exprMethodsLength; j++)
+                                               if (castTbMethods[i].returnType != expressionTbMethods[j].returnType)
+                                                       if (castTbMethods[i].selector == expressionTbMethods[j].selector)
+                                                               if (castTbMethods[i].areParametersEqual(expressionTbMethods[j]))
+                                                                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                       }
+               }
+               needRuntimeCheckcast = true;
+               return;
+       }
+
+       /**
+        * Cast expression code generation
+        *
+        * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+        * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+        * @param valueRequired boolean
+        */
+       public void generateCode(
+               BlockScope currentScope,
+               CodeStream codeStream,
+               boolean valueRequired) {
+
+               int pc = codeStream.position;
+               if (constant != NotAConstant) {
+                       if (valueRequired
+                               || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check
+                               codeStream.generateConstant(constant, implicitConversion);
+                               if (needRuntimeCheckcast) {
+                                       codeStream.checkcast(castTb);
+                                       if (!valueRequired)
+                                               codeStream.pop();
+                               }
+                       }
+                       codeStream.recordPositionsFrom(pc, this.sourceStart);
+                       return;
+               }
+               expression.generateCode(
+                       currentScope,
+                       codeStream,
+                       valueRequired || needRuntimeCheckcast);
+               if (needRuntimeCheckcast) {
+                       codeStream.checkcast(castTb);
+                       if (!valueRequired)
+                               codeStream.pop();
+               } else {
+                       if (valueRequired)
+                               codeStream.generateImplicitConversion(implicitConversion);
+               }
+               codeStream.recordPositionsFrom(pc, this.sourceStart);
+       }
+
+       public TypeBinding resolveType(BlockScope scope) {
+               // compute a new constant if the cast is effective
+
+               // due to the fact an expression may start with ( and that a cast can also start with (
+               // the field is an expression....it can be a TypeReference OR a NameReference Or
+               // any kind of Expression <-- this last one is invalid.......
+
+               constant = Constant.NotAConstant;
+               implicitConversion = T_undefined;
+               TypeBinding expressionTb = expression.resolveType(scope);
+               if (expressionTb == null)
+                       return null;
+
+               if ((type instanceof TypeReference) || (type instanceof NameReference)) {
+                       if ((castTb = type.resolveType(scope)) == null)
+                               return null;
+                       areTypesCastCompatible(scope, castTb, expressionTb);
+                       return castTb;
+               } else { // expression as a cast !!!!!!!! 
+                       scope.problemReporter().invalidTypeReference(type);
+                       return null;
+               }
+       }
+
+       public String toStringExpression() {
+
+               return "(" + type.toString(0) + ") " + //$NON-NLS-2$ //$NON-NLS-1$
+               expression.toStringExpression();
+       }
+
+       public void traverse(
+               IAbstractSyntaxTreeVisitor visitor,
+               BlockScope blockScope) {
+
+               if (visitor.visit(this, blockScope)) {
+                       type.traverse(visitor, blockScope);
+                       expression.traverse(visitor, blockScope);
+               }
+               visitor.endVisit(this, blockScope);
+       }
+}
\ No newline at end of file