示例#1
0
        private object EvaluateBinaryExpression(ScriptBinaryExpression expression, ScriptDate left,
                                                ScriptDate right)
        {
            switch (expression.Operator)
            {
            case ScriptBinaryOperator.Substract:
                return(new ScriptTimeSpan(left.value - right.value));

            case ScriptBinaryOperator.CompareEqual:
                return(left.value == right.value);

            case ScriptBinaryOperator.CompareNotEqual:
                return(left.value != right.value);

            case ScriptBinaryOperator.CompareLess:
                return(left.value < right.value);

            case ScriptBinaryOperator.CompareLessOrEqual:
                return(left.value <= right.value);

            case ScriptBinaryOperator.CompareGreater:
                return(left.value > right.value);

            case ScriptBinaryOperator.CompareGreaterOrEqual:
                return(left.value >= right.value);
            }

            throw new ScriptRuntimeException(expression.Span, $"Operator [{expression.Operator}] is not supported for timespan");
        }
        public override object Evaluate(TemplateContext context)
        {
            var increment        = this.Operator == ScriptUnaryOperator.Increment ? 1 : -1;
            var value            = Evaluate(context, this.Right.Span, ScriptUnaryOperator.Plus, context.Evaluate(this.Right));
            var incrementedValue = ScriptBinaryExpression.Evaluate(context, this.Right.Span, ScriptBinaryOperator.Add, value, increment);

            context.SetValue(Right, incrementedValue);
            return(Post ? value : incrementedValue);
        }
示例#3
0
        private object EvaluateBinaryExpression(ScriptBinaryExpression expression, ScriptDate left,
                                                ScriptTimeSpan right)
        {
            switch (expression.Operator)
            {
            case ScriptBinaryOperator.Add:
                return(new ScriptDate((DateTime)left + right));
            }

            throw new ScriptRuntimeException(expression.Span, $"Operator [{expression.Operator}] is not supported for between <date> and <timespan>");
        }
示例#4
0
        object IScriptCustomType.EvaluateBinaryExpression(ScriptBinaryExpression expression, object left, object right)
        {
            if (left is ScriptDate && right is ScriptDate)
            {
                return(EvaluateBinaryExpression(expression, (ScriptDate)left, (ScriptDate)right));
            }

            if (left is ScriptDate && right is ScriptTimeSpan)
            {
                return(EvaluateBinaryExpression(expression, (ScriptDate)left, (ScriptTimeSpan)right));
            }

            throw new ScriptRuntimeException(expression.Span, $"Operator [{expression.Operator}] is not supported for between [{left?.GetType()}] and [{right?.GetType()}]");
        }
示例#5
0
        public object Dot(object x, object y)
        {
            if (x is KalkVector vx)
            {
                if (y is KalkVector vy)
                {
                    return(KalkVector.Dot(vx, vy));
                }
                return(KalkVector.Dot(vx, vx.FromValue(Engine.ToObject(1, y, vx.ElementType))));
            }
            else if (y is KalkVector vy)
            {
                return(KalkVector.Dot(vy.FromValue(Engine.ToObject(1, x, vy.ElementType)), vy));
            }

            return(ScriptBinaryExpression.Evaluate(Engine, Engine.CurrentSpan, ScriptBinaryOperator.Multiply, x, y));
        }
示例#6
0
        /// <summary>
        /// Divides the specified value by another value. If the divisor is an integer, the result will
        /// be floor to and converted back to an integer.
        /// </summary>
        /// <param name="context">The template context</param>
        /// <param name="span">The source span</param>
        /// <param name="value">The input value</param>
        /// <param name="divisor">The divisor value</param>
        /// <returns>The division of `value` by `divisor`.</returns>
        /// <remarks>
        /// ```scriban-html
        /// {{ 8.4 | math.divided_by 2.0 | math.round 1 }}
        /// {{ 8.4 | math.divided_by 2 }}
        /// ```
        /// ```html
        /// 4.2
        /// 4
        /// ```
        /// </remarks>
        public static object DividedBy(TemplateContext context, SourceSpan span, double value, object divisor)
        {
            var result = ScriptBinaryExpression.Evaluate(context, span, ScriptBinaryOperator.Divide, value, divisor);

            // If the divisor is an integer, return a an integer
            if (divisor is int)
            {
                if (result is double)
                {
                    return((int)Math.Floor((double)result));
                }
                if (result is float)
                {
                    return((int)Math.Floor((float)result));
                }
            }
            return(result);
        }
