diff options
author | Matthew Olsson <matthewcolsson@gmail.com> | 2020-05-28 11:09:19 -0700 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-05-29 16:20:32 +0200 |
commit | 10bf4ba3dcb7bc79606b29991be497453d0e410b (patch) | |
tree | dc65cce2f0d59211f2d2fca945f8fa931ea13508 | |
parent | 5cd01ed79e816bb0a81c429f7efaa5de24c4b598 (diff) | |
download | serenity-10bf4ba3dcb7bc79606b29991be497453d0e410b.zip |
LibJS: Parse labelled statements
All statements now have an optional label string that can be null.
-rw-r--r-- | Libraries/LibJS/AST.h | 6 | ||||
-rw-r--r-- | Libraries/LibJS/Parser.cpp | 24 | ||||
-rw-r--r-- | Libraries/LibJS/Parser.h | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/labels.js | 13 |
4 files changed, 44 insertions, 0 deletions
diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index be605409c9..9f9b4faf9e 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -70,6 +70,12 @@ private: }; class Statement : public ASTNode { +public: + const FlyString& label() const { return m_label; } + void set_label(FlyString string) { m_label = string; } + +protected: + FlyString m_label; }; class EmptyStatement final : public Statement { diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index c06028f5a9..dbb1db4215 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -269,6 +269,9 @@ NonnullRefPtr<Statement> Parser::parse_statement() consume(); return create_ast_node<EmptyStatement>(); default: + auto result = try_parse_labelled_statement(); + if (!result.is_null()) + return result.release_nonnull(); if (match_expression()) { auto expr = parse_expression(0); consume_or_insert_semicolon(); @@ -383,6 +386,27 @@ RefPtr<FunctionExpression> Parser::try_parse_arrow_function_expression(bool expe return nullptr; } +RefPtr<Statement> Parser::try_parse_labelled_statement() +{ + save_state(); + ArmedScopeGuard state_rollback_guard = [&] { + load_state(); + }; + + auto identifier = consume(TokenType::Identifier).value(); + if (!match(TokenType::Colon)) + return {}; + consume(TokenType::Colon); + + if (!match_statement()) + return {}; + auto statement = parse_statement(); + + statement->set_label(identifier); + state_rollback_guard.disarm(); + return statement; +} + NonnullRefPtr<Expression> Parser::parse_primary_expression() { if (match_unary_prefixed_expression()) diff --git a/Libraries/LibJS/Parser.h b/Libraries/LibJS/Parser.h index 2c861d1969..890fe12195 100644 --- a/Libraries/LibJS/Parser.h +++ b/Libraries/LibJS/Parser.h @@ -78,6 +78,7 @@ public: NonnullRefPtr<CallExpression> parse_call_expression(NonnullRefPtr<Expression>); NonnullRefPtr<NewExpression> parse_new_expression(); RefPtr<FunctionExpression> try_parse_arrow_function_expression(bool expect_parens); + RefPtr<Statement> try_parse_labelled_statement(); struct Error { String message; diff --git a/Libraries/LibJS/Tests/labels.js b/Libraries/LibJS/Tests/labels.js new file mode 100644 index 0000000000..21150b296f --- /dev/null +++ b/Libraries/LibJS/Tests/labels.js @@ -0,0 +1,13 @@ +load("test-common.js"); + +try { + test: + { + let o = 1; + assert(o === 1); + } + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} |