summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2020-05-28 11:09:19 -0700
committerAndreas Kling <kling@serenityos.org>2020-05-29 16:20:32 +0200
commit10bf4ba3dcb7bc79606b29991be497453d0e410b (patch)
treedc65cce2f0d59211f2d2fca945f8fa931ea13508
parent5cd01ed79e816bb0a81c429f7efaa5de24c4b598 (diff)
downloadserenity-10bf4ba3dcb7bc79606b29991be497453d0e410b.zip
LibJS: Parse labelled statements
All statements now have an optional label string that can be null.
-rw-r--r--Libraries/LibJS/AST.h6
-rw-r--r--Libraries/LibJS/Parser.cpp24
-rw-r--r--Libraries/LibJS/Parser.h1
-rw-r--r--Libraries/LibJS/Tests/labels.js13
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);
+}