예제 #1
0
    /// <summary>
    /// Gets the next binary precedence.
    /// </summary>
    /// <param name="literal">The literal.</param>
    /// <returns>System.Int32.</returns>
    static int GetNextBinaryPrecedence(this ReadOnlySpan <char> literal)
    {
        if (!literal.IsNullOrEmpty() && !literal[0].IsExpressionTerminatorChar())
        {
            literal.ParseJsBinaryOperator(out var binaryOp);
            if (binaryOp != null)
            {
                return(JsTokenUtils.GetBinaryPrecedence(binaryOp.Token));
            }
        }

        return(0);
    }
예제 #2
0
    /// <summary>
    /// Parses the binary expression.
    /// </summary>
    /// <param name="literal">The literal.</param>
    /// <param name="expr">The expr.</param>
    /// <param name="filterExpression">if set to <c>true</c> [filter expression].</param>
    /// <returns>ReadOnlySpan&lt;System.Char&gt;.</returns>
    /// <exception cref="ServiceStack.Script.SyntaxErrorException">Expected Expression but was {lhs.DebugToken()}</exception>
    /// <exception cref="ServiceStack.Script.SyntaxErrorException">Expected binary operator near: {literal.DebugLiteral()}</exception>
    /// <exception cref="ServiceStack.Script.SyntaxErrorException">Expected expression near: '{literal.DebugLiteral()}'</exception>
    /// <exception cref="ServiceStack.Script.SyntaxErrorException">Expected Expression but was {lhs.DebugToken()}</exception>
    public static ReadOnlySpan <char> ParseBinaryExpression(this ReadOnlySpan <char> literal, out JsExpression expr, bool filterExpression)
    {
        literal = literal.AdvancePastWhitespace();

        literal = literal.ParseJsToken(out var lhs, filterExpression: filterExpression);

        if (literal.IsNullOrEmpty())
        {
            expr = lhs as JsExpression ?? throw new SyntaxErrorException($"Expected Expression but was {lhs.DebugToken()}");
        }
        else
        {
            literal = literal.ParseJsBinaryOperator(out var op);

            if (op == null)
            {
                throw new SyntaxErrorException($"Expected binary operator near: {literal.DebugLiteral()}");
            }

            var prec = JsTokenUtils.GetBinaryPrecedence(op.Token);
            if (prec > 0 || op == JsAssignment.Operator)
            {
                literal = literal.ParseJsToken(out JsToken rhs, filterExpression: filterExpression);

                var stack = new Stack <JsToken>();
                stack.Push(lhs);
                stack.Push(op);
                stack.Push(rhs);

                var precedences = new List <int> {
                    prec
                };

                while (true)
                {
                    literal = literal.AdvancePastWhitespace();
                    if (filterExpression && literal.Length > 2 && literal[0] == '|' && literal[1] != '|')
                    {
                        break;
                    }

                    prec = literal.GetNextBinaryPrecedence();
                    if (prec == 0)
                    {
                        break;
                    }

                    while (stack.Count > 2 && prec <= precedences[precedences.Count - 1])
                    {
                        rhs = stack.Pop();
                        var operand = (JsBinaryOperator)stack.Pop();
                        precedences.RemoveAt(precedences.Count - 1);
                        lhs = stack.Pop();
                        stack.Push(CreateJsExpression(lhs, operand, rhs));
                    }

                    literal = literal.ParseJsBinaryOperator(out op);

                    if (literal.IsNullOrEmpty())
                    {
                        throw new SyntaxErrorException($"Expected expression near: '{literal.DebugLiteral()}'");
                    }

                    literal = literal.ParseJsToken(out var token, filterExpression: filterExpression);

                    stack.Push(op);
                    stack.Push(token);
                    precedences.Add(prec);
                }

                var i   = stack.Count - 1;
                var ret = stack.Pop();

                while (stack.Count > 0)
                {
                    op  = (JsBinaryOperator)stack.Pop();
                    lhs = stack.Pop();
                    ret = CreateJsExpression(lhs, op, ret);
                }

                expr = (JsExpression)ret;
            }
            else
            {
                expr = lhs as JsExpression ?? throw new SyntaxErrorException($"Expected Expression but was {lhs.DebugToken()}");
            }
        }

        return(literal);
    }