blob: 41b897fea128cbf157fd752803e2c693d0458092 [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 org.eclipse.emf.common.util.Diagnostic;
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.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 a logical binary operator per JSP.2.3.6.1 (logical and/or)
*
* @author cbateman
*
*/
/*package*/abstract class LogicalBinaryOperator extends BinaryOperator
{
LogicalBinaryOperator(DiagnosticFactory diagnosticFactory) {
super(diagnosticFactory);
}
public ValueType performOperation(ValueType firstArg, ValueType secondArg)
{
final boolean canCoerceFirstArg =
TypeCoercer.canCoerceToBoolean(TypeTransformer.transformBoxPrimitives(firstArg.getSignature()));
final boolean canCoerceSecondArg =
TypeCoercer.canCoerceToBoolean(TypeTransformer.transformBoxPrimitives(secondArg.getSignature()));
// if can't perform, must return null
if (! (canCoerceFirstArg && canCoerceSecondArg))
{
return null;
}
Boolean firstArgResolvedValue = null;
if (firstArg instanceof LiteralType)
{
try
{
firstArgResolvedValue = ((LiteralType)firstArg).coerceToBoolean();
}
catch (TypeCoercionException tce)
{
// should never be throw due to already checking if can coerce
throw new AssertionError("coercion already checked; this should never be reached");
}
}
Boolean secondArgResolvedValue = null;
if (secondArg instanceof LiteralType)
{
try
{
secondArgResolvedValue = ((LiteralType)secondArg).coerceToBoolean();
}
catch (TypeCoercionException tce)
{
// should never be throw due to already checking if can coerce
throw new AssertionError("coercion already checked; this should never be reached");
}
}
if (firstArgResolvedValue != null && secondArgResolvedValue != null)
{
boolean result =
doRealOperation(firstArgResolvedValue, secondArgResolvedValue);
return result ? BooleanLiteralType.TRUE : BooleanLiteralType.FALSE;
}
// otherwise, just return a boolean
// result can only be an rvalue
return new ValueType(TypeConstants.TYPE_BOOLEAN, IAssignable.ASSIGNMENT_TYPE_RHS);
}
public Diagnostic validate(ValueType firstArg, ValueType secondArg)
{
final boolean canCoerceFirstArg =
TypeCoercer.canCoerceToBoolean(TypeTransformer.transformBoxPrimitives(firstArg.getSignature()));
final boolean canCoerceSecondArg =
TypeCoercer.canCoerceToBoolean(TypeTransformer.transformBoxPrimitives(secondArg.getSignature()));
if (!canCoerceFirstArg)
{
return _diagnosticFactory.
create_BINARY_OP_CANNOT_COERCE_ARGUMENT_TO_BOOLEAN("first");
//return new BasicDiagnostic(Diagnostic.ERROR, "", 0, "Cannot coerce first argument of "+readableOperatorName()+" to boolean", null);
}
if (!canCoerceSecondArg)
{
return _diagnosticFactory.
create_BINARY_OP_CANNOT_COERCE_ARGUMENT_TO_BOOLEAN("first");
//return new BasicDiagnostic(Diagnostic.ERROR, "", 0, "Cannot coerce second argument of "+readableOperatorName()+" to boolean", null);
}
if (firstArg instanceof LiteralType)
{
try
{
final Boolean boolValue =
((LiteralType)firstArg).coerceToBoolean();
if (boolValue.booleanValue() == shortCircuitValue())
{
return _diagnosticFactory.
create_BINARY_OP_FIRST_ARGUMENT_SHORT_CIRCUITS
(shortCircuitValue(), readableOperatorName());
}
}
catch (TypeCoercionException tce)
{
// should never be throw due to already checking if can coerce
throw new AssertionError("coercion already checked; this should never be reached");
}
}
if (secondArg instanceof LiteralType)
{
try
{
final Boolean boolValue =
((LiteralType)secondArg).coerceToBoolean();
if (boolValue.booleanValue() == shortCircuitValue())
{
return _diagnosticFactory.
create_BINARY_OP_SECOND_ARGUMENT_ALWAYS_EVAL_SAME
(shortCircuitValue(), readableOperatorName());
}
}
catch (TypeCoercionException tce)
{
// should never be throw due to already checking if can coerce
throw new AssertionError("coercion already checked; this should never be reached");
}
}
// otherwise, nothing to report
return Diagnostic.OK_INSTANCE;
}
/**
* @return a human readable name for the operator
*/
protected abstract String readableOperatorName();
/**
* @return the boolean value on which the operator short-circuits
*/
protected abstract boolean shortCircuitValue();
/**
* @param firstArg
* @param secondArg
* @return the result of performing the operator to two actual values
*/
protected abstract boolean doRealOperation(Boolean firstArg, Boolean secondArg);
}