Beispiel #1
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");
        }
            public object Evaluate(TemplateContext context, ScriptNode callerContext, ScriptArray parameters, ScriptBlockStatement blockStatement)
            {
                // Check parameters
                if ((hasObjectParams && parameters.Count < parametersInfo.Length - 1) || (!hasObjectParams && parameters.Count != parametersInfo.Length))
                {
                    throw new ScriptRuntimeException(callerContext.Span, $"Invalid number of arguments passed [{parameters.Count}] while expecting [{parametersInfo.Length}] for [{callerContext}]");
                }

                // Convert arguments
                var arguments = new object[parametersInfo.Length];

                object[] paramArguments = null;
                if (hasObjectParams)
                {
                    paramArguments             = new object[parameters.Count - lastParamsIndex];
                    arguments[lastParamsIndex] = paramArguments;
                }

                for (int i = 0; i < parameters.Count; i++)
                {
                    var destType = hasObjectParams && i >= lastParamsIndex ? typeof(object) : parametersInfo[i].ParameterType;
                    try
                    {
                        var argValue = ScriptValueConverter.ToObject(callerContext.Span, parameters[i], destType);
                        if (hasObjectParams && i >= lastParamsIndex)
                        {
                            paramArguments[i - lastParamsIndex] = argValue;
                        }
                        else
                        {
                            arguments[i] = argValue;
                        }
                    }
                    catch (Exception exception)
                    {
                        throw new ScriptRuntimeException(callerContext.Span, $"Unable to convert parameter #{i} of type [{parameters[i]?.GetType()}] to type [{destType}]", exception);
                    }
                }

                // Call method
                try
                {
                    var result = method.Invoke(target, arguments);
                    return(result);
                }
                catch (Exception exception)
                {
                    throw new ScriptRuntimeException(callerContext.Span, $"Unexpected exception when calling {callerContext}", exception);
                }
            }
Beispiel #3
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
        }
Beispiel #4
0
        public override void Evaluate(TemplateContext context)
        {
            var    leftValueOriginal  = context.Evaluate(Left);
            var    leftValue          = leftValueOriginal;
            var    rightValueOriginal = context.Evaluate(Right);
            object rightValue         = rightValueOriginal;

            if (Operator == ScriptBinaryOperator.EmptyCoalescing)
            {
                context.Result = leftValue ?? rightValue;
                return;
            }
            else if (Operator == ScriptBinaryOperator.And || Operator == ScriptBinaryOperator.Or)
            {
                var leftBoolValue  = ScriptValueConverter.ToBool(leftValue);
                var rightBoolValue = ScriptValueConverter.ToBool(rightValue);
                if (Operator == ScriptBinaryOperator.And)
                {
                    context.Result = leftBoolValue && rightBoolValue;
                }
                else
                {
                    context.Result = leftBoolValue || rightBoolValue;
                }

                return;
            }
            else
            {
                switch (Operator)
                {
                case ScriptBinaryOperator.ShiftLeft:
                case ScriptBinaryOperator.ShiftRight:
                    if (leftValue is IList || rightValue is IList)
                    {
                        // Special path for IList to allow custom binary expression
                        context.Result = ScriptArray.CustomOperator.EvaluateBinaryExpression(this, leftValue,
                                                                                             rightValue);
                        return;
                    }
                    break;

                case ScriptBinaryOperator.CompareEqual:
                case ScriptBinaryOperator.CompareNotEqual:
                case ScriptBinaryOperator.CompareGreater:
                case ScriptBinaryOperator.CompareLess:
                case ScriptBinaryOperator.CompareGreaterOrEqual:
                case ScriptBinaryOperator.CompareLessOrEqual:
                case ScriptBinaryOperator.Add:
                case ScriptBinaryOperator.Substract:
                case ScriptBinaryOperator.Multiply:
                case ScriptBinaryOperator.Divide:
                case ScriptBinaryOperator.DivideRound:
                case ScriptBinaryOperator.Modulus:
                case ScriptBinaryOperator.RangeInclude:
                case ScriptBinaryOperator.RangeExclude:
                    var leftType  = leftValue?.GetType();
                    var rightType = rightValue?.GetType();

                    if (leftValue is string || rightValue is string)
                    {
                        context.Result = CalculateToString(Operator, leftValue, rightValue);
                        {
                            // TODO: Log an error if CalculateToString return null?
                            //context.LogError(Span, $"Operation [{Operator}] on strings not supported");
                        }
                    }
                    else
                    {
                        context.Result = Calculate(Operator, leftValue, leftType, rightValue, rightType);
                    }
                    return;
                }
            }

            throw new ScriptRuntimeException(Span, $"Operator [{Operator.ToText()}] is not implemented for the left [{Left}] / right [{Right}]");
        }
Beispiel #5
0
 private TKey TransformToKey(string member)
 {
     return((TKey)ScriptValueConverter.ToObject(new SourceSpan(), member, typeof(TKey)));
 }
        public override void Evaluate(TemplateContext context)
        {
            switch (Operator)
            {
            case ScriptUnaryOperator.Not:
            {
                var value = context.Evaluate(Right);
                context.Result = !ScriptValueConverter.ToBool(value);
            }
            break;

            case ScriptUnaryOperator.Negate:
            case ScriptUnaryOperator.Plus:
            {
                var value = context.Evaluate(Right);

                bool negate = Operator == ScriptUnaryOperator.Negate;

                var customType = value as IScriptCustomType;
                if (customType != null)
                {
                    context.Result = customType.EvaluateUnaryExpression(this);
                }
                else if (value != null)
                {
                    if (value is int)
                    {
                        context.Result = negate ? -((int)value) : value;
                    }
                    else if (value is double)
                    {
                        context.Result = negate ? -((double)value) : value;
                    }
                    else if (value is float)
                    {
                        context.Result = negate ? -((float)value) : value;
                    }
                    else if (value is long)
                    {
                        context.Result = negate ? -((long)value) : value;
                    }
                    else
                    {
                        throw new ScriptRuntimeException(this.Span,
                                                         $"Unexpected value [{value} / Type: {value?.GetType()}]. Cannot negate(-)/positive(+) a non-numeric value");
                    }
                }
            }
            break;

            case ScriptUnaryOperator.FunctionAlias:
                context.Result = context.Evaluate(Right, true);
                break;

            case ScriptUnaryOperator.FunctionParametersExpand:
                // Function parameters expand is done at the function level, so here, we simply return the actual list
                Right?.Evaluate(context);
                break;

            default:
                throw new ScriptRuntimeException(Span, $"Operator [{Operator}] is not supported");
            }
        }