/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.parser.expressions;
import gw.internal.gosu.parser.Expression;
import gw.lang.IDimension;
import gw.lang.parser.expressions.IUnaryExpression;
import gw.lang.reflect.IPlaceholder;
import gw.lang.reflect.IType;
import gw.lang.reflect.TypeSystem;
import gw.lang.reflect.java.JavaTypes;
import gw.config.CommonServices;
/**
* Represents a unary expression as defined in the Gosu grammar.
*
* @see gw.lang.parser.IGosuParser
*/
public final class UnaryExpression extends Expression implements IUnaryExpression
{
protected boolean _bNegated;
protected Expression _expression;
public boolean isNegated()
{
return _bNegated;
}
public void setNegated( boolean bNegated )
{
_bNegated = bNegated;
}
public Expression getExpression()
{
return _expression;
}
public void setExpression( Expression e )
{
_expression = e;
}
public boolean isCompileTimeConstant()
{
return getExpression().isCompileTimeConstant();
}
public Object evaluate()
{
if( !isCompileTimeConstant() )
{
return super.evaluate();
}
Object value = getExpression().evaluate();
if( value == null )
{
return null;
}
IType type = getExpression().getType();
if( isNegated() )
{
IDimension dimension = null;
if( JavaTypes.IDIMENSION().isAssignableFrom( type ) )
{
dimension = (IDimension)value;
type = TypeSystem.get( ((IDimension)value).numberType() );
value = ((IDimension)value).toNumber();
}
if( type == JavaTypes.BIG_DECIMAL() )
{
value = CommonServices.getCoercionManager().makeBigDecimalFrom( value ).negate();
}
else if( type == JavaTypes.BIG_INTEGER() )
{
value = CommonServices.getCoercionManager().makeBigIntegerFrom( value ).negate();
}
else if( type == JavaTypes.INTEGER() || type == JavaTypes.pINT() )
{
value = makeInteger( -CommonServices.getCoercionManager().makeIntegerFrom( value ) );
}
else if( type == JavaTypes.LONG() || type == JavaTypes.pLONG() )
{
value = makeLong( -CommonServices.getCoercionManager().makeLongFrom( value ) );
}
else if( type == JavaTypes.DOUBLE() || type == JavaTypes.pDOUBLE() )
{
value = makeDoubleValue( -makeDoubleValue( value ) );
}
else if( type == JavaTypes.FLOAT() || type == JavaTypes.pFLOAT() )
{
value = makeFloatValue( -makeFloatValue( value ) );
}
else if( type == JavaTypes.SHORT() || type == JavaTypes.pSHORT() )
{
value = makeInteger( -CommonServices.getCoercionManager().makeIntegerFrom( value ) ).shortValue();
}
else if( type == JavaTypes.BYTE() || type == JavaTypes.pBYTE() )
{
value = makeInteger( -CommonServices.getCoercionManager().makeIntegerFrom( value ) ).byteValue();
}
else
{
throw new UnsupportedNumberTypeException(type);
}
if( dimension != null )
{
//noinspection unchecked
value = dimension.fromNumber( (Number)value );
}
}
return value;
}
public boolean isSupportedType( IType type )
{
return
type == JavaTypes.BIG_DECIMAL() ||
type == JavaTypes.BIG_INTEGER() ||
type == JavaTypes.INTEGER() || type == JavaTypes.pINT() ||
type == JavaTypes.LONG() || type == JavaTypes.pLONG() ||
type == JavaTypes.DOUBLE() || type == JavaTypes.pDOUBLE() ||
type == JavaTypes.FLOAT() || type == JavaTypes.pFLOAT() ||
type == JavaTypes.SHORT() || type == JavaTypes.pSHORT() ||
type == JavaTypes.BYTE() || type == JavaTypes.pBYTE() ||
JavaTypes.IDIMENSION().isAssignableFrom( type ) ||
(type instanceof IPlaceholder && ((IPlaceholder)type).isPlaceholder());
}
@Override
public String toString()
{
return (isNegated() ? "-" : "+" ) + getExpression().toString();
}
}