private static object CalculateToString(TemplateContext context, SourceSpan span, ScriptBinaryOperator op, object left, object right) { switch (op) { case ScriptBinaryOperator.Add: return(context.ToString(span, left) + context.ToString(span, right)); case ScriptBinaryOperator.Multiply: if (right is int) { var temp = left; left = right; right = temp; } if (left is int) { var rightText = context.ToString(span, right); var builder = new StringBuilder(); for (int i = 0; i < (int)left; i++) { builder.Append(rightText); } return(builder.ToString()); } throw new ScriptRuntimeException(span, $"Operator `{op.ToText()}` is not supported for the expression. Only working on string x int or int x string"); // unit test: 112-binary-string-error1.txt case ScriptBinaryOperator.CompareEqual: return(context.ToString(span, left) == context.ToString(span, right)); case ScriptBinaryOperator.CompareNotEqual: return(context.ToString(span, left) != context.ToString(span, right)); case ScriptBinaryOperator.CompareGreater: return(context.ToString(span, left).CompareTo(context.ToString(span, right)) > 0); case ScriptBinaryOperator.CompareLess: return(context.ToString(span, left).CompareTo(context.ToString(span, right)) < 0); case ScriptBinaryOperator.CompareGreaterOrEqual: return(context.ToString(span, left).CompareTo(context.ToString(span, right)) >= 0); case ScriptBinaryOperator.CompareLessOrEqual: return(context.ToString(span, left).CompareTo(context.ToString(span, right)) <= 0); case ScriptBinaryOperator.LiquidContains: return(context.ToString(span, left).Contains(context.ToString(span, right))); case ScriptBinaryOperator.LiquidStartsWith: return(context.ToString(span, left).StartsWith(context.ToString(span, right))); case ScriptBinaryOperator.LiquidEndsWith: return(context.ToString(span, left).EndsWith(context.ToString(span, right))); } // unit test: 150-range-expression-error1.out.txt throw new ScriptRuntimeException(span, $"Operator `{op.ToText()}` is not supported on string objects"); // unit test: 112-binary-string-error2.txt }
private object CalculateToString(ScriptBinaryOperator op, object left, object right) { switch (op) { case ScriptBinaryOperator.Add: return(ScriptValueConverter.ToString(Span, left) + ScriptValueConverter.ToString(Span, right)); case ScriptBinaryOperator.Multiply: if (right is int) { var temp = left; left = right; right = temp; } if (left is int) { var rightText = ScriptValueConverter.ToString(Span, right); var builder = new StringBuilder(); for (int i = 0; i < (int)left; i++) { builder.Append(rightText); } return(builder.ToString()); } throw new ScriptRuntimeException(Span, $"Operator [{op.ToText()}] is not supported for the expression [{this}]. Only working on string x int or int x string"); // unit test: 112-binary-string-error1.txt case ScriptBinaryOperator.CompareEqual: return(ScriptValueConverter.ToString(Span, left) == ScriptValueConverter.ToString(Span, right)); case ScriptBinaryOperator.CompareNotEqual: return(ScriptValueConverter.ToString(Span, left) != ScriptValueConverter.ToString(Span, right)); case ScriptBinaryOperator.CompareGreater: return(ScriptValueConverter.ToString(Span, left).CompareTo(ScriptValueConverter.ToString(Span, right)) > 0); case ScriptBinaryOperator.CompareLess: return(ScriptValueConverter.ToString(Span, left).CompareTo(ScriptValueConverter.ToString(Span, right)) < 0); case ScriptBinaryOperator.CompareGreaterOrEqual: return(ScriptValueConverter.ToString(Span, left).CompareTo(ScriptValueConverter.ToString(Span, right)) >= 0); case ScriptBinaryOperator.CompareLessOrEqual: return(ScriptValueConverter.ToString(Span, left).CompareTo(ScriptValueConverter.ToString(Span, right)) <= 0); } // unit test: 150-range-expression-error1.out.txt throw new ScriptRuntimeException(Span, $"Operator [{op.ToText()}] is not supported on string objects"); // unit test: 112-binary-string-error2.txt }
private object Calculate(ScriptBinaryOperator op, bool left, bool right) { switch (op) { case ScriptBinaryOperator.CompareEqual: return(left == right); case ScriptBinaryOperator.CompareNotEqual: return(left != right); } throw new ScriptRuntimeException(Span, $"The operator [{op.ToText()}] is not valid for bool<->bool"); }
private static object CalculateBool(ScriptBinaryOperator op, SourceSpan span, bool left, bool right) { switch (op) { case ScriptBinaryOperator.CompareEqual: return(left == right); case ScriptBinaryOperator.CompareNotEqual: return(left != right); } throw new ScriptRuntimeException(span, $"The operator `{op.ToText()}` is not valid for bool<->bool"); }
private static object CalculateLong(ScriptBinaryOperator op, SourceSpan span, long left, long right) { switch (op) { case ScriptBinaryOperator.Add: return(left + right); case ScriptBinaryOperator.Substract: return(left - right); case ScriptBinaryOperator.Multiply: return(left * right); case ScriptBinaryOperator.Divide: return((double)left / right); case ScriptBinaryOperator.DivideRound: return(left / right); case ScriptBinaryOperator.Modulus: return(left % right); case ScriptBinaryOperator.CompareEqual: return(left == right); case ScriptBinaryOperator.CompareNotEqual: return(left != right); case ScriptBinaryOperator.CompareGreater: return(left > right); case ScriptBinaryOperator.CompareLess: return(left < right); case ScriptBinaryOperator.CompareGreaterOrEqual: return(left >= right); case ScriptBinaryOperator.CompareLessOrEqual: return(left <= right); case ScriptBinaryOperator.RangeInclude: return(RangeInclude(left, right)); case ScriptBinaryOperator.RangeExclude: return(RangeExclude(left, right)); } throw new ScriptRuntimeException(span, $"The operator `{op.ToText()}` is not implemented for long<->long"); }
private object Calculate(ScriptBinaryOperator op, int left, int right) { switch (op) { case ScriptBinaryOperator.Add: return(left + right); case ScriptBinaryOperator.Substract: return(left - right); case ScriptBinaryOperator.Multiply: return(left * right); case ScriptBinaryOperator.Divide: return((float)left / right); case ScriptBinaryOperator.DivideRound: return(left / right); case ScriptBinaryOperator.Modulus: return(left % right); case ScriptBinaryOperator.CompareEqual: return(left == right); case ScriptBinaryOperator.CompareNotEqual: return(left != right); case ScriptBinaryOperator.CompareGreater: return(left > right); case ScriptBinaryOperator.CompareLess: return(left < right); case ScriptBinaryOperator.CompareGreaterOrEqual: return(left >= right); case ScriptBinaryOperator.CompareLessOrEqual: return(left <= right); case ScriptBinaryOperator.RangeInclude: return(RangeInclude(left, right)); case ScriptBinaryOperator.RangeExclude: return(RangeExclude(left, right)); } throw new ScriptRuntimeException(Span, $"The operator [{op.ToText()}] is not implemented for int<->int"); }
private static object CalculateDecimal(ScriptBinaryOperator op, SourceSpan span, decimal left, decimal right) { switch (op) { case ScriptBinaryOperator.Add: return(left + right); case ScriptBinaryOperator.Substract: return(left - right); case ScriptBinaryOperator.Multiply: return(left * right); case ScriptBinaryOperator.Divide: return(left / right); case ScriptBinaryOperator.DivideRound: return(Math.Round(left / right)); case ScriptBinaryOperator.Modulus: return(left % right); case ScriptBinaryOperator.CompareEqual: return(left == right); case ScriptBinaryOperator.CompareNotEqual: return(left != right); case ScriptBinaryOperator.CompareGreater: return(left > right); case ScriptBinaryOperator.CompareLess: return(left < right); case ScriptBinaryOperator.CompareGreaterOrEqual: return(left >= right); case ScriptBinaryOperator.CompareLessOrEqual: return(left <= right); } throw new ScriptRuntimeException(span, $"The operator `{op.ToText()}` is not implemented for decimal<->decimal"); }
private static object CalculateFloat(ScriptBinaryOperator op, SourceSpan span, float left, float right) { switch (op) { case ScriptBinaryOperator.Add: return(left + right); case ScriptBinaryOperator.Substract: return(left - right); case ScriptBinaryOperator.Multiply: return(left * right); case ScriptBinaryOperator.Divide: return((float)left / right); case ScriptBinaryOperator.DivideRound: return((double)(int)(left / right)); case ScriptBinaryOperator.Modulus: return(left % right); case ScriptBinaryOperator.CompareEqual: return(left == right); case ScriptBinaryOperator.CompareNotEqual: return(left != right); case ScriptBinaryOperator.CompareGreater: return(left > right); case ScriptBinaryOperator.CompareLess: return(left < right); case ScriptBinaryOperator.CompareGreaterOrEqual: return(left >= right); case ScriptBinaryOperator.CompareLessOrEqual: return(left <= right); } throw new ScriptRuntimeException(span, $"The operator `{op.ToText()}` is not implemented for float<->float"); }
private static object CalculateOthers(TemplateContext context, SourceSpan span, ScriptBinaryOperator op, object leftValue, object rightValue) { // Both values are null, applies the relevant binary ops if (leftValue == null && rightValue == null) { switch (op) { case ScriptBinaryOperator.CompareEqual: return(true); case ScriptBinaryOperator.CompareNotEqual: return(false); case ScriptBinaryOperator.CompareGreater: case ScriptBinaryOperator.CompareLess: case ScriptBinaryOperator.CompareGreaterOrEqual: case ScriptBinaryOperator.CompareLessOrEqual: return(false); case ScriptBinaryOperator.Add: case ScriptBinaryOperator.Substract: case ScriptBinaryOperator.Multiply: case ScriptBinaryOperator.Divide: case ScriptBinaryOperator.DivideRound: case ScriptBinaryOperator.Modulus: case ScriptBinaryOperator.RangeInclude: case ScriptBinaryOperator.RangeExclude: return(null); case ScriptBinaryOperator.LiquidContains: case ScriptBinaryOperator.LiquidStartsWith: case ScriptBinaryOperator.LiquidEndsWith: return(false); } return(null); } // One value is null if (leftValue == null || rightValue == null) { switch (op) { case ScriptBinaryOperator.CompareEqual: case ScriptBinaryOperator.CompareNotEqual: case ScriptBinaryOperator.CompareGreater: case ScriptBinaryOperator.CompareLess: case ScriptBinaryOperator.CompareGreaterOrEqual: case ScriptBinaryOperator.CompareLessOrEqual: case ScriptBinaryOperator.LiquidContains: case ScriptBinaryOperator.LiquidStartsWith: case ScriptBinaryOperator.LiquidEndsWith: return(false); case ScriptBinaryOperator.Add: case ScriptBinaryOperator.Substract: case ScriptBinaryOperator.Multiply: case ScriptBinaryOperator.Divide: case ScriptBinaryOperator.DivideRound: case ScriptBinaryOperator.Modulus: case ScriptBinaryOperator.RangeInclude: case ScriptBinaryOperator.RangeExclude: return(null); } return(null); } var leftType = leftValue.GetType(); var rightType = rightValue.GetType(); // The order matters: decimal, double, float, long, int if (leftType == typeof(decimal)) { var rightDecimal = (decimal)context.ToObject(span, rightValue, typeof(decimal)); return(CalculateDecimal(op, span, (decimal)leftValue, rightDecimal)); } if (rightType == typeof(decimal)) { var leftDecimal = (decimal)context.ToObject(span, leftValue, typeof(decimal)); return(CalculateDecimal(op, span, leftDecimal, (decimal)rightValue)); } if (leftType == typeof(double)) { var rightDouble = (double)context.ToObject(span, rightValue, typeof(double)); return(CalculateDouble(op, span, (double)leftValue, rightDouble)); } if (rightType == typeof(double)) { var leftDouble = (double)context.ToObject(span, leftValue, typeof(double)); return(CalculateDouble(op, span, leftDouble, (double)rightValue)); } if (leftType == typeof(float)) { var rightFloat = (float)context.ToObject(span, rightValue, typeof(float)); return(CalculateFloat(op, span, (float)leftValue, rightFloat)); } if (rightType == typeof(float)) { var leftFloat = (float)context.ToObject(span, leftValue, typeof(float)); return(CalculateFloat(op, span, leftFloat, (float)rightValue)); } if (leftType == typeof(long)) { var rightLong = (long)context.ToObject(span, rightValue, typeof(long)); return(CalculateLong(op, span, (long)leftValue, rightLong)); } if (rightType == typeof(long)) { var leftLong = (long)context.ToObject(span, leftValue, typeof(long)); return(CalculateLong(op, span, leftLong, (long)rightValue)); } if (leftType == typeof(int) || (leftType != null && leftType.GetTypeInfo().IsEnum)) { var rightInt = (int)context.ToObject(span, rightValue, typeof(int)); return(CalculateInt(op, span, (int)leftValue, rightInt)); } if (rightType == typeof(int) || (rightType != null && rightType.GetTypeInfo().IsEnum)) { var leftInt = (int)context.ToObject(span, leftValue, typeof(int)); return(CalculateInt(op, span, leftInt, (int)rightValue)); } if (leftType == typeof(bool)) { var rightBool = (bool)context.ToObject(span, rightValue, typeof(bool)); return(CalculateBool(op, span, (bool)leftValue, rightBool)); } if (rightType == typeof(bool)) { var leftBool = (bool)context.ToObject(span, leftValue, typeof(bool)); return(CalculateBool(op, span, leftBool, (bool)rightValue)); } if (leftType == typeof(DateTime) && rightType == typeof(DateTime)) { return(CalculateDateTime(op, span, (DateTime)leftValue, (DateTime)rightValue)); } if (leftType == typeof(DateTime) && rightType == typeof(TimeSpan)) { return(CalculateDateTime(op, span, (DateTime)leftValue, (TimeSpan)rightValue)); } //allows to check equality for objects with not only primitive types if (op == ScriptBinaryOperator.CompareEqual) { return(leftValue.Equals(rightValue)); } throw new ScriptRuntimeException(span, $"Unsupported types `{leftValue}/{leftType}` {op.ToText()} `{rightValue}/{rightType}` for binary operation"); }
private object Calculate(ScriptBinaryOperator op, object leftValue, Type leftType, object rightValue, Type rightType) { var customType = leftValue as IScriptCustomType ?? rightValue as IScriptCustomType; if (customType != null) { return customType.EvaluateBinaryExpression(this, leftValue, rightValue); } // The order matters: double, float, long, int if (leftType == typeof(double)) { var rightDouble = (double)ScriptValueConverter.ToObject(Span, rightValue, typeof(double)); return Calculate(op, (double)leftValue, rightDouble); } if (rightType == typeof(double)) { var leftDouble = (double)ScriptValueConverter.ToObject(Span, leftValue, typeof(double)); return Calculate(op, leftDouble, (double)rightValue); } if (leftType == typeof(float)) { var rightFloat = (float)ScriptValueConverter.ToObject(Span, rightValue, typeof(float)); return Calculate(op, (float)leftValue, rightFloat); } if (rightType == typeof(float)) { var leftFloat = (float)ScriptValueConverter.ToObject(Span, leftValue, typeof(float)); return Calculate(op, leftFloat, (float)rightValue); } if (leftType == typeof(long)) { var rightLong = (long)ScriptValueConverter.ToObject(Span, rightValue, typeof(long)); return Calculate(op, (long)leftValue, rightLong); } if (rightType == typeof(long)) { var leftLong = (long)ScriptValueConverter.ToObject(Span, leftValue, typeof(long)); return Calculate(op, leftLong, (long)rightValue); } if (leftType == typeof (int) || (leftType != null && leftType.GetTypeInfo().IsEnum)) { var rightInt = (int) ScriptValueConverter.ToObject(Span, rightValue, typeof (int)); return Calculate(op, (int) leftValue, rightInt); } if (rightType == typeof (int) || (rightType != null && rightType.GetTypeInfo().IsEnum)) { var leftInt = (int) ScriptValueConverter.ToObject(Span, leftValue, typeof (int)); return Calculate(op, leftInt, (int) rightValue); } throw new ScriptRuntimeException(Span, $"Unsupported types [{leftValue ?? "null"}/{leftType?.ToString() ?? "null"}] {op.ToText()} [{rightValue ?? "null"}/{rightType?.ToString() ?? "null"}] for binary operation"); }
private static object CalculateEmpty(TemplateContext context, SourceSpan span, ScriptBinaryOperator op, object leftValue, object rightValue) { var leftIsEmptyObject = leftValue == EmptyScriptObject.Default; var rightIsEmptyObject = rightValue == EmptyScriptObject.Default; // If both are empty, we return false or empty if (leftIsEmptyObject && rightIsEmptyObject) { switch (op) { case ScriptBinaryOperator.CompareEqual: case ScriptBinaryOperator.CompareGreaterOrEqual: case ScriptBinaryOperator.CompareLessOrEqual: return(true); case ScriptBinaryOperator.CompareNotEqual: case ScriptBinaryOperator.CompareGreater: case ScriptBinaryOperator.CompareLess: case ScriptBinaryOperator.LiquidContains: case ScriptBinaryOperator.LiquidStartsWith: case ScriptBinaryOperator.LiquidEndsWith: return(false); } return(EmptyScriptObject.Default); } var against = leftIsEmptyObject ? rightValue : leftValue; var againstEmpty = context.IsEmpty(span, against); switch (op) { case ScriptBinaryOperator.CompareEqual: return(againstEmpty); case ScriptBinaryOperator.CompareNotEqual: return(againstEmpty is bool? !(bool)againstEmpty : againstEmpty); case ScriptBinaryOperator.CompareGreater: case ScriptBinaryOperator.CompareLess: return(false); case ScriptBinaryOperator.CompareGreaterOrEqual: case ScriptBinaryOperator.CompareLessOrEqual: return(againstEmpty); case ScriptBinaryOperator.Add: case ScriptBinaryOperator.Substract: case ScriptBinaryOperator.Multiply: case ScriptBinaryOperator.Divide: case ScriptBinaryOperator.DivideRound: case ScriptBinaryOperator.Modulus: case ScriptBinaryOperator.RangeInclude: case ScriptBinaryOperator.RangeExclude: return(EmptyScriptObject.Default); case ScriptBinaryOperator.LiquidContains: case ScriptBinaryOperator.LiquidStartsWith: case ScriptBinaryOperator.LiquidEndsWith: return(false); } throw new ScriptRuntimeException(span, $"Operator `{op.ToText()}` is not implemented for `{(leftIsEmptyObject ? "empty" : leftValue)}` / `{(rightIsEmptyObject ? "empty" : rightValue)}`"); }
private object Calculate(ScriptBinaryOperator op, object leftValue, Type leftType, object rightValue, Type rightType) { var customType = leftValue as IScriptCustomType ?? rightValue as IScriptCustomType; if (customType != null) { return(customType.EvaluateBinaryExpression(this, leftValue, rightValue)); } // The order matters: double, float, long, int if (leftType == typeof(double)) { var rightDouble = (double)ScriptValueConverter.ToObject(Span, rightValue, typeof(double)); return(Calculate(op, (double)leftValue, rightDouble)); } if (rightType == typeof(double)) { var leftDouble = (double)ScriptValueConverter.ToObject(Span, leftValue, typeof(double)); return(Calculate(op, leftDouble, (double)rightValue)); } if (leftType == typeof(float)) { var rightFloat = (float)ScriptValueConverter.ToObject(Span, rightValue, typeof(float)); return(Calculate(op, (float)leftValue, rightFloat)); } if (rightType == typeof(float)) { var leftFloat = (float)ScriptValueConverter.ToObject(Span, leftValue, typeof(float)); return(Calculate(op, leftFloat, (float)rightValue)); } if (leftType == typeof(long)) { var rightLong = (long)ScriptValueConverter.ToObject(Span, rightValue, typeof(long)); return(Calculate(op, (long)leftValue, rightLong)); } if (rightType == typeof(long)) { var leftLong = (long)ScriptValueConverter.ToObject(Span, leftValue, typeof(long)); return(Calculate(op, leftLong, (long)rightValue)); } if (leftType == typeof(int) || (leftType != null && leftType.GetTypeInfo().IsEnum)) { var rightInt = (int)ScriptValueConverter.ToObject(Span, rightValue, typeof(int)); return(Calculate(op, (int)leftValue, rightInt)); } if (rightType == typeof(int) || (rightType != null && rightType.GetTypeInfo().IsEnum)) { var leftInt = (int)ScriptValueConverter.ToObject(Span, leftValue, typeof(int)); return(Calculate(op, leftInt, (int)rightValue)); } throw new ScriptRuntimeException(Span, $"Unsupported types [{leftValue ?? "null"}/{leftType?.ToString() ?? "null"}] {op.ToText()} [{rightValue ?? "null"}/{rightType?.ToString() ?? "null"}] for binary operation"); }
private static object CalculateDateTime(ScriptBinaryOperator op, SourceSpan span, DateTime left, DateTime right) { switch (op) { case ScriptBinaryOperator.Substract: return(left - right); case ScriptBinaryOperator.CompareEqual: return(left == right); case ScriptBinaryOperator.CompareNotEqual: return(left != right); case ScriptBinaryOperator.CompareLess: return(left < right); case ScriptBinaryOperator.CompareLessOrEqual: return(left <= right); case ScriptBinaryOperator.CompareGreater: return(left > right); case ScriptBinaryOperator.CompareGreaterOrEqual: return(left >= right); } throw new ScriptRuntimeException(span, string.Format(RS.UnsupportedOperatorForType, op.ToText(), "datetime")); }
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); }
public bool TryEvaluate(TemplateContext context, SourceSpan span, ScriptBinaryOperator op, SourceSpan leftSpan, object leftValue, SourceSpan rightSpan, object rightValue, out object result) { result = null; var leftArray = TryGetRange(leftValue); var rightArray = TryGetRange(rightValue); int intModifier = 0; var intSpan = leftSpan; var errorSpan = span; string reason = null; switch (op) { case ScriptBinaryOperator.BinaryOr: case ScriptBinaryOperator.BinaryAnd: case ScriptBinaryOperator.CompareEqual: case ScriptBinaryOperator.CompareNotEqual: case ScriptBinaryOperator.CompareLessOrEqual: case ScriptBinaryOperator.CompareGreaterOrEqual: case ScriptBinaryOperator.CompareLess: case ScriptBinaryOperator.CompareGreater: case ScriptBinaryOperator.Add: if (leftArray == null) { errorSpan = leftSpan; reason = " Expecting an array for the left argument."; } if (rightArray == null) { errorSpan = rightSpan; reason = " Expecting an array for the right argument."; } break; case ScriptBinaryOperator.Multiply: if (leftArray == null && rightArray == null || leftArray != null && rightArray != null) { reason = " Expecting only one array for the left or right argument."; } else { intModifier = context.ToInt(span, leftArray == null ? leftValue : rightValue); if (rightArray == null) { intSpan = rightSpan; } } break; case ScriptBinaryOperator.Divide: case ScriptBinaryOperator.DivideRound: case ScriptBinaryOperator.Modulus: if (leftArray == null) { errorSpan = leftSpan; reason = " Expecting an array for the left argument."; } else { intModifier = context.ToInt(span, rightValue); intSpan = rightSpan; } break; case ScriptBinaryOperator.ShiftLeft: if (leftArray == null) { errorSpan = leftSpan; reason = " Expecting an array for the left argument."; } break; case ScriptBinaryOperator.ShiftRight: if (rightArray == null) { errorSpan = rightSpan; reason = " Expecting an array for the right argument."; } break; default: reason = string.Empty; break; } if (intModifier < 0) { errorSpan = intSpan; reason = $" Integer {intModifier} cannot be negative when multiplying"; } if (reason != null) { throw new ScriptRuntimeException(errorSpan, $"The operator `{op.ToText()}` is not supported between {context.GetTypeName(leftValue)} and {context.GetTypeName(rightValue)}.{reason}"); } switch (op) { case ScriptBinaryOperator.BinaryOr: result = BinaryOr(leftArray, rightArray); return(true); case ScriptBinaryOperator.BinaryAnd: result = BinaryAnd(leftArray, rightArray); return(true); case ScriptBinaryOperator.Add: result = Concat(leftArray, rightArray); return(true); case ScriptBinaryOperator.CompareEqual: case ScriptBinaryOperator.CompareNotEqual: case ScriptBinaryOperator.CompareLessOrEqual: case ScriptBinaryOperator.CompareGreaterOrEqual: case ScriptBinaryOperator.CompareLess: case ScriptBinaryOperator.CompareGreater: result = CompareTo(context, span, op, leftArray, rightArray); return(true); case ScriptBinaryOperator.Multiply: { // array with integer var array = leftArray ?? rightArray; if (intModifier == 0) { result = new ScriptRange(); return(true); } result = Multiply(array, intModifier); return(true); } case ScriptBinaryOperator.Divide: case ScriptBinaryOperator.DivideRound: { // array with integer var array = leftArray ?? rightArray; if (intModifier == 0) { throw new ScriptRuntimeException(intSpan, "Cannot divide by 0"); } result = Divide(array, intModifier); return(true); } case ScriptBinaryOperator.Modulus: { // array with integer var array = leftArray ?? rightArray; if (intModifier == 0) { throw new ScriptRuntimeException(intSpan, "Cannot divide by 0"); } result = Modulus(array, intModifier); return(true); } case ScriptBinaryOperator.ShiftLeft: result = ShiftLeft(leftArray, rightValue); return(true); case ScriptBinaryOperator.ShiftRight: result = ShiftRight(leftValue, rightArray); return(true); } return(false); }
private string ToDebuggerDisplay() { return(Expression != null?Expression.ToString() : OperatorToken?.ToString() ?? $"`{Operator.ToText()}` - CallKind = {CallKind}"); }
private static object CalculateBool(ScriptBinaryOperator op, SourceSpan span, bool left, bool right) { switch (op) { case ScriptBinaryOperator.CompareEqual: return(left == right); case ScriptBinaryOperator.CompareNotEqual: return(left != right); } throw new ScriptRuntimeException(span, string.Format(RS.UnsupportedOperatorForType, op.ToText(), "bool")); }
private static object CalculateDateTime(ScriptBinaryOperator op, SourceSpan span, DateTime left, TimeSpan right) { switch (op) { case ScriptBinaryOperator.Add: return(left + right); } throw new ScriptRuntimeException(span, string.Format(RS.OperatorNotImplemented, op.ToText(), "datetime", "timespan")); }
private object Calculate(ScriptBinaryOperator op, float left, float right) { switch (op) { case ScriptBinaryOperator.Add: return left + right; case ScriptBinaryOperator.Substract: return left - right; case ScriptBinaryOperator.Multiply: return left * right; case ScriptBinaryOperator.Divide: return (float)left / right; case ScriptBinaryOperator.DivideRound: return (double)(int)(left / right); case ScriptBinaryOperator.Modulus: return left % right; case ScriptBinaryOperator.CompareEqual: return left == right; case ScriptBinaryOperator.CompareNotEqual: return left != right; case ScriptBinaryOperator.CompareGreater: return left > right; case ScriptBinaryOperator.CompareLess: return left < right; case ScriptBinaryOperator.CompareGreaterOrEqual: return left >= right; case ScriptBinaryOperator.CompareLessOrEqual: return left <= right; } throw new ScriptRuntimeException(Span, $"The operator [{op.ToText()}] is not implemented for float<->float"); }
private static object CalculateFloat(ScriptBinaryOperator op, SourceSpan span, float left, float right) { switch (op) { case ScriptBinaryOperator.Add: return(left + right); case ScriptBinaryOperator.Substract: return(left - right); case ScriptBinaryOperator.Multiply: return(left * right); case ScriptBinaryOperator.Divide: return((float)left / right); case ScriptBinaryOperator.DivideRound: return((double)(int)(left / right)); case ScriptBinaryOperator.Modulus: return(left % right); case ScriptBinaryOperator.CompareEqual: return(left == right); case ScriptBinaryOperator.CompareNotEqual: return(left != right); case ScriptBinaryOperator.CompareGreater: return(left > right); case ScriptBinaryOperator.CompareLess: return(left < right); case ScriptBinaryOperator.CompareGreaterOrEqual: return(left >= right); case ScriptBinaryOperator.CompareLessOrEqual: return(left <= right); } throw new ScriptRuntimeException(span, string.Format(RS.UnsupportedOperatorForType, op.ToText(), "float")); }
public static object Evaluate(TemplateContext context, SourceSpan span, ScriptBinaryOperator op, object leftValue, object rightValue) { if (op == ScriptBinaryOperator.EmptyCoalescing) { return(leftValue ?? rightValue); } switch (op) { case ScriptBinaryOperator.ShiftLeft: var leftList = leftValue as IList; if (leftList != null) { var newList = new ScriptArray(leftList) { rightValue }; return(newList); } break; case ScriptBinaryOperator.ShiftRight: var rightList = rightValue as IList; if (rightList != null) { var newList = new ScriptArray(rightList); newList.Insert(0, leftValue); return(newList); } break; case ScriptBinaryOperator.LiquidHasKey: { var leftDict = leftValue as IDictionary <string, object>; if (leftDict != null) { return(ObjectFunctions.HasKey(leftDict, context.ToString(span, rightValue))); } } break; case ScriptBinaryOperator.LiquidHasValue: { var leftDict = leftValue as IDictionary <string, object>; if (leftDict != null) { return(ObjectFunctions.HasValue(leftDict, context.ToString(span, rightValue))); } } 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: case ScriptBinaryOperator.LiquidContains: case ScriptBinaryOperator.LiquidStartsWith: case ScriptBinaryOperator.LiquidEndsWith: if (leftValue is string || rightValue is string) { return(CalculateToString(context, span, op, leftValue, rightValue)); } else if (leftValue == EmptyScriptObject.Default || rightValue == EmptyScriptObject.Default) { return(CalculateEmpty(context, span, op, leftValue, rightValue)); } else { return(CalculateOthers(context, span, op, leftValue, rightValue)); } } throw new ScriptRuntimeException(span, $"Operator `{op.ToText()}` is not implemented for `{leftValue}` and `{rightValue}`"); }
private object CalculateToString(ScriptBinaryOperator op, object left, object right) { switch (op) { case ScriptBinaryOperator.Add: return ScriptValueConverter.ToString(Span, left) + ScriptValueConverter.ToString(Span, right); case ScriptBinaryOperator.Multiply: if (right is int) { var temp = left; left = right; right = temp; } if (left is int) { var rightText = ScriptValueConverter.ToString(Span, right); var builder = new StringBuilder(); for (int i = 0; i < (int) left; i++) { builder.Append(rightText); } return builder.ToString(); } throw new ScriptRuntimeException(Span, $"Operator [{op.ToText()}] is not supported for the expression [{this}]. Only working on string x int or int x string"); // unit test: 112-binary-string-error1.txt case ScriptBinaryOperator.CompareEqual: return ScriptValueConverter.ToString(Span, left) == ScriptValueConverter.ToString(Span, right); case ScriptBinaryOperator.CompareNotEqual: return ScriptValueConverter.ToString(Span, left) != ScriptValueConverter.ToString(Span, right); case ScriptBinaryOperator.CompareGreater: return ScriptValueConverter.ToString(Span, left).CompareTo(ScriptValueConverter.ToString(Span, right)) > 0; case ScriptBinaryOperator.CompareLess: return ScriptValueConverter.ToString(Span, left).CompareTo(ScriptValueConverter.ToString(Span, right)) < 0; case ScriptBinaryOperator.CompareGreaterOrEqual: return ScriptValueConverter.ToString(Span, left).CompareTo(ScriptValueConverter.ToString(Span, right)) >= 0; case ScriptBinaryOperator.CompareLessOrEqual: return ScriptValueConverter.ToString(Span, left).CompareTo(ScriptValueConverter.ToString(Span, right)) <= 0; } // unit test: 150-range-expression-error1.out.txt throw new ScriptRuntimeException(Span, $"Operator [{op.ToText()}] is not supported on string objects"); // unit test: 112-binary-string-error2.txt }