blob: 0b6ac7d016c46c2894a0b703076c6a07fb15d98b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 Oracle Corporation.
* 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:
* Cameron Bateman/Oracle - initial API and implementation
*
********************************************************************************/
package org.eclipse.jst.jsf.validation.internal.el.operators;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jst.jsf.common.internal.types.FloatLiteralType;
import org.eclipse.jst.jsf.common.internal.types.IAssignable;
import org.eclipse.jst.jsf.common.internal.types.IntegerLiteralType;
import org.eclipse.jst.jsf.common.internal.types.LiteralType;
import org.eclipse.jst.jsf.common.internal.types.TypeCoercer;
import org.eclipse.jst.jsf.common.internal.types.TypeCoercionException;
import org.eclipse.jst.jsf.common.internal.types.TypeConstants;
import org.eclipse.jst.jsf.common.internal.types.TypeTransformer;
import org.eclipse.jst.jsf.common.internal.types.ValueType;
import org.eclipse.jst.jsf.validation.internal.el.diagnostics.DiagnosticFactory;
/**
* Represents the EL modulo operator: % or mod
* Based JSP.2.3.5.3
*
* @author cbateman
*
*/
/*package*/ class ModArithmeticBinaryOperator extends ArithmeticBinaryOperator
{
private static final String MODULO = "modulo"; //$NON-NLS-1$
ModArithmeticBinaryOperator(DiagnosticFactory diagnosticFactory) {
super(diagnosticFactory);
}
public ValueType performOperation(ValueType firstArg, ValueType secondArg)
{
// JSP.2.3.5.3, step 1 if both null, then return zero
if (TypeCoercer.typeIsNull(firstArg.getSignature())
&& TypeCoercer.typeIsNull(secondArg.getSignature()))
{
return IntegerLiteralType.ZERO;
}
final String boxedFirstArg = TypeTransformer.transformBoxPrimitives(firstArg.getSignature());
final String boxedSecondArg = TypeTransformer.transformBoxPrimitives(secondArg.getSignature());
// JSP.2.3.5.3, step 2, if either arg is BigDecimal, Float, Double
// or String (ignoring whether it is value coercable), then coerce
// to Double and do op
if (TypeConstants.TYPE_BIG_DOUBLE.equals(boxedFirstArg)
|| TypeConstants.TYPE_BIG_DOUBLE.equals(boxedSecondArg)
|| TypeConstants.TYPE_BOXED_DOUBLE.equals(boxedFirstArg)
|| TypeConstants.TYPE_BOXED_DOUBLE.equals(boxedSecondArg)
|| TypeConstants.TYPE_BOXED_FLOAT.equals(boxedFirstArg)
|| TypeConstants.TYPE_BOXED_FLOAT.equals(boxedSecondArg))
{
// TODO: handle case where one is a literal or resolvable string value
// that containss ".", "e" or "E"
return performDouble(firstArg, secondArg);
}
// JSP.2.3.5.3, step 3, if either arg is a BigInteger, coerce
// both to BigInteger
if (TypeConstants.TYPE_BIG_INTEGER.equals(boxedFirstArg)
|| TypeConstants.TYPE_BIG_INTEGER.equals(boxedSecondArg))
{
return performBigInteger(firstArg, secondArg);
}
// JSP.2.3.5.3, step 4, otherwise try to perform as a Long op
return performLong(firstArg, secondArg);
}
public Diagnostic validate(ValueType firstArg, ValueType secondArg) {
if (TypeConstants.TYPE_JAVAOBJECT.equals(firstArg.getSignature()) ||
TypeConstants.TYPE_JAVAOBJECT.equals(secondArg.getSignature())) {
return Diagnostic.OK_INSTANCE;
}
// JSP.2.3.5.3, step 1 if both null, then return zero
if (TypeCoercer.typeIsNull(firstArg.getSignature())
&& TypeCoercer.typeIsNull(secondArg.getSignature()))
{
return _diagnosticFactory.create_BINARY_OP_BOTH_OPERANDS_NULL(MODULO);
}
final String boxedFirstArg = TypeTransformer.transformBoxPrimitives(firstArg.getSignature());
final String boxedSecondArg = TypeTransformer.transformBoxPrimitives(secondArg.getSignature());
// JSP.2.3.5.3, step 2, if either arg is BigDecimal, Float, Double
// or String (ignoring whether it is value coercable), then coerce
// to Double and do op
if (TypeConstants.TYPE_BIG_DOUBLE.equals(boxedFirstArg)
|| TypeConstants.TYPE_BIG_DOUBLE.equals(boxedSecondArg)
|| TypeConstants.TYPE_BOXED_DOUBLE.equals(boxedFirstArg)
|| TypeConstants.TYPE_BOXED_DOUBLE.equals(boxedSecondArg)
|| TypeConstants.TYPE_BOXED_FLOAT.equals(boxedFirstArg)
|| TypeConstants.TYPE_BOXED_FLOAT.equals(boxedSecondArg))
{
// TODO: handle case where one is a literal or resolvable string value
// that containss ".", "e" or "E"
return validateDouble(firstArg, secondArg);
}
// JSP.2.3.5.3, step 3, if either arg is a BigInteger, coerce
// both to BigInteger
if (TypeConstants.TYPE_BIG_INTEGER.equals(boxedFirstArg)
|| TypeConstants.TYPE_BIG_INTEGER.equals(boxedSecondArg))
{
return validateBigInteger(firstArg, secondArg);
}
// JSP.2.3.5.3, step 4, otherwise try to perform as a Long op
return validateLong(firstArg, secondArg);
}
private ValueType performDouble(ValueType firstArg, ValueType secondArg)
{
try
{
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(firstArg.getSignature()));
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(secondArg.getSignature()));
Number secondValue = null;
if (secondArg instanceof LiteralType)
{
secondValue = ((LiteralType)secondArg).coerceToNumber(Double.class);
if (secondValue.doubleValue() == 0.0)
{
// division by zero
return null;
}
}
Number firstValue = null;
if (firstArg instanceof LiteralType)
{
firstValue = ((LiteralType)firstArg).coerceToNumber(Double.class);
}
if (firstValue != null && secondValue != null)
{
return new FloatLiteralType(
doRealOperation(new Double(firstValue.doubleValue()),
new Double(secondValue.doubleValue())).doubleValue());
}
// if we get to here, the coercion is valid, so a Double will be
// returned
return new ValueType(Signature.SIG_DOUBLE, IAssignable.ASSIGNMENT_TYPE_RHS);
}
catch (TypeCoercionException tce)
{
// could not coerce, so null
return null;
}
}
private ValueType performBigInteger(ValueType firstArg, ValueType secondArg)
{
try
{
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(firstArg.getSignature()));
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(secondArg.getSignature()));
// check second arg for zero
if (secondArg instanceof LiteralType)
{
if (((LiteralType)secondArg).coerceToNumber(BigInteger.class).equals(BigInteger.ZERO))
{
// division by zero
return null;
}
}
// since one of the args is BigInteger, they are not both literals,
// so if we get to here, we have a successful mod of two
// big integers to one big integer
return new ValueType(TypeConstants.TYPE_BIG_INTEGER, IAssignable.ASSIGNMENT_TYPE_RHS);
}
catch (TypeCoercionException tce)
{
// no coercion
return null;
}
}
private ValueType performLong(ValueType firstArg, ValueType secondArg)
{
try
{
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(firstArg.getSignature()));
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(secondArg.getSignature()));
Number secondValue = null;
if (secondArg instanceof LiteralType)
{
secondValue = ((LiteralType)secondArg).coerceToNumber(Long.class);
if (secondValue.longValue() == 0)
{
// division by zero
return null;
}
}
Number firstValue = null;
if (firstArg instanceof LiteralType)
{
firstValue = ((LiteralType)firstArg).coerceToNumber(Long.class);
}
if (firstValue != null && secondValue != null)
{
return new IntegerLiteralType(
doRealOperation(Long.valueOf(firstValue.longValue()),
Long.valueOf(secondValue.longValue())).longValue());
}
// if we get to here, the coercion is valid, so a Long will be
// returned
return new ValueType(Signature.SIG_LONG, IAssignable.ASSIGNMENT_TYPE_RHS);
}
catch (TypeCoercionException tce)
{
// could not coerce, so null
return null;
}
}
private Diagnostic validateDouble(ValueType firstArg, ValueType secondArg)
{
try
{
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(firstArg.getSignature()));
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(secondArg.getSignature()));
Number secondValue = null;
if (secondArg instanceof LiteralType)
{
secondValue = ((LiteralType)secondArg).coerceToNumber(Double.class);
if (secondValue.doubleValue() == 0.0)
{
// division by zero
return _diagnosticFactory.create_BINARY_OP_POSSIBLE_DIVISION_BY_ZERO();
}
}
Number firstValue = null;
if (firstArg instanceof LiteralType)
{
firstValue = ((LiteralType)firstArg).coerceToNumber(Double.class);
}
if (firstValue != null && secondValue != null)
{
return _diagnosticFactory.
create_BINARY_OP_CONSTANT_EXPRESSION_ALWAYS_EVAL_SAME
(MODULO, Double.toString(
firstValue.doubleValue()%secondValue.doubleValue()));
}
// if we get to here, the coercion is valid, so a Double will be
// returned and everything is good
return Diagnostic.OK_INSTANCE;
}
catch (TypeCoercionException tce)
{
// could not coerce, so error
return _diagnosticFactory.
create_BINARY_OP_COULD_NOT_MAKE_NUMERIC_COERCION(MODULO);
}
}
private Diagnostic validateBigInteger(ValueType firstArg, ValueType secondArg)
{
try
{
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(firstArg.getSignature()));
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(secondArg.getSignature()));
// check second arg for zero
if (secondArg instanceof LiteralType)
{
if (((LiteralType)secondArg).coerceToNumber(BigInteger.class).equals(BigInteger.ZERO))
{
// division by zero
return _diagnosticFactory.create_BINARY_OP_POSSIBLE_DIVISION_BY_ZERO();
}
}
// since one of the args is BigInteger, they are not both literals,
// so if we get to here, we have a successful mod of two
// big integers to one big integer
return Diagnostic.OK_INSTANCE;
}
catch (TypeCoercionException tce)
{
// no coercion
return _diagnosticFactory.
create_BINARY_OP_COULD_NOT_MAKE_NUMERIC_COERCION(MODULO);
}
}
private Diagnostic validateLong(ValueType firstArg, ValueType secondArg)
{
try
{
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(firstArg.getSignature()));
TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(secondArg.getSignature()));
Number secondValue = null;
if (secondArg instanceof LiteralType)
{
secondValue = ((LiteralType)secondArg).coerceToNumber(Long.class);
if (secondValue.longValue() == 0)
{
// division by zero
return _diagnosticFactory.
create_BINARY_OP_POSSIBLE_DIVISION_BY_ZERO();
}
}
Number firstValue = null;
if (firstArg instanceof LiteralType)
{
firstValue = ((LiteralType)firstArg).coerceToNumber(Long.class);
}
if (firstValue != null && secondValue != null)
{
return _diagnosticFactory.
create_BINARY_OP_CONSTANT_EXPRESSION_ALWAYS_EVAL_SAME
(MODULO, Long.toString(firstValue.longValue()%secondValue.longValue()));
}
// if we get to here, the coercion is valid, so a Long will be
// returned
return Diagnostic.OK_INSTANCE;
}
catch (TypeCoercionException tce)
{
// could not coerce, so error
return _diagnosticFactory.
create_BINARY_OP_COULD_NOT_MAKE_NUMERIC_COERCION(MODULO);
}
}
protected Long doRealOperation(Long firstArg, Long secondArg) {
return Long.valueOf(firstArg.longValue() % secondArg.longValue());
}
protected Double doRealOperation(Double firstArg, Double secondArg) {
return new Double(firstArg.doubleValue() % secondArg.doubleValue());
}
protected BigDecimal doRealOperation(BigDecimal firstArg,
BigDecimal secondArg) {
return new BigDecimal(firstArg.doubleValue() % secondArg.doubleValue());
}
protected String getOperatorName() {
return MODULO;
}
}