diff options
-rw-r--r-- | Userland/Applications/Spreadsheet/Spreadsheet.cpp | 2 | ||||
-rw-r--r-- | Userland/Applications/Spreadsheet/SpreadsheetModel.cpp | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/AST.cpp | 17 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/AST.h | 12 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Forward.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Lexer.h | 8 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/MarkupGenerator.cpp | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Parser.cpp | 311 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Parser.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/Error.cpp | 10 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/VM.cpp | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/SourceCode.cpp | 81 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/SourceCode.h | 30 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/SourceRange.h | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/Scripting/ExceptionReporter.cpp | 2 |
16 files changed, 315 insertions, 179 deletions
diff --git a/Userland/Applications/Spreadsheet/Spreadsheet.cpp b/Userland/Applications/Spreadsheet/Spreadsheet.cpp index f6dc5bde53..8141791e19 100644 --- a/Userland/Applications/Spreadsheet/Spreadsheet.cpp +++ b/Userland/Applications/Spreadsheet/Spreadsheet.cpp @@ -71,7 +71,7 @@ Sheet::Sheet(Workbook& workbook) for (auto& traceback_frame : error.traceback()) { auto& function_name = traceback_frame.function_name; auto& source_range = traceback_frame.source_range; - dbgln(" {} at {}:{}:{}", function_name, source_range.filename, source_range.start.line, source_range.start.column); + dbgln(" {} at {}:{}:{}", function_name, source_range.filename(), source_range.start.line, source_range.start.column); } } else { warnln(); diff --git a/Userland/Applications/Spreadsheet/SpreadsheetModel.cpp b/Userland/Applications/Spreadsheet/SpreadsheetModel.cpp index dd45c10988..8b5d4c8678 100644 --- a/Userland/Applications/Spreadsheet/SpreadsheetModel.cpp +++ b/Userland/Applications/Spreadsheet/SpreadsheetModel.cpp @@ -122,13 +122,13 @@ GUI::Variant SheetModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) StringBuilder builder; builder.appendff("{}\n", error.get_without_side_effects(object.vm().names.message).to_string_without_side_effects()); for (auto const& frame : trace.in_reverse()) { - if (frame.source_range.filename.contains("runtime.js"sv)) { + if (frame.source_range.filename().contains("runtime.js"sv)) { if (frame.function_name == "<unknown>") builder.appendff(" in a builtin function at line {}, column {}\n", frame.source_range.start.line, frame.source_range.start.column); else builder.appendff(" while evaluating builtin '{}'\n", frame.function_name); - } else if (frame.source_range.filename.starts_with("cell "sv)) { - builder.appendff(" in cell '{}', at line {}, column {}\n", frame.source_range.filename.substring_view(5), frame.source_range.start.line, frame.source_range.start.column); + } else if (frame.source_range.filename().starts_with("cell "sv)) { + builder.appendff(" in cell '{}', at line {}, column {}\n", frame.source_range.filename().substring_view(5), frame.source_range.start.line, frame.source_range.start.column); } } return builder.to_string(); diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index a128568f11..de4b57a4c2 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -61,6 +61,18 @@ private: ExecutingASTNodeChain m_chain_node; }; +ASTNode::ASTNode(SourceRange source_range) + : m_source_code(source_range.code) + , m_start_offset(source_range.start.offset) + , m_end_offset(source_range.end.offset) +{ +} + +SourceRange ASTNode::source_range() const +{ + return m_source_code->range_from_offsets(m_start_offset, m_end_offset); +} + String ASTNode::class_name() const { // NOTE: We strip the "JS::" prefix. @@ -4794,4 +4806,9 @@ ModuleRequest::ModuleRequest(FlyString module_specifier_, Vector<Assertion> asse }); } +String const& SourceRange::filename() const +{ + return code->filename(); +} + } diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index d06496c16a..eaa7ccd600 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -52,8 +52,7 @@ public: virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const; virtual void dump(int indent) const; - SourceRange const& source_range() const { return m_source_range; } - SourceRange& source_range() { return m_source_range; } + SourceRange source_range() const; String class_name() const; @@ -84,13 +83,12 @@ public: virtual bool is_class_method() const { return false; } protected: - explicit ASTNode(SourceRange source_range) - : m_source_range(source_range) - { - } + explicit ASTNode(SourceRange); private: - SourceRange m_source_range; + RefPtr<SourceCode> m_source_code; + u32 m_start_offset { 0 }; + u32 m_end_offset { 0 }; }; class Statement : public ASTNode { diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt index 0bd369652b..46b77da9a1 100644 --- a/Userland/Libraries/LibJS/CMakeLists.txt +++ b/Userland/Libraries/LibJS/CMakeLists.txt @@ -244,6 +244,7 @@ set(SOURCES Runtime/WeakSetPrototype.cpp Runtime/WrappedFunction.cpp Script.cpp + SourceCode.cpp SourceTextModule.cpp SyntaxHighlighter.cpp SyntheticModule.cpp diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h index 9e2a6fda05..2181bd5afb 100644 --- a/Userland/Libraries/LibJS/Forward.h +++ b/Userland/Libraries/LibJS/Forward.h @@ -188,6 +188,8 @@ class Script; class Shape; class Statement; class StringOrSymbol; +class SourceCode; +struct SourceRange; class SourceTextModule; class Symbol; class Token; diff --git a/Userland/Libraries/LibJS/Lexer.h b/Userland/Libraries/LibJS/Lexer.h index 3cb25f68db..4b115be43b 100644 --- a/Userland/Libraries/LibJS/Lexer.h +++ b/Userland/Libraries/LibJS/Lexer.h @@ -20,8 +20,8 @@ public: Token next(); - StringView source() const { return m_source; }; - StringView filename() const { return m_filename; }; + String const& source() const { return m_source; }; + String const& filename() const { return m_filename; }; void disallow_html_comments() { m_allow_html_comments = false; }; @@ -57,13 +57,13 @@ private: TokenType consume_regex_literal(); - StringView m_source; + String m_source; size_t m_position { 0 }; Token m_current_token; char m_current_char { 0 }; bool m_eof { false }; - StringView m_filename; + String m_filename; size_t m_line_number { 1 }; size_t m_line_column { 0 }; diff --git a/Userland/Libraries/LibJS/MarkupGenerator.cpp b/Userland/Libraries/LibJS/MarkupGenerator.cpp index 33afb5fe1f..892c44c00f 100644 --- a/Userland/Libraries/LibJS/MarkupGenerator.cpp +++ b/Userland/Libraries/LibJS/MarkupGenerator.cpp @@ -150,7 +150,7 @@ void MarkupGenerator::trace_to_html(TracebackFrame const& traceback_frame, Strin auto last_slash_index = filename.find_last('/'); return last_slash_index.has_value() ? filename.substring_view(*last_slash_index + 1) : filename; }; - auto filename = escape_html_entities(get_filename_from_path(traceback_frame.source_range.filename)); + auto filename = escape_html_entities(get_filename_from_path(traceback_frame.source_range.filename())); auto trace = String::formatted("at {} ({}:{}:{})", function_name, filename, line, column); html_output.appendff(" {}<br>", trace); diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index 4fb31c0c2b..18edff0528 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -419,7 +419,8 @@ Parser::ParserState::ParserState(Lexer l, Program::Type program_type) } Parser::Parser(Lexer lexer, Program::Type program_type, Optional<EvalInitialState> initial_state_for_eval) - : m_state(move(lexer), program_type) + : m_source_code(SourceCode::create(lexer.filename(), lexer.source())) + , m_state(move(lexer), program_type) , m_program_type(program_type) { if (initial_state_for_eval.has_value()) { @@ -503,7 +504,7 @@ bool Parser::parse_directive(ScopeNode& body) NonnullRefPtr<Program> Parser::parse_program(bool starts_in_strict_mode) { auto rule_start = push_start(); - auto program = adopt_ref(*new Program({ m_filename, rule_start.position(), position() }, m_program_type)); + auto program = adopt_ref(*new Program({ m_source_code, rule_start.position(), position() }, m_program_type)); ScopePusher program_scope = ScopePusher::program_scope(*this, *program); if (m_program_type == Program::Type::Script) @@ -614,7 +615,7 @@ NonnullRefPtr<Declaration> Parser::parse_declaration() default: expected("declaration"); consume(); - return create_ast_node<ErrorDeclaration>({ m_state.current_token.filename(), rule_start.position(), position() }); + return create_ast_node<ErrorDeclaration>({ m_source_code, rule_start.position(), position() }); } } @@ -658,7 +659,7 @@ NonnullRefPtr<Statement> Parser::parse_statement(AllowLabelledFunction allow_lab return parse_debugger_statement(); case TokenType::Semicolon: consume(); - return create_ast_node<EmptyStatement>({ m_state.current_token.filename(), rule_start.position(), position() }); + 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(); @@ -685,11 +686,11 @@ NonnullRefPtr<Statement> Parser::parse_statement(AllowLabelledFunction allow_lab auto expr = parse_expression(0); consume_or_insert_semicolon(); - return create_ast_node<ExpressionStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(expr)); + return create_ast_node<ExpressionStatement>({ m_source_code, rule_start.position(), position() }, move(expr)); } expected("statement"); consume(); - return create_ast_node<ErrorStatement>({ m_state.current_token.filename(), rule_start.position(), position() }); + return create_ast_node<ErrorStatement>({ m_source_code, rule_start.position(), position() }); } } @@ -835,10 +836,10 @@ RefPtr<FunctionExpression> Parser::try_parse_arrow_function_expression(bool expe // for arrow function bodies which are a single expression. // Esprima generates a single "ArrowFunctionExpression" // with a "body" property. - auto return_block = create_ast_node<FunctionBody>({ m_state.current_token.filename(), rule_start.position(), position() }); + auto return_block = create_ast_node<FunctionBody>({ m_source_code, rule_start.position(), position() }); ScopePusher function_scope = ScopePusher::function_scope(*this, return_block, parameters); auto return_expression = parse_expression(2); - return_block->append<ReturnStatement>({ m_filename, rule_start.position(), position() }, move(return_expression)); + return_block->append<ReturnStatement>({ m_source_code, rule_start.position(), position() }, move(return_expression)); if (m_state.strict_mode) return_block->set_strict_mode(); contains_direct_call_to_eval = function_scope.contains_direct_call_to_eval(); @@ -869,7 +870,7 @@ RefPtr<FunctionExpression> Parser::try_parse_arrow_function_expression(bool expe auto function_end_offset = position().offset - m_state.current_token.trivia().length(); auto source_text = String { m_state.lexer.source().substring_view(function_start_offset, function_end_offset - function_start_offset) }; return create_ast_node<FunctionExpression>( - { m_state.current_token.filename(), rule_start.position(), position() }, "", move(source_text), + { m_source_code, rule_start.position(), position() }, "", move(source_text), move(body), move(parameters), function_length, function_kind, body->in_strict_mode(), /* might_need_arguments_object */ false, contains_direct_call_to_eval, /* is_arrow_function */ true); } @@ -958,7 +959,7 @@ RefPtr<LabelledStatement> Parser::try_parse_labelled_statement(AllowLabelledFunc m_state.labels_in_scope.remove(identifier); - return create_ast_node<LabelledStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, identifier, labelled_item.release_nonnull()); + return create_ast_node<LabelledStatement>({ m_source_code, rule_start.position(), position() }, identifier, labelled_item.release_nonnull()); } RefPtr<MetaProperty> Parser::try_parse_new_target_expression() @@ -983,7 +984,7 @@ RefPtr<MetaProperty> Parser::try_parse_new_target_expression() state_rollback_guard.disarm(); discard_saved_state(); - return create_ast_node<MetaProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, MetaProperty::Type::NewTarget); + return create_ast_node<MetaProperty>({ m_source_code, rule_start.position(), position() }, MetaProperty::Type::NewTarget); } RefPtr<MetaProperty> Parser::try_parse_import_meta_expression() @@ -1008,7 +1009,7 @@ RefPtr<MetaProperty> Parser::try_parse_import_meta_expression() state_rollback_guard.disarm(); discard_saved_state(); - return create_ast_node<MetaProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, MetaProperty::Type::ImportMeta); + return create_ast_node<MetaProperty>({ m_source_code, rule_start.position(), position() }, MetaProperty::Type::ImportMeta); } NonnullRefPtr<ImportCall> Parser::parse_import_call() @@ -1040,13 +1041,13 @@ NonnullRefPtr<ImportCall> Parser::parse_import_call() consume(TokenType::ParenClose); - return create_ast_node<ImportCall>({ m_state.current_token.filename(), rule_start.position(), position() }, move(argument), move(options)); + return create_ast_node<ImportCall>({ m_source_code, rule_start.position(), position() }, move(argument), move(options)); } NonnullRefPtr<ClassDeclaration> Parser::parse_class_declaration() { auto rule_start = push_start(); - return create_ast_node<ClassDeclaration>({ m_state.current_token.filename(), rule_start.position(), position() }, parse_class_expression(true)); + return create_ast_node<ClassDeclaration>({ m_source_code, rule_start.position(), position() }, parse_class_expression(true)); } NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_name) @@ -1078,7 +1079,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ for (;;) { if (match(TokenType::TemplateLiteralStart)) { auto template_literal = parse_template_literal(true); - expression = create_ast_node<TaggedTemplateLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, move(expression), move(template_literal)); + expression = create_ast_node<TaggedTemplateLiteral>({ m_source_code, rule_start.position(), position() }, move(expression), move(template_literal)); continue; } if (match(TokenType::BracketOpen) || match(TokenType::Period) || match(TokenType::ParenOpen)) { @@ -1167,7 +1168,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ switch (m_state.current_token.type()) { case TokenType::Identifier: name = consume().value(); - property_key = create_ast_node<StringLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, name); + property_key = create_ast_node<StringLiteral>({ m_source_code, rule_start.position(), position() }, name); break; case TokenType::PrivateIdentifier: name = consume().value(); @@ -1204,7 +1205,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ syntax_error(String::formatted("Duplicate private field or method named '{}'", name)); } - property_key = create_ast_node<PrivateIdentifier>({ m_state.current_token.filename(), rule_start.position(), position() }, name); + property_key = create_ast_node<PrivateIdentifier>({ m_source_code, rule_start.position(), position() }, name); break; case TokenType::StringLiteral: { auto string_literal = parse_string_literal(consume()); @@ -1243,12 +1244,12 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ method_kind = ClassMethod::Kind::Method; break; } - property_key = create_ast_node<StringLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, name); + property_key = create_ast_node<StringLiteral>({ m_source_code, rule_start.position(), position() }, name); } else if (match(TokenType::CurlyOpen) && is_static) { auto static_start = push_start(); consume(TokenType::CurlyOpen); - auto static_init_block = create_ast_node<FunctionBody>({ m_state.current_token.filename(), rule_start.position(), position() }); + auto static_init_block = create_ast_node<FunctionBody>({ m_source_code, rule_start.position(), position() }); TemporaryChange break_context_rollback(m_state.in_break_context, false); TemporaryChange continue_context_rollback(m_state.in_continue_context, false); @@ -1263,7 +1264,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ parse_statement_list(static_init_block); consume(TokenType::CurlyClose); - elements.append(create_ast_node<StaticInitializer>({ m_state.current_token.filename(), static_start.position(), position() }, move(static_init_block), static_init_scope.contains_direct_call_to_eval())); + elements.append(create_ast_node<StaticInitializer>({ m_source_code, static_start.position(), position() }, move(static_init_block), static_init_scope.contains_direct_call_to_eval())); continue; } else { expected("property key"); @@ -1300,7 +1301,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ if (is_constructor) { constructor = move(function); } else if (!property_key.is_null()) { - elements.append(create_ast_node<ClassMethod>({ m_state.current_token.filename(), rule_start.position(), position() }, property_key.release_nonnull(), move(function), method_kind, is_static)); + elements.append(create_ast_node<ClassMethod>({ m_source_code, rule_start.position(), position() }, property_key.release_nonnull(), move(function), method_kind, is_static)); } else { syntax_error("No key for class method"); } @@ -1328,7 +1329,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ contains_direct_call_to_eval = class_field_scope.contains_direct_call_to_eval(); } - elements.append(create_ast_node<ClassField>({ m_state.current_token.filename(), rule_start.position(), position() }, property_key.release_nonnull(), move(initializer), contains_direct_call_to_eval, is_static)); + elements.append(create_ast_node<ClassField>({ m_source_code, rule_start.position(), position() }, property_key.release_nonnull(), move(initializer), contains_direct_call_to_eval, is_static)); consume_or_insert_semicolon(); } } @@ -1336,7 +1337,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ consume(TokenType::CurlyClose); if (constructor.is_null()) { - auto constructor_body = create_ast_node<BlockStatement>({ m_state.current_token.filename(), rule_start.position(), position() }); + auto constructor_body = create_ast_node<BlockStatement>({ m_source_code, rule_start.position(), position() }); if (!super_class.is_null()) { // Set constructor to the result of parsing the source text // constructor(... args){ super (...args);} @@ -1347,21 +1348,21 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ // method on %Array.prototype% visibly. FlyString argument_name = "args"; auto super_call = create_ast_node<SuperCall>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, SuperCall::IsPartOfSyntheticConstructor::Yes, - CallExpression::Argument { create_ast_node<Identifier>({ m_state.current_token.filename(), rule_start.position(), position() }, "args"), true }); + CallExpression::Argument { create_ast_node<Identifier>({ m_source_code, rule_start.position(), position() }, "args"), true }); // NOTE: While the JS approximation above doesn't do `return super(...args)`, the // abstract closure is expected to capture and return the result, so we do need a // return statement here to create the correct completion. - constructor_body->append(create_ast_node<ReturnStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(super_call))); + constructor_body->append(create_ast_node<ReturnStatement>({ m_source_code, rule_start.position(), position() }, move(super_call))); constructor = create_ast_node<FunctionExpression>( - { m_state.current_token.filename(), rule_start.position(), position() }, class_name, "", + { m_source_code, rule_start.position(), position() }, class_name, "", move(constructor_body), Vector { FunctionNode::Parameter { move(argument_name), nullptr, true } }, 0, FunctionKind::Normal, /* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false); } else { constructor = create_ast_node<FunctionExpression>( - { m_state.current_token.filename(), rule_start.position(), position() }, class_name, "", + { m_source_code, rule_start.position(), position() }, class_name, "", move(constructor_body), Vector<FunctionNode::Parameter> {}, 0, FunctionKind::Normal, /* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false); } @@ -1381,7 +1382,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_ auto function_end_offset = position().offset - m_state.current_token.trivia().length(); auto source_text = String { m_state.lexer.source().substring_view(function_start_offset, function_end_offset - function_start_offset) }; - return create_ast_node<ClassExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(class_name), move(source_text), move(constructor), move(super_class), move(elements)); + return create_ast_node<ClassExpression>({ m_source_code, rule_start.position(), position() }, move(class_name), move(source_text), move(constructor), move(super_class), move(elements)); } Parser::PrimaryExpressionParseResult Parser::parse_primary_expression() @@ -1422,14 +1423,14 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression() } case TokenType::This: consume(); - return { create_ast_node<ThisExpression>({ m_state.current_token.filename(), rule_start.position(), position() }) }; + return { create_ast_node<ThisExpression>({ m_source_code, rule_start.position(), position() }) }; case TokenType::Class: return { parse_class_expression(false) }; case TokenType::Super: consume(); if (!m_state.allow_super_property_lookup) syntax_error("'super' keyword unexpected here"); - return { create_ast_node<SuperExpression>({ m_state.current_token.filename(), rule_start.position(), position() }) }; + return { create_ast_node<SuperExpression>({ m_source_code, rule_start.position(), position() }) }; case TokenType::EscapedKeyword: if (match_invalid_escaped_keyword()) syntax_error("Keyword must not contain escaped characters"); @@ -1446,16 +1447,16 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression() return { parse_identifier() }; } case TokenType::NumericLiteral: - return { create_ast_node<NumericLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, consume_and_validate_numeric_literal().double_value()) }; + return { create_ast_node<NumericLiteral>({ m_source_code, rule_start.position(), position() }, consume_and_validate_numeric_literal().double_value()) }; case TokenType::BigIntLiteral: - return { create_ast_node<BigIntLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, consume().value()) }; + return { create_ast_node<BigIntLiteral>({ m_source_code, rule_start.position(), position() }, consume().value()) }; case TokenType::BoolLiteral: - return { create_ast_node<BooleanLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, consume().bool_value()) }; + return { create_ast_node<BooleanLiteral>({ m_source_code, rule_start.position(), position() }, consume().bool_value()) }; case TokenType::StringLiteral: return { parse_string_literal(consume()) }; case TokenType::NullLiteral: consume(); - return { create_ast_node<NullLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }) }; + return { create_ast_node<NullLiteral>({ m_source_code, rule_start.position(), position() }) }; case TokenType::CurlyOpen: return { parse_object_expression() }; case TokenType::Async: { @@ -1524,7 +1525,7 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression() syntax_error(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'"); - return { create_ast_node<PrivateIdentifier>({ m_state.current_token.filename(), rule_start.position(), position() }, consume().value()) }; + return { create_ast_node<PrivateIdentifier>({ m_source_code, rule_start.position(), position() }, consume().value()) }; default: if (match_identifier_name()) goto read_as_identifier; @@ -1532,7 +1533,7 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression() } expected("primary expression"); consume(); - return { create_ast_node<ErrorExpression>({ m_state.current_token.filename(), rule_start.position(), position() }) }; + return { create_ast_node<ErrorExpression>({ m_source_code, rule_start.position(), position() }) }; } NonnullRefPtr<RegExpLiteral> Parser::parse_regexp_literal() @@ -1569,7 +1570,7 @@ NonnullRefPtr<RegExpLiteral> Parser::parse_regexp_literal() if (parsed_regex.error != regex::Error::NoError) syntax_error(String::formatted("RegExp compile error: {}", Regex<ECMA262>(parsed_regex, parsed_pattern, parsed_flags).error_string()), rule_start.position()); - SourceRange range { m_state.current_token.filename(), rule_start.position(), position() }; + SourceRange range { m_source_code, rule_start.position(), position() }; return create_ast_node<RegExpLiteral>(move(range), move(parsed_regex), move(parsed_pattern), move(parsed_flags), pattern.to_string(), move(flags)); } @@ -1594,7 +1595,7 @@ NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression() check_identifier_name_for_assignment_validity(name); } - return create_ast_node<UpdateExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UpdateOp::Increment, move(rhs), true); + return create_ast_node<UpdateExpression>({ m_source_code, rule_start.position(), position() }, UpdateOp::Increment, move(rhs), true); } case TokenType::MinusMinus: { consume(); @@ -1611,29 +1612,29 @@ NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression() check_identifier_name_for_assignment_validity(name); } - return create_ast_node<UpdateExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UpdateOp::Decrement, move(rhs), true); + return create_ast_node<UpdateExpression>({ m_source_code, rule_start.position(), position() }, UpdateOp::Decrement, move(rhs), true); } case TokenType::ExclamationMark: consume(); - return create_ast_node<UnaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UnaryOp::Not, parse_expression(precedence, associativity)); + return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Not, parse_expression(precedence, associativity)); case TokenType::Tilde: consume(); - return create_ast_node<UnaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UnaryOp::BitwiseNot, parse_expression(precedence, associativity)); + return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::BitwiseNot, parse_expression(precedence, associativity)); case TokenType::Plus: consume(); - return create_ast_node<UnaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UnaryOp::Plus, parse_expression(precedence, associativity)); + return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Plus, parse_expression(precedence, associativity)); case TokenType::Minus: consume(); - return create_ast_node<UnaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UnaryOp::Minus, parse_expression(precedence, associativity)); + return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Minus, parse_expression(precedence, associativity)); case TokenType::Typeof: consume(); - return create_ast_node<UnaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UnaryOp::Typeof, parse_expression(precedence, associativity)); + return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Typeof, parse_expression(precedence, associativity)); case TokenType::Void: consume(); // FIXME: This check is really hiding the fact that we don't deal with different expressions correctly. if (match(TokenType::Yield) && m_state.in_generator_function_context) syntax_error("'yield' is not an identifier in generator function context"); - return create_ast_node<UnaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UnaryOp::Void, parse_expression(precedence, associativity)); + return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Void, parse_expression(precedence, associativity)); case TokenType::Delete: { consume(); auto rhs_start = position(); @@ -1646,12 +1647,12 @@ NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression() if (member_expression.ends_in_private_name()) syntax_error("Private fields cannot be deleted"); } - return create_ast_node<UnaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UnaryOp::Delete, move(rhs)); + return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Delete, move(rhs)); } default: expected("primary expression"); consume(); - return create_ast_node<ErrorExpression>({ m_state.current_token.filename(), rule_start.position(), position() }); + return create_ast_node<ErrorExpression>({ m_source_code, rule_start.position(), position() }); } } @@ -1661,9 +1662,9 @@ NonnullRefPtr<Expression> Parser::parse_property_key() if (match(TokenType::StringLiteral)) { return parse_string_literal(consume()); } else if (match(TokenType::NumericLiteral)) { - return create_ast_node<NumericLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, consume().double_value()); + return create_ast_node<NumericLiteral>({ m_source_code, rule_start.position(), position() }, consume().double_value()); } else if (match(TokenType::BigIntLiteral)) { - return create_ast_node<BigIntLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, consume().value()); + return create_ast_node<BigIntLiteral>({ m_source_code, rule_start.position(), position() }, consume().value()); } else if (match(TokenType::BracketOpen)) { consume(TokenType::BracketOpen); auto result = parse_expression(2); @@ -1672,7 +1673,7 @@ NonnullRefPtr<Expression> Parser::parse_property_key() } else { if (!match_identifier_name()) expected("IdentifierName"); - return create_ast_node<StringLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, consume().value()); + return create_ast_node<StringLiteral>({ m_source_code, rule_start.position(), position() }, consume().value()); } } @@ -1704,7 +1705,7 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression() if (match(TokenType::TripleDot)) { consume(); property_key = parse_expression(4); - properties.append(create_ast_node<ObjectProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, *property_key, nullptr, ObjectProperty::Type::Spread, false)); + properties.append(create_ast_node<ObjectProperty>({ m_source_code, rule_start.position(), position() }, *property_key, nullptr, ObjectProperty::Type::Spread, false)); if (!match(TokenType::Comma)) break; consume(TokenType::Comma); @@ -1740,8 +1741,8 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression() property_type = ObjectProperty::Type::Setter; property_key = parse_property_key(); } else { - property_key = create_ast_node<StringLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, identifier.value()); - property_value = create_ast_node<Identifier>({ m_state.current_token.filename(), rule_start.position(), position() }, identifier.flystring_value()); + property_key = create_ast_node<StringLiteral>({ m_source_code, rule_start.position(), position() }, identifier.value()); + property_value = create_ast_node<Identifier>({ m_source_code, rule_start.position(), position() }, identifier.flystring_value()); } } else { property_key = parse_property_key(); @@ -1777,7 +1778,7 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression() if (function_kind == FunctionKind::Async || function_kind == FunctionKind::AsyncGenerator) parse_options |= FunctionNodeParseOptions::IsAsyncFunction; auto function = parse_function_node<FunctionExpression>(parse_options, function_start); - properties.append(create_ast_node<ObjectProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, *property_key, function, property_type, true)); + properties.append(create_ast_node<ObjectProperty>({ m_source_code, rule_start.position(), position() }, *property_key, function, property_type, true)); } else if (match(TokenType::Colon)) { if (!property_key) { expected("a property name"); @@ -1792,7 +1793,7 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression() } if (is_proto && property_type == ObjectProperty::Type::KeyValue) property_type = ObjectProperty::Type::ProtoSetter; - properties.append(create_ast_node<ObjectProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, *property_key, parse_expression(2), property_type, false)); + properties.append(create_ast_node<ObjectProperty>({ m_source_code, rule_start.position(), position() }, *property_key, parse_expression(2), property_type, false)); } else if (property_key && property_value) { if (m_state.strict_mode && is<StringLiteral>(*property_key)) { auto& string_literal = static_cast<StringLiteral const&>(*property_key); @@ -1800,7 +1801,7 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression() syntax_error(String::formatted("'{}' is a reserved keyword", string_literal.value())); } - properties.append(create_ast_node<ObjectProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, *property_key, *property_value, property_type, false)); + properties.append(create_ast_node<ObjectProperty>({ m_source_code, rule_start.position(), position() }, *property_key, *property_value, property_type, false)); } else { expected("a property"); skip_to_next_property(); @@ -1814,7 +1815,7 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression() consume(TokenType::CurlyClose); return create_ast_node<ObjectExpression>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, move(properties), move(invalid_object_literal_property_range)); } @@ -1830,7 +1831,7 @@ NonnullRefPtr<ArrayExpression> Parser::parse_array_expression() if (match(TokenType::TripleDot)) { consume(TokenType::TripleDot); - expression = create_ast_node<SpreadExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, parse_expression(2)); + expression = create_ast_node<SpreadExpression>({ m_source_code, rule_start.position(), position() }, parse_expression(2)); } else if (match_expression()) { expression = parse_expression(2); } @@ -1842,7 +1843,7 @@ NonnullRefPtr<ArrayExpression> Parser::parse_array_expression() } consume(TokenType::BracketClose); - return create_ast_node<ArrayExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(elements)); + return create_ast_node<ArrayExpression>({ m_source_code, rule_start.position(), position() }, move(elements)); } NonnullRefPtr<StringLiteral> Parser::parse_string_literal(Token const& token, StringLiteralType string_literal_type, bool* contains_invalid_escape) @@ -1881,7 +1882,7 @@ NonnullRefPtr<StringLiteral> Parser::parse_string_literal(Token const& token, St auto is_use_strict_directive = string_literal_type == StringLiteralType::Normal && (token.value() == "'use strict'" || token.value() == "\"use strict\""); - return create_ast_node<StringLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, string, is_use_strict_directive); + return create_ast_node<StringLiteral>({ m_source_code, rule_start.position(), position() }, string, is_use_strict_directive); } NonnullRefPtr<TemplateLiteral> Parser::parse_template_literal(bool is_tagged) @@ -1893,7 +1894,7 @@ NonnullRefPtr<TemplateLiteral> Parser::parse_template_literal(bool is_tagged) NonnullRefPtrVector<Expression> raw_strings; auto append_empty_string = [this, &rule_start, &expressions, &raw_strings, is_tagged]() { - auto string_literal = create_ast_node<StringLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, ""); + auto string_literal = create_ast_node<StringLiteral>({ m_source_code, rule_start.position(), position() }, ""); expressions.append(string_literal); if (is_tagged) raw_strings.append(string_literal); @@ -1911,22 +1912,22 @@ NonnullRefPtr<TemplateLiteral> Parser::parse_template_literal(bool is_tagged) is_tagged ? &contains_invalid_escape : nullptr); // An invalid string leads to a cooked value of `undefined` but still gives the raw string. if (contains_invalid_escape) - expressions.append(create_ast_node<NullLiteral>({ m_state.current_token.filename(), rule_start.position(), position() })); + expressions.append(create_ast_node<NullLiteral>({ m_source_code, rule_start.position(), position() })); else expressions.append(move(parsed_string_value)); if (is_tagged) - raw_strings.append(create_ast_node<StringLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, token.raw_template_value())); + raw_strings.append(create_ast_node<StringLiteral>({ m_source_code, rule_start.position(), position() }, token.raw_template_value())); } else if (match(TokenType::TemplateLiteralExprStart)) { consume(TokenType::TemplateLiteralExprStart); if (match(TokenType::TemplateLiteralExprEnd)) { syntax_error("Empty template literal expression block"); - return create_ast_node<TemplateLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, expressions); + return create_ast_node<TemplateLiteral>({ m_source_code, rule_start.position(), position() }, expressions); } expressions.append(parse_expression(0)); if (match(TokenType::UnterminatedTemplateLiteral)) { syntax_error("Unterminated template literal"); - return create_ast_node<TemplateLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, expressions); + return create_ast_node<TemplateLiteral>({ m_source_code, rule_start.position(), position() }, expressions); } consume(TokenType::TemplateLiteralExprEnd); @@ -1945,8 +1946,8 @@ NonnullRefPtr<TemplateLiteral> Parser::parse_template_literal(bool is_tagged) } if (is_tagged) - return create_ast_node<TemplateLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, expressions, raw_strings); - return create_ast_node<TemplateLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, expressions); + return create_ast_node<TemplateLiteral>({ m_source_code, rule_start.position(), position() }, expressions, raw_strings); + return create_ast_node<TemplateLiteral>({ m_source_code, rule_start.position(), position() }, expressions); } NonnullRefPtr<Expression> Parser::parse_expression(int min_precedence, Associativity associativity, ForbiddenTokens forbidden) @@ -1979,7 +1980,7 @@ NonnullRefPtr<Expression> Parser::parse_expression(int min_precedence, Associati while (match(TokenType::TemplateLiteralStart)) { auto template_literal = parse_template_literal(true); - expression = create_ast_node<TaggedTemplateLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, move(expression), move(template_literal)); + expression = create_ast_node<TaggedTemplateLiteral>({ m_source_code, rule_start.position(), position() }, move(expression), move(template_literal)); } if (should_continue_parsing) { while (match_secondary_expression(forbidden)) { @@ -1996,7 +1997,7 @@ NonnullRefPtr<Expression> Parser::parse_expression(int min_precedence, Associati forbidden = forbidden.merge(result.forbidden); while (match(TokenType::TemplateLiteralStart) && !is<UpdateExpression>(*expression)) { auto template_literal = parse_template_literal(true); - expression = create_ast_node<TaggedTemplateLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, move(expression), move(template_literal)); + expression = create_ast_node<TaggedTemplateLiteral>({ m_source_code, rule_start.position(), position() }, move(expression), move(template_literal)); } } } @@ -2031,7 +2032,7 @@ NonnullRefPtr<Expression> Parser::parse_expression(int min_precedence, Associati consume(); expressions.append(parse_expression(2)); } - expression = create_ast_node<SequenceExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(expressions)); + expression = create_ast_node<SequenceExpression>({ m_source_code, rule_start.position(), position() }, move(expressions)); } return expression; } @@ -2042,92 +2043,92 @@ Parser::ExpressionResult Parser::parse_secondary_expression(NonnullRefPtr<Expres switch (m_state.current_token.type()) { case TokenType::Plus: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Addition, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::Addition, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::PlusEquals: return parse_assignment_expression(AssignmentOp::AdditionAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::Minus: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Subtraction, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::Subtraction, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::MinusEquals: return parse_assignment_expression(AssignmentOp::SubtractionAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::Asterisk: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Multiplication, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::Multiplication, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::AsteriskEquals: return parse_assignment_expression(AssignmentOp::MultiplicationAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::Slash: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Division, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::Division, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::SlashEquals: return parse_assignment_expression(AssignmentOp::DivisionAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::Percent: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Modulo, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::Modulo, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::PercentEquals: return parse_assignment_expression(AssignmentOp::ModuloAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::DoubleAsterisk: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Exponentiation, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::Exponentiation, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::DoubleAsteriskEquals: return parse_assignment_expression(AssignmentOp::ExponentiationAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::GreaterThan: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::GreaterThan, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::GreaterThan, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::GreaterThanEquals: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::GreaterThanEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::GreaterThanEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::LessThan: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LessThan, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::LessThan, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::LessThanEquals: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LessThanEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::LessThanEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::EqualsEqualsEquals: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::StrictlyEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::StrictlyEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::ExclamationMarkEqualsEquals: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::StrictlyInequals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::StrictlyInequals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::EqualsEquals: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LooselyEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::LooselyEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::ExclamationMarkEquals: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LooselyInequals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::LooselyInequals, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::In: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::In, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::In, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::Instanceof: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::InstanceOf, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::InstanceOf, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::Ampersand: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::BitwiseAnd, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::BitwiseAnd, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::AmpersandEquals: return parse_assignment_expression(AssignmentOp::BitwiseAndAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::Pipe: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::BitwiseOr, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::BitwiseOr, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::PipeEquals: return parse_assignment_expression(AssignmentOp::BitwiseOrAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::Caret: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::BitwiseXor, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::BitwiseXor, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::CaretEquals: return parse_assignment_expression(AssignmentOp::BitwiseXorAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::ShiftLeft: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LeftShift, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::LeftShift, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::ShiftLeftEquals: return parse_assignment_expression(AssignmentOp::LeftShiftAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::ShiftRight: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::RightShift, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::RightShift, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::ShiftRightEquals: return parse_assignment_expression(AssignmentOp::RightShiftAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::UnsignedShiftRight: consume(); - return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::UnsignedRightShift, move(lhs), parse_expression(min_precedence, associativity, forbidden)); + return create_ast_node<BinaryExpression>({ m_source_code, rule_start.position(), position() }, BinaryOp::UnsignedRightShift, move(lhs), parse_expression(min_precedence, associativity, forbidden)); case TokenType::UnsignedShiftRightEquals: return parse_assignment_expression(AssignmentOp::UnsignedRightShiftAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::ParenOpen: @@ -2142,15 +2143,15 @@ Parser::ExpressionResult Parser::parse_secondary_expression(NonnullRefPtr<Expres else if (is<SuperExpression>(*lhs)) syntax_error(String::formatted("Cannot access private field or method '{}' on super", m_state.current_token.value())); - return create_ast_node<MemberExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(lhs), create_ast_node<PrivateIdentifier>({ m_state.current_token.filename(), rule_start.position(), position() }, consume().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().value())); } else if (!match_identifier_name()) { expected("IdentifierName"); } - return create_ast_node<MemberExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(lhs), create_ast_node<Identifier>({ m_state.current_token.filename(), rule_start.position(), position() }, consume().flystring_value())); + return create_ast_node<MemberExpression>({ m_source_code, rule_start.position(), position() }, move(lhs), create_ast_node<Identifier>({ m_source_code, rule_start.position(), position() }, consume().flystring_value())); case TokenType::BracketOpen: { consume(TokenType::BracketOpen); - auto expression = create_ast_node<MemberExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(lhs), parse_expression(0), true); + auto expression = create_ast_node<MemberExpression>({ m_source_code, rule_start.position(), position() }, move(lhs), parse_expression(0), true); consume(TokenType::BracketClose); return expression; } @@ -2167,7 +2168,7 @@ Parser::ExpressionResult Parser::parse_secondary_expression(NonnullRefPtr<Expres } consume(); - return create_ast_node<UpdateExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UpdateOp::Increment, move(lhs)); + return create_ast_node<UpdateExpression>({ m_source_code, rule_start.position(), position() }, UpdateOp::Increment, move(lhs)); case TokenType::MinusMinus: // FIXME: Apparently for functions this should also not be enforced on a parser level, // other engines throw ReferenceError for foo()-- @@ -2180,24 +2181,24 @@ Parser::ExpressionResult Parser::parse_secondary_expression(NonnullRefPtr<Expres check_identifier_name_for_assignment_validity(name); } consume(); - return create_ast_node<UpdateExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UpdateOp::Decrement, move(lhs)); + return create_ast_node<UpdateExpression>({ m_source_code, rule_start.position(), position() }, UpdateOp::Decrement, move(lhs)); case TokenType::DoubleAmpersand: { consume(); - auto expression = create_ast_node<LogicalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, LogicalOp::And, move(lhs), parse_expression(min_precedence, associativity, forbidden.forbid({ TokenType::DoubleQuestionMark }))); + auto expression = create_ast_node<LogicalExpression>({ m_source_code, rule_start.position(), position() }, LogicalOp::And, move(lhs), parse_expression(min_precedence, associativity, forbidden.forbid({ TokenType::DoubleQuestionMark }))); return { expression, { TokenType::DoubleQuestionMark } }; } case TokenType::DoubleAmpersandEquals: return parse_assignment_expression(AssignmentOp::AndAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::DoublePipe: { consume(); - auto expression = create_ast_node<LogicalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, LogicalOp::Or, move(lhs), parse_expression(min_precedence, associativity, forbidden.forbid({ TokenType::DoubleQuestionMark }))); + auto expression = create_ast_node<LogicalExpression>({ m_source_code, rule_start.position(), position() }, LogicalOp::Or, move(lhs), parse_expression(min_precedence, associativity, forbidden.forbid({ TokenType::DoubleQuestionMark }))); return { expression, { TokenType::DoubleQuestionMark } }; } case TokenType::DoublePipeEquals: return parse_assignment_expression(AssignmentOp::OrAssignment, move(lhs), min_precedence, associativity, forbidden); case TokenType::DoubleQuestionMark: { consume(); - auto expression = create_ast_node<LogicalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, LogicalOp::NullishCoalescing, move(lhs), parse_expression(min_precedence, associativity, forbidden.forbid({ TokenType::DoubleAmpersand, TokenType::DoublePipe }))); + auto expression = create_ast_node<LogicalExpression>({ m_source_code, rule_start.position(), position() }, LogicalOp::NullishCoalescing, move(lhs), parse_expression(min_precedence, associativity, forbidden.forbid({ TokenType::DoubleAmpersand, TokenType::DoublePipe }))); return { expression, { TokenType::DoubleAmpersand, TokenType::DoublePipe } }; } case TokenType::DoubleQuestionMarkEquals: @@ -2216,7 +2217,7 @@ Parser::ExpressionResult Parser::parse_secondary_expression(NonnullRefPtr<Expres default: expected("secondary expression"); consume(); - return create_ast_node<ErrorExpression>({ m_state.current_token.filename(), rule_start.position(), position() }); + return create_ast_node<ErrorExpression>({ m_source_code, rule_start.position(), position() }); } } @@ -2296,7 +2297,7 @@ NonnullRefPtr<AssignmentExpression> Parser::parse_assignment_expression(Assignme if (binding_pattern) { auto rhs = parse_expression(min_precedence, associativity); return create_ast_node<AssignmentExpression>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, assignment_op, binding_pattern.release_nonnull(), move(rhs)); @@ -2312,7 +2313,7 @@ NonnullRefPtr<AssignmentExpression> Parser::parse_assignment_expression(Assignme syntax_error("Cannot assign to function call"); } auto rhs = parse_expression(min_precedence, associativity, forbidden); - return create_ast_node<AssignmentExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, assignment_op, move(lhs), move(rhs)); + return create_ast_node<AssignmentExpression>({ m_source_code, rule_start.position(), position() }, assignment_op, move(lhs), move(rhs)); } NonnullRefPtr<Identifier> Parser::parse_identifier() @@ -2322,7 +2323,7 @@ NonnullRefPtr<Identifier> Parser::parse_identifier() if (m_state.in_class_field_initializer && token.value() == "arguments"sv) syntax_error("'arguments' is not allowed in class field initializer"); return create_ast_node<Identifier>( - { m_state.current_token.filename(), identifier_start, position() }, + { m_source_code, identifier_start, position() }, token.flystring_value()); } @@ -2356,9 +2357,9 @@ NonnullRefPtr<Expression> Parser::parse_call_expression(NonnullRefPtr<Expression auto arguments = parse_arguments(); if (is<SuperExpression>(*lhs)) - return create_ast_node<SuperCall>({ m_state.current_token.filename(), rule_start.position(), position() }, move(arguments)); + return create_ast_node<SuperCall>({ m_source_code, rule_start.position(), position() }, move(arguments)); - return create_ast_node<CallExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(lhs), move(arguments)); + return create_ast_node<CallExpression>({ m_source_code, rule_start.position(), position() }, move(lhs), move(arguments)); } NonnullRefPtr<NewExpression> Parser::parse_new_expression() @@ -2388,7 +2389,7 @@ NonnullRefPtr<NewExpression> Parser::parse_new_expression() consume(TokenType::ParenClose); } - return create_ast_node<NewExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(callee), move(arguments)); + return create_ast_node<NewExpression>({ m_source_code, rule_start.position(), position() }, move(callee), move(arguments)); } NonnullRefPtr<YieldExpression> Parser::parse_yield_expression() @@ -2412,7 +2413,7 @@ NonnullRefPtr<YieldExpression> Parser::parse_yield_expression() argument = parse_expression(2); } - return create_ast_node<YieldExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(argument), yield_from); + return create_ast_node<YieldExpression>({ m_source_code, rule_start.position(), position() }, move(argument), yield_from); } NonnullRefPtr<AwaitExpression> Parser::parse_await_expression() @@ -2430,7 +2431,7 @@ NonnullRefPtr<AwaitExpression> Parser::parse_await_expression() m_state.current_scope_pusher->set_contains_await_expression(); - return create_ast_node<AwaitExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(argument)); + return create_ast_node<AwaitExpression>({ m_source_code, rule_start.position(), position() }, move(argument)); } NonnullRefPtr<ReturnStatement> Parser::parse_return_statement() @@ -2443,16 +2444,16 @@ NonnullRefPtr<ReturnStatement> Parser::parse_return_statement() // Automatic semicolon insertion: terminate statement when return is followed by newline if (m_state.current_token.trivia_contains_line_terminator()) - return create_ast_node<ReturnStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, nullptr); + return create_ast_node<ReturnStatement>({ m_source_code, rule_start.position(), position() }, nullptr); if (match_expression()) { auto expression = parse_expression(0); consume_or_insert_semicolon(); - return create_ast_node<ReturnStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(expression)); + return create_ast_node<ReturnStatement>({ m_source_code, rule_start.position(), position() }, move(expression)); } consume_or_insert_semicolon(); - return create_ast_node<ReturnStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, nullptr); + return create_ast_node<ReturnStatement>({ m_source_code, rule_start.position(), position() }, nullptr); } void Parser::parse_statement_list(ScopeNode& output_node, AllowLabelledFunction allow_labelled_functions) @@ -2475,7 +2476,7 @@ void Parser::parse_statement_list(ScopeNode& output_node, AllowLabelledFunction NonnullRefPtr<FunctionBody> Parser::parse_function_body(Vector<FunctionDeclaration::Parameter> const& parameters, FunctionKind function_kind, bool& contains_direct_call_to_eval) { auto rule_start = push_start(); - auto function_body = create_ast_node<FunctionBody>({ m_state.current_token.filename(), rule_start.position(), position() }); + auto function_body = create_ast_node<FunctionBody>({ m_source_code, rule_start.position(), position() }); ScopePusher function_scope = ScopePusher::function_scope(*this, function_body, parameters); // FIXME <- auto has_use_strict = parse_directive(function_body); bool previous_strict_mode = m_state.strict_mode; @@ -2544,7 +2545,7 @@ NonnullRefPtr<FunctionBody> Parser::parse_function_body(Vector<FunctionDeclarati NonnullRefPtr<BlockStatement> Parser::parse_block_statement() { auto rule_start = push_start(); - auto block = create_ast_node<BlockStatement>({ m_state.current_token.filename(), rule_start.position(), position() }); + auto block = create_ast_node<BlockStatement>({ m_source_code, rule_start.position(), position() }); ScopePusher block_scope = ScopePusher::block_scope(*this, block); consume(TokenType::CurlyOpen); parse_statement_list(block); @@ -2640,7 +2641,7 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u16 parse_options, O auto function_end_offset = position().offset - m_state.current_token.trivia().length(); auto source_text = String { m_state.lexer.source().substring_view(function_start_offset, function_end_offset - function_start_offset) }; return create_ast_node<FunctionNodeType>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, name, move(source_text), move(body), move(parameters), function_length, function_kind, has_strict_directive, m_state.function_might_need_arguments_object, contains_direct_call_to_eval); @@ -2800,17 +2801,17 @@ RefPtr<BindingPattern> Parser::parse_binding_pattern(Parser::AllowDuplicates all auto string_literal = parse_string_literal(token); name = create_ast_node<Identifier>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, string_literal->value()); } else if (match(TokenType::BigIntLiteral)) { auto string_value = consume().flystring_value(); VERIFY(string_value.ends_with("n"sv)); name = create_ast_node<Identifier>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, FlyString(string_value.view().substring_view(0, string_value.length() - 1))); } else { name = create_ast_node<Identifier>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, consume().flystring_value()); } } else if (match(TokenType::BracketOpen)) { @@ -2848,7 +2849,7 @@ RefPtr<BindingPattern> Parser::parse_binding_pattern(Parser::AllowDuplicates all alias = binding_pattern.release_nonnull(); } else if (match_identifier_name()) { alias = create_ast_node<Identifier>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, consume().flystring_value()); } else { @@ -2887,7 +2888,7 @@ RefPtr<BindingPattern> Parser::parse_binding_pattern(Parser::AllowDuplicates all // BindingElement must always have an Empty name field auto identifier_name = consume_identifier().flystring_value(); alias = create_ast_node<Identifier>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, identifier_name); } else { expected("identifier or binding pattern"); @@ -2973,7 +2974,7 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(bool for_l auto identifier_start = push_start(); auto name = consume_identifier().flystring_value(); target = create_ast_node<Identifier>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, name); check_identifier_name_for_assignment_validity(name); if ((declaration_kind == DeclarationKind::Let || declaration_kind == DeclarationKind::Const) && name == "let"sv) @@ -2992,14 +2993,14 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(bool for_l syntax_error("Identifier must not be a reserved word in strict mode ('yield')"); target = create_ast_node<Identifier>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, consume().flystring_value()); } else if (!m_state.await_expression_is_valid && match(TokenType::Async)) { if (m_program_type == Program::Type::Module) syntax_error("Identifier must not be a reserved word in modules ('async')"); target = create_ast_node<Identifier>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, consume().flystring_value()); } @@ -3028,7 +3029,7 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(bool for_l } declarations.append(create_ast_node<VariableDeclarator>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, move(target).downcast<NonnullRefPtr<Identifier>, NonnullRefPtr<BindingPattern>>(), move(init))); @@ -3041,7 +3042,7 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(bool for_l if (!for_loop_variable_declaration) consume_or_insert_semicolon(); - auto declaration = create_ast_node<VariableDeclaration>({ m_state.current_token.filename(), rule_start.position(), position() }, declaration_kind, move(declarations)); + auto declaration = create_ast_node<VariableDeclaration>({ m_source_code, rule_start.position(), position() }, declaration_kind, move(declarations)); return declaration; } @@ -3053,12 +3054,12 @@ NonnullRefPtr<ThrowStatement> Parser::parse_throw_statement() // Automatic semicolon insertion: terminate statement when throw is followed by newline if (m_state.current_token.trivia_contains_line_terminator()) { syntax_error("No line break is allowed between 'throw' and its expression"); - return create_ast_node<ThrowStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, create_ast_node<ErrorExpression>({ m_state.current_token.filename(), rule_start.position(), position() })); + return create_ast_node<ThrowStatement>({ m_source_code, rule_start.position(), position() }, create_ast_node<ErrorExpression>({ m_source_code, rule_start.position(), position() })); } auto expression = parse_expression(0); consume_or_insert_semicolon(); - return create_ast_node<ThrowStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(expression)); + return create_ast_node<ThrowStatement>({ m_source_code, rule_start.position(), position() }, move(expression)); } NonnullRefPtr<BreakStatement> Parser::parse_break_statement() @@ -3082,7 +3083,7 @@ NonnullRefPtr<BreakStatement> Parser::parse_break_statement() if (target_label.is_null() && !m_state.in_break_context) syntax_error("Unlabeled 'break' not allowed outside of a loop or switch statement"); - return create_ast_node<BreakStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, target_label); + return create_ast_node<BreakStatement>({ m_source_code, rule_start.position(), position() }, target_label); } NonnullRefPtr<ContinueStatement> Parser::parse_continue_statement() @@ -3095,7 +3096,7 @@ NonnullRefPtr<ContinueStatement> Parser::parse_continue_statement() FlyString target_label; if (match(TokenType::Semicolon)) { consume(); - return create_ast_node<ContinueStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, target_label); + return create_ast_node<ContinueStatement>({ m_source_code, rule_start.position(), position() }, target_label); } if (!m_state.current_token.trivia_contains_line_terminator() && match_identifier()) { auto label_position = position(); @@ -3108,7 +3109,7 @@ NonnullRefPtr<ContinueStatement> Parser::parse_continue_statement() label->value = label_position; } consume_or_insert_semicolon(); - return create_ast_node<ContinueStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, target_label); + return create_ast_node<ContinueStatement>({ m_source_code, rule_start.position(), position() }, target_label); } NonnullRefPtr<ConditionalExpression> Parser::parse_conditional_expression(NonnullRefPtr<Expression> test, ForbiddenTokens forbidden) @@ -3118,7 +3119,7 @@ NonnullRefPtr<ConditionalExpression> Parser::parse_conditional_expression(Nonnul auto consequent = parse_expression(2); consume(TokenType::Colon); auto alternate = parse_expression(2, Associativity::Right, forbidden); - return create_ast_node<ConditionalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(test), move(consequent), move(alternate)); + return create_ast_node<ConditionalExpression>({ m_source_code, rule_start.position(), position() }, move(test), move(consequent), move(alternate)); } NonnullRefPtr<OptionalChain> Parser::parse_optional_chain(NonnullRefPtr<Expression> base) @@ -3144,7 +3145,7 @@ NonnullRefPtr<OptionalChain> Parser::parse_optional_chain(NonnullRefPtr<Expressi auto start = position(); auto private_identifier = consume(); chain.append(OptionalChain::PrivateMemberReference { - create_ast_node<PrivateIdentifier>({ m_state.current_token.filename(), start, position() }, private_identifier.value()), + create_ast_node<PrivateIdentifier>({ m_source_code, start, position() }, private_identifier.value()), OptionalChain::Mode::Optional }); break; } @@ -3161,7 +3162,7 @@ NonnullRefPtr<OptionalChain> Parser::parse_optional_chain(NonnullRefPtr<Expressi auto start = position(); auto identifier = consume(); chain.append(OptionalChain::MemberReference { - create_ast_node<Identifier>({ m_state.current_token.filename(), start, position() }, identifier.flystring_value()), + create_ast_node<Identifier>({ m_source_code, start, position() }, identifier.flystring_value()), OptionalChain::Mode::Optional, }); } else { @@ -3180,14 +3181,14 @@ NonnullRefPtr<OptionalChain> Parser::parse_optional_chain(NonnullRefPtr<Expressi auto start = position(); auto private_identifier = consume(); chain.append(OptionalChain::PrivateMemberReference { - create_ast_node<PrivateIdentifier>({ m_state.current_token.filename(), start, position() }, private_identifier.value()), + create_ast_node<PrivateIdentifier>({ m_source_code, start, position() }, private_identifier.value()), OptionalChain::Mode::NotOptional, }); } else if (match_identifier_name()) { auto start = position(); auto identifier = consume(); chain.append(OptionalChain::MemberReference { - create_ast_node<Identifier>({ m_state.current_token.filename(), start, position() }, identifier.flystring_value()), + create_ast_node<Identifier>({ m_source_code, start, position() }, identifier.flystring_value()), OptionalChain::Mode::NotOptional, }); } else { @@ -3211,7 +3212,7 @@ NonnullRefPtr<OptionalChain> Parser::parse_optional_chain(NonnullRefPtr<Expressi } while (!done()); return create_ast_node<OptionalChain>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, move(base), move(chain)); } @@ -3236,7 +3237,7 @@ NonnullRefPtr<TryStatement> Parser::parse_try_statement() if (!handler && !finalizer) syntax_error("try statement must have a 'catch' or 'finally' clause"); - return create_ast_node<TryStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(block), move(handler), move(finalizer)); + return create_ast_node<TryStatement>({ m_source_code, rule_start.position(), position() }, move(block), move(handler), move(finalizer)); } NonnullRefPtr<DoWhileStatement> Parser::parse_do_while_statement() @@ -3261,7 +3262,7 @@ NonnullRefPtr<DoWhileStatement> Parser::parse_do_while_statement() if (match(TokenType::Semicolon)) consume(); - return create_ast_node<DoWhileStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(test), move(body)); + return create_ast_node<DoWhileStatement>({ m_source_code, rule_start.position(), position() }, move(test), move(body)); } NonnullRefPtr<WhileStatement> Parser::parse_while_statement() @@ -3278,7 +3279,7 @@ NonnullRefPtr<WhileStatement> Parser::parse_while_statement() TemporaryChange continue_change(m_state.in_continue_context, true); auto body = parse_statement(); - return create_ast_node<WhileStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(test), move(body)); + return create_ast_node<WhileStatement>({ m_source_code, rule_start.position(), position() }, move(test), move(body)); } NonnullRefPtr<SwitchStatement> Parser::parse_switch_statement() @@ -3294,7 +3295,7 @@ NonnullRefPtr<SwitchStatement> Parser::parse_switch_statement() NonnullRefPtrVector<SwitchCase> cases; - auto switch_statement = create_ast_node<SwitchStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(determinant)); + auto switch_statement = create_ast_node<SwitchStatement>({ m_source_code, rule_start.position(), position() }, move(determinant)); ScopePusher switch_scope = ScopePusher::block_scope(*this, switch_statement); @@ -3324,7 +3325,7 @@ NonnullRefPtr<WithStatement> Parser::parse_with_statement() consume(TokenType::ParenClose); auto body = parse_statement(); - return create_ast_node<WithStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(object), move(body)); + return create_ast_node<WithStatement>({ m_source_code, rule_start.position(), position() }, move(object), move(body)); } NonnullRefPtr<SwitchCase> Parser::parse_switch_case() @@ -3340,7 +3341,7 @@ NonnullRefPtr<SwitchCase> Parser::parse_switch_case() NonnullRefPtrVector<Statement> consequent; TemporaryChange break_change(m_state.in_break_context, true); - auto switch_case = create_ast_node<SwitchCase>({ m_state.current_token.filename(), rule_start.position(), position() }, move(test)); + auto switch_case = create_ast_node<SwitchCase>({ m_source_code, rule_start.position(), position() }, move(test)); parse_statement_list(switch_case); return switch_case; @@ -3395,13 +3396,13 @@ NonnullRefPtr<CatchClause> Parser::parse_catch_clause() if (pattern_parameter) { return create_ast_node<CatchClause>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, pattern_parameter.release_nonnull(), move(body)); } return create_ast_node<CatchClause>( - { m_state.current_token.filename(), rule_start.position(), position() }, + { m_source_code, rule_start.position(), position() }, move(parameter), move(body)); } @@ -3418,7 +3419,7 @@ NonnullRefPtr<IfStatement> Parser::parse_if_statement() // The semantics of such a synthetic BlockStatement includes the web legacy // compatibility semantics specified in B.3.2. VERIFY(match(TokenType::Function)); - auto block = create_ast_node<BlockStatement>({ m_state.current_token.filename(), rule_start.position(), position() }); + auto block = create_ast_node<BlockStatement>({ m_source_code, rule_start.position(), position() }); ScopePusher block_scope = ScopePusher::block_scope(*this, *block); auto declaration = parse_declaration(); VERIFY(m_state.current_scope_pusher); @@ -3453,7 +3454,7 @@ NonnullRefPtr<IfStatement> Parser::parse_if_statement() else alternate = parse_statement(); } - return create_ast_node<IfStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(predicate), move(*consequent), move(alternate)); + return create_ast_node<IfStatement>({ m_source_code, rule_start.position(), position() }, move(predicate), move(*consequent), move(alternate)); } NonnullRefPtr<Statement> Parser::parse_for_statement() @@ -3549,7 +3550,7 @@ NonnullRefPtr<Statement> Parser::parse_for_statement() ScopePusher for_loop_scope = ScopePusher::for_loop_scope(*this, init); auto body = parse_statement(); - return create_ast_node<ForStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(init), move(test), move(update), move(body)); + return create_ast_node<ForStatement>({ m_source_code, rule_start.position(), position() }, move(init), move(test), move(update), move(body)); } NonnullRefPtr<Statement> Parser::parse_for_in_of_statement(NonnullRefPtr<ASTNode> lhs, IsForAwaitLoop is_for_await_loop) @@ -3608,10 +3609,10 @@ NonnullRefPtr<Statement> Parser::parse_for_in_of_statement(NonnullRefPtr<ASTNode ScopePusher for_loop_scope = ScopePusher::for_loop_scope(*this, lhs); auto body = parse_statement(); if (is_in) - return create_ast_node<ForInStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(for_declaration), move(rhs), move(body)); + return create_ast_node<ForInStatement>({ m_source_code, rule_start.position(), position() }, move(for_declaration), move(rhs), move(body)); if (is_for_await_loop == IsForAwaitLoop::Yes) - return create_ast_node<ForAwaitOfStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(for_declaration), move(rhs), move(body)); - return create_ast_node<ForOfStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(for_declaration), move(rhs), move(body)); + return create_ast_node<ForAwaitOfStatement>({ m_source_code, rule_start.position(), position() }, move(for_declaration), move(rhs), move(body)); + return create_ast_node<ForOfStatement>({ m_source_code, rule_start.position(), position() }, move(for_declaration), move(rhs), move(body)); } NonnullRefPtr<DebuggerStatement> Parser::parse_debugger_statement() @@ -3619,7 +3620,7 @@ NonnullRefPtr<DebuggerStatement> Parser::parse_debugger_statement() auto rule_start = push_start(); consume(TokenType::Debugger); consume_or_insert_semicolon(); - return create_ast_node<DebuggerStatement>({ m_state.current_token.filename(), rule_start.position(), position() }); + return create_ast_node<DebuggerStatement>({ m_source_code, rule_start.position(), position() }); } bool Parser::match(TokenType type) const @@ -4162,7 +4163,7 @@ NonnullRefPtr<ImportStatement> Parser::parse_import_statement(Program& program) if (match(TokenType::StringLiteral)) { // import ModuleSpecifier ; auto module_request = parse_module_request(); - return create_ast_node<ImportStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(module_request)); + return create_ast_node<ImportStatement>({ m_source_code, rule_start.position(), position() }, move(module_request)); } auto match_imported_binding = [&] { @@ -4302,7 +4303,7 @@ NonnullRefPtr<ImportStatement> Parser::parse_import_statement(Program& program) entries.append(move(entry.entry)); } - return create_ast_node<ImportStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(module_request), move(entries)); + return create_ast_node<ImportStatement>({ m_source_code, rule_start.position(), position() }, move(module_request), move(entries)); } NonnullRefPtr<ExportStatement> Parser::parse_export_statement(Program& program) @@ -4603,7 +4604,7 @@ NonnullRefPtr<ExportStatement> Parser::parse_export_statement(Program& program) entries.append(move(entry.entry)); } - return create_ast_node<ExportStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(expression), move(entries), is_default, move(from_specifier)); + return create_ast_node<ExportStatement>({ m_source_code, rule_start.position(), position() }, move(expression), move(entries), is_default, move(from_specifier)); } Parser::ForbiddenTokens::ForbiddenTokens(std::initializer_list<TokenType> const& forbidden) diff --git a/Userland/Libraries/LibJS/Parser.h b/Userland/Libraries/LibJS/Parser.h index 4e9b904aaa..9d00032463 100644 --- a/Userland/Libraries/LibJS/Parser.h +++ b/Userland/Libraries/LibJS/Parser.h @@ -343,6 +343,7 @@ private: } }; + NonnullRefPtr<SourceCode> m_source_code; Vector<Position> m_rule_starts; ParserState m_state; FlyString m_filename; diff --git a/Userland/Libraries/LibJS/Runtime/Error.cpp b/Userland/Libraries/LibJS/Runtime/Error.cpp index 25642c4564..5c2946cd27 100644 --- a/Userland/Libraries/LibJS/Runtime/Error.cpp +++ b/Userland/Libraries/LibJS/Runtime/Error.cpp @@ -54,6 +54,8 @@ ThrowCompletionOr<void> Error::install_error_cause(Value options) void Error::populate_stack() { + static auto dummy_source_range = SourceRange { .code = SourceCode::create("", ""), .start = {}, .end = {} }; + auto& vm = this->vm(); m_traceback.ensure_capacity(vm.execution_context_stack().size()); for (ssize_t i = vm.execution_context_stack().size() - 1; i >= 0; i--) { @@ -67,7 +69,7 @@ void Error::populate_stack() // reaction jobs (which aren't called anywhere from the source code). // They're not going to generate any _unhandled_ exceptions though, so a meaningless // source range is fine. - context->current_node ? context->current_node->source_range() : SourceRange {}); + context->current_node ? context->current_node->source_range() : dummy_source_range); } } @@ -82,12 +84,12 @@ String Error::stack_string() const auto const& frame = m_traceback[i]; auto function_name = frame.function_name; // Note: Since we don't know whether we have a valid SourceRange here we just check for some default values. - if (!frame.source_range.filename.is_null() || frame.source_range.start.offset != 0 || frame.source_range.end.offset != 0) { + if (!frame.source_range.filename().is_null() || frame.source_range.start.offset != 0 || frame.source_range.end.offset != 0) { if (function_name == "<unknown>"sv) - stack_string_builder.appendff(" at {}:{}:{}\n", frame.source_range.filename, frame.source_range.start.line, frame.source_range.start.column); + stack_string_builder.appendff(" at {}:{}:{}\n", frame.source_range.filename(), frame.source_range.start.line, frame.source_range.start.column); else - stack_string_builder.appendff(" at {} ({}:{}:{})\n", function_name, frame.source_range.filename, frame.source_range.start.line, frame.source_range.start.column); + stack_string_builder.appendff(" at {} ({}:{}:{})\n", function_name, frame.source_range.filename(), frame.source_range.start.line, frame.source_range.start.column); } else { stack_string_builder.appendff(" at {}\n", function_name.is_empty() ? "<unknown>"sv : function_name.view()); } diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index 5a2a72cb4d..ccf701f154 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -728,8 +728,8 @@ void VM::dump_backtrace() const for (ssize_t i = m_execution_context_stack.size() - 1; i >= 0; --i) { auto& frame = m_execution_context_stack[i]; if (frame->current_node) { - auto& source_range = frame->current_node->source_range(); - dbgln("-> {} @ {}:{},{}", frame->function_name, source_range.filename, source_range.start.line, source_range.start.column); + auto source_range = frame->current_node->source_range(); + dbgln("-> {} @ {}:{},{}", frame->function_name, source_range.filename(), source_range.start.line, source_range.start.column); } else { dbgln("-> {}", frame->function_name); } diff --git a/Userland/Libraries/LibJS/SourceCode.cpp b/Userland/Libraries/LibJS/SourceCode.cpp new file mode 100644 index 0000000000..89a844f3e3 --- /dev/null +++ b/Userland/Libraries/LibJS/SourceCode.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Utf8View.h> +#include <LibJS/SourceCode.h> +#include <LibJS/SourceRange.h> +#include <LibJS/Token.h> + +namespace JS { + +NonnullRefPtr<SourceCode> SourceCode::create(String filename, String code) +{ + return adopt_ref(*new SourceCode(move(filename), move(code))); +} + +SourceCode::SourceCode(String filename, String code) + : m_filename(move(filename)) + , m_code(move(code)) +{ +} + +String const& SourceCode::filename() const +{ + return m_filename; +} + +String const& SourceCode::code() const +{ + return m_code; +} + +SourceRange SourceCode::range_from_offsets(u32 start_offset, u32 end_offset) const +{ + Position start; + Position end; + + size_t line = 1; + size_t column = 1; + + bool previous_code_point_was_carriage_return = false; + + Utf8View view(m_code); + for (auto it = view.begin(); it != view.end(); ++it) { + + if (start_offset == view.byte_offset_of(it)) { + start = Position { + .line = line, + .column = column, + .offset = start_offset, + }; + } + + if (end_offset == view.byte_offset_of(it)) { + end = Position { + .line = line, + .column = column, + .offset = end_offset, + }; + break; + } + + u32 code_point = *it; + + bool is_line_terminator = code_point == '\r' || (code_point == '\n' && !previous_code_point_was_carriage_return) || code_point == LINE_SEPARATOR || code_point == PARAGRAPH_SEPARATOR; + previous_code_point_was_carriage_return = code_point == '\r'; + + if (is_line_terminator) { + ++line; + column = 1; + continue; + } + ++column; + } + + return SourceRange { *this, start, end }; +} + +} diff --git a/Userland/Libraries/LibJS/SourceCode.h b/Userland/Libraries/LibJS/SourceCode.h new file mode 100644 index 0000000000..3980efed69 --- /dev/null +++ b/Userland/Libraries/LibJS/SourceCode.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/String.h> +#include <LibJS/Forward.h> + +namespace JS { + +class SourceCode : public RefCounted<SourceCode> { +public: + static NonnullRefPtr<SourceCode> create(String filename, String code); + + String const& filename() const; + String const& code() const; + + SourceRange range_from_offsets(u32 start_offset, u32 end_offset) const; + +private: + SourceCode(String filename, String code); + + String m_filename; + String m_code; +}; + +} diff --git a/Userland/Libraries/LibJS/SourceRange.h b/Userland/Libraries/LibJS/SourceRange.h index 485e2b2a61..b3e9377fc8 100644 --- a/Userland/Libraries/LibJS/SourceRange.h +++ b/Userland/Libraries/LibJS/SourceRange.h @@ -8,6 +8,7 @@ #include <AK/StringView.h> #include <AK/Types.h> +#include <LibJS/SourceCode.h> namespace JS { @@ -20,9 +21,11 @@ struct Position { struct SourceRange { [[nodiscard]] bool contains(Position const& position) const { return position.offset <= end.offset && position.offset >= start.offset; } - StringView filename; + NonnullRefPtr<SourceCode> code; Position start; Position end; + + String const& filename() const; }; } diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/ExceptionReporter.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/ExceptionReporter.cpp index cb2fa3edd9..e50078e773 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/ExceptionReporter.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/ExceptionReporter.cpp @@ -34,7 +34,7 @@ void report_exception_to_console(JS::Value value, JS::Realm& realm, ErrorInPromi for (auto& traceback_frame : error_value.traceback()) { auto& function_name = traceback_frame.function_name; auto& source_range = traceback_frame.source_range; - dbgln(" {} at {}:{}:{}", function_name, source_range.filename, source_range.start.line, source_range.start.column); + dbgln(" {} at {}:{}:{}", function_name, source_range.filename(), source_range.start.line, source_range.start.column); } console.report_exception(error_value, error_in_promise == ErrorInPromise::Yes); |