blob: b5b37f3d27ca854353011f46a6e84051d771797f [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.BooleanLiteralType;
import org.eclipse.jst.jsf.common.internal.types.IAssignable;
import org.eclipse.jst.jsf.common.internal.types.TypeCoercer;
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;
/**
* Encapsulates the EL binary operators "<", ">", "<=", ">="
*
* @author cbateman
*
*/
/*package*/ abstract class LtGtRelationalBinaryOperator extends RelationalBinaryOperator {
protected abstract boolean doRealOperation(Number firstArg, Number secondArg);
protected abstract boolean doRealOperation(String firstArg, String secondArg);
public ValueType performOperation(ValueType firstArg, ValueType secondArg)
{
// JSP.2.3.5.6 step 2 if either operand is null, then always false
if (TypeCoercer.typeIsNull(firstArg.getSignature())
|| TypeCoercer.typeIsNull(secondArg.getSignature()))
{
return BooleanLiteralType.FALSE;
}
String boxedFirstType = TypeTransformer.transformBoxPrimitives(firstArg.getSignature());
String boxedSecondType = TypeTransformer.transformBoxPrimitives(secondArg.getSignature());
// JSP.2.3.5.6 step 3, if either is BigDecimal, promote both and compare
if (TypeConstants.TYPE_BIG_DOUBLE.equals(boxedFirstType)
|| TypeConstants.TYPE_BIG_DOUBLE.equals(boxedSecondType))
{
return handleNumericComparison(firstArg, secondArg, BigDecimal.class);
}
// JSP.2.3.5.6, step 4 if either is a float or double, promote both to
// double and compare
if (TypeConstants.TYPE_BOXED_DOUBLE.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_FLOAT.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_DOUBLE.equals(boxedSecondType)
|| TypeConstants.TYPE_BOXED_FLOAT.equals(boxedSecondType))
{
return handleNumericComparison(firstArg, secondArg, Double.class);
}
// JSP.2.3.5.6, step 5 if either is a big integer, promote and compare
if (TypeConstants.TYPE_BIG_INTEGER.equals(boxedFirstType)
|| TypeConstants.TYPE_BIG_INTEGER.equals(boxedSecondType))
{
return handleNumericComparison(firstArg, secondArg, BigInteger.class);
}
// JSP.2.3.5.6, step 6 if either is Long or smaller, coerce both to Long
if (TypeConstants.TYPE_BOXED_LONG.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_LONG.equals(boxedSecondType)
|| TypeConstants.TYPE_BOXED_INTEGER.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_INTEGER.equals(boxedSecondType)
|| TypeConstants.TYPE_BOXED_SHORT.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_SHORT.equals(boxedSecondType)
|| TypeConstants.TYPE_BOXED_BYTE.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_BYTE.equals(boxedSecondType)
|| TypeConstants.SIGNATURE_BOXED_CHARACTER.equals(boxedFirstType)
|| TypeConstants.SIGNATURE_BOXED_CHARACTER.equals(boxedSecondType))
{
return handleNumericComparison(firstArg, secondArg, Long.class);
}
// JSP.2.3.5.7, step 7 if either is a string, coerce to string and
// compare lexically
if (TypeConstants.TYPE_STRING.equals(boxedFirstType)
|| TypeConstants.TYPE_STRING.equals(boxedSecondType))
{
return handleStringComparison(firstArg, secondArg);
}
// JSP.2.3.5.7, steps 8 and 9 -- if either one implements the
// Comparable interface, then as far as we can determine statically
// (compareTo may not work on the other arg, but who knows),
// we are good
if (firstArg.isInstanceOf(TypeConstants.TYPE_COMPARABLE)
|| secondArg.isInstanceOf(TypeConstants.TYPE_COMPARABLE))
{
return new ValueType(Signature.SIG_BOOLEAN, IAssignable.ASSIGNMENT_TYPE_RHS);
}
// JSP.2.3.5.6, step 10 -- otherwise, error
return null;
}
public Diagnostic validate(ValueType firstArg, ValueType secondArg)
{
// JSP.2.3.5.6 step 2 if either operand is null, then always false
if (TypeCoercer.typeIsNull(firstArg.getSignature())
|| TypeCoercer.typeIsNull(secondArg.getSignature()))
{
return DiagnosticFactory.
create_BINARY_OP_EQUALITY_COMP_WITH_NULL_ALWAYS_EVAL_SAME("false");
}
String boxedFirstType = TypeTransformer.transformBoxPrimitives(firstArg.getSignature());
String boxedSecondType = TypeTransformer.transformBoxPrimitives(secondArg.getSignature());
// JSP.2.3.5.6 step 3, if either is BigDecimal, promote both and compare
if (TypeConstants.TYPE_BIG_DOUBLE.equals(boxedFirstType)
|| TypeConstants.TYPE_BIG_DOUBLE.equals(boxedSecondType))
{
return validateNumericComparison(firstArg, secondArg, BigDecimal.class);
}
// JSP.2.3.5.6, step 4 if either is a float or double, promote both to
// double and compare
if (TypeConstants.TYPE_BOXED_DOUBLE.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_FLOAT.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_DOUBLE.equals(boxedSecondType)
|| TypeConstants.TYPE_BOXED_FLOAT.equals(boxedSecondType))
{
return validateNumericComparison(firstArg, secondArg, Double.class);
}
// JSP.2.3.5.6, step 5 if either is a big integer, promote and compare
if (TypeConstants.TYPE_BIG_INTEGER.equals(boxedFirstType)
|| TypeConstants.TYPE_BIG_INTEGER.equals(boxedSecondType))
{
return validateNumericComparison(firstArg, secondArg, BigInteger.class);
}
// JSP.2.3.5.6, step 6 if either is Long or smaller, coerce both to Long
if (TypeConstants.TYPE_BOXED_LONG.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_LONG.equals(boxedSecondType)
|| TypeConstants.TYPE_BOXED_INTEGER.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_INTEGER.equals(boxedSecondType)
|| TypeConstants.TYPE_BOXED_SHORT.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_SHORT.equals(boxedSecondType)
|| TypeConstants.TYPE_BOXED_BYTE.equals(boxedFirstType)
|| TypeConstants.TYPE_BOXED_BYTE.equals(boxedSecondType)
|| TypeConstants.SIGNATURE_BOXED_CHARACTER.equals(boxedFirstType)
|| TypeConstants.SIGNATURE_BOXED_CHARACTER.equals(boxedSecondType))
{
return validateNumericComparison(firstArg, secondArg, Long.class);
}
// JSP.2.3.5.7, step 7 if either is a string, coerce to string and
// compare lexically
if (TypeConstants.TYPE_STRING.equals(boxedFirstType)
|| TypeConstants.TYPE_STRING.equals(boxedSecondType))
{
return validateStringComparison(firstArg, secondArg);
}
// JSP.2.3.5.7, steps 8 and 9 -- if either one implements the
// Comparable interface, then as far as we can determine statically
// (compareTo may not work on the other arg, but who knows),
// we are good
if (firstArg.isInstanceOf(TypeConstants.TYPE_COMPARABLE)
|| secondArg.isInstanceOf(TypeConstants.TYPE_COMPARABLE))
{
return Diagnostic.OK_INSTANCE;
}
// JSP.2.3.5.6, step 10 -- otherwise, error
return DiagnosticFactory.create_BINARY_OP_NO_AVAILABLE_TYPE_COERCION();
}
}