diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index 23d7de88367..f8ab09a7a7f 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -372,7 +372,7 @@ ThrowCompletionOr CallExpression::compute_this_an } // 13.3.8.1 Runtime Semantics: ArgumentListEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-argumentlistevaluation -static ThrowCompletionOr argument_list_evaluation(Interpreter& interpreter, Vector const& arguments, MarkedVector& list) +static ThrowCompletionOr argument_list_evaluation(Interpreter& interpreter, Span const arguments, MarkedVector& list) { auto& vm = interpreter.vm(); list.ensure_capacity(arguments.size()); @@ -406,7 +406,7 @@ Completion NewExpression::execute(Interpreter& interpreter) const // 4. Else, // a. Let argList be ? ArgumentListEvaluation of arguments. MarkedVector arg_list(vm.heap()); - TRY(argument_list_evaluation(interpreter, m_arguments, arg_list)); + TRY(argument_list_evaluation(interpreter, arguments(), arg_list)); // 5. If IsConstructor(constructor) is false, throw a TypeError exception. if (!constructor.is_constructor()) @@ -451,7 +451,7 @@ Completion CallExpression::execute(Interpreter& interpreter) const VERIFY(!callee.is_empty()); MarkedVector arg_list(vm.heap()); - TRY(argument_list_evaluation(interpreter, m_arguments, arg_list)); + TRY(argument_list_evaluation(interpreter, arguments(), arg_list)); if (!callee.is_function()) return throw_type_error_for_callee(interpreter, callee, "function"sv); @@ -2183,7 +2183,7 @@ void CallExpression::dump(int indent) const else outln("CallExpression"); m_callee->dump(indent + 1); - for (auto& argument : m_arguments) + for (auto& argument : arguments()) argument.value->dump(indent + 1); } @@ -3216,7 +3216,7 @@ ThrowCompletionOr OptionalChain::to_reference_ auto expression = reference.visit( [&](Call const& call) -> NonnullRefPtr { - return create_ast_node(source_range(), + return CallExpression::create(source_range(), create_ast_node(source_range(), base_reference, base), call.arguments); }, @@ -4823,4 +4823,14 @@ DeprecatedString const& SourceRange::filename() const return code->filename(); } +NonnullRefPtr CallExpression::create(SourceRange source_range, NonnullRefPtr callee, Span arguments) +{ + return ASTNodeWithTailArray::create(arguments.size(), move(source_range), move(callee), arguments); +} + +NonnullRefPtr NewExpression::create(SourceRange source_range, NonnullRefPtr callee, Span arguments) +{ + return ASTNodeWithTailArray::create(arguments.size(), move(source_range), move(callee), arguments); +} + } diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index fa1b8dca007..27482d3cd91 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -1472,19 +1472,18 @@ public: virtual Bytecode::CodeGenerationErrorOr generate_bytecode(Bytecode::Generator&) const override; }; -class CallExpression : public Expression { -public: - struct Argument { - NonnullRefPtr value; - bool is_spread; - }; +struct CallExpressionArgument { + NonnullRefPtr value; + bool is_spread; +}; - CallExpression(SourceRange source_range, NonnullRefPtr callee, Vector arguments = {}) - : Expression(source_range) - , m_callee(move(callee)) - , m_arguments(move(arguments)) - { - } +class CallExpression : public ASTNodeWithTailArray { + friend class ASTNodeWithTailArray; + +public: + using Argument = CallExpressionArgument; + + static NonnullRefPtr create(SourceRange, NonnullRefPtr callee, Span arguments); virtual Completion execute(Interpreter&) const override; virtual void dump(int indent) const override; @@ -1492,6 +1491,22 @@ public: Expression const& callee() const { return m_callee; } + Span arguments() const { return tail_span(); } + +protected: + CallExpression(SourceRange source_range, NonnullRefPtr callee, Span arguments) + : ASTNodeWithTailArray(move(source_range), arguments) + , m_callee(move(callee)) + { + } + +private: + struct ThisAndCallee { + Value this_value; + Value callee; + }; + ThrowCompletionOr compute_this_and_callee(Interpreter&, Reference const&) const; + protected: virtual bool is_call_expression() const override { return true; } @@ -1499,28 +1514,27 @@ protected: Optional expression_string() const; NonnullRefPtr m_callee; - Vector const m_arguments; - -private: - struct ThisAndCallee { - Value this_value; - Value callee; - }; - ThrowCompletionOr compute_this_and_callee(Interpreter&, Reference const&) const; }; class NewExpression final : public CallExpression { + friend class ASTNodeWithTailArray; + public: - NewExpression(SourceRange source_range, NonnullRefPtr callee, Vector arguments = {}) - : CallExpression(source_range, move(callee), move(arguments)) - { - } + static NonnullRefPtr create(SourceRange, NonnullRefPtr callee, Span arguments); virtual Completion execute(Interpreter&) const override; virtual bool is_new_expression() const override { return true; } + +private: + NewExpression(SourceRange source_range, NonnullRefPtr callee, Span arguments) + : CallExpression(move(source_range), move(callee), arguments) + { + } }; +static_assert(sizeof(NewExpression) == sizeof(CallExpression), "Adding members to NewExpression will break CallExpression memory layout"); + class SuperCall final : public Expression { public: // This is here to be able to make a constructor like diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 33052b30ee7..9b2587ae292 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -1551,7 +1551,7 @@ Bytecode::CodeGenerationErrorOr CallExpression::generate_bytecode(Bytecode generator.emit(callee_reg); } - TRY(arguments_to_array_for_call(generator, m_arguments)); + TRY(arguments_to_array_for_call(generator, arguments())); Bytecode::Op::Call::CallType call_type; if (is(*this)) { diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index bf5dfd21eab..a6066907a17 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -2350,7 +2350,7 @@ NonnullRefPtr Parser::parse_call_expression(NonnullRefPtr(*lhs)) return create_ast_node({ m_source_code, rule_start.position(), position() }, move(arguments)); - return create_ast_node({ m_source_code, rule_start.position(), position() }, move(lhs), move(arguments)); + return CallExpression::create({ m_source_code, rule_start.position(), position() }, move(lhs), arguments.span()); } NonnullRefPtr Parser::parse_new_expression() @@ -2380,7 +2380,7 @@ NonnullRefPtr Parser::parse_new_expression() consume(TokenType::ParenClose); } - return create_ast_node({ m_source_code, rule_start.position(), position() }, move(callee), move(arguments)); + return NewExpression::create({ m_source_code, rule_start.position(), position() }, move(callee), move(arguments)); } NonnullRefPtr Parser::parse_yield_expression()