mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 03:27:45 +00:00
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 :^).
This commit is contained in:
parent
73eb29dabe
commit
045a42cf35
4 changed files with 125 additions and 6 deletions
|
@ -2880,17 +2880,39 @@ void MetaProperty::dump(int indent) const
|
||||||
outln("{} {}", class_name(), name);
|
outln("{} {}", class_name(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value MetaProperty::execute(Interpreter& interpreter, GlobalObject&) const
|
Value MetaProperty::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
||||||
{
|
{
|
||||||
InterpreterNodeScope node_scope { interpreter, *this };
|
InterpreterNodeScope node_scope { interpreter, *this };
|
||||||
|
|
||||||
if (m_type == MetaProperty::Type::NewTarget)
|
if (m_type == MetaProperty::Type::NewTarget)
|
||||||
return interpreter.vm().get_new_target().value_or(js_undefined());
|
return interpreter.vm().get_new_target().value_or(js_undefined());
|
||||||
if (m_type == MetaProperty::Type::ImportMeta)
|
if (m_type == MetaProperty::Type::ImportMeta) {
|
||||||
TODO();
|
interpreter.vm().throw_exception<InternalError>(global_object, ErrorType::NotImplemented, "'import.meta' in modules");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImportCall::dump(int indent) const
|
||||||
|
{
|
||||||
|
ASTNode::dump(indent);
|
||||||
|
print_indent(indent);
|
||||||
|
outln("(Specifier)");
|
||||||
|
m_specifier->dump(indent + 1);
|
||||||
|
if (m_options) {
|
||||||
|
outln("(Options)");
|
||||||
|
m_options->dump(indent + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value ImportCall::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
||||||
|
{
|
||||||
|
InterpreterNodeScope node_scope { interpreter, *this };
|
||||||
|
interpreter.vm().throw_exception<InternalError>(global_object, ErrorType::NotImplemented, "'import(...)' in modules");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Value StringLiteral::execute(Interpreter& interpreter, GlobalObject&) const
|
Value StringLiteral::execute(Interpreter& interpreter, GlobalObject&) const
|
||||||
{
|
{
|
||||||
InterpreterNodeScope node_scope { interpreter, *this };
|
InterpreterNodeScope node_scope { interpreter, *this };
|
||||||
|
|
|
@ -1671,6 +1671,23 @@ private:
|
||||||
Type m_type;
|
Type m_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ImportCall final : public Expression {
|
||||||
|
public:
|
||||||
|
ImportCall(SourceRange source_range, NonnullRefPtr<Expression> specifier, RefPtr<Expression> options)
|
||||||
|
: Expression(source_range)
|
||||||
|
, m_specifier(move(specifier))
|
||||||
|
, m_options(move(options))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void dump(int indent) const override;
|
||||||
|
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
NonnullRefPtr<Expression> m_specifier;
|
||||||
|
RefPtr<Expression> m_options;
|
||||||
|
};
|
||||||
|
|
||||||
class ConditionalExpression final : public Expression {
|
class ConditionalExpression final : public Expression {
|
||||||
public:
|
public:
|
||||||
ConditionalExpression(SourceRange source_range, NonnullRefPtr<Expression> test, NonnullRefPtr<Expression> consequent, NonnullRefPtr<Expression> alternate)
|
ConditionalExpression(SourceRange source_range, NonnullRefPtr<Expression> test, NonnullRefPtr<Expression> consequent, NonnullRefPtr<Expression> alternate)
|
||||||
|
|
|
@ -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);
|
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()
|
NonnullRefPtr<ClassDeclaration> Parser::parse_class_declaration()
|
||||||
{
|
{
|
||||||
auto rule_start = push_start();
|
auto rule_start = push_start();
|
||||||
|
@ -1305,6 +1362,19 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression()
|
||||||
}
|
}
|
||||||
return { parse_new_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:
|
case TokenType::Yield:
|
||||||
if (!m_state.in_generator_function_context)
|
if (!m_state.in_generator_function_context)
|
||||||
goto read_as_identifier;
|
goto read_as_identifier;
|
||||||
|
@ -1321,10 +1391,11 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression()
|
||||||
default:
|
default:
|
||||||
if (match_identifier_name())
|
if (match_identifier_name())
|
||||||
goto read_as_identifier;
|
goto read_as_identifier;
|
||||||
expected("primary expression");
|
break;
|
||||||
consume();
|
|
||||||
return { create_ast_node<ErrorExpression>({ m_state.current_token.filename(), rule_start.position(), position() }) };
|
|
||||||
}
|
}
|
||||||
|
expected("primary expression");
|
||||||
|
consume();
|
||||||
|
return { create_ast_node<ErrorExpression>({ m_state.current_token.filename(), rule_start.position(), position() }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullRefPtr<RegExpLiteral> Parser::parse_regexp_literal()
|
NonnullRefPtr<RegExpLiteral> Parser::parse_regexp_literal()
|
||||||
|
@ -2115,6 +2186,8 @@ NonnullRefPtr<NewExpression> Parser::parse_new_expression()
|
||||||
consume(TokenType::New);
|
consume(TokenType::New);
|
||||||
|
|
||||||
auto callee = parse_expression(g_operator_precedence.get(TokenType::New), Associativity::Right, { TokenType::ParenOpen, TokenType::QuestionMarkPeriod });
|
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;
|
Vector<CallExpression::Argument> arguments;
|
||||||
|
|
||||||
|
@ -3343,6 +3416,11 @@ bool Parser::match(TokenType type) const
|
||||||
bool Parser::match_expression() const
|
bool Parser::match_expression() const
|
||||||
{
|
{
|
||||||
auto type = m_state.current_token.type();
|
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
|
return type == TokenType::BoolLiteral
|
||||||
|| type == TokenType::NumericLiteral
|
|| type == TokenType::NumericLiteral
|
||||||
|| type == TokenType::BigIntLiteral
|
|| type == TokenType::BigIntLiteral
|
||||||
|
|
|
@ -122,6 +122,8 @@ public:
|
||||||
RefPtr<FunctionExpression> try_parse_arrow_function_expression(bool expect_parens, bool is_async = false);
|
RefPtr<FunctionExpression> try_parse_arrow_function_expression(bool expect_parens, bool is_async = false);
|
||||||
RefPtr<Statement> try_parse_labelled_statement(AllowLabelledFunction allow_function);
|
RefPtr<Statement> try_parse_labelled_statement(AllowLabelledFunction allow_function);
|
||||||
RefPtr<MetaProperty> try_parse_new_target_expression();
|
RefPtr<MetaProperty> try_parse_new_target_expression();
|
||||||
|
RefPtr<MetaProperty> try_parse_import_meta_expression();
|
||||||
|
NonnullRefPtr<ImportCall> parse_import_call();
|
||||||
|
|
||||||
Vector<CallExpression::Argument> parse_arguments();
|
Vector<CallExpression::Argument> parse_arguments();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue