mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00:00
LibJS: Don't store current token in both Lexer and Parser
Just give Parser a way to access the one stored in Lexer.
This commit is contained in:
parent
d3e8fbd9cd
commit
841fe0b51c
Notes:
github-actions[bot]
2025-11-09 11:15:45 +00:00
Author: https://github.com/awesomekling
Commit: 841fe0b51c
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6764
4 changed files with 100 additions and 98 deletions
|
|
@ -636,7 +636,7 @@ bool Lexer::slash_means_division() const
|
|||
|| type == TokenType::TemplateLiteralEnd;
|
||||
}
|
||||
|
||||
Token Lexer::next()
|
||||
Token const& Lexer::next()
|
||||
{
|
||||
auto trivia_start = m_position;
|
||||
auto in_template = !m_template_states.is_empty();
|
||||
|
|
@ -970,7 +970,7 @@ Token Lexer::next()
|
|||
return m_current_token;
|
||||
}
|
||||
|
||||
Token Lexer::force_slash_as_regex()
|
||||
Token const& Lexer::force_slash_as_regex()
|
||||
{
|
||||
VERIFY(m_current_token.type() == TokenType::Slash || m_current_token.type() == TokenType::SlashEquals);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,15 +19,17 @@ public:
|
|||
explicit Lexer(StringView source, StringView filename = "(unknown)"sv, size_t line_number = 1, size_t line_column = 0);
|
||||
explicit Lexer(Utf16String source, StringView filename = "(unknown)"sv, size_t line_number = 1, size_t line_column = 0);
|
||||
|
||||
Token next();
|
||||
// These both advance the lexer and return a reference to the current token.
|
||||
Token const& next();
|
||||
Token const& force_slash_as_regex();
|
||||
|
||||
[[nodiscard]] Token const& current_token() const { return m_current_token; }
|
||||
|
||||
Utf16String const& source() const { return m_source; }
|
||||
String const& filename() const { return m_filename; }
|
||||
|
||||
void disallow_html_comments() { m_allow_html_comments = false; }
|
||||
|
||||
Token force_slash_as_regex();
|
||||
|
||||
private:
|
||||
void consume();
|
||||
bool consume_exponent();
|
||||
|
|
|
|||
|
|
@ -684,7 +684,7 @@ Parser::ParserState::ParserState(Lexer l, Program::Type program_type)
|
|||
{
|
||||
if (program_type == Program::Type::Module)
|
||||
lexer.disallow_html_comments();
|
||||
current_token = lexer.next();
|
||||
lexer.next();
|
||||
}
|
||||
|
||||
Parser::Parser(Lexer lexer, Program::Type program_type, Optional<EvalInitialState> initial_state_for_eval)
|
||||
|
|
@ -747,7 +747,7 @@ bool Parser::parse_directive(ScopeNode& body)
|
|||
{
|
||||
bool found_use_strict = false;
|
||||
while (!done() && match(TokenType::StringLiteral)) {
|
||||
auto raw_value = m_state.current_token.original_value();
|
||||
auto raw_value = m_state.current_token().original_value();
|
||||
// It cannot be a labelled function since we hit a string literal.
|
||||
auto statement = parse_statement(AllowLabelledFunction::No);
|
||||
body.append(statement);
|
||||
|
|
@ -823,8 +823,8 @@ void Parser::parse_module(Program& program)
|
|||
break;
|
||||
|
||||
if (match_export_or_import()) {
|
||||
VERIFY(m_state.current_token.type() == TokenType::Export || m_state.current_token.type() == TokenType::Import);
|
||||
if (m_state.current_token.type() == TokenType::Export)
|
||||
VERIFY(m_state.current_token().type() == TokenType::Export || m_state.current_token().type() == TokenType::Import);
|
||||
if (m_state.current_token().type() == TokenType::Export)
|
||||
program.append_export(parse_export_statement(program));
|
||||
else
|
||||
program.append_import(parse_import_statement(program));
|
||||
|
|
@ -876,9 +876,9 @@ void Parser::parse_module(Program& program)
|
|||
NonnullRefPtr<Declaration const> Parser::parse_declaration()
|
||||
{
|
||||
auto rule_start = push_start();
|
||||
if (m_state.current_token.type() == TokenType::Async && next_token().type() == TokenType::Function)
|
||||
if (m_state.current_token().type() == TokenType::Async && next_token().type() == TokenType::Function)
|
||||
return parse_function_node<FunctionDeclaration>();
|
||||
switch (m_state.current_token.type()) {
|
||||
switch (m_state.current_token().type()) {
|
||||
case TokenType::Class:
|
||||
return parse_class_declaration();
|
||||
case TokenType::Function:
|
||||
|
|
@ -887,7 +887,7 @@ NonnullRefPtr<Declaration const> Parser::parse_declaration()
|
|||
case TokenType::Const:
|
||||
return parse_variable_declaration();
|
||||
case TokenType::Identifier:
|
||||
if (m_state.current_token.original_value() == "using"sv) {
|
||||
if (m_state.current_token().original_value() == "using"sv) {
|
||||
if (!m_state.current_scope_pusher->can_have_using_declaration())
|
||||
syntax_error("'using' not allowed outside of block, for loop or function"_string);
|
||||
|
||||
|
|
@ -904,7 +904,7 @@ NonnullRefPtr<Declaration const> Parser::parse_declaration()
|
|||
NonnullRefPtr<Statement const> Parser::parse_statement(AllowLabelledFunction allow_labelled_function)
|
||||
{
|
||||
auto rule_start = push_start();
|
||||
auto type = m_state.current_token.type();
|
||||
auto type = m_state.current_token().type();
|
||||
switch (type) {
|
||||
case TokenType::CurlyOpen:
|
||||
return parse_block_statement();
|
||||
|
|
@ -944,7 +944,7 @@ NonnullRefPtr<Statement const> Parser::parse_statement(AllowLabelledFunction all
|
|||
return create_ast_node<EmptyStatement>({ m_source_code, rule_start.position(), position() });
|
||||
case TokenType::Slash:
|
||||
case TokenType::SlashEquals:
|
||||
m_state.current_token = m_state.lexer.force_slash_as_regex();
|
||||
m_state.lexer.force_slash_as_regex();
|
||||
[[fallthrough]];
|
||||
default:
|
||||
if (match_invalid_escaped_keyword())
|
||||
|
|
@ -961,7 +961,7 @@ NonnullRefPtr<Statement const> Parser::parse_statement(AllowLabelledFunction all
|
|||
if (lookahead_token.type() == TokenType::Function && !lookahead_token.trivia_contains_line_terminator())
|
||||
syntax_error("Async function declaration not allowed in single-statement context"_string);
|
||||
} else if (match(TokenType::Function) || match(TokenType::Class)) {
|
||||
syntax_error(MUST(String::formatted("{} declaration not allowed in single-statement context", m_state.current_token.name())));
|
||||
syntax_error(MUST(String::formatted("{} declaration not allowed in single-statement context", m_state.current_token().name())));
|
||||
} else if (match(TokenType::Let) && next_token().type() == TokenType::BracketOpen) {
|
||||
syntax_error(MUST(String::formatted("let followed by [ is not allowed in single-statement context")));
|
||||
}
|
||||
|
|
@ -978,9 +978,9 @@ NonnullRefPtr<Statement const> Parser::parse_statement(AllowLabelledFunction all
|
|||
|
||||
bool Parser::match_invalid_escaped_keyword() const
|
||||
{
|
||||
if (m_state.current_token.type() != TokenType::EscapedKeyword)
|
||||
if (m_state.current_token().type() != TokenType::EscapedKeyword)
|
||||
return false;
|
||||
auto token_value = m_state.current_token.value();
|
||||
auto token_value = m_state.current_token().value();
|
||||
if (token_value == "await"sv)
|
||||
return m_program_type == Program::Type::Module || m_state.await_expression_is_valid;
|
||||
if (token_value == "async"sv)
|
||||
|
|
@ -1042,7 +1042,7 @@ RefPtr<FunctionExpression const> Parser::try_parse_arrow_function_expression(boo
|
|||
if (is_async) {
|
||||
consume(TokenType::Async);
|
||||
function_kind = FunctionKind::Async;
|
||||
if (m_state.current_token.trivia_contains_line_terminator())
|
||||
if (m_state.current_token().trivia_contains_line_terminator())
|
||||
return nullptr;
|
||||
|
||||
// Since we have async it can be followed by paren open in the expect_parens case
|
||||
|
|
@ -1097,7 +1097,7 @@ RefPtr<FunctionExpression const> Parser::try_parse_arrow_function_expression(boo
|
|||
|
||||
// If there's a newline between the closing paren and arrow it's not a valid arrow function,
|
||||
// ASI should kick in instead (it'll then fail with "Unexpected token Arrow")
|
||||
if (m_state.current_token.trivia_contains_line_terminator())
|
||||
if (m_state.current_token().trivia_contains_line_terminator())
|
||||
return nullptr;
|
||||
if (!match(TokenType::Arrow))
|
||||
return nullptr;
|
||||
|
|
@ -1166,7 +1166,7 @@ RefPtr<FunctionExpression const> Parser::try_parse_arrow_function_expression(boo
|
|||
}
|
||||
|
||||
auto function_start_offset = rule_start.position().offset;
|
||||
auto function_end_offset = position().offset - m_state.current_token.trivia().length_in_code_units();
|
||||
auto function_end_offset = position().offset - m_state.current_token().trivia().length_in_code_units();
|
||||
|
||||
auto source_text = m_state.lexer.source().substring_view(function_start_offset, function_end_offset - function_start_offset);
|
||||
|
||||
|
|
@ -1190,16 +1190,16 @@ RefPtr<LabelledStatement const> Parser::try_parse_labelled_statement(AllowLabell
|
|||
load_state();
|
||||
};
|
||||
|
||||
if (m_state.current_token.value() == "yield"sv && (m_state.strict_mode || m_state.in_generator_function_context)) {
|
||||
if (m_state.current_token().value() == "yield"sv && (m_state.strict_mode || m_state.in_generator_function_context)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (m_state.current_token.value() == "await"sv && (m_program_type == Program::Type::Module || m_state.await_expression_is_valid || m_state.in_class_static_init_block)) {
|
||||
if (m_state.current_token().value() == "await"sv && (m_program_type == Program::Type::Module || m_state.await_expression_is_valid || m_state.in_class_static_init_block)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto identifier = [&] {
|
||||
if (m_state.current_token.value() == "await"sv) {
|
||||
if (m_state.current_token().value() == "await"sv) {
|
||||
return consume().fly_string_value();
|
||||
}
|
||||
return consume_identifier_reference().fly_string_value();
|
||||
|
|
@ -1391,7 +1391,7 @@ NonnullRefPtr<ClassExpression const> Parser::parse_class_expression(bool expect_
|
|||
continue;
|
||||
}
|
||||
if (match(TokenType::BracketOpen) || match(TokenType::Period) || match(TokenType::ParenOpen)) {
|
||||
auto precedence = g_operator_precedence.get(m_state.current_token.type());
|
||||
auto precedence = g_operator_precedence.get(m_state.current_token().type());
|
||||
expression = parse_secondary_expression(move(expression), precedence).expression;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1444,7 +1444,7 @@ NonnullRefPtr<ClassExpression const> Parser::parse_class_expression(bool expect_
|
|||
|
||||
Utf16FlyString name;
|
||||
if (match_property_key() || match(TokenType::PrivateIdentifier)) {
|
||||
if (!is_generator && !is_async && m_state.current_token.original_value() == "static"sv) {
|
||||
if (!is_generator && !is_async && m_state.current_token().original_value() == "static"sv) {
|
||||
if (match(TokenType::Identifier)) {
|
||||
consume();
|
||||
is_static = true;
|
||||
|
|
@ -1461,7 +1461,7 @@ NonnullRefPtr<ClassExpression const> Parser::parse_class_expression(bool expect_
|
|||
}
|
||||
|
||||
if (match(TokenType::Identifier)) {
|
||||
auto identifier_name = m_state.current_token.original_value();
|
||||
auto identifier_name = m_state.current_token().original_value();
|
||||
|
||||
if (identifier_name == "get"sv) {
|
||||
method_kind = ClassMethod::Kind::Getter;
|
||||
|
|
@ -1473,7 +1473,7 @@ NonnullRefPtr<ClassExpression const> Parser::parse_class_expression(bool expect_
|
|||
}
|
||||
|
||||
if (match_property_key() || match(TokenType::PrivateIdentifier)) {
|
||||
switch (m_state.current_token.type()) {
|
||||
switch (m_state.current_token().type()) {
|
||||
case TokenType::Identifier:
|
||||
name = consume().fly_string_value();
|
||||
property_key = create_ast_node<StringLiteral>({ m_source_code, rule_start.position(), position() }, name.to_utf16_string());
|
||||
|
|
@ -1698,7 +1698,7 @@ NonnullRefPtr<ClassExpression const> Parser::parse_class_expression(bool expect_
|
|||
}
|
||||
|
||||
auto function_start_offset = rule_start.position().offset;
|
||||
auto function_end_offset = position().offset - m_state.current_token.trivia().length_in_code_units();
|
||||
auto function_end_offset = position().offset - m_state.current_token().trivia().length_in_code_units();
|
||||
|
||||
auto source_text = m_state.lexer.source().substring_view(function_start_offset, function_end_offset - function_start_offset);
|
||||
|
||||
|
|
@ -1722,7 +1722,7 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression()
|
|||
return nullptr;
|
||||
};
|
||||
|
||||
switch (m_state.current_token.type()) {
|
||||
switch (m_state.current_token().type()) {
|
||||
case TokenType::ParenOpen: {
|
||||
auto paren_position = position();
|
||||
consume(TokenType::ParenOpen);
|
||||
|
|
@ -1768,7 +1768,7 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression()
|
|||
if (auto arrow_function_result = try_arrow_function_parse_or_fail(position(), false))
|
||||
return { arrow_function_result.release_nonnull(), false };
|
||||
|
||||
auto string = m_state.current_token.fly_string_value();
|
||||
auto string = m_state.current_token().fly_string_value();
|
||||
// This could be 'eval' or 'arguments' and thus needs a custom check (`eval[1] = true`)
|
||||
if (m_state.strict_mode && (string == "let"sv || is_strict_reserved_word(string)))
|
||||
syntax_error(MUST(String::formatted("Identifier must not be a reserved word in strict mode ('{}')", string)));
|
||||
|
|
@ -1850,7 +1850,7 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression()
|
|||
return { parse_await_expression() };
|
||||
case TokenType::PrivateIdentifier:
|
||||
if (!is_private_identifier_valid())
|
||||
syntax_error(MUST(String::formatted("Reference to undeclared private field or method '{}'", m_state.current_token.value())));
|
||||
syntax_error(MUST(String::formatted("Reference to undeclared private field or method '{}'", m_state.current_token().value())));
|
||||
if (next_token().type() != TokenType::In)
|
||||
syntax_error("Cannot have a private identifier in expression if not followed by 'in'"_string);
|
||||
return { create_ast_node<PrivateIdentifier>({ m_source_code, rule_start.position(), position() }, consume().fly_string_value()) };
|
||||
|
|
@ -1911,8 +1911,8 @@ static bool is_simple_assignment_target(Expression const& expression, bool allow
|
|||
NonnullRefPtr<Expression const> Parser::parse_unary_prefixed_expression()
|
||||
{
|
||||
auto rule_start = push_start();
|
||||
auto precedence = g_operator_precedence.get_unary(m_state.current_token.type());
|
||||
auto associativity = operator_associativity(m_state.current_token.type());
|
||||
auto precedence = g_operator_precedence.get_unary(m_state.current_token().type());
|
||||
auto associativity = operator_associativity(m_state.current_token().type());
|
||||
|
||||
auto verify_next_token_is_not_exponentiation = [this]() {
|
||||
auto lookahead_token = next_token();
|
||||
|
|
@ -1920,7 +1920,7 @@ NonnullRefPtr<Expression const> Parser::parse_unary_prefixed_expression()
|
|||
syntax_error("Unary operator must not be used before exponentiation expression without brackets"_string);
|
||||
};
|
||||
|
||||
switch (m_state.current_token.type()) {
|
||||
switch (m_state.current_token().type()) {
|
||||
case TokenType::PlusPlus: {
|
||||
consume();
|
||||
auto rhs_start = position();
|
||||
|
|
@ -2056,7 +2056,7 @@ NonnullRefPtr<ObjectExpression const> Parser::parse_object_expression()
|
|||
continue;
|
||||
}
|
||||
|
||||
auto type = m_state.current_token.type();
|
||||
auto type = m_state.current_token().type();
|
||||
auto function_start = position();
|
||||
|
||||
if (match(TokenType::Async)) {
|
||||
|
|
@ -2344,14 +2344,14 @@ NonnullRefPtr<Expression const> Parser::parse_expression(int min_precedence, Ass
|
|||
if (should_continue_parsing) {
|
||||
auto original_forbidden = forbidden;
|
||||
while (match_secondary_expression(forbidden)) {
|
||||
int new_precedence = g_operator_precedence.get(m_state.current_token.type());
|
||||
int new_precedence = g_operator_precedence.get(m_state.current_token().type());
|
||||
if (new_precedence < min_precedence)
|
||||
break;
|
||||
if (new_precedence == min_precedence && associativity == Associativity::Left)
|
||||
break;
|
||||
check_for_invalid_object_property(expression);
|
||||
|
||||
Associativity new_associativity = operator_associativity(m_state.current_token.type());
|
||||
Associativity new_associativity = operator_associativity(m_state.current_token().type());
|
||||
auto result = parse_secondary_expression(move(expression), new_precedence, new_associativity, original_forbidden);
|
||||
expression = result.expression;
|
||||
forbidden = forbidden.merge(result.forbidden);
|
||||
|
|
@ -2391,7 +2391,7 @@ NonnullRefPtr<Expression const> Parser::parse_expression(int min_precedence, Ass
|
|||
Parser::ExpressionResult Parser::parse_secondary_expression(NonnullRefPtr<Expression const> lhs, int min_precedence, Associativity associativity, ForbiddenTokens forbidden)
|
||||
{
|
||||
auto rule_start = push_start();
|
||||
switch (m_state.current_token.type()) {
|
||||
switch (m_state.current_token().type()) {
|
||||
case TokenType::Plus:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::Addition, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
|
|
@ -2490,9 +2490,9 @@ Parser::ExpressionResult Parser::parse_secondary_expression(NonnullRefPtr<Expres
|
|||
consume();
|
||||
if (match(TokenType::PrivateIdentifier)) {
|
||||
if (!is_private_identifier_valid())
|
||||
syntax_error(MUST(String::formatted("Reference to undeclared private field or method '{}'", m_state.current_token.value())));
|
||||
syntax_error(MUST(String::formatted("Reference to undeclared private field or method '{}'", m_state.current_token().value())));
|
||||
else if (is<SuperExpression>(*lhs))
|
||||
syntax_error(MUST(String::formatted("Cannot access private field or method '{}' on super", m_state.current_token.value())));
|
||||
syntax_error(MUST(String::formatted("Cannot access private field or method '{}' on super", m_state.current_token().value())));
|
||||
|
||||
return create_ast_node<MemberExpression>({ m_source_code, rule_start.position(), position() }, move(lhs), create_ast_node<PrivateIdentifier>({ m_source_code, rule_start.position(), position() }, consume().fly_string_value()));
|
||||
} else if (!match_identifier_name()) {
|
||||
|
|
@ -2578,7 +2578,7 @@ bool Parser::is_private_identifier_valid() const
|
|||
return false;
|
||||
|
||||
// We might not have hit the declaration yet so class will check this in the end
|
||||
m_state.referenced_private_names->set(m_state.current_token.fly_string_value());
|
||||
m_state.referenced_private_names->set(m_state.current_token().fly_string_value());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2762,7 +2762,7 @@ NonnullRefPtr<YieldExpression const> Parser::parse_yield_expression()
|
|||
RefPtr<Expression const> argument;
|
||||
bool yield_from = false;
|
||||
|
||||
if (!m_state.current_token.trivia_contains_line_terminator()) {
|
||||
if (!m_state.current_token().trivia_contains_line_terminator()) {
|
||||
if (match(TokenType::Asterisk)) {
|
||||
consume();
|
||||
yield_from = true;
|
||||
|
|
@ -2802,7 +2802,7 @@ NonnullRefPtr<ReturnStatement const> Parser::parse_return_statement()
|
|||
consume(TokenType::Return);
|
||||
|
||||
// Automatic semicolon insertion: terminate statement when return is followed by newline
|
||||
if (m_state.current_token.trivia_contains_line_terminator())
|
||||
if (m_state.current_token().trivia_contains_line_terminator())
|
||||
return create_ast_node<ReturnStatement>({ m_source_code, rule_start.position(), position() }, nullptr);
|
||||
|
||||
if (match_expression()) {
|
||||
|
|
@ -3031,7 +3031,7 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u16 parse_options, O
|
|||
check_identifier_name_for_assignment_validity(name->string(), true);
|
||||
|
||||
auto function_start_offset = rule_start.position().offset;
|
||||
auto function_end_offset = position().offset - m_state.current_token.trivia().length_in_code_units();
|
||||
auto function_end_offset = position().offset - m_state.current_token().trivia().length_in_code_units();
|
||||
auto source_text = m_state.lexer.source().substring_view(function_start_offset, function_end_offset - function_start_offset);
|
||||
|
||||
parsing_insights.might_need_arguments_object = m_state.function_might_need_arguments_object;
|
||||
|
|
@ -3379,7 +3379,7 @@ NonnullRefPtr<VariableDeclaration const> Parser::parse_variable_declaration(IsFo
|
|||
auto rule_start = push_start();
|
||||
DeclarationKind declaration_kind;
|
||||
|
||||
switch (m_state.current_token.type()) {
|
||||
switch (m_state.current_token().type()) {
|
||||
case TokenType::Var:
|
||||
declaration_kind = DeclarationKind::Var;
|
||||
break;
|
||||
|
|
@ -3463,9 +3463,9 @@ NonnullRefPtr<UsingDeclaration const> Parser::parse_using_declaration(IsForLoopV
|
|||
{
|
||||
// using [no LineTerminator here] BindingList[?In, ?Yield, ?Await, +Using] ;
|
||||
auto rule_start = push_start();
|
||||
VERIFY(m_state.current_token.original_value() == "using"sv);
|
||||
VERIFY(m_state.current_token().original_value() == "using"sv);
|
||||
consume(TokenType::Identifier);
|
||||
VERIFY(!m_state.current_token.trivia_contains_line_terminator());
|
||||
VERIFY(!m_state.current_token().trivia_contains_line_terminator());
|
||||
Vector<NonnullRefPtr<VariableDeclarator const>> declarations;
|
||||
|
||||
for (;;) {
|
||||
|
|
@ -3514,7 +3514,7 @@ NonnullRefPtr<ThrowStatement const> Parser::parse_throw_statement()
|
|||
consume(TokenType::Throw);
|
||||
|
||||
// Automatic semicolon insertion: terminate statement when throw is followed by newline
|
||||
if (m_state.current_token.trivia_contains_line_terminator()) {
|
||||
if (m_state.current_token().trivia_contains_line_terminator()) {
|
||||
syntax_error("No line break is allowed between 'throw' and its expression"_string);
|
||||
return create_ast_node<ThrowStatement>({ m_source_code, rule_start.position(), position() }, create_ast_node<ErrorExpression>({ m_source_code, rule_start.position(), position() }));
|
||||
}
|
||||
|
|
@ -3532,7 +3532,7 @@ NonnullRefPtr<BreakStatement const> Parser::parse_break_statement()
|
|||
if (match(TokenType::Semicolon)) {
|
||||
consume();
|
||||
} else {
|
||||
if (!m_state.current_token.trivia_contains_line_terminator() && match_identifier()) {
|
||||
if (!m_state.current_token().trivia_contains_line_terminator() && match_identifier()) {
|
||||
target_label = consume().fly_string_value();
|
||||
|
||||
auto label = m_state.labels_in_scope.find(target_label.value());
|
||||
|
|
@ -3562,7 +3562,7 @@ NonnullRefPtr<ContinueStatement const> Parser::parse_continue_statement()
|
|||
return create_ast_node<ContinueStatement>({ m_source_code, rule_start.position(), position() }, OptionalNone {});
|
||||
}
|
||||
|
||||
if (!m_state.current_token.trivia_contains_line_terminator() && match_identifier()) {
|
||||
if (!m_state.current_token().trivia_contains_line_terminator() && match_identifier()) {
|
||||
auto label_position = position();
|
||||
target_label = consume().fly_string_value();
|
||||
|
||||
|
|
@ -3595,7 +3595,7 @@ NonnullRefPtr<OptionalChain const> Parser::parse_optional_chain(NonnullRefPtr<Ex
|
|||
do {
|
||||
if (match(TokenType::QuestionMarkPeriod)) {
|
||||
consume(TokenType::QuestionMarkPeriod);
|
||||
switch (m_state.current_token.type()) {
|
||||
switch (m_state.current_token().type()) {
|
||||
case TokenType::ParenOpen:
|
||||
chain.append(OptionalChain::Call { parse_arguments(), OptionalChain::Mode::Optional });
|
||||
break;
|
||||
|
|
@ -3606,7 +3606,7 @@ NonnullRefPtr<OptionalChain const> Parser::parse_optional_chain(NonnullRefPtr<Ex
|
|||
break;
|
||||
case TokenType::PrivateIdentifier: {
|
||||
if (!is_private_identifier_valid())
|
||||
syntax_error(MUST(String::formatted("Reference to undeclared private field or method '{}'", m_state.current_token.value())));
|
||||
syntax_error(MUST(String::formatted("Reference to undeclared private field or method '{}'", m_state.current_token().value())));
|
||||
|
||||
auto start = position();
|
||||
auto private_identifier = consume();
|
||||
|
|
@ -3642,7 +3642,7 @@ NonnullRefPtr<OptionalChain const> Parser::parse_optional_chain(NonnullRefPtr<Ex
|
|||
consume();
|
||||
if (match(TokenType::PrivateIdentifier)) {
|
||||
if (!is_private_identifier_valid())
|
||||
syntax_error(MUST(String::formatted("Reference to undeclared private field or method '{}'", m_state.current_token.value())));
|
||||
syntax_error(MUST(String::formatted("Reference to undeclared private field or method '{}'", m_state.current_token().value())));
|
||||
|
||||
auto start = position();
|
||||
auto private_identifier = consume();
|
||||
|
|
@ -3951,7 +3951,7 @@ NonnullRefPtr<Statement const> Parser::parse_for_statement()
|
|||
};
|
||||
|
||||
auto match_for_in_of = [&]() {
|
||||
bool is_of = match_of(m_state.current_token);
|
||||
bool is_of = match_of(m_state.current_token());
|
||||
if (is_await_loop == IsForAwaitLoop::Yes) {
|
||||
if (!is_of)
|
||||
syntax_error("for await loop is only valid with 'of'"_string);
|
||||
|
|
@ -3980,7 +3980,7 @@ NonnullRefPtr<Statement const> Parser::parse_for_statement()
|
|||
if (!match(TokenType::Semicolon)) {
|
||||
|
||||
auto match_for_using_declaration = [&] {
|
||||
if (!match(TokenType::Identifier) || m_state.current_token.original_value() != "using"sv)
|
||||
if (!match(TokenType::Identifier) || m_state.current_token().original_value() != "using"sv)
|
||||
return false;
|
||||
|
||||
auto lookahead = next_token();
|
||||
|
|
@ -3996,7 +3996,7 @@ NonnullRefPtr<Statement const> Parser::parse_for_statement()
|
|||
if (match_for_using_declaration()) {
|
||||
auto declaration = parse_using_declaration(IsForLoopVariableDeclaration::Yes);
|
||||
|
||||
if (match_of(m_state.current_token)) {
|
||||
if (match_of(m_state.current_token())) {
|
||||
if (declaration->declarations().size() != 1)
|
||||
syntax_error("Must have exactly one declaration in for using of"_string);
|
||||
else if (declaration->declarations().first()->init())
|
||||
|
|
@ -4035,7 +4035,7 @@ NonnullRefPtr<Statement const> Parser::parse_for_statement()
|
|||
init = parse_expression(0, Associativity::Right, { TokenType::In });
|
||||
if (match_for_in_of()) {
|
||||
if (is_await_loop != IsForAwaitLoop::Yes
|
||||
&& starts_with_async_of && match_of(m_state.current_token))
|
||||
&& starts_with_async_of && match_of(m_state.current_token()))
|
||||
syntax_error("for-of loop may not start with async of"_string);
|
||||
return parse_for_in_of_statement(*init, is_await_loop);
|
||||
}
|
||||
|
|
@ -4134,12 +4134,12 @@ NonnullRefPtr<DebuggerStatement const> Parser::parse_debugger_statement()
|
|||
|
||||
bool Parser::match(TokenType type) const
|
||||
{
|
||||
return m_state.current_token.type() == type;
|
||||
return m_state.current_token().type() == type;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -4172,7 +4172,7 @@ bool Parser::match_expression() const
|
|||
|
||||
bool Parser::match_unary_prefixed_expression() const
|
||||
{
|
||||
auto type = m_state.current_token.type();
|
||||
auto type = m_state.current_token().type();
|
||||
return type == TokenType::PlusPlus
|
||||
|| type == TokenType::MinusMinus
|
||||
|| type == TokenType::ExclamationMark
|
||||
|
|
@ -4186,7 +4186,7 @@ bool Parser::match_unary_prefixed_expression() const
|
|||
|
||||
bool Parser::match_secondary_expression(ForbiddenTokens forbidden) const
|
||||
{
|
||||
auto type = m_state.current_token.type();
|
||||
auto type = m_state.current_token().type();
|
||||
if (!forbidden.allows(type))
|
||||
return false;
|
||||
return type == TokenType::Plus
|
||||
|
|
@ -4213,8 +4213,8 @@ bool Parser::match_secondary_expression(ForbiddenTokens forbidden) const
|
|||
|| type == TokenType::ParenOpen
|
||||
|| type == TokenType::Period
|
||||
|| type == TokenType::BracketOpen
|
||||
|| (type == TokenType::PlusPlus && !m_state.current_token.trivia_contains_line_terminator())
|
||||
|| (type == TokenType::MinusMinus && !m_state.current_token.trivia_contains_line_terminator())
|
||||
|| (type == TokenType::PlusPlus && !m_state.current_token().trivia_contains_line_terminator())
|
||||
|| (type == TokenType::MinusMinus && !m_state.current_token().trivia_contains_line_terminator())
|
||||
|| type == TokenType::In
|
||||
|| type == TokenType::Instanceof
|
||||
|| type == TokenType::QuestionMark
|
||||
|
|
@ -4241,7 +4241,7 @@ bool Parser::match_secondary_expression(ForbiddenTokens forbidden) const
|
|||
|
||||
bool Parser::match_statement() const
|
||||
{
|
||||
auto type = m_state.current_token.type();
|
||||
auto type = m_state.current_token().type();
|
||||
return match_expression()
|
||||
|| type == TokenType::Return
|
||||
|| type == TokenType::Yield
|
||||
|
|
@ -4263,14 +4263,14 @@ bool Parser::match_statement() const
|
|||
|
||||
bool Parser::match_export_or_import() const
|
||||
{
|
||||
auto type = m_state.current_token.type();
|
||||
auto type = m_state.current_token().type();
|
||||
return type == TokenType::Export
|
||||
|| type == TokenType::Import;
|
||||
}
|
||||
|
||||
bool Parser::match_declaration(AllowUsingDeclaration allow_using) const
|
||||
{
|
||||
auto type = m_state.current_token.type();
|
||||
auto type = m_state.current_token().type();
|
||||
|
||||
if (type == TokenType::Let && !m_state.strict_mode) {
|
||||
return try_match_let_declaration();
|
||||
|
|
@ -4281,7 +4281,7 @@ bool Parser::match_declaration(AllowUsingDeclaration allow_using) const
|
|||
return lookahead_token.type() == TokenType::Function && !lookahead_token.trivia_contains_line_terminator();
|
||||
}
|
||||
|
||||
if (allow_using == AllowUsingDeclaration::Yes && type == TokenType::Identifier && m_state.current_token.original_value() == "using"sv)
|
||||
if (allow_using == AllowUsingDeclaration::Yes && type == TokenType::Identifier && m_state.current_token().original_value() == "using"sv)
|
||||
return try_match_using_declaration();
|
||||
|
||||
return type == TokenType::Function
|
||||
|
|
@ -4300,7 +4300,7 @@ Token Parser::next_token() const
|
|||
|
||||
bool Parser::try_match_let_declaration() const
|
||||
{
|
||||
VERIFY(m_state.current_token.type() == TokenType::Let);
|
||||
VERIFY(m_state.current_token().type() == TokenType::Let);
|
||||
auto token_after = next_token();
|
||||
|
||||
if (token_after.is_identifier_name() && token_after.value() != "in"sv)
|
||||
|
|
@ -4314,8 +4314,8 @@ bool Parser::try_match_let_declaration() const
|
|||
|
||||
bool Parser::try_match_using_declaration() const
|
||||
{
|
||||
VERIFY(m_state.current_token.type() == TokenType::Identifier);
|
||||
VERIFY(m_state.current_token.original_value() == "using"sv);
|
||||
VERIFY(m_state.current_token().type() == TokenType::Identifier);
|
||||
VERIFY(m_state.current_token().original_value() == "using"sv);
|
||||
|
||||
auto token_after = next_token();
|
||||
if (token_after.trivia_contains_line_terminator())
|
||||
|
|
@ -4326,7 +4326,7 @@ bool Parser::try_match_using_declaration() const
|
|||
|
||||
bool Parser::match_variable_declaration() const
|
||||
{
|
||||
auto type = m_state.current_token.type();
|
||||
auto type = m_state.current_token().type();
|
||||
|
||||
if (type == TokenType::Let && !m_state.strict_mode) {
|
||||
return try_match_let_declaration();
|
||||
|
|
@ -4339,7 +4339,7 @@ bool Parser::match_variable_declaration() const
|
|||
|
||||
bool Parser::match_identifier() const
|
||||
{
|
||||
return token_is_identifier(m_state.current_token);
|
||||
return token_is_identifier(m_state.current_token());
|
||||
}
|
||||
|
||||
bool Parser::token_is_identifier(Token const& token) const
|
||||
|
|
@ -4363,12 +4363,12 @@ bool Parser::token_is_identifier(Token const& token) const
|
|||
|
||||
bool Parser::match_identifier_name() const
|
||||
{
|
||||
return m_state.current_token.is_identifier_name();
|
||||
return m_state.current_token().is_identifier_name();
|
||||
}
|
||||
|
||||
bool Parser::match_property_key() const
|
||||
{
|
||||
auto type = m_state.current_token.type();
|
||||
auto type = m_state.current_token().type();
|
||||
return match_identifier_name()
|
||||
|| type == TokenType::BracketOpen
|
||||
|| type == TokenType::StringLiteral
|
||||
|
|
@ -4383,12 +4383,12 @@ bool Parser::done() const
|
|||
|
||||
Token Parser::consume()
|
||||
{
|
||||
auto old_token = m_state.current_token;
|
||||
m_state.current_token = m_state.lexer.next();
|
||||
auto old_token = m_state.current_token();
|
||||
m_state.lexer.next();
|
||||
|
||||
// If an IdentifierName is not parsed as an Identifier a slash after it should not be a division
|
||||
if (old_token.is_identifier_name() && (m_state.current_token.type() == TokenType::Slash || m_state.current_token.type() == TokenType::SlashEquals)) {
|
||||
m_state.current_token = m_state.lexer.force_slash_as_regex();
|
||||
if (old_token.is_identifier_name() && (m_state.current_token().type() == TokenType::Slash || m_state.current_token().type() == TokenType::SlashEquals)) {
|
||||
m_state.lexer.force_slash_as_regex();
|
||||
}
|
||||
m_state.previous_token_was_period = old_token.type() == TokenType::Period;
|
||||
return old_token;
|
||||
|
|
@ -4396,8 +4396,8 @@ Token Parser::consume()
|
|||
|
||||
Token Parser::consume_and_allow_division()
|
||||
{
|
||||
auto old_token = m_state.current_token;
|
||||
m_state.current_token = m_state.lexer.next();
|
||||
auto old_token = m_state.current_token();
|
||||
m_state.lexer.next();
|
||||
|
||||
// NOTE: This is the bare minimum needed to decide whether we might need an `arguments` object
|
||||
// in a function expression or declaration. ("Might" because ESFO implements some further
|
||||
|
|
@ -4421,7 +4421,7 @@ void Parser::consume_or_insert_semicolon()
|
|||
}
|
||||
// Insert semicolon if...
|
||||
// ...token is preceded by one or more newlines
|
||||
if (m_state.current_token.trivia_contains_line_terminator())
|
||||
if (m_state.current_token().trivia_contains_line_terminator())
|
||||
return;
|
||||
// ...token is a closing curly brace
|
||||
if (match(TokenType::CurlyClose))
|
||||
|
|
@ -4477,7 +4477,7 @@ Token Parser::consume_identifier_reference()
|
|||
return consume(TokenType::Identifier);
|
||||
|
||||
if (match(TokenType::EscapedKeyword)) {
|
||||
auto name = m_state.current_token.value();
|
||||
auto name = m_state.current_token().value();
|
||||
if (m_state.strict_mode && (name == "let"sv || name == "yield"sv))
|
||||
syntax_error(MUST(String::formatted("'{}' is not allowed as an identifier in strict mode", name)));
|
||||
if (m_program_type == Program::Type::Module && name == "await"sv)
|
||||
|
|
@ -4534,25 +4534,25 @@ Token Parser::consume_and_validate_numeric_literal()
|
|||
auto token = consume(TokenType::NumericLiteral);
|
||||
if (m_state.strict_mode && is_unprefixed_octal_number(token.value()))
|
||||
syntax_error("Unprefixed octal number not allowed in strict mode"_string, literal_start);
|
||||
if (match_identifier_name() && m_state.current_token.trivia().is_empty())
|
||||
if (match_identifier_name() && m_state.current_token().trivia().is_empty())
|
||||
syntax_error("Numeric literal must not be immediately followed by identifier"_string);
|
||||
return token;
|
||||
}
|
||||
|
||||
void Parser::expected(char const* what)
|
||||
{
|
||||
auto message = m_state.current_token.message();
|
||||
auto message = m_state.current_token().message();
|
||||
if (message.is_empty())
|
||||
message = MUST(String::formatted("Unexpected token {}. Expected {}", m_state.current_token.name(), what));
|
||||
message = MUST(String::formatted("Unexpected token {}. Expected {}", m_state.current_token().name(), what));
|
||||
syntax_error(message);
|
||||
}
|
||||
|
||||
Position Parser::position() const
|
||||
{
|
||||
return {
|
||||
m_state.current_token.line_number(),
|
||||
m_state.current_token.line_column(),
|
||||
m_state.current_token.offset(),
|
||||
m_state.current_token().line_number(),
|
||||
m_state.current_token().line_column(),
|
||||
m_state.current_token().offset(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -4645,7 +4645,7 @@ ModuleRequest Parser::parse_module_request()
|
|||
while (!done() && !match(TokenType::CurlyClose)) {
|
||||
Utf16String key;
|
||||
if (match(TokenType::StringLiteral)) {
|
||||
key = parse_string_literal(m_state.current_token)->value();
|
||||
key = parse_string_literal(m_state.current_token())->value();
|
||||
consume();
|
||||
} else if (match_identifier_name()) {
|
||||
key = consume().fly_string_value().to_utf16_string();
|
||||
|
|
@ -4661,7 +4661,7 @@ ModuleRequest Parser::parse_module_request()
|
|||
if (entries.key == key)
|
||||
syntax_error(MUST(String::formatted("Duplicate attribute clauses with name: {}", key)));
|
||||
}
|
||||
request.add_attribute(move(key), parse_string_literal(m_state.current_token)->value());
|
||||
request.add_attribute(move(key), parse_string_literal(m_state.current_token())->value());
|
||||
}
|
||||
consume(TokenType::StringLiteral);
|
||||
|
||||
|
|
@ -4702,7 +4702,7 @@ NonnullRefPtr<ImportStatement const> Parser::parse_import_statement(Program& pro
|
|||
};
|
||||
|
||||
auto match_as = [&] {
|
||||
return match(TokenType::Identifier) && m_state.current_token.original_value() == "as"sv;
|
||||
return match(TokenType::Identifier) && m_state.current_token().original_value() == "as"sv;
|
||||
};
|
||||
|
||||
bool continue_parsing = true;
|
||||
|
|
@ -4742,7 +4742,7 @@ NonnullRefPtr<ImportStatement const> Parser::parse_import_statement(Program& pro
|
|||
consume(TokenType::Asterisk);
|
||||
|
||||
if (!match_as())
|
||||
syntax_error(MUST(String::formatted("Unexpected token: {}", m_state.current_token.name())));
|
||||
syntax_error(MUST(String::formatted("Unexpected token: {}", m_state.current_token().name())));
|
||||
|
||||
consume(TokenType::Identifier);
|
||||
|
||||
|
|
@ -4751,7 +4751,7 @@ NonnullRefPtr<ImportStatement const> Parser::parse_import_statement(Program& pro
|
|||
auto namespace_name = consume().fly_string_value();
|
||||
entries_with_location.append({ ImportEntry({}, move(namespace_name)), namespace_position });
|
||||
} else {
|
||||
syntax_error(MUST(String::formatted("Unexpected token: {}", m_state.current_token.name())));
|
||||
syntax_error(MUST(String::formatted("Unexpected token: {}", m_state.current_token().name())));
|
||||
}
|
||||
|
||||
} else if (match(TokenType::CurlyOpen)) {
|
||||
|
|
@ -4854,15 +4854,15 @@ NonnullRefPtr<ExportStatement const> Parser::parse_export_statement(Program& pro
|
|||
syntax_error("Cannot use export statement outside a module"_string);
|
||||
|
||||
auto match_as = [&] {
|
||||
return match(TokenType::Identifier) && m_state.current_token.original_value() == "as"sv;
|
||||
return match(TokenType::Identifier) && m_state.current_token().original_value() == "as"sv;
|
||||
};
|
||||
|
||||
auto match_from = [&] {
|
||||
return match(TokenType::Identifier) && m_state.current_token.original_value() == "from"sv;
|
||||
return match(TokenType::Identifier) && m_state.current_token().original_value() == "from"sv;
|
||||
};
|
||||
|
||||
auto match_default = [&] {
|
||||
return match(TokenType::Default) && m_state.current_token.original_value() == "default"sv;
|
||||
return match(TokenType::Default) && m_state.current_token().original_value() == "default"sv;
|
||||
};
|
||||
|
||||
consume(TokenType::Export);
|
||||
|
|
@ -4915,7 +4915,7 @@ NonnullRefPtr<ExportStatement const> Parser::parse_export_statement(Program& pro
|
|||
// Hack part 1.
|
||||
// Match a function declaration with a name, since we have async and generator
|
||||
// and asyncgenerator variants this is quite complicated.
|
||||
auto current_type = m_state.current_token.type();
|
||||
auto current_type = m_state.current_token().type();
|
||||
Lexer lookahead_lexer = m_state.lexer;
|
||||
lookahead_lexer.next();
|
||||
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ private:
|
|||
struct ParserState {
|
||||
Lexer lexer;
|
||||
mutable Optional<Lexer> lookahead_lexer;
|
||||
Token current_token;
|
||||
[[nodiscard]] Token const& current_token() const { return lexer.current_token(); }
|
||||
bool previous_token_was_period { false };
|
||||
Vector<ParserError> errors;
|
||||
ScopePusher* current_scope_pusher { nullptr };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue