Пример #1
0
        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, $"The operator `{op}` is not supported for DateTime");
        }
 public BinaryExpressionOrOperator(ScriptBinaryOperator @operator, ScriptToken operatorToken)
 {
     Expression    = null;
     Operator      = @operator;
     OperatorToken = operatorToken;
     CallKind      = FunctionCallKind.None;
 }
Пример #3
0
        public bool TryEvaluate(TemplateContext context, SourceSpan span, ScriptBinaryOperator op, SourceSpan leftSpan, object leftValue, SourceSpan rightSpan, object rightValue, out object result)
        {
            result = null;
            if (leftValue is KalkComplex leftComplex && rightValue is KalkComplex rightComplex)
            {
                switch (op)
                {
                case ScriptBinaryOperator.Add:
                    result = (KalkComplex)(leftComplex._value + rightComplex._value);
                    return(true);

                case ScriptBinaryOperator.Substract:
                    result = (KalkComplex)(leftComplex._value - rightComplex._value);
                    return(true);

                case ScriptBinaryOperator.Divide:
                    result = (KalkComplex)(leftComplex._value / rightComplex._value);
                    return(true);

                case ScriptBinaryOperator.DivideRound:
                    result = (KalkComplex)(leftComplex._value / rightComplex._value);
                    return(true);

                case ScriptBinaryOperator.Multiply:
                    result = (KalkComplex)(leftComplex._value * rightComplex._value);
                    return(true);

                case ScriptBinaryOperator.Power:
                    result = (KalkComplex)(Complex.Pow(leftComplex._value, rightComplex._value));
                    return(true);
                }
            }
Пример #4
0
        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"));
        }
Пример #5
0
        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");
        }
Пример #6
0
        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"));
        }
Пример #7
0
        private static object CalculateDateTime(ScriptBinaryOperator op, SourceSpan span, DateTime left, TimeSpan right)
        {
            switch (op)
            {
            case ScriptBinaryOperator.Add:
                return(left + right);
            }

            throw new ScriptRuntimeException(span, $"The operator `{op}` is not supported for between <DateTime> and <TimeSpan>");
        }
Пример #8
0
        public static string ToText(this ScriptBinaryOperator op)
        {
            switch (op)
            {
            case ScriptBinaryOperator.Add:
                return("+");

            case ScriptBinaryOperator.Substract:
                return("-");

            case ScriptBinaryOperator.Divide:
                return("/");

            case ScriptBinaryOperator.DivideRound:
                return("//");

            case ScriptBinaryOperator.Multiply:
                return("*");

            case ScriptBinaryOperator.Modulus:
                return("%");

            case ScriptBinaryOperator.RangeInclude:
                return("..");

            case ScriptBinaryOperator.RangeExclude:
                return("...");

            case ScriptBinaryOperator.CompareEqual:
                return("==");

            case ScriptBinaryOperator.CompareNotEqual:
                return("!=");

            case ScriptBinaryOperator.CompareLessOrEqual:
                return("<=");

            case ScriptBinaryOperator.CompareGreaterOrEqual:
                return(">=");

            case ScriptBinaryOperator.CompareLess:
                return("<");

            case ScriptBinaryOperator.CompareGreater:
                return(">");

            case ScriptBinaryOperator.And:
                return("&&");

            case ScriptBinaryOperator.Or:
                return("||");
            }
            return(op.ToString());
        }
Пример #9
0
        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");
        }
Пример #10
0
        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");
        }
