소스 검색

LibJS: Add Parser save_state() and load_state() functions

These functions allow us to try to parse ambiguous expressions (such as
arrow function arguments in parentheses), and
rewind the state of the Parser if an expression candidate failed to
parse.
Jack Karamanian 5 년 전
부모
커밋
f90da71d28
2개의 변경된 파일59개의 추가작업 그리고 35개의 파일을 삭제
  1. 46 31
      Libraries/LibJS/Parser.cpp
  2. 13 4
      Libraries/LibJS/Parser.h

+ 46 - 31
Libraries/LibJS/Parser.cpp

@@ -32,10 +32,14 @@
 namespace JS {
 namespace JS {
 
 
 static HashMap<TokenType, int> g_operator_precedence;
 static HashMap<TokenType, int> g_operator_precedence;
-
-Parser::Parser(Lexer lexer)
+Parser::ParserState::ParserState(Lexer lexer)
     : m_lexer(move(lexer))
     : m_lexer(move(lexer))
     , m_current_token(m_lexer.next())
     , m_current_token(m_lexer.next())
+{
+}
+
+Parser::Parser(Lexer lexer)
+    : m_parser_state(move(lexer))
 {
 {
     if (g_operator_precedence.is_empty()) {
     if (g_operator_precedence.is_empty()) {
         // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
         // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
@@ -183,7 +187,7 @@ NonnullRefPtr<Program> Parser::parse_program()
 NonnullRefPtr<Statement> Parser::parse_statement()
 NonnullRefPtr<Statement> Parser::parse_statement()
 {
 {
     auto statement = [this]() -> NonnullRefPtr<Statement> {
     auto statement = [this]() -> NonnullRefPtr<Statement> {
-    switch (m_current_token.type()) {
+    switch (m_parser_state.m_current_token.type()) {
     case TokenType::Function:
     case TokenType::Function:
         return parse_function_node<FunctionDeclaration>();
         return parse_function_node<FunctionDeclaration>();
     case TokenType::CurlyOpen:
     case TokenType::CurlyOpen:
@@ -209,7 +213,7 @@ NonnullRefPtr<Statement> Parser::parse_statement()
     default:
     default:
         if (match_expression())
         if (match_expression())
             return adopt(*new ExpressionStatement(parse_expression(0)));
             return adopt(*new ExpressionStatement(parse_expression(0)));
-        m_has_errors = true;
+        m_parser_state.m_has_errors = true;
         expected("statement (missing switch case)");
         expected("statement (missing switch case)");
         consume();
         consume();
         return create_ast_node<ErrorStatement>();
         return create_ast_node<ErrorStatement>();
@@ -224,7 +228,7 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression()
     if (match_unary_prefixed_expression())
     if (match_unary_prefixed_expression())
         return parse_unary_prefixed_expression();
         return parse_unary_prefixed_expression();
 
 
-    switch (m_current_token.type()) {
+    switch (m_parser_state.m_current_token.type()) {
     case TokenType::ParenOpen: {
     case TokenType::ParenOpen: {
         consume(TokenType::ParenOpen);
         consume(TokenType::ParenOpen);
         auto expression = parse_expression(0);
         auto expression = parse_expression(0);
@@ -254,7 +258,7 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression()
     case TokenType::New:
     case TokenType::New:
         return parse_new_expression();
         return parse_new_expression();
     default:
     default:
-        m_has_errors = true;
+        m_parser_state.m_has_errors = true;
         expected("primary expression (missing switch case)");
         expected("primary expression (missing switch case)");
         consume();
         consume();
         return create_ast_node<ErrorExpression>();
         return create_ast_node<ErrorExpression>();
@@ -263,9 +267,9 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression()
 
 
 NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression()
 NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression()
 {
 {
-    auto precedence = operator_precedence(m_current_token.type());
-    auto associativity = operator_associativity(m_current_token.type());
-    switch (m_current_token.type()) {
+    auto precedence = operator_precedence(m_parser_state.m_current_token.type());
+    auto associativity = operator_associativity(m_parser_state.m_current_token.type());
+    switch (m_parser_state.m_current_token.type()) {
     case TokenType::PlusPlus:
     case TokenType::PlusPlus:
         consume();
         consume();
         return create_ast_node<UpdateExpression>(UpdateOp::Increment, parse_expression(precedence, associativity), true);
         return create_ast_node<UpdateExpression>(UpdateOp::Increment, parse_expression(precedence, associativity), true);
@@ -282,7 +286,7 @@ NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression()
         consume();
         consume();
         return create_ast_node<UnaryExpression>(UnaryOp::Typeof, parse_expression(precedence, associativity));
         return create_ast_node<UnaryExpression>(UnaryOp::Typeof, parse_expression(precedence, associativity));
     default:
     default:
-        m_has_errors = true;
+        m_parser_state.m_has_errors = true;
         expected("primary expression (missing switch case)");
         expected("primary expression (missing switch case)");
         consume();
         consume();
         return create_ast_node<ErrorExpression>();
         return create_ast_node<ErrorExpression>();
@@ -334,13 +338,13 @@ NonnullRefPtr<Expression> Parser::parse_expression(int min_precedence, Associati
 {
 {
     auto expression = parse_primary_expression();
     auto expression = parse_primary_expression();
     while (match_secondary_expression()) {
     while (match_secondary_expression()) {
-        int new_precedence = operator_precedence(m_current_token.type());
+        int new_precedence = operator_precedence(m_parser_state.m_current_token.type());
         if (new_precedence < min_precedence)
         if (new_precedence < min_precedence)
             break;
             break;
         if (new_precedence == min_precedence && associativity == Associativity::Left)
         if (new_precedence == min_precedence && associativity == Associativity::Left)
             break;
             break;
 
 
-        Associativity new_associativity = operator_associativity(m_current_token.type());
+        Associativity new_associativity = operator_associativity(m_parser_state.m_current_token.type());
         expression = parse_secondary_expression(move(expression), new_precedence, new_associativity);
         expression = parse_secondary_expression(move(expression), new_precedence, new_associativity);
     }
     }
     return expression;
     return expression;
@@ -348,7 +352,7 @@ NonnullRefPtr<Expression> Parser::parse_expression(int min_precedence, Associati
 
 
 NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expression> lhs, int min_precedence, Associativity associativity)
 NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expression> lhs, int min_precedence, Associativity associativity)
 {
 {
-    switch (m_current_token.type()) {
+    switch (m_parser_state.m_current_token.type()) {
     case TokenType::Plus:
     case TokenType::Plus:
         consume();
         consume();
         return create_ast_node<BinaryExpression>(BinaryOp::Plus, move(lhs), parse_expression(min_precedence, associativity));
         return create_ast_node<BinaryExpression>(BinaryOp::Plus, move(lhs), parse_expression(min_precedence, associativity));
@@ -427,7 +431,7 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre
         consume();
         consume();
         return create_ast_node<LogicalExpression>(LogicalOp::Or, move(lhs), parse_expression(min_precedence, associativity));
         return create_ast_node<LogicalExpression>(LogicalOp::Or, move(lhs), parse_expression(min_precedence, associativity));
     default:
     default:
-        m_has_errors = true;
+        m_parser_state.m_has_errors = true;
         expected("secondary expression (missing switch case)");
         expected("secondary expression (missing switch case)");
         consume();
         consume();
         return create_ast_node<ErrorExpression>();
         return create_ast_node<ErrorExpression>();
@@ -532,7 +536,7 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration()
 {
 {
     DeclarationType declaration_type;
     DeclarationType declaration_type;
 
 
-    switch (m_current_token.type()) {
+    switch (m_parser_state.m_current_token.type()) {
     case TokenType::Var:
     case TokenType::Var:
         declaration_type = DeclarationType::Var;
         declaration_type = DeclarationType::Var;
         consume(TokenType::Var);
         consume(TokenType::Var);
@@ -663,7 +667,7 @@ NonnullRefPtr<ForStatement> Parser::parse_for_statement()
     consume(TokenType::ParenOpen);
     consume(TokenType::ParenOpen);
 
 
     RefPtr<ASTNode> init;
     RefPtr<ASTNode> init;
-    switch (m_current_token.type()) {
+    switch (m_parser_state.m_current_token.type()) {
     case TokenType::Semicolon:
     case TokenType::Semicolon:
         break;
         break;
     default:
     default:
@@ -679,7 +683,7 @@ NonnullRefPtr<ForStatement> Parser::parse_for_statement()
     consume(TokenType::Semicolon);
     consume(TokenType::Semicolon);
 
 
     RefPtr<Expression> test;
     RefPtr<Expression> test;
-    switch (m_current_token.type()) {
+    switch (m_parser_state.m_current_token.type()) {
     case TokenType::Semicolon:
     case TokenType::Semicolon:
         break;
         break;
     default:
     default:
@@ -690,7 +694,7 @@ NonnullRefPtr<ForStatement> Parser::parse_for_statement()
     consume(TokenType::Semicolon);
     consume(TokenType::Semicolon);
 
 
     RefPtr<Expression> update;
     RefPtr<Expression> update;
-    switch (m_current_token.type()) {
+    switch (m_parser_state.m_current_token.type()) {
     case TokenType::ParenClose:
     case TokenType::ParenClose:
         break;
         break;
     default:
     default:
@@ -707,12 +711,12 @@ NonnullRefPtr<ForStatement> Parser::parse_for_statement()
 
 
 bool Parser::match(TokenType type) const
 bool Parser::match(TokenType type) const
 {
 {
-    return m_current_token.type() == type;
+    return m_parser_state.m_current_token.type() == type;
 }
 }
 
 
 bool Parser::match_variable_declaration() const
 bool Parser::match_variable_declaration() const
 {
 {
-    switch (m_current_token.type()) {
+    switch (m_parser_state.m_current_token.type()) {
     case TokenType::Var:
     case TokenType::Var:
     case TokenType::Let:
     case TokenType::Let:
     case TokenType::Const:
     case TokenType::Const:
@@ -724,7 +728,7 @@ bool Parser::match_variable_declaration() const
 
 
 bool Parser::match_expression() const
 bool Parser::match_expression() const
 {
 {
-    auto type = m_current_token.type();
+    auto type = m_parser_state.m_current_token.type();
     return type == TokenType::BoolLiteral
     return type == TokenType::BoolLiteral
         || type == TokenType::NumericLiteral
         || type == TokenType::NumericLiteral
         || type == TokenType::StringLiteral
         || type == TokenType::StringLiteral
@@ -741,7 +745,7 @@ bool Parser::match_expression() const
 
 
 bool Parser::match_unary_prefixed_expression() const
 bool Parser::match_unary_prefixed_expression() const
 {
 {
-    auto type = m_current_token.type();
+    auto type = m_parser_state.m_current_token.type();
     return type == TokenType::PlusPlus
     return type == TokenType::PlusPlus
         || type == TokenType::MinusMinus
         || type == TokenType::MinusMinus
         || type == TokenType::ExclamationMark
         || type == TokenType::ExclamationMark
@@ -751,7 +755,7 @@ bool Parser::match_unary_prefixed_expression() const
 
 
 bool Parser::match_secondary_expression() const
 bool Parser::match_secondary_expression() const
 {
 {
-    auto type = m_current_token.type();
+    auto type = m_parser_state.m_current_token.type();
     return type == TokenType::Plus
     return type == TokenType::Plus
         || type == TokenType::PlusEquals
         || type == TokenType::PlusEquals
         || type == TokenType::Minus
         || type == TokenType::Minus
@@ -779,7 +783,7 @@ bool Parser::match_secondary_expression() const
 
 
 bool Parser::match_statement() const
 bool Parser::match_statement() const
 {
 {
-    auto type = m_current_token.type();
+    auto type = m_parser_state.m_current_token.type();
     return match_expression()
     return match_expression()
         || type == TokenType::Function
         || type == TokenType::Function
         || type == TokenType::Return
         || type == TokenType::Return
@@ -806,24 +810,35 @@ bool Parser::done() const
 
 
 Token Parser::consume()
 Token Parser::consume()
 {
 {
-    auto old_token = m_current_token;
-    m_current_token = m_lexer.next();
+    auto old_token = m_parser_state.m_current_token;
+    m_parser_state.m_current_token = m_parser_state.m_lexer.next();
     return old_token;
     return old_token;
 }
 }
 
 
 Token Parser::consume(TokenType type)
 Token Parser::consume(TokenType type)
 {
 {
-    if (m_current_token.type() != type) {
-        m_has_errors = true;
-        fprintf(stderr, "Error: Unexpected token %s. Expected %s\n", m_current_token.name(), Token::name(type));
+    if (m_parser_state.m_current_token.type() != type) {
+        m_parser_state.m_has_errors = true;
+        fprintf(stderr, "Error: Unexpected token %s. Expected %s\n", m_parser_state.m_current_token.name(), Token::name(type));
     }
     }
     return consume();
     return consume();
 }
 }
 
 
 void Parser::expected(const char* what)
 void Parser::expected(const char* what)
 {
 {
-    m_has_errors = true;
-    fprintf(stderr, "Error: Unexpected token %s. Expected %s\n", m_current_token.name(), what);
+    m_parser_state.m_has_errors = true;
+    fprintf(stderr, "Error: Unexpected token %s. Expected %s\n", m_parser_state.m_current_token.name(), what);
 }
 }
 
 
+void Parser::save_state()
+{
+    m_saved_state = m_parser_state;
+}
+
+void Parser::load_state()
+{
+    ASSERT(m_saved_state.has_value());
+    m_parser_state = m_saved_state.value();
+    m_saved_state.clear();
+}
 }
 }

+ 13 - 4
Libraries/LibJS/Parser.h

@@ -68,7 +68,7 @@ public:
     NonnullRefPtr<CallExpression> parse_call_expression(NonnullRefPtr<Expression>);
     NonnullRefPtr<CallExpression> parse_call_expression(NonnullRefPtr<Expression>);
     NonnullRefPtr<NewExpression> parse_new_expression();
     NonnullRefPtr<NewExpression> parse_new_expression();
 
 
-    bool has_errors() const { return m_has_errors; }
+    bool has_errors() const { return m_parser_state.m_has_errors; }
 
 
 private:
 private:
     int operator_precedence(TokenType) const;
     int operator_precedence(TokenType) const;
@@ -83,9 +83,18 @@ private:
     void expected(const char* what);
     void expected(const char* what);
     Token consume();
     Token consume();
     Token consume(TokenType type);
     Token consume(TokenType type);
+    void save_state();
+    void load_state();
 
 
-    Lexer m_lexer;
-    Token m_current_token;
-    bool m_has_errors = false;
+    struct ParserState {
+        Lexer m_lexer;
+        Token m_current_token;
+        bool m_has_errors = false;
+
+        explicit ParserState(Lexer);
+    };
+
+    ParserState m_parser_state;
+    Optional<ParserState> m_saved_state;
 };
 };
 }
 }