diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index a6a1e5c764..696c36cb84 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -1852,7 +1852,7 @@ Completion ClassExpression::execute(Interpreter& interpreter) const // 1. Let className be StringValue of BindingIdentifier. // 2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments className and className. - auto* value = TRY(class_definition_evaluation(interpreter.vm(), m_name, m_name.is_null() ? "" : m_name)); + auto* value = TRY(class_definition_evaluation(interpreter.vm(), name(), name())); // 3. Set value.[[SourceText]] to the source text matched by ClassExpression. value->set_source_text(m_source_text); @@ -2311,7 +2311,7 @@ ThrowCompletionOr ClassDeclaration::for_each_bound_name(ThrowCompletionOrV void ClassExpression::dump(int indent) const { print_indent(indent); - outln("ClassExpression: \"{}\"", m_name); + outln("ClassExpression: \"{}\"", name()); print_indent(indent); outln("(Constructor)"); diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index ef77764ebf..490cd12560 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -1405,7 +1405,7 @@ public: class ClassExpression final : public Expression { public: - ClassExpression(SourceRange source_range, DeprecatedString name, DeprecatedString source_text, RefPtr constructor, RefPtr super_class, Vector> elements) + ClassExpression(SourceRange source_range, RefPtr name, DeprecatedString source_text, RefPtr constructor, RefPtr super_class, Vector> elements) : Expression(source_range) , m_name(move(name)) , m_source_text(move(source_text)) @@ -1415,7 +1415,8 @@ public: { } - StringView name() const { return m_name; } + StringView name() const { return m_name ? m_name->string().view() : ""sv; } + DeprecatedString const& source_text() const { return m_source_text; } RefPtr constructor() const { return m_constructor; } @@ -1424,7 +1425,7 @@ public: virtual Bytecode::CodeGenerationErrorOr generate_bytecode(Bytecode::Generator&) const override; virtual Bytecode::CodeGenerationErrorOr generate_bytecode_with_lhs_name(Bytecode::Generator&, Optional lhs_name) const; - bool has_name() const { return !m_name.is_empty(); } + bool has_name() const { return m_name; } ThrowCompletionOr class_definition_evaluation(VM&, DeprecatedFlyString const& binding_name = {}, DeprecatedFlyString const& class_name = {}) const; ThrowCompletionOr create_class_constructor(VM&, Environment* class_environment, Environment* environment, Value super_class, DeprecatedFlyString const& binding_name = {}, DeprecatedFlyString const& class_name = {}) const; @@ -1432,7 +1433,7 @@ public: private: virtual bool is_class_expression() const override { return true; } - DeprecatedString m_name; + RefPtr m_name; DeprecatedString m_source_text; RefPtr m_constructor; RefPtr m_super_class; diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index fe9103ba31..688b75aa89 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -2323,7 +2323,7 @@ Bytecode::CodeGenerationErrorOr ClassExpression::generate_bytecode_with_lh if (has_name() || !lhs_name.has_value()) { // NOTE: Step 3.a is not a part of NewClass instruction because it is assumed to be done before super class expression evaluation - auto interned_index = generator.intern_identifier(m_name); + auto interned_index = generator.intern_identifier(name()); generator.emit(interned_index, Bytecode::Op::EnvironmentMode::Lexical, true); } diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index 518275399d..34a3e401f2 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -1071,12 +1071,17 @@ NonnullRefPtr Parser::parse_class_expression(bool expect_ RefPtr constructor; HashTable found_private_names; - DeprecatedFlyString class_name = expect_class_name || match_identifier() || match(TokenType::Yield) || match(TokenType::Await) - ? consume_identifier_reference().DeprecatedFlyString_value() - : ""; + RefPtr class_name { nullptr }; + if (expect_class_name || match_identifier() || match(TokenType::Yield) || match(TokenType::Await)) { + class_name = create_ast_node( + { m_source_code, rule_start.position(), position() }, + consume_identifier_reference().DeprecatedFlyString_value() + ); + } - check_identifier_name_for_assignment_validity(class_name, true); - if (m_state.in_class_static_init_block && class_name == "await"sv) + if (class_name) + check_identifier_name_for_assignment_validity(class_name->string(), true); + if (m_state.in_class_static_init_block && class_name && class_name->string() == "await"sv) syntax_error("Identifier must not be a reserved word in modules ('await')"); if (match(TokenType::Extends)) { @@ -1365,12 +1370,12 @@ NonnullRefPtr Parser::parse_class_expression(bool expect_ constructor_body->append(create_ast_node({ m_source_code, rule_start.position(), position() }, move(super_call))); constructor = create_ast_node( - { m_source_code, rule_start.position(), position() }, class_name, "", + { m_source_code, rule_start.position(), position() }, class_name ? class_name->string() : "", "", move(constructor_body), Vector { FunctionParameter { 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( - { m_source_code, rule_start.position(), position() }, class_name, "", + { m_source_code, rule_start.position(), position() }, class_name ? class_name->string() : "", "", move(constructor_body), Vector {}, 0, FunctionKind::Normal, /* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false); }