示例#7
0
        private void SquashPowers()
        {
            if (_powers == null)
            {
                return;
            }
            _powers.Sort(SortPowerPerSymbol);

            // Compress the powers: a^x * a^y = a^(x+y)
            KalkBinaryExpression previousPower = null;

            for (var i = 0; i < _powers.Count; i++)
            {
                var power = _powers[i];
                if (previousPower != null && ReferenceEquals(power.Value, previousPower.Value))
                {
                    var powerResult = ScriptBinaryExpression.Evaluate(_context, _context.CurrentSpan, ScriptBinaryOperator.Add, power.Unit, previousPower.Unit);
                    _powers[i - 1] = new KalkBinaryExpression(power.Value, ScriptBinaryOperator.Power, powerResult);
                    _powers.RemoveAt(i);
                    i--;
                    continue;
                }

                previousPower = power;
            }

            // Remove any powers a^0.0
            for (var i = 0; i < _powers.Count; i++)
            {
                var power      = _powers[i];
                var powerValue = _context.ToObject <double>(_context.CurrentSpan, power.Unit);
                if (Math.Abs(powerValue) < (float.Epsilon * 4))
                {
                    _powers.RemoveAt(i);
                    i--;
                }
            }

            // Sort power per Power first and symbol after
            // From largest to smallest
            _powers.Sort(SortPowerPerPower);
        }
        private ScriptStatement ParseLiquidIncDecStatement(bool isDec)
        {
            ScriptExpressionStatement incdecStatement = Open <ScriptExpressionStatement>();

            NextToken(); // skip increment/decrement keyword

            ScriptBinaryExpression binaryExpression = Open <ScriptBinaryExpression>();

            binaryExpression.Left  = ExpectAndParseVariable(incdecStatement);
            binaryExpression.Right = new ScriptLiteral()
            {
                Span = binaryExpression.Span, Value = 1
            };
            binaryExpression.Operator = isDec ? ScriptBinaryOperator.Substract : ScriptBinaryOperator.Add;
            ExpectEndOfStatement(incdecStatement);

            incdecStatement.Expression = binaryExpression;

            Close(binaryExpression);
            return(Close(incdecStatement));
        }
示例#9
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);
        }
示例#10
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);
        }
示例#11
0
 /// <summary>
 /// Substracts from the input value the `with` value
 /// </summary>
 /// <param name="context">The template context</param>
 /// <param name="span">The source span</param>
 /// <param name="value">The input value</param>
 /// <param name="with">The with value to substract from `value`</param>
 /// <returns>The results of the substraction: `value` - `with`</returns>
 /// <remarks>
 /// ```scriban-html
 /// {{ 255 | math.minus 5}}
 /// ```
 /// ```html
 /// 250
 /// ```
 /// </remarks>
 public static object Minus(TemplateContext context, SourceSpan span, object value, object with)
 {
     return(ScriptBinaryExpression.Evaluate(context, span, ScriptBinaryOperator.Substract, value, with));
 }
示例#12
0
 /// <summary>
 /// Performs the multiplication of the input value with the `with` value
 /// </summary>
 /// <param name="context">The template context</param>
 /// <param name="span">The source span</param>
 /// <param name="value">The input value</param>
 /// <param name="with">The with value to multiply to`value`</param>
 /// <returns>The results of the multiplication: `value` * `with`</returns>
 /// <remarks>
 /// ```scriban-html
 /// {{ 2 | math.times 3}}
 /// ```
 /// ```html
 /// 6
 /// ```
 /// </remarks>
 public static object Times(TemplateContext context, SourceSpan span, object value, object with)
 {
     return(ScriptBinaryExpression.Evaluate(context, span, ScriptBinaryOperator.Multiply, value, with));
 }
