public Evaluate ( TemplateContext context ) : void | ||
context | TemplateContext | |
return | void |
public override void Evaluate(TemplateContext context)
{
var leftValueOriginal = context.Evaluate(Left);
var leftValue = leftValueOriginal;
var rightValueOriginal = context.Evaluate(Right);
object rightValue = rightValueOriginal;
if (Operator == ScriptBinaryOperator.EmptyCoalescing)
{
context.Result = leftValue ?? rightValue;
return;
}
else if (Operator == ScriptBinaryOperator.And || Operator == ScriptBinaryOperator.Or)
{
var leftBoolValue = ScriptValueConverter.ToBool(leftValue);
var rightBoolValue = ScriptValueConverter.ToBool(rightValue);
if (Operator == ScriptBinaryOperator.And)
{
context.Result = leftBoolValue && rightBoolValue;
}
else
{
context.Result = leftBoolValue || rightBoolValue;
}
return;
}
else
{
switch (Operator)
{
case ScriptBinaryOperator.ShiftLeft:
case ScriptBinaryOperator.ShiftRight:
if (leftValue is IList || rightValue is IList)
{
// Special path for IList to allow custom binary expression
context.Result = ScriptArray.CustomOperator.EvaluateBinaryExpression(this, leftValue,
rightValue);
return;
}
break;
case ScriptBinaryOperator.CompareEqual:
case ScriptBinaryOperator.CompareNotEqual:
case ScriptBinaryOperator.CompareGreater:
case ScriptBinaryOperator.CompareLess:
case ScriptBinaryOperator.CompareGreaterOrEqual:
case ScriptBinaryOperator.CompareLessOrEqual:
case ScriptBinaryOperator.Add:
case ScriptBinaryOperator.Substract:
case ScriptBinaryOperator.Multiply:
case ScriptBinaryOperator.Divide:
case ScriptBinaryOperator.DivideRound:
case ScriptBinaryOperator.Modulus:
case ScriptBinaryOperator.RangeInclude:
case ScriptBinaryOperator.RangeExclude:
var leftType = leftValue?.GetType();
var rightType = rightValue?.GetType();
if (leftValue is string || rightValue is string)
{
context.Result = CalculateToString(Operator, leftValue, rightValue);
{
// TODO: Log an error if CalculateToString return null?
//context.LogError(Span, $"Operation [{Operator}] on strings not supported");
}
}
else
{
context.Result = Calculate(Operator, leftValue, leftType, rightValue, rightType);
}
return;
}
}
throw new ScriptRuntimeException(Span, $"Operator [{Operator.ToText()}] is not implemented for the left [{Left}] / right [{Right}]");
}
private static bool CompareTo(TemplateContext context, SourceSpan span, ScriptBinaryOperator op, IEnumerable <object> left, IEnumerable <object> right) { // Compare the length first var leftCount = left.Count(); var rightCount = right.Count(); var compare = leftCount.CompareTo(rightCount); switch (op) { case ScriptBinaryOperator.CompareEqual: if (compare != 0) { return(false); } break; case ScriptBinaryOperator.CompareNotEqual: if (compare != 0) { return(true); } if (leftCount == 0) { return(false); } break; case ScriptBinaryOperator.CompareLessOrEqual: case ScriptBinaryOperator.CompareLess: if (compare < 0) { return(true); } if (compare > 0) { return(false); } if (leftCount == 0 && op == ScriptBinaryOperator.CompareLess) { return(false); } break; case ScriptBinaryOperator.CompareGreaterOrEqual: case ScriptBinaryOperator.CompareGreater: if (compare < 0) { return(false); } if (compare > 0) { return(true); } if (leftCount == 0 && op == ScriptBinaryOperator.CompareGreater) { return(false); } break; default: throw new ScriptRuntimeException(span, $"The operator `{op.ToText()}` is not supported between {context.GetTypeName(left)} and {context.GetTypeName(right)}."); } // Otherwise we need to compare each element var leftIterator = left.GetEnumerator(); var rightIterator = right.GetEnumerator(); while (leftIterator.MoveNext() && rightIterator.MoveNext()) { var leftValue = leftIterator.Current; var rightValue = rightIterator.Current; var result = (bool)ScriptBinaryExpression.Evaluate(context, span, op, leftValue, rightValue); if (!result) { return(false); } } return(true); }