Exemple #1
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
        }
Exemple #2
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
        }
Exemple #3
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");
        }
Exemple #4
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");
        }
Exemple #5
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");
        }
Exemple #6
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");
        }
Exemple #7
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");
        }
Exemple #8
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");
        }
Exemple #9
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");
        }
        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");
        }
Exemple #11
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)}`");
        }
Exemple #12
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");
        }
        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"));
        }
Exemple #14
0
        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);
        }
Exemple #15
0
        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"));
        }
Exemple #21
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}`");
        }
        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
        }