示例#13
0
        private ScriptExpression ParseExpression(ScriptNode parentNode, ref bool hasAnonymousFunction, ScriptExpression parentExpression = null, int precedence = 0,
                                                 ParseExpressionMode mode = ParseExpressionMode.Default)
        {
            int expressionCount = 0;

            _expressionLevel++;
            int expressionDepthBeforeEntering = _expressionDepth;

            EnterExpression();

            try
            {
                ScriptFunctionCall functionCall = null;
parseExpression:
                expressionCount++;
                ScriptExpression leftOperand = null;
                switch (Current.Type)
                {
                case TokenType.Identifier:
                case TokenType.IdentifierSpecial:
                    leftOperand = ParseVariable();

                    // In case of liquid template, we accept the syntax colon after a tag
                    if (_isLiquid && parentNode is ScriptPipeCall && Current.Type == TokenType.Colon)
                    {
                        NextToken();
                    }

                    // Special handle of the $$ block delegate variable
                    if (ScriptVariable.BlockDelegate.Equals(leftOperand))
                    {
                        if (expressionCount != 1 || _expressionLevel > 1)
                        {
                            LogError(RS.DelegateBlockInNestedExpr);
                        }

                        if (!(parentNode is ScriptExpressionStatement))
                        {
                            LogError(parentNode, RS.DelegateBlockOutsideExpr);
                        }

                        return(leftOperand);
                    }
                    break;

                case TokenType.Integer:
                    leftOperand = ParseInteger();
                    break;

                case TokenType.Float:
                    leftOperand = ParseFloat();
                    break;

                case TokenType.String:
                    leftOperand = ParseString();
                    break;

                case TokenType.ImplicitString:
                    leftOperand = ParseImplicitString();
                    break;

                case TokenType.VerbatimString:
                    leftOperand = ParseVerbatimString();
                    break;

                case TokenType.OpenParent:
                    leftOperand = ParseParenthesis(ref hasAnonymousFunction);
                    break;

                case TokenType.OpenBrace:
                    leftOperand = ParseObjectInitializer();
                    break;

                case TokenType.OpenBracket:
                    leftOperand = ParseArrayInitializer();
                    break;

                case TokenType.Not:
                case TokenType.Minus:
                case TokenType.Arroba:
                case TokenType.Plus:
                case TokenType.Caret:
                    leftOperand = ParseUnaryExpression(ref hasAnonymousFunction);
                    break;
                }

                // Should not happen but in case
                if (leftOperand == null)
                {
                    if (functionCall != null)
                    {
                        LogError(string.Format(RS.UnexpectedTokenInFunc, GetAsText(Current), functionCall));
                    }
                    else
                    {
                        LogError(string.Format(RS.UnexpectedTokenInExpr, GetAsText(Current)));
                    }

                    return(null);
                }

                if (leftOperand is ScriptAnonymousFunction)
                {
                    hasAnonymousFunction = true;
                }

                while (!hasAnonymousFunction)
                {
                    if (_isLiquid && Current.Type == TokenType.Comma && functionCall != null)
                    {
                        NextToken(); // Skip the comma for arguments in a function call
                    }
                    // Parse Member expression are expected to be followed only by an identifier
                    if (Current.Type == TokenType.Dot)
                    {
                        Token nextToken = PeekToken();
                        if (nextToken.Type == TokenType.Identifier)
                        {
                            NextToken();

                            if (GetAsText(Current) == "empty" && PeekToken().Type == TokenType.Question)
                            {
                                ScriptIsEmptyExpression memberExpression = Open <ScriptIsEmptyExpression>();
                                NextToken(); // skip empty
                                NextToken(); // skip ?
                                memberExpression.Target = leftOperand;
                                leftOperand             = Close(memberExpression);
                            }
                            else
                            {
                                ScriptMemberExpression memberExpression = Open <ScriptMemberExpression>();
                                memberExpression.Target = leftOperand;
                                ScriptExpression member = ParseVariable();
                                if (!(member is ScriptVariable))
                                {
                                    LogError(string.Format(RS.UnexpectedLiteralMember, member));
                                    return(null);
                                }
                                memberExpression.Member = (ScriptVariable)member;
                                leftOperand             = Close(memberExpression);
                            }
                        }
                        else
                        {
                            LogError(nextToken, string.Format(RS.InvalidTokenAfterDot, nextToken.Type));
                            return(null);
                        }
                        continue;
                    }

                    // If we have a bracket but left operand is a (variable || member || indexer), then we consider next as an indexer
                    // unit test: 130-indexer-accessor-accept1.txt
                    if (Current.Type == TokenType.OpenBracket && leftOperand is IScriptVariablePath && !IsPreviousCharWhitespace())
                    {
                        NextToken();
                        ScriptIndexerExpression indexerExpression = Open <ScriptIndexerExpression>();
                        indexerExpression.Target = leftOperand;
                        // unit test: 130-indexer-accessor-error5.txt
                        indexerExpression.Index = ExpectAndParseExpression(indexerExpression, ref hasAnonymousFunction, functionCall, 0, string.Format(RS.ExpectToken, "index_expression", Current.Type));

                        if (Current.Type != TokenType.CloseBracket)
                        {
                            LogError(string.Format(RS.ExpectToken, "]", Current.Type));
                        }
                        else
                        {
                            NextToken();
                        }

                        leftOperand = Close(indexerExpression);
                        continue;
                    }

                    if (mode == ParseExpressionMode.BasicExpression)
                    {
                        break;
                    }

                    if (Current.Type == TokenType.Equal)
                    {
                        ScriptAssignExpression assignExpression = Open <ScriptAssignExpression>();

                        if (_expressionLevel > 1)
                        {
                            // unit test: 101-assign-complex-error1.txt
                            LogError(assignExpression, RS.ExprForTopLevelAssignmentOnly);
                        }

                        NextToken();

                        assignExpression.Target = TransformKeyword(leftOperand);

                        // unit test: 105-assign-error3.txt
                        assignExpression.Value = ExpectAndParseExpression(assignExpression, ref hasAnonymousFunction, parentExpression);

                        leftOperand = Close(assignExpression);
                        continue;
                    }

                    // Handle binary operators here
                    ScriptBinaryOperator binaryOperatorType;
                    if (BinaryOperators.TryGetValue(Current.Type, out binaryOperatorType) || (_isLiquid && TryLiquidBinaryOperator(out binaryOperatorType)))
                    {
                        int newPrecedence = GetOperatorPrecedence(binaryOperatorType);

                        // Check precedence to see if we should "take" this operator here (Thanks TimJones for the tip code! ;)
                        if (newPrecedence < precedence)
                        {
                            break;
                        }

                        // We fake entering an expression here to limit the number of expression
                        EnterExpression();
                        ScriptBinaryExpression binaryExpression = Open <ScriptBinaryExpression>();
                        binaryExpression.Left     = leftOperand;
                        binaryExpression.Operator = binaryOperatorType;

                        NextToken(); // skip the operator

                        // unit test: 110-binary-simple-error1.txt
                        binaryExpression.Right = ExpectAndParseExpression(binaryExpression, ref hasAnonymousFunction,
                                                                          functionCall ?? parentExpression, newPrecedence,
                                                                          string.Format(RS.ExpectTokenInRightOperator, "expression", Current.Type));
                        leftOperand = Close(binaryExpression);

                        continue;
                    }

                    if (precedence > 0)
                    {
                        break;
                    }

                    if (StartAsExpression())
                    {
                        // If we can parse a statement, we have a method call
                        if (parentExpression != null)
                        {
                            break;
                        }

                        // Parse named parameters
                        var paramContainer = parentNode as IScriptNamedArgumentContainer;
                        if (Current.Type == TokenType.Identifier && (parentNode is IScriptNamedArgumentContainer || !_isLiquid && PeekToken().Type == TokenType.Colon))
                        {
                            if (paramContainer == null)
                            {
                                if (functionCall == null)
                                {
                                    functionCall            = Open <ScriptFunctionCall>();
                                    functionCall.Target     = leftOperand;
                                    functionCall.Span.Start = leftOperand.Span.Start;
                                }
                                else
                                {
                                    functionCall.Arguments.Add(leftOperand);
                                }
                                Close(leftOperand);
                            }

                            while (true)
                            {
                                if (Current.Type != TokenType.Identifier)
                                {
                                    break;
                                }

                                ScriptNamedArgument parameter = Open <ScriptNamedArgument>();
                                string parameterName          = GetAsText(Current);
                                parameter.Name = parameterName;

                                // Skip argument name
                                NextToken();

                                if (paramContainer != null)
                                {
                                    paramContainer.AddParameter(Close(parameter));
                                }
                                else
                                {
                                    functionCall.Arguments.Add(parameter);
                                }

                                // If we have a colon, we have a value
                                // otherwise it is a boolean argument name
                                if (Current.Type == TokenType.Colon)
                                {
                                    NextToken();
                                    parameter.Value    = ExpectAndParseExpression(parentNode, mode: ParseExpressionMode.BasicExpression);
                                    parameter.Span.End = parameter.Value.Span.End;
                                }

                                if (functionCall != null)
                                {
                                    functionCall.Span.End = parameter.Span.End;
                                }
                            }

                            // As we have handled leftOperand here, we don't let the function out of this while to pick up the leftOperand
                            if (functionCall != null)
                            {
                                leftOperand  = functionCall;
                                functionCall = null;
                            }

                            // We don't allow anything after named parameters
                            break;
                        }

                        if (functionCall == null)
                        {
                            functionCall        = Open <ScriptFunctionCall>();
                            functionCall.Target = leftOperand;

                            // If we need to convert liquid to textscript functions:
                            if (_isLiquid && Options.ConvertLiquidFunctions)
                            {
                                TransformFromLiquidFunctionCall(functionCall);
                            }

                            functionCall.Span.Start = leftOperand.Span.Start;
                        }
                        else
                        {
                            functionCall.Arguments.Add(leftOperand);
                        }

                        goto parseExpression;
                    }

                    if (Current.Type == TokenType.Pipe)
                    {
                        if (functionCall != null)
                        {
                            functionCall.Arguments.Add(leftOperand);
                            leftOperand = functionCall;
                        }

                        ScriptPipeCall pipeCall = Open <ScriptPipeCall>();
                        pipeCall.From = leftOperand;
                        NextToken(); // skip |

                        // unit test: 310-func-pipe-error1.txt
                        pipeCall.To = ExpectAndParseExpression(pipeCall, ref hasAnonymousFunction);
                        return(Close(pipeCall));
                    }

                    break;
                }

                if (functionCall != null)
                {
                    functionCall.Arguments.Add(leftOperand);
                    functionCall.Span.End = leftOperand.Span.End;
                    return(functionCall);
                }
                return(Close(leftOperand));
            }
            finally
            {
                LeaveExpression();
                // Force to restore back to a level
                _expressionDepth = expressionDepthBeforeEntering;
                _expressionLevel--;
            }
        }
