| /******************************************************************************* |
| * 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) |
| { |
| if (TypeConstants.TYPE_JAVAOBJECT.equals(firstArg.getSignature()) || |
| TypeConstants.TYPE_JAVAOBJECT.equals(secondArg.getSignature())) { |
| return Diagnostic.OK_INSTANCE; |
| } |
| |
| // 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; |
| } |
| |
| } |