浏览代码

LibJS: Parse "try", "catch" and "finally"

This is the first step towards support exceptions. :^)
Andreas Kling 5 年之前
父节点
当前提交
c33d4aefc3
共有 5 个文件被更改,包括 132 次插入1 次删除
  1. 9 0
      Base/home/anon/js/try.js
  2. 40 0
      Libraries/LibJS/AST.cpp
  3. 45 0
      Libraries/LibJS/AST.h
  4. 36 1
      Libraries/LibJS/Parser.cpp
  5. 2 0
      Libraries/LibJS/Parser.h

+ 9 - 0
Base/home/anon/js/try.js

@@ -0,0 +1,9 @@
+try {
+    console.log("you should see me");
+    foo();
+    console.log("not me");
+} catch (e) {
+    console.log("catch");
+} finally {
+    console.log("finally");
+}

+ 40 - 0
Libraries/LibJS/AST.cpp

@@ -715,4 +715,44 @@ Value ArrayExpression::execute(Interpreter& interpreter) const
     return array;
 }
 
+void TryStatement::dump(int indent) const
+{
+    ASTNode::dump(indent);
+    print_indent(indent);
+    printf("(Block)\n");
+    block().dump(indent + 1);
+
+    if (handler()) {
+        print_indent(indent);
+        printf("(Handler)\n");
+        handler()->dump(indent + 1);
+    }
+
+    if (finalizer()) {
+        print_indent(indent);
+        printf("(Finalizer)\n");
+        finalizer()->dump(indent + 1);
+    }
+}
+
+void CatchClause::dump(int indent) const
+{
+    print_indent(indent);
+    printf("CatchClause");
+    if (!m_parameter.is_null())
+        printf(" (%s)", m_parameter.characters());
+    printf("\n");
+    body().dump(indent + 1);
+}
+
+Value TryStatement::execute(Interpreter&) const
+{
+    return {};
+}
+
+Value CatchClause::execute(Interpreter&) const
+{
+    return {};
+}
+
 }

+ 45 - 0
Libraries/LibJS/AST.h

@@ -630,4 +630,49 @@ private:
     bool m_computed { false };
 };
 
+class CatchClause final : public ASTNode {
+public:
+    CatchClause(const FlyString& parameter, NonnullRefPtr<BlockStatement> body)
+        : m_parameter(parameter)
+        , m_body(move(body))
+    {
+    }
+
+    const FlyString& parameter() const { return m_parameter; }
+    const BlockStatement& body() const { return m_body; }
+
+    virtual void dump(int indent) const override;
+    virtual Value execute(Interpreter&) const override;
+
+private:
+    virtual const char* class_name() const override { return "CatchClause"; }
+
+    FlyString m_parameter;
+    NonnullRefPtr<BlockStatement> m_body;
+};
+
+class TryStatement final : public Statement {
+public:
+    TryStatement(NonnullRefPtr<BlockStatement> block, RefPtr<CatchClause> handler, RefPtr<BlockStatement> finalizer)
+        : m_block(move(block))
+        , m_handler(move(handler))
+        , m_finalizer(move(finalizer))
+    {
+    }
+
+    const BlockStatement& block() const { return m_block; }
+    const CatchClause* handler() const { return m_handler; }
+    const BlockStatement* finalizer() const { return m_finalizer; }
+
+    virtual void dump(int indent) const override;
+    virtual Value execute(Interpreter&) const override;
+
+private:
+    virtual const char* class_name() const override { return "TryStatement"; }
+
+    NonnullRefPtr<BlockStatement> m_block;
+    RefPtr<CatchClause> m_handler;
+    RefPtr<BlockStatement> m_finalizer;
+};
+
 }

+ 36 - 1
Libraries/LibJS/Parser.cpp

@@ -197,6 +197,8 @@ NonnullRefPtr<Statement> Parser::parse_statement()
         return parse_for_statement();
     case TokenType::If:
         return parse_if_statement();
+    case TokenType::Try:
+        return parse_try_statement();
     default:
         if (match_expression())
             return adopt(*new ExpressionStatement(parse_expression(0)));
@@ -518,6 +520,40 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration()
     return create_ast_node<VariableDeclaration>(create_ast_node<Identifier>(name), move(initializer), declaration_type);
 }
 
+NonnullRefPtr<TryStatement> Parser::parse_try_statement()
+{
+    consume(TokenType::Try);
+
+    auto block = parse_block_statement();
+
+    RefPtr<CatchClause> handler;
+    if (match(TokenType::Catch))
+        handler = parse_catch_clause();
+
+    RefPtr<BlockStatement> finalizer;
+    if (match(TokenType::Finally)) {
+        consume();
+        finalizer = parse_block_statement();
+    }
+
+    return create_ast_node<TryStatement>(move(block), move(handler), move(finalizer));
+}
+
+NonnullRefPtr<CatchClause> Parser::parse_catch_clause()
+{
+    consume(TokenType::Catch);
+
+    String parameter;
+    if (match(TokenType::ParenOpen)) {
+        consume();
+        parameter = consume(TokenType::Identifier).value();
+        consume(TokenType::ParenClose);
+    }
+
+    auto body = parse_block_statement();
+    return create_ast_node<CatchClause>(parameter, move(body));
+}
+
 NonnullRefPtr<IfStatement> Parser::parse_if_statement()
 {
     consume(TokenType::If);
@@ -660,7 +696,6 @@ bool Parser::match_statement() const
         || type == TokenType::Function
         || type == TokenType::Return
         || type == TokenType::Let
-        || type == TokenType::Catch
         || type == TokenType::Class
         || type == TokenType::Delete
         || type == TokenType::Do

+ 2 - 0
Libraries/LibJS/Parser.h

@@ -52,6 +52,8 @@ public:
     NonnullRefPtr<VariableDeclaration> parse_variable_declaration();
     NonnullRefPtr<ForStatement> parse_for_statement();
     NonnullRefPtr<IfStatement> parse_if_statement();
+    NonnullRefPtr<TryStatement> parse_try_statement();
+    NonnullRefPtr<CatchClause> parse_catch_clause();
 
     NonnullRefPtr<Expression> parse_expression(int min_precedence, Associativity associate = Associativity::Right);
     NonnullRefPtr<Expression> parse_primary_expression();