示例#14
0
        private void Collect(object value)
        {
            if (value == null)
            {
                return;
            }

            if (value is KalkUnit symbol)
            {
                if (symbol.Value != null)
                {
                    Collect(symbol.Value);
                }
                else
                {
                    if (_powers == null)
                    {
                        _powers = new List <KalkBinaryExpression>();
                    }
                    _powers.Add(new KalkBinaryExpression(symbol, ScriptBinaryOperator.Power, 1));
                }
            }
            else if (value is KalkBinaryExpression binary)
            {
                if (binary.Operator == ScriptBinaryOperator.Multiply)
                {
                    var leftSimplifier = new KalkExpressionSimplifier(_context);
                    leftSimplifier.Collect(binary.Value);
                    Collect(leftSimplifier);

                    var rightSimplifier = new KalkExpressionSimplifier(_context);
                    rightSimplifier.Collect(binary.Unit);
                    Collect(rightSimplifier);
                }
                else if (binary.Operator == ScriptBinaryOperator.Divide)
                {
                    Collect(binary.Value);
                    if (binary.Unit is KalkExpression)
                    {
                        Collect(new KalkBinaryExpression(binary.Unit, ScriptBinaryOperator.Power, -1));
                    }
                    else
                    {
                        var result = ScriptBinaryExpression.Evaluate(_context, _context.CurrentSpan, ScriptBinaryOperator.Divide, 1, binary.Unit);
                        SquashValue(result);
                    }
                }
                else
                {
                    Debug.Assert(binary.Operator == ScriptBinaryOperator.Power);
                    if (_powers == null)
                    {
                        _powers = new List <KalkBinaryExpression>();
                    }

                    // (a * b^2) ^ 5
                    // a ^ 5 * b ^ 10
                    var subSimplifier = new KalkExpressionSimplifier(_context);
                    subSimplifier.Collect(binary.Value);

                    var subValue = _context.ToObject <double>(_context.CurrentSpan, subSimplifier._value);

                    if (!KalkValue.AlmostEqual(subValue, 1.0))
                    {
                        var result = ScriptBinaryExpression.Evaluate(_context, _context.CurrentSpan, ScriptBinaryOperator.Power, subSimplifier._value, binary.Unit);
                        SquashValue(result);
                    }

                    if (subSimplifier._powers != null)
                    {
                        foreach (var powerExpression in subSimplifier._powers)
                        {
                            var powerResult = ScriptBinaryExpression.Evaluate(_context, _context.CurrentSpan, ScriptBinaryOperator.Multiply, powerExpression.Unit, binary.Unit);
                            var newPower    = new KalkBinaryExpression(powerExpression.Value, ScriptBinaryOperator.Power, powerResult);
                            _powers.Add(newPower);
                        }
                    }
                }
            }
            else
            {
                SquashValue(value);
            }
        }
