Esempio n. 1
0
        private static ReadOnlySpan <char> ParseJsConditionalExpression(this ReadOnlySpan <char> literal, JsToken test, out JsConditionalExpression expression)
        {
            literal = literal.Advance(1);

            literal = literal.ParseJsExpression(out var consequent);
            literal = literal.AdvancePastWhitespace();

            if (!literal.FirstCharEquals(':'))
            {
                throw new SyntaxErrorException($"Expected Conditional ':' but was {literal.DebugFirstChar()}");
            }

            literal = literal.Advance(1);

            literal = literal.ParseJsExpression(out var alternate);

            expression = new JsConditionalExpression(test, consequent, alternate);
            return(literal);
        }
Esempio n. 2
0
        public static ReadOnlySpan <char> ParseJsCallExpression(this ReadOnlySpan <char> literal, out JsCallExpression expression, bool filterExpression = false)
        {
            literal = literal.ParseIdentifier(out var token);

            if (!(token is JsIdentifier identifier))
            {
                throw new SyntaxErrorException($"Expected identifier but instead found {token.DebugToken()}");
            }

            literal = literal.AdvancePastWhitespace();

            if (literal.FirstCharEquals(WhitespaceArgument))
            {
                literal    = literal.Advance(1);
                literal    = literal.ParseWhitespaceArgument(out var argument);
                expression = new JsCallExpression(identifier, argument);
                return(literal);
            }

            if (literal.StartsWith("=>"))
            {
                literal    = literal.ParseArrowExpressionBody(new[] { new JsIdentifier("it") }, out var arrowExpr);
                expression = new JsCallExpression(identifier, arrowExpr);
                return(literal);
            }

            if (!literal.FirstCharEquals('('))
            {
                expression = new JsCallExpression(identifier);
                return(literal);
            }

            literal = literal.Advance(1);

            literal = literal.ParseArguments(out var args, termination: ')');

            expression = new JsCallExpression(identifier, args.ToArray());
            return(literal);
        }
Esempio n. 3
0
        internal static ReadOnlySpan <char> ParseArguments(this ReadOnlySpan <char> literal, out List <JsToken> arguments, char termination)
        {
            arguments = new List <JsToken>();

            while (!literal.IsNullOrEmpty())
            {
                JsToken listValue;

                literal = literal.AdvancePastWhitespace();
                if (literal[0] == termination)
                {
                    literal = literal.Advance(1);
                    break;
                }

                if (literal.StartsWith("..."))
                {
                    literal = literal.Advance(3);
                    literal = literal.ParseJsExpression(out listValue);
                    if (!(listValue is JsIdentifier) && !(listValue is JsArrayExpression))
                    {
                        throw new SyntaxErrorException($"Spread operator expected array but instead found {listValue.DebugToken()}");
                    }

                    listValue = new JsSpreadElement(listValue);
                }
                else
                {
                    literal = literal.ParseJsExpression(out listValue);
                }

                arguments.Add(listValue);

                literal = literal.AdvancePastWhitespace();
                if (literal.IsNullOrEmpty())
                {
                    break;
                }

                if (literal[0] == termination)
                {
                    literal = literal.Advance(1);
                    break;
                }

                literal = literal.AdvancePastWhitespace();
                var c = literal.SafeGetChar(0);
                if (c.IsEnd() || c == termination)
                {
                    literal = literal.Advance(1);
                    break;
                }

                if (c != ',')
                {
                    throw new SyntaxErrorException($"Unterminated arguments expression near: {literal.DebugLiteral()}");
                }

                literal = literal.Advance(1);
                literal = literal.AdvancePastWhitespace();
            }

            literal = literal.AdvancePastWhitespace();

            return(literal);
        }
Esempio n. 4
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);
        }
