blob: e4695ac889c069cf10b7c957832d07df92964299 [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.common.util.TypeUtil;
import org.eclipse.jst.jsf.validation.internal.el.diagnostics.DiagnosticFactory;
/**
* Encapsulates the EL binary operators "<", ">", "<=", ">="
*
* @author cbateman
*
*/
/*package*/ abstract class LtGtRelationalBinaryOperator extends RelationalBinaryOperator
{
LtGtRelationalBinaryOperator(final DiagnosticFactory diagnosticFactory, String jsfVersion)
{
super(diagnosticFactory, jsfVersion);
}
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))
{
if (checkIfIncompatibleEnums(firstArg, secondArg))
{
// error: no point in validating further since expr will probably throw an exception
return null;
}
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(Messages.getString("LtGtRelationalBinaryOperator.ConstantName.False")); //$NON-NLS-1$
}
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))
{
Diagnostic diag = Diagnostic.OK_INSTANCE;
if(checkIfIncompatibleEnums(firstArg, secondArg))
{
diag = _diagnosticFactory.create_BINARY_OP_COMPARISON_OF_ENUMS_INCOMPATIBLE();
}
return diag;
}
// JSP.2.3.5.6, step 10 -- otherwise, error
return _diagnosticFactory.create_BINARY_OP_NO_AVAILABLE_TYPE_COERCION();
}
/**
* @param firstArg
* @param secondArg
* @return diagnostic if firstArg and secondArg are incompatible with each other
* for compareTo purpose or OK if not
*/
private boolean checkIfIncompatibleEnums(ValueType firstArg,
ValueType secondArg)
{
if (firstArg.isEnumType()
&& secondArg.isEnumType()
&& !TypeUtil.isEnumsCompareCompatible(firstArg.getSignature()
, secondArg.getSignature()))
{
return true;
}
return false;
}
}