summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Parser.cpp
diff options
context:
space:
mode:
authordavidot <davidot@serenityos.org>2021-11-26 23:45:10 +0100
committerLinus Groh <mail@linusgroh.de>2021-11-30 17:05:32 +0000
commit045a42cf35ae9f58d0a4bcfb9af94118d580d83f (patch)
tree392e74c525e13e64e3c489696eb442c26596f219 /Userland/Libraries/LibJS/Parser.cpp
parent73eb29dabe855488e9c436323f6959ac423bebe6 (diff)
downloadserenity-045a42cf35ae9f58d0a4bcfb9af94118d580d83f.zip
LibJS: Parse dynamic import calls 'import()' and 'import.meta'
For now both just throw when executing but this can be implemented when modules are implemented :^).
Diffstat (limited to 'Userland/Libraries/LibJS/Parser.cpp')
-rw-r--r--Userland/Libraries/LibJS/Parser.cpp84
1 files changed, 81 insertions, 3 deletions
diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp
index 0f1127d6c3..2fd41c36fd 100644
--- a/Userland/Libraries/LibJS/Parser.cpp
+++ b/Userland/Libraries/LibJS/Parser.cpp
@@ -874,6 +874,63 @@ RefPtr<MetaProperty> Parser::try_parse_new_target_expression()
return create_ast_node<MetaProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, MetaProperty::Type::NewTarget);
}
+RefPtr<MetaProperty> Parser::try_parse_import_meta_expression()
+{
+ // Optimization which skips the save/load state.
+ if (next_token().type() != TokenType::Period)
+ return {};
+
+ save_state();
+ auto rule_start = push_start();
+ ArmedScopeGuard state_rollback_guard = [&] {
+ load_state();
+ };
+
+ consume(TokenType::Import);
+ consume(TokenType::Period);
+ if (!match(TokenType::Identifier))
+ return {};
+ // The string 'meta' cannot have escapes so we check original value.
+ if (consume().original_value() != "meta"sv)
+ return {};
+
+ state_rollback_guard.disarm();
+ discard_saved_state();
+ return create_ast_node<MetaProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, MetaProperty::Type::ImportMeta);
+}
+
+NonnullRefPtr<ImportCall> Parser::parse_import_call()
+{
+ auto rule_start = push_start();
+
+ // We use the extended definition:
+ // ImportCall[Yield, Await]:
+ // import(AssignmentExpression[+In, ?Yield, ?Await] ,opt)
+ // import(AssignmentExpression[+In, ?Yield, ?Await] ,AssignmentExpression[+In, ?Yield, ?Await] ,opt)
+ // From https://tc39.es/proposal-import-assertions/#sec-evaluate-import-call
+
+ consume(TokenType::Import);
+ consume(TokenType::ParenOpen);
+ auto argument = parse_expression(2);
+
+ RefPtr<Expression> options;
+ if (match(TokenType::Comma)) {
+ consume(TokenType::Comma);
+
+ if (!match(TokenType::ParenClose)) {
+ options = parse_expression(2);
+
+ // Second optional comma
+ if (match(TokenType::Comma))
+ consume(TokenType::Comma);
+ }
+ }
+
+ consume(TokenType::ParenClose);
+
+ return create_ast_node<ImportCall>({ m_state.current_token.filename(), rule_start.position(), position() }, move(argument), move(options));
+}
+
NonnullRefPtr<ClassDeclaration> Parser::parse_class_declaration()
{
auto rule_start = push_start();
@@ -1305,6 +1362,19 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression()
}
return { parse_new_expression() };
}
+ case TokenType::Import: {
+ auto lookahead_token = next_token();
+ VERIFY(lookahead_token.type() == TokenType::Period || lookahead_token.type() == TokenType::ParenOpen);
+ if (lookahead_token.type() == TokenType::ParenOpen)
+ return { parse_import_call() };
+
+ if (auto import_meta = try_parse_import_meta_expression()) {
+ if (m_program_type != Program::Type::Module)
+ syntax_error("import.meta is only allowed in modules");
+ return { import_meta.release_nonnull() };
+ }
+ break;
+ }
case TokenType::Yield:
if (!m_state.in_generator_function_context)
goto read_as_identifier;
@@ -1321,10 +1391,11 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression()
default:
if (match_identifier_name())
goto read_as_identifier;
- expected("primary expression");
- consume();
- return { create_ast_node<ErrorExpression>({ m_state.current_token.filename(), rule_start.position(), position() }) };
+ break;
}
+ expected("primary expression");
+ consume();
+ return { create_ast_node<ErrorExpression>({ m_state.current_token.filename(), rule_start.position(), position() }) };
}
NonnullRefPtr<RegExpLiteral> Parser::parse_regexp_literal()
@@ -2115,6 +2186,8 @@ NonnullRefPtr<NewExpression> Parser::parse_new_expression()
consume(TokenType::New);
auto callee = parse_expression(g_operator_precedence.get(TokenType::New), Associativity::Right, { TokenType::ParenOpen, TokenType::QuestionMarkPeriod });
+ if (is<ImportCall>(*callee))
+ syntax_error("Cannot call new on dynamic import", callee->source_range().start);
Vector<CallExpression::Argument> arguments;
@@ -3343,6 +3416,11 @@ bool Parser::match(TokenType type) const
bool Parser::match_expression() const
{
auto type = m_state.current_token.type();
+ if (type == TokenType::Import) {
+ auto lookahead_token = next_token();
+ return lookahead_token.type() == TokenType::Period || lookahead_token.type() == TokenType::ParenOpen;
+ }
+
return type == TokenType::BoolLiteral
|| type == TokenType::NumericLiteral
|| type == TokenType::BigIntLiteral