Esempio n. 5
0
        public static ReadOnlySpan <char> ParseJsExpression(this ReadOnlySpan <char> literal, out JsToken token, bool filterExpression)
        {
            var peekLiteral = literal.ParseJsToken(out var node, filterExpression: filterExpression);

            peekLiteral = peekLiteral.AdvancePastWhitespace();

            var peekChar = peekLiteral.SafeGetChar(0);

            if (literal.IsNullOrEmpty() || peekChar.IsExpressionTerminatorChar())
            {
                token = node;
                return(peekLiteral);
            }

            if (peekChar == ConditionalExpressionTestChar &&
                peekLiteral.SafeGetChar(1) != ConditionalExpressionTestChar) // not ??
            {
                literal = peekLiteral.ParseJsConditionalExpression(node, out var expression);
                token   = expression;
                return(literal);
            }

            if (node is JsIdentifier identifier)
            {
                if (peekLiteral.StartsWith("=>"))
                {
                    literal = peekLiteral.ParseArrowExpressionBody(new[] { identifier }, out var arrowExpr);
                    token   = arrowExpr;
                    return(literal);
                }

                var kind = identifier.Name == "var"
                    ? JsVariableDeclarationKind.Var
                    : identifier.Name == "let"
                        ? JsVariableDeclarationKind.Let
                        : identifier.Name == "const"
                            ? JsVariableDeclarationKind.Const
                            : (JsVariableDeclarationKind?)null;
                if (kind != null)
                {
                    literal = peekLiteral.ParseVariableDeclaration(kind.Value, out var varDec);
                    token   = varDec;
                    return(literal);
                }

                if (peekChar == '=' && peekLiteral.SafeGetChar(1) != '=') // not ==, ===
                {
                    literal = peekLiteral.ParseAssignmentExpression(identifier, out var assignExpr);
                    token   = assignExpr;
                    return(literal);
                }
            }

            peekLiteral = peekLiteral.AdvancePastWhitespace();

            if (!peekLiteral.IsNullOrEmpty())
            {
                if (filterExpression && peekLiteral.Length > 2)
                {
                    var char1 = peekLiteral[0];
                    var char2 = peekLiteral[1];
                    if ((char1 == '|' && char2 != '|') || (char1 == '}' && char2 == '}'))
                    {
                        token = node;
                        return(peekLiteral);
                    }
                }
            }

            peekLiteral = peekLiteral.ParseJsBinaryOperator(out var op);
            if (op != null)
            {
                literal = literal.ParseBinaryExpression(out var expr, filterExpression);
                token   = expr;

                literal = literal.AdvancePastWhitespace();
                if (literal.FirstCharEquals(ConditionalExpressionTestChar))
                {
                    literal = literal.ParseJsConditionalExpression(expr, out var conditionalExpr);
                    token   = conditionalExpr;
                    return(literal);
                }

                return(literal);
            }

            literal = peekLiteral.ParseJsMemberExpression(ref node, filterExpression);

            token = node;
            return(literal);
        }
        public static ReadOnlySpan <char> ParseJsExpression(this ReadOnlySpan <char> literal, out JsToken token, bool filterExpression)
        {
            var peekLiteral = literal.ParseJsToken(out var node, filterExpression: filterExpression);

            peekLiteral = peekLiteral.AdvancePastWhitespace();

            var peekChar = peekLiteral.SafeGetChar(0);

            if (literal.IsNullOrEmpty() || peekChar.IsExpressionTerminatorChar())
            {
                token = node;
                return(peekLiteral);
            }

            if (peekChar == ConditionalExpressionTestChar &&
                peekLiteral.SafeGetChar(1) != ConditionalExpressionTestChar) // not ??
            {
                literal = peekLiteral.ParseJsConditionalExpression(node, out var expression);
                token   = expression;
                return(literal);
            }

            if (node is JsIdentifier identifier && peekLiteral.StartsWith("=>"))
            {
                literal = peekLiteral.ParseArrowExpressionBody(new[] { identifier }, out var arrowExpr);
                token   = arrowExpr;
                return(literal);
            }

            peekLiteral = peekLiteral.AdvancePastWhitespace();

            if (!peekLiteral.IsNullOrEmpty())
            {
                if (filterExpression && peekLiteral.Length > 2)
                {
                    var char1 = peekLiteral[0];
                    var char2 = peekLiteral[1];
                    if ((char1 == '|' && char2 != '|') || (char1 == '}' && char2 == '}'))
                    {
                        token = node;
                        return(peekLiteral);
                    }
                }
            }

            peekLiteral = peekLiteral.ParseJsBinaryOperator(out var op);
            if (op != null)
            {
                literal = literal.ParseBinaryExpression(out var expr, filterExpression);
                token   = expr;

                literal = literal.AdvancePastWhitespace();
                if (literal.FirstCharEquals(ConditionalExpressionTestChar))
                {
                    literal = literal.ParseJsConditionalExpression(expr, out var conditionalExpr);
                    token   = conditionalExpr;
                    return(literal);
                }

                return(literal);
            }

            literal = peekLiteral.ParseJsMemberExpression(ref node, filterExpression);

            token = node;
            return(literal);
        }