/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.ir.transform.expression;
import gw.config.CommonServices;
import gw.internal.gosu.ir.transform.ExpressionTransformer;
import gw.internal.gosu.ir.transform.TopLevelTransformationContext;
import gw.internal.gosu.parser.BeanAccess;
import gw.internal.gosu.parser.expressions.UnaryExpression;
import gw.internal.gosu.parser.expressions.UnsupportedNumberTypeException;
import gw.lang.IDimension;
import gw.lang.ir.IRExpression;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
*/
public class UnaryExpressionTransformer extends AbstractExpressionTransformer<UnaryExpression>
{
public static IRExpression compile( TopLevelTransformationContext cc, UnaryExpression expr )
{
UnaryExpressionTransformer gen = new UnaryExpressionTransformer( cc, expr );
return gen.compile();
}
private UnaryExpressionTransformer( TopLevelTransformationContext cc, UnaryExpression expr )
{
super( cc, expr );
}
protected IRExpression compile_impl()
{
IRExpression root = ExpressionTransformer.compile( _expr().getExpression(), _cc() );
if( _expr().getType().isPrimitive() && BeanAccess.isNumericType( _expr().getType() ) )
{
return negateSimple( root );
}
else
{
return negateComplex(root );
}
}
private IRExpression negateSimple( IRExpression root )
{
if (_expr().isNegated()) {
return buildNegation( root );
} else {
// Nothing to do if it's not a negation
return root;
}
}
private IRExpression negateComplex( IRExpression root )
{
// Call into Gosu's runtime for the answer
IRExpression negateCall = callStaticMethod( getClass(), "negateComplex", new Class[]{Object.class, boolean.class},
exprList( boxValue( _expr().getExpression().getType(), root ),
pushConstant( _expr().isNegated() ) ) );
// Ensure value is unboxed if type is primitive
return unboxValueToType( _expr().getType(), negateCall );
}
public static Object negateComplex( Object value, boolean bNegated )
{
if( value == null )
{
return null;
}
if( bNegated )
{
IDimension dimension = null;
if( value instanceof IDimension )
{
dimension = (IDimension)value;
value = ((IDimension)value).toNumber();
}
if( value instanceof BigDecimal )
{
value = CommonServices.getCoercionManager().makeBigDecimalFrom( value ).negate();
}
else if( value instanceof BigInteger )
{
value = CommonServices.getCoercionManager().makeBigIntegerFrom( value ).negate();
}
else if( value instanceof Integer )
{
value = -CommonServices.getCoercionManager().makeIntegerFrom( value );
}
else if( value instanceof Long )
{
value = -CommonServices.getCoercionManager().makeLongFrom( value );
}
else if( value instanceof Double )
{
value = -CommonServices.getCoercionManager().makeDoubleFrom( value );
}
else if( value instanceof Float )
{
value = -CommonServices.getCoercionManager().makeFloatFrom( value );
}
else if( value instanceof Short )
{
value = (short)-CommonServices.getCoercionManager().makeIntegerFrom( value ).shortValue();
}
else if( value instanceof Byte )
{
value = (byte)-CommonServices.getCoercionManager().makeIntegerFrom( value ).byteValue();
}
else
{
throw new UnsupportedNumberTypeException( value.getClass() );
}
if( dimension != null )
{
//noinspection unchecked
value = dimension.fromNumber( (Number)value );
}
}
return value;
}
}