| /******************************************************************************* |
| * Copyright (c) 2006, 2010 Oracle Corporation. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Cameron Bateman/Oracle - initial API and implementation |
| * |
| ********************************************************************************/ |
| |
| package org.eclipse.jst.jsf.validation.internal.el.operators; |
| |
| import org.eclipse.emf.common.util.Diagnostic; |
| import org.eclipse.jst.jsf.common.internal.types.IAssignable; |
| 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 ternary choice op in EL: a ? b :c |
| * Based on JSP.2.3.8 |
| * |
| * @author cbateman |
| * |
| */ |
| public class TernaryChoiceOperator |
| { |
| private final DiagnosticFactory _diagnosticFactory; |
| |
| |
| /** |
| * @param diagnosticFactory |
| */ |
| public TernaryChoiceOperator(DiagnosticFactory diagnosticFactory) |
| { |
| super(); |
| _diagnosticFactory = diagnosticFactory; |
| } |
| |
| /** |
| * @param choiceArg |
| * @param whenTrueArg |
| * @param whenFalseArg |
| * @return the result of the choice arguments or null if indeterminant |
| */ |
| public ValueType perform(ValueType choiceArg, ValueType whenTrueArg, ValueType whenFalseArg) |
| { |
| final boolean isChoiceBoolean = |
| TypeCoercer.canCoerceToBoolean(TypeTransformer.transformBoxPrimitives(choiceArg.getSignature())); |
| |
| if (isChoiceBoolean) |
| { |
| if (choiceArg instanceof LiteralType) |
| { |
| try |
| { |
| Boolean result = ((LiteralType)choiceArg).coerceToBoolean(); |
| |
| if (result != null) |
| { |
| return result.booleanValue() ? whenTrueArg : whenFalseArg; |
| } |
| } |
| catch (TypeCoercionException tce) |
| { |
| return null; |
| } |
| } |
| |
| final String boxedWhenTrueArg = |
| TypeTransformer.transformBoxPrimitives(whenTrueArg.getSignature()); |
| |
| final String boxedWhenFalseArg = |
| TypeTransformer.transformBoxPrimitives(whenFalseArg.getSignature()); |
| // check if the two results are the same type |
| // TODO: could increase accuracy by appoximating type:i.e. if both |
| // are numeric etc. |
| if (boxedWhenTrueArg.equals(boxedWhenFalseArg)) |
| { |
| return new ValueType(whenTrueArg, IAssignable.ASSIGNMENT_TYPE_RHS); |
| } |
| |
| // otherwise, we have no idea what the resulting type is |
| return null; |
| } |
| |
| // if choice is not boolean, then can't resolve |
| return null; |
| } |
| |
| /** |
| * @param choiceArg |
| * @return a diagnostic validating the choice expr with these arguments |
| */ |
| public Diagnostic validate(ValueType choiceArg) |
| { |
| if (TypeConstants.TYPE_JAVAOBJECT.equals(choiceArg.getSignature())) { |
| return Diagnostic.OK_INSTANCE; |
| } |
| |
| final boolean isChoiceBoolean = |
| TypeCoercer.canCoerceToBoolean(TypeTransformer.transformBoxPrimitives(choiceArg.getSignature())); |
| |
| if (isChoiceBoolean) |
| { |
| if (choiceArg instanceof LiteralType) |
| { |
| try |
| { |
| Boolean result = ((LiteralType)choiceArg).coerceToBoolean(); |
| |
| if (result != null) |
| { |
| String whichSelected = result.booleanValue() ? "first" : "second"; //$NON-NLS-1$ //$NON-NLS-2$ |
| return _diagnosticFactory. |
| create_TERNARY_OP_CHOICE_IS_ALWAYS_SAME |
| (result.booleanValue(), whichSelected); |
| } |
| } |
| catch (TypeCoercionException tce) |
| { |
| return _diagnosticFactory. |
| create_TERNARY_OP_CANNOT_COERCE_CHOICE_TO_BOOLEAN(); |
| } |
| } |
| |
| // in both the case where the two arguments are the same and when |
| // they are different types, the best we can say is "OK", since |
| // we really don't know |
| return Diagnostic.OK_INSTANCE; |
| } |
| |
| // if choice is not boolean, then can't resolve |
| return _diagnosticFactory. |
| create_TERNARY_OP_CANNOT_COERCE_CHOICE_TO_BOOLEAN(); |
| } |
| } |