Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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 is JsExpression jsExpr
                    ? jsExpr
                    : 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 is JsExpression jsExpr
                        ? jsExpr
                        : throw new SyntaxErrorException($"Expected Expression but was {lhs.DebugToken()}");
                }
            }

            return(literal);
        }