/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.parser.expressions; import gw.config.CommonServices; import gw.internal.gosu.parser.ParserBase; import gw.lang.IDimension; import gw.lang.parser.expressions.IMultiplicativeExpression; import gw.lang.reflect.IPlaceholder; import gw.lang.reflect.IType; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.java.JavaTypes; import java.math.BigDecimal; import java.math.MathContext; /** * Represents a multiplicative expression in the Gosu grammar: * <pre> * <i>multiplicative-expression</i> * <unary-expression> * <multiplicative-expression> <b>*</b> <unary-expression> * <multiplicative-expression> <b>/</b> <unary-expression> * <multiplicative-expression> <b>%</b> <unary-expression> * </pre> * <p/> * * @see gw.lang.parser.IGosuParser */ public final class MultiplicativeExpression extends ArithmeticExpression implements IMultiplicativeExpression { /** * Evaluate the expression. */ public Object evaluate() { if( !isCompileTimeConstant() ) { return super.evaluate(); } return evaluate( getType(), getLHS().evaluate(), getRHS().evaluate(), getLHS().getType(), getRHS().getType(), getOperator().charAt( 0 ), false ); } public static Object evaluate( IType type, Object lhsValue, Object rhsValue, IType lhsType, IType rhsType, int iOperator, boolean bNullSafe, Object ctx, int startLhs, int endLhs, int startRhs, int endRhs ) { AdditiveExpression.maybeThrowRichNPE( lhsValue, rhsValue, bNullSafe, ctx, startLhs, endLhs, startRhs, endRhs ); return evaluate( type, lhsValue, rhsValue, lhsType, rhsType, iOperator, bNullSafe ); } // Potentially called from generated bytecode @SuppressWarnings({"ConstantConditions"}) public static Object evaluate( IType type, Object lhsValue, Object rhsValue, IType lhsType, IType rhsType, int iOperator, boolean bNullSafe ) { if( lhsType instanceof IPlaceholder && ((IPlaceholder)lhsType).isPlaceholder() ) { lhsType = TypeSystem.getFromObject( lhsValue ); type = ParserBase.resolveRuntimeType( lhsType, iOperator, rhsType ); } if( rhsType instanceof IPlaceholder && ((IPlaceholder)rhsType).isPlaceholder() ) { rhsType = TypeSystem.getFromObject( rhsValue ); type = ParserBase.resolveRuntimeType( lhsType, iOperator, rhsType ); } if( lhsValue == null ) { if( bNullSafe ) { return null; } throw new NullPointerException("left-hand operand was null"); } if( rhsValue == null ) { if( bNullSafe ) { return null; } throw new NullPointerException("right-hand operand was null"); } DimensionOperandResolver customNumberResolver = DimensionOperandResolver.resolve( type, (char)iOperator, lhsType, lhsValue, rhsType, rhsValue ); type = customNumberResolver.getRawNumberType(); lhsValue = customNumberResolver.getLhsValue(); rhsValue = customNumberResolver.getRhsValue(); IDimension customNumberBase = customNumberResolver.getBase(); Object retValue; switch( iOperator ) { case '*': { if( type == JavaTypes.BIG_DECIMAL() ) { BigDecimal lhsBD = CommonServices.getCoercionManager().makeBigDecimalFrom( lhsValue ); BigDecimal rhsBD = CommonServices.getCoercionManager().makeBigDecimalFrom( rhsValue ); retValue = lhsBD.multiply( rhsBD ); } else if( type == JavaTypes.BIG_INTEGER() ) { retValue = CommonServices.getCoercionManager().makeBigIntegerFrom( lhsValue ).multiply( CommonServices.getCoercionManager().makeBigIntegerFrom( rhsValue ) ); } else if( type == JavaTypes.INTEGER() || type == JavaTypes.pINT() ) { retValue = CommonServices.getCoercionManager().makeIntegerFrom( lhsValue ) * CommonServices.getCoercionManager().makeIntegerFrom( rhsValue ); } else if( type == JavaTypes.LONG() || type == JavaTypes.pLONG() ) { retValue = makeLong( CommonServices.getCoercionManager().makeLongFrom( lhsValue ) * CommonServices.getCoercionManager().makeLongFrom( rhsValue ) ); } else if( type == JavaTypes.DOUBLE() || type == JavaTypes.pDOUBLE() ) { retValue = makeDoubleValue( makeDoubleValue( lhsValue ) * makeDoubleValue( rhsValue ) ); } else if( type == JavaTypes.FLOAT() || type == JavaTypes.pFLOAT() ) { retValue = makeFloatValue( makeFloatValue( lhsValue ) * makeFloatValue( rhsValue ) ); } else if( type == JavaTypes.SHORT() || type == JavaTypes.pSHORT() ) { retValue = Integer.valueOf( CommonServices.getCoercionManager().makeIntegerFrom( lhsValue ) * CommonServices.getCoercionManager().makeIntegerFrom( rhsValue ) ).shortValue(); } else if( type == JavaTypes.BYTE() || type == JavaTypes.pBYTE() ) { retValue = (byte)(CommonServices.getCoercionManager().makeIntegerFrom( lhsValue ) * CommonServices.getCoercionManager().makeIntegerFrom( rhsValue )); } else { throw new UnsupportedNumberTypeException(type); } break; } case '/': { if( type == JavaTypes.BIG_DECIMAL() ) { BigDecimal lhsBD = CommonServices.getCoercionManager().makeBigDecimalFrom( lhsValue ); BigDecimal rhsBD = CommonServices.getCoercionManager().makeBigDecimalFrom( rhsValue ); retValue = lhsBD.divide( rhsBD, MathContext.DECIMAL128 ); } else if( type == JavaTypes.BIG_INTEGER() ) { retValue = CommonServices.getCoercionManager().makeBigIntegerFrom( lhsValue ).divide( CommonServices.getCoercionManager().makeBigIntegerFrom( rhsValue ) ); } else if( type == JavaTypes.INTEGER() || type == JavaTypes.pINT() ) { retValue = CommonServices.getCoercionManager().makeIntegerFrom( lhsValue ) / CommonServices.getCoercionManager().makeIntegerFrom( rhsValue ); } else if( type == JavaTypes.LONG() || type == JavaTypes.pLONG() ) { retValue = makeLong( CommonServices.getCoercionManager().makeLongFrom( lhsValue ) / CommonServices.getCoercionManager().makeLongFrom( rhsValue ) ); } else if( type == JavaTypes.DOUBLE() || type == JavaTypes.pDOUBLE() ) { retValue = makeDoubleValue( makeDoubleValue( lhsValue ) / makeDoubleValue( rhsValue ) ); } else if( type == JavaTypes.FLOAT() || type == JavaTypes.pFLOAT() ) { retValue = makeFloatValue( makeFloatValue( lhsValue ) / makeFloatValue( rhsValue ) ); } else if( type == JavaTypes.SHORT() || type == JavaTypes.pSHORT() ) { retValue = Integer.valueOf( CommonServices.getCoercionManager().makeIntegerFrom( lhsValue ) / CommonServices.getCoercionManager().makeIntegerFrom( rhsValue ) ).shortValue(); } else if( type == JavaTypes.BYTE() || type == JavaTypes.pBYTE() ) { retValue = (byte)(CommonServices.getCoercionManager().makeIntegerFrom( lhsValue ) / CommonServices.getCoercionManager().makeIntegerFrom( rhsValue )); } else { throw new UnsupportedNumberTypeException(type); } break; } case '%': { if( type == JavaTypes.BIG_DECIMAL() ) { BigDecimal lhsBD = CommonServices.getCoercionManager().makeBigDecimalFrom( lhsValue ); BigDecimal rhsBD = CommonServices.getCoercionManager().makeBigDecimalFrom( rhsValue ); BigDecimal result = lhsBD.remainder( rhsBD, MathContext.DECIMAL128 ); retValue = result.abs(); } else if( type == JavaTypes.BIG_INTEGER() ) { retValue = CommonServices.getCoercionManager().makeBigIntegerFrom( lhsValue ).mod( CommonServices.getCoercionManager().makeBigIntegerFrom( rhsValue ) ); } else if( type == JavaTypes.INTEGER() || type == JavaTypes.pINT() ) { retValue = CommonServices.getCoercionManager().makeIntegerFrom( lhsValue ) % CommonServices.getCoercionManager().makeIntegerFrom( rhsValue ); } else if( type == JavaTypes.LONG() || type == JavaTypes.pLONG() ) { retValue = makeLong( CommonServices.getCoercionManager().makeLongFrom( lhsValue ) % CommonServices.getCoercionManager().makeLongFrom( rhsValue ) ); } else if( type == JavaTypes.DOUBLE() || type == JavaTypes.pDOUBLE() ) { retValue = makeDoubleValue( makeDoubleValue( lhsValue ) % makeDoubleValue( rhsValue ) ); } else if( type == JavaTypes.FLOAT() || type == JavaTypes.pFLOAT() ) { retValue = makeFloatValue( makeFloatValue( lhsValue ) % makeFloatValue( rhsValue ) ); } else if( type == JavaTypes.SHORT() || type == JavaTypes.pSHORT() ) { retValue = Integer.valueOf( CommonServices.getCoercionManager().makeIntegerFrom( lhsValue ) % CommonServices.getCoercionManager().makeIntegerFrom( rhsValue ) ).shortValue(); } else if( type == JavaTypes.BYTE() || type == JavaTypes.pBYTE() ) { retValue = (byte)(CommonServices.getCoercionManager().makeIntegerFrom( lhsValue ) % CommonServices.getCoercionManager().makeIntegerFrom( rhsValue )); } else { throw new UnsupportedNumberTypeException(type); } break; } default: retValue = null; } if( retValue != null ) { if( customNumberBase != null ) { //noinspection unchecked retValue = customNumberBase.fromNumber( (Number)retValue ); } } return retValue; } }