Пример #11
0
        private static int GetOperatorPrecedence(ScriptBinaryOperator op)
        {
            switch (op)
            {
            case ScriptBinaryOperator.EmptyCoalescing:
                return(20);

            case ScriptBinaryOperator.ShiftLeft:
            case ScriptBinaryOperator.ShiftRight:
                return(25);

            case ScriptBinaryOperator.Or:
                return(30);

            case ScriptBinaryOperator.And:
                return(40);

            case ScriptBinaryOperator.CompareEqual:
            case ScriptBinaryOperator.CompareNotEqual:
                return(50);

            case ScriptBinaryOperator.CompareLess:
            case ScriptBinaryOperator.CompareLessOrEqual:
            case ScriptBinaryOperator.CompareGreater:
            case ScriptBinaryOperator.CompareGreaterOrEqual:
                return(60);

            case ScriptBinaryOperator.LiquidContains:
            case ScriptBinaryOperator.LiquidStartsWith:
            case ScriptBinaryOperator.LiquidEndsWith:
            case ScriptBinaryOperator.LiquidHasKey:
            case ScriptBinaryOperator.LiquidHasValue:
                return(65);

            case ScriptBinaryOperator.Add:
            case ScriptBinaryOperator.Substract:
                return(70);

            case ScriptBinaryOperator.Multiply:
            case ScriptBinaryOperator.Divide:
            case ScriptBinaryOperator.DivideRound:
            case ScriptBinaryOperator.Modulus:
                return(80);

            case ScriptBinaryOperator.RangeInclude:
            case ScriptBinaryOperator.RangeExclude:
                return(90);

            default:
                return(0);
            }
        }
Пример #12
0
        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"));
        }
Пример #13
0
        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
        }
Пример #14
0
        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");
        }
Пример #15
0
        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, string.Format(RS.UnsupportedOperatorForType, op.ToText(), "long"));
        }
Пример #16
0
        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");
        }
Пример #17
0
        private static bool HasSimilarPrecedenceThanMultiply(ScriptBinaryOperator op)
        {
            switch (op)
            {
            case ScriptBinaryOperator.Multiply:
            case ScriptBinaryOperator.Divide:
            case ScriptBinaryOperator.DivideRound:
            case ScriptBinaryOperator.Modulus:
            case ScriptBinaryOperator.ShiftLeft:
            case ScriptBinaryOperator.ShiftRight:
            case ScriptBinaryOperator.Power:
                return(true);
            }

            return(false);
        }
Пример #18
0
        private bool TryLiquidBinaryOperator(out ScriptBinaryOperator binOp)
        {
            binOp = 0;
            if (Current.Type != TokenType.Identifier)
            {
                return(false);
            }

            var text = GetAsText(Current);

            switch (text)
            {
            case "or":
                binOp = ScriptBinaryOperator.Or;
                return(true);

            case "and":
                binOp = ScriptBinaryOperator.And;
                return(true);

            case "contains":
                binOp = ScriptBinaryOperator.LiquidContains;
                return(true);

            case "startsWith":
                binOp = ScriptBinaryOperator.LiquidStartsWith;
                return(true);

            case "endsWith":
                binOp = ScriptBinaryOperator.LiquidEndsWith;
                return(true);

            case "hasKey":
                binOp = ScriptBinaryOperator.LiquidHasKey;
                return(true);

            case "hasValue":
                binOp = ScriptBinaryOperator.LiquidHasValue;
                return(true);
            }

            return(false);
        }
Пример #19
0
        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, string.Format(RS.UnsupportedOperatorForType, op.ToText(), "decimal"));
        }
Пример #20
0
        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");
        }
Пример #21
0
        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");
        }
Пример #22
0
        public bool TryEvaluate(TemplateContext context, SourceSpan span, ScriptBinaryOperator op, SourceSpan leftSpan, object leftValue, SourceSpan rightSpan, object rightValue, out object result)
        {
            result = null;
            if (leftValue is KalkHalf leftHalf && rightValue is KalkHalf rightHalf)
            {
                result = (KalkHalf)(float)ScriptBinaryExpression.Evaluate(context, span, op, leftSpan, (float)leftHalf, rightSpan, (float)rightHalf);
                return(true);
            }

            if (leftValue is KalkHalf leftHalf1)
            {
                result = (KalkHalf)(float)ScriptBinaryExpression.Evaluate(context, span, op, leftSpan, (float)leftHalf1, rightSpan, rightValue);
                return(true);
            }

            if (rightValue is KalkHalf rightHalf1)
            {
                result = (KalkHalf)(float)ScriptBinaryExpression.Evaluate(context, span, op, leftSpan, leftValue, rightSpan, rightHalf1);
                return(true);
            }

            return(false);
        }
Пример #23
0
        public static string ToText(this ScriptBinaryOperator op)
        {
            switch (op)
            {
            case ScriptBinaryOperator.Add:
                return("+");

            case ScriptBinaryOperator.Substract:
                // The substract operator requires to be separated by space
                return("-");

            case ScriptBinaryOperator.Divide:
                return("/");

            case ScriptBinaryOperator.DivideRound:
                return("//");

            case ScriptBinaryOperator.Multiply:
                return("*");

            case ScriptBinaryOperator.Modulus:
                return("%");

            case ScriptBinaryOperator.RangeInclude:
                return("..");

            case ScriptBinaryOperator.RangeExclude:
                return("..<");

            case ScriptBinaryOperator.CompareEqual:
                return("==");

            case ScriptBinaryOperator.CompareNotEqual:
                return("!=");

            case ScriptBinaryOperator.CompareLessOrEqual:
                return("<=");

            case ScriptBinaryOperator.CompareGreaterOrEqual:
                return(">=");

            case ScriptBinaryOperator.CompareLess:
                return("<");

            case ScriptBinaryOperator.CompareGreater:
                return(">");

            case ScriptBinaryOperator.And:
                return("&&");

            case ScriptBinaryOperator.Or:
                return("||");

            case ScriptBinaryOperator.EmptyCoalescing:
                return("??");

            case ScriptBinaryOperator.ShiftLeft:
                return("<<");

            case ScriptBinaryOperator.ShiftRight:
                return(">>");

            case ScriptBinaryOperator.LiquidContains:
                return("| string.contains ");

            case ScriptBinaryOperator.LiquidStartsWith:
                return("| string.starts_with ");

            case ScriptBinaryOperator.LiquidEndsWith:
                return("| string.ends_with ");

            case ScriptBinaryOperator.LiquidHasKey:
                return("| object.has_key ");

            case ScriptBinaryOperator.LiquidHasValue:
                return("| object.has_value ");

            default:
                throw new ArgumentOutOfRangeException(nameof(op));
            }
        }
Пример #24
0
        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}`");
        }
Пример #25
0
        public bool TryEvaluate(TemplateContext context, SourceSpan span, ScriptBinaryOperator op, SourceSpan leftSpan, object leftValue, SourceSpan rightSpan, object rightValue, out object result)
        {
            var leftExpr = leftValue as KalkExpression;

            if (leftExpr is null && !KalkValue.IsNumber(leftValue))
            {
                throw new ScriptRuntimeException(leftSpan, "Expecting a number, vector or matrix");
            }
            var rightExpr = rightValue as KalkExpression;

            if (rightExpr is null && !KalkValue.IsNumber(rightValue))
            {
                throw new ScriptRuntimeException(rightSpan, "Expecting a number, vector or matrix");
            }

            result = null;
            switch (op)
            {
            case ScriptBinaryOperator.CompareEqual:
            case ScriptBinaryOperator.CompareNotEqual:
            case ScriptBinaryOperator.CompareLessOrEqual:
            case ScriptBinaryOperator.CompareGreaterOrEqual:
            case ScriptBinaryOperator.CompareLess:
            case ScriptBinaryOperator.CompareGreater:
                if (leftExpr != null && rightExpr != null)
                {
                    var leftSimplifier = new KalkExpressionSimplifier(context);
                    var(leftValueMultiplier, newLeftExpr) = leftSimplifier.Canonical(leftExpr);

                    var rightSimplifier = new KalkExpressionSimplifier(context);
                    var(rightValueMultiplier, newRightExpr) = rightSimplifier.Canonical(rightExpr);

                    var exprEquals = Equals(context, newLeftExpr, newRightExpr);
                    if (exprEquals)
                    {
                        var almostEqual = KalkValue.AlmostEqual(leftValueMultiplier, rightValueMultiplier);
                        switch (op)
                        {
                        case ScriptBinaryOperator.CompareEqual:
                            result = almostEqual;
                            break;

                        case ScriptBinaryOperator.CompareNotEqual:
                            result = !almostEqual;
                            break;

                        case ScriptBinaryOperator.CompareLessOrEqual:
                            result = almostEqual || ScriptBinaryExpression.Evaluate(context, span, op, leftSpan, leftValueMultiplier, rightSpan, rightValueMultiplier) is bool v1 && v1;
                            break;

                        case ScriptBinaryOperator.CompareGreaterOrEqual:
                            result = almostEqual || ScriptBinaryExpression.Evaluate(context, span, op, leftSpan, leftValueMultiplier, rightSpan, rightValueMultiplier) is bool v2 && v2;
                            break;

                        case ScriptBinaryOperator.CompareLess:
                            result = ScriptBinaryExpression.Evaluate(context, span, op, leftSpan, leftValueMultiplier, rightSpan, rightValueMultiplier) is bool v3 && v3;
                            break;

                        case ScriptBinaryOperator.CompareGreater:
                            result = ScriptBinaryExpression.Evaluate(context, span, op, leftSpan, leftValueMultiplier, rightSpan, rightValueMultiplier) is bool v4 && v4;
                            break;
                        }
                    }
                    else
                    {
                        result = op == ScriptBinaryOperator.CompareNotEqual;
                    }
                }
                else
                {
                    if (op == ScriptBinaryOperator.CompareEqual || op == ScriptBinaryOperator.CompareNotEqual)
                    {
                        result = op == ScriptBinaryOperator.CompareNotEqual;
                    }
                    else
                    {
                        throw NotMatching(leftSpan, leftExpr, rightSpan, rightExpr);
                    }
                }
                return(true);

            case ScriptBinaryOperator.Multiply:
            case ScriptBinaryOperator.Divide:
            case ScriptBinaryOperator.Power:
            {
                if (op != ScriptBinaryOperator.Power || rightExpr == null)
                {
                    var simplifier = new KalkExpressionSimplifier(context);
                    var(valueMul, valueExpr) = simplifier.Canonical(new KalkBinaryExpression(leftValue, op, rightValue));
                    var valueBinExpr = valueExpr as KalkBinaryExpression;

                    result = KalkValue.AlmostEqual(valueMul, 1.0) && valueBinExpr == null ? valueExpr ?? (object)1.0 : valueExpr == null ? valueMul : (object)new KalkBinaryExpression(valueMul, ScriptBinaryOperator.Multiply, valueExpr)
                    {
                        OriginalExpression = new KalkBinaryExpression(leftValue, op, rightValue)
                    };
                    return(true);
                }
                else
                {
                    throw new ScriptRuntimeException(rightSpan, "Cannot use a unit as an exponent.");
                }
            }

            case ScriptBinaryOperator.Add:
            case ScriptBinaryOperator.Substract:

                if (leftExpr != null && rightExpr != null)
                {
                    var leftSimplifier = new KalkExpressionSimplifier(context);
                    var(leftValueMultiplier, newLeftExpr) = leftSimplifier.Canonical(leftExpr);

                    var rightSimplifier = new KalkExpressionSimplifier(context);
                    var(rightValueMultiplier, newRightExpr) = rightSimplifier.Canonical(rightExpr);

                    if (!Equals(context, newLeftExpr, newRightExpr))
                    {
                        throw new ScriptRuntimeException(span, $"Cannot {(op == ScriptBinaryOperator.Add ? "add" : "subtract")} the expression. Units are not matching. The left expression with unit `{newLeftExpr}` is not matching the right expression with unit `{newRightExpr}`.");
                    }

                    result = new KalkBinaryExpression(ScriptBinaryExpression.Evaluate(context, span, op, leftSpan, leftValueMultiplier, rightSpan, rightValueMultiplier), ScriptBinaryOperator.Multiply, newLeftExpr)
                    {
                        OriginalExpression = new KalkBinaryExpression(leftValue, op, rightValue)
                    };
                }
                else
                {
                    throw NotMatching(leftSpan, leftExpr, rightSpan, rightExpr);
                }

                return(true);
            }

            return(false);
        }
Пример #26
0
        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");
        }
Пример #27
0
 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");
 }
Пример #28
0
        public static TokenType ToTokenType(this ScriptBinaryOperator op)
        {
            switch (op)
            {
            case ScriptBinaryOperator.Add:
                return(TokenType.Plus);

            case ScriptBinaryOperator.Substract:
                return(TokenType.Minus);

            case ScriptBinaryOperator.Divide:
                return(TokenType.Divide);

            case ScriptBinaryOperator.DivideRound:
                return(TokenType.DoubleDivide);

            case ScriptBinaryOperator.Multiply:
                return(TokenType.Asterisk);

            case ScriptBinaryOperator.Modulus:
                return(TokenType.Percent);

            case ScriptBinaryOperator.RangeInclude:
                return(TokenType.DoubleDot);

            case ScriptBinaryOperator.RangeExclude:
                return(TokenType.DoubleDotLess);

            case ScriptBinaryOperator.CompareEqual:
                return(TokenType.DoubleEqual);

            case ScriptBinaryOperator.CompareNotEqual:
                return(TokenType.ExclamationEqual);

            case ScriptBinaryOperator.CompareLessOrEqual:
                return(TokenType.LessEqual);

            case ScriptBinaryOperator.CompareGreaterOrEqual:
                return(TokenType.GreaterEqual);

            case ScriptBinaryOperator.CompareLess:
                return(TokenType.Less);

            case ScriptBinaryOperator.CompareGreater:
                return(TokenType.Greater);

            case ScriptBinaryOperator.And:
                return(TokenType.DoubleAmp);

            case ScriptBinaryOperator.Or:
                return(TokenType.DoubleVerticalBar);

            case ScriptBinaryOperator.EmptyCoalescing:
                return(TokenType.DoubleQuestion);

            case ScriptBinaryOperator.ShiftLeft:
                return(TokenType.DoubleLessThan);

            case ScriptBinaryOperator.ShiftRight:
                return(TokenType.DoubleGreaterThan);

            case ScriptBinaryOperator.Power:
                return(TokenType.Caret);

            case ScriptBinaryOperator.BinaryAnd:
                return(TokenType.Amp);

            case ScriptBinaryOperator.BinaryOr:
                return(TokenType.VerticalBar);

            default:
                throw new ArgumentOutOfRangeException(nameof(op));
            }
        }
Пример #29
0
 public static ScriptToken ToToken(this ScriptBinaryOperator op)
 {
     return(new ScriptToken(op.ToTokenType()));
 }
Пример #30
0
 private static int GetOperatorPrecedence(ScriptBinaryOperator op)
 {
     switch (op)
     {
         case ScriptBinaryOperator.EmptyCoalescing:
             return 20;
         case ScriptBinaryOperator.ShiftLeft:
         case ScriptBinaryOperator.ShiftRight:
             return 25;
         case ScriptBinaryOperator.Or:
             return 30;
         case ScriptBinaryOperator.And:
             return 40;
         case ScriptBinaryOperator.CompareEqual:
         case ScriptBinaryOperator.CompareNotEqual:
             return 50;
         case ScriptBinaryOperator.CompareLess:
         case ScriptBinaryOperator.CompareLessOrEqual:
         case ScriptBinaryOperator.CompareGreater:
         case ScriptBinaryOperator.CompareGreaterOrEqual:
             return 60;
         case ScriptBinaryOperator.Add:
         case ScriptBinaryOperator.Substract:
             return 70;
         case ScriptBinaryOperator.Multiply:
         case ScriptBinaryOperator.Divide:
         case ScriptBinaryOperator.DivideRound:
         case ScriptBinaryOperator.Modulus:
             return 80;
         case ScriptBinaryOperator.RangeInclude:
         case ScriptBinaryOperator.RangeExclude:
             return 90;
         default:
             return 0;
     }
 }
Пример #31
0
        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
        }
Пример #32
0
        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");
        }
Пример #33
0
        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
        }
Пример #34
0
        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)}`");
        }