blob: 62f5a07f6c3d90a2c4665cc5ac9e31ab57d8f563 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.jsdt.internal.compiler.ast;
import org.eclipse.wst.jsdt.core.ast.IASTNode;
import org.eclipse.wst.jsdt.core.ast.IUnaryExpression;
import org.eclipse.wst.jsdt.internal.compiler.ASTVisitor;
import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.wst.jsdt.internal.compiler.flow.FlowContext;
import org.eclipse.wst.jsdt.internal.compiler.flow.FlowInfo;
import org.eclipse.wst.jsdt.internal.compiler.impl.BooleanConstant;
import org.eclipse.wst.jsdt.internal.compiler.impl.Constant;
import org.eclipse.wst.jsdt.internal.compiler.lookup.BlockScope;
import org.eclipse.wst.jsdt.internal.compiler.lookup.TypeBinding;
public class UnaryExpression extends OperatorExpression implements IUnaryExpression {
public Expression expression;
public Constant optimizedBooleanConstant;
public UnaryExpression(Expression expression, int operator) {
this.expression = expression;
this.bits |= operator << OperatorSHIFT; // encode operator
}
public FlowInfo analyseCode(
BlockScope currentScope,
FlowContext flowContext,
FlowInfo flowInfo) {
this.expression.checkNPE(currentScope, flowContext, flowInfo);
if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
return this.expression.
analyseCode(currentScope, flowContext, flowInfo).
asNegatedCondition();
} else {
return this.expression.
analyseCode(currentScope, flowContext, flowInfo);
}
}
public Constant optimizedBooleanConstant() {
return this.optimizedBooleanConstant == null
? this.constant
: this.optimizedBooleanConstant;
}
public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
output.append(operatorToString()).append(' ');
return this.expression.printExpression(0, output);
}
protected final int getOperator()
{
return (bits & OperatorMASK) >> OperatorSHIFT;
}
public TypeBinding resolveType(BlockScope scope) {
if (this.expression instanceof CastExpression == true) this.expression.bits |= DisableUnnecessaryCastCheck; // will check later on
TypeBinding expressionType = null;
if (getOperator()==TYPEOF && (this.expression instanceof SingleNameReference))
expressionType=TypeBinding.UNKNOWN;
else
expressionType = this.expression.resolveType(scope);
if (expressionType == null) {
this.constant = Constant.NotAConstant;
return null;
}
int expressionTypeID = expressionType.id;
// autoboxing support
boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
if (use15specifics) {
if (!expressionType.isBaseType()) {
expressionTypeID = scope.environment().computeBoxingType(expressionType).id;
}
}
if (expressionTypeID > 15) {
this.constant = Constant.NotAConstant;
scope.problemReporter().invalidOperator(this, expressionType);
return null;
}
int tableId=-1;
int operator = (bits & OperatorMASK) >> OperatorSHIFT;
switch (operator) {
case NOT :
this.resolvedType= TypeBinding.BOOLEAN;
break;
case TWIDDLE :
tableId = LEFT_SHIFT;
break;
case TYPEOF :
this.resolvedType= scope.getJavaLangString();
break;
case OperatorIds.VOID :
this.resolvedType= TypeBinding.VOID;
break;
default :
tableId = MINUS;
} //+ and - cases
// the code is an int
// (cast) left Op (cast) rigth --> result
// 0000 0000 0000 0000 0000
// <<16 <<12 <<8 <<4 <<0
if (tableId>-1) // not already determined
{
int operatorSignature = OperatorSignatures[tableId][(expressionTypeID << 4) + expressionTypeID];
// this.expression.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), expressionType);
this.bits |= operatorSignature & 0xF;
switch (operatorSignature & 0xF) { // only switch on possible result type.....
case T_boolean :
this.resolvedType = TypeBinding.BOOLEAN;
break;
case T_byte :
this.resolvedType = TypeBinding.BYTE;
break;
case T_char :
this.resolvedType = TypeBinding.CHAR;
break;
case T_double :
this.resolvedType = TypeBinding.DOUBLE;
break;
case T_float :
this.resolvedType = TypeBinding.FLOAT;
break;
case T_int :
this.resolvedType = scope.getJavaLangNumber();
break;
case T_long :
this.resolvedType = TypeBinding.LONG;
break;
case T_any :
this.resolvedType = TypeBinding.UNKNOWN;
break;
default : //error........
this.constant = Constant.NotAConstant;
if (expressionTypeID != T_undefined)
scope.problemReporter().invalidOperator(this, expressionType);
return null;
}
}
// compute the constant when valid
if (this.expression.constant != Constant.NotAConstant) {
this.constant =
Constant.computeConstantOperation(
this.expression.constant,
expressionTypeID,
operator);
} else {
this.constant = Constant.NotAConstant;
if (operator == NOT) {
Constant cst = expression.optimizedBooleanConstant();
if (cst != Constant.NotAConstant)
this.optimizedBooleanConstant = BooleanConstant.fromValue(!cst.booleanValue());
}
}
// if (expressionIsCast) {
// // check need for operand cast
// CastExpression.checkNeedForArgumentCast(scope, tableId, operatorSignature, this.expression, expressionTypeID);
// }
return this.resolvedType;
}
public void traverse(
ASTVisitor visitor,
BlockScope blockScope) {
if (visitor.visit(this, blockScope)) {
this.expression.traverse(visitor, blockScope);
}
visitor.endVisit(this, blockScope);
}
public int getASTType() {
return IASTNode.UNARY_EXPRESSION;
}
}