示例#15
0
        public ScriptExpression ReplaceCondition(ScriptExpression condition, object replaceValue)
        {
            if (condition is ScriptVariableLocal localVar)
            {
                if (localVar.Name == string.Empty)
                {
                    return(new ScriptLiteral(replaceValue));
                }
                else
                {
                    return(localVar);
                }
            }
            else if (condition is ScriptMemberExpression objExpr)
            {
                return(new ScriptMemberExpression()
                {
                    Member = objExpr.Member,
                    Trivias = objExpr.Trivias,
                    Target = ReplaceCondition(objExpr.Target, replaceValue)
                });
            }
            else if (condition is ScriptNestedExpression nestedExpr)
            {
                return(new ScriptNestedExpression()
                {
                    Expression = ReplaceCondition(nestedExpr.Expression, replaceValue),
                    Trivias = nestedExpr.Trivias
                });
            }
            else if (condition is ScriptFunctionCall funcCall)
            {
                ScriptFunctionCall funcResult = new ScriptFunctionCall()
                {
                    Target  = funcCall.Target,
                    Trivias = funcCall.Trivias
                };

                foreach (ScriptExpression expr in funcCall.Arguments)
                {
                    funcResult.Arguments.Add(ReplaceCondition(expr, replaceValue));
                }

                return(funcResult);
            }
            else if (condition is ScriptPipeCall pipeCall)
            {
                ScriptPipeCall pipeResult = new ScriptPipeCall()
                {
                    From    = ReplaceCondition(pipeCall.From, replaceValue),
                    To      = ReplaceCondition(pipeCall.To, replaceValue),
                    Trivias = pipeCall.Trivias
                };

                return(pipeResult);
            }
            else if (condition is ScriptBinaryExpression binCondition)
            {
                ScriptBinaryExpression binExprResult = new ScriptBinaryExpression()
                {
                    Left     = ReplaceCondition(binCondition.Left, replaceValue),
                    Right    = ReplaceCondition(binCondition.Right, replaceValue),
                    Operator = binCondition.Operator,
                    Trivias  = binCondition.Trivias
                };

                return(binExprResult);
            }
            else
            {
                return(condition);
            }
        }
示例#16
0
 private void SquashValue(object value)
 {
     _value = ScriptBinaryExpression.Evaluate(_context, _context.CurrentSpan, ScriptBinaryOperator.Multiply, _value, value);
 }
示例#17
0
 public object Normalize(object x)
 {
     return(ScriptBinaryExpression.Evaluate(Engine, Engine.CurrentSpan, ScriptBinaryOperator.Divide, x, Length(x)));
 }