mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-18 18:00:31 +00:00
Now that the Rust pipeline is the sole compilation path, remove all C++ parser/codegen fallback paths from the callers: - Script::parse() no longer falls back to C++ Parser - SourceTextModule::parse() no longer falls back to C++ Parser - perform_eval() no longer falls back to C++ Parser + Generator - create_dynamic_function() no longer falls back to C++ Parser - ShadowRealm eval no longer falls back to C++ Parser + Generator - Interpreter::run(Script&) no longer falls back to Generator Also remove the now-dead old constructors that took C++ AST nodes, the module_requests() helper, and AST dump code from js.cpp.
238 lines
9.9 KiB
C++
238 lines
9.9 KiB
C++
/*
|
|
* Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibJS/Runtime/AbstractOperations.h>
|
|
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
|
|
#include <LibJS/Runtime/Error.h>
|
|
#include <LibJS/Runtime/FunctionConstructor.h>
|
|
#include <LibJS/Runtime/FunctionObject.h>
|
|
#include <LibJS/Runtime/GeneratorPrototype.h>
|
|
#include <LibJS/Runtime/GlobalEnvironment.h>
|
|
#include <LibJS/Runtime/GlobalObject.h>
|
|
#include <LibJS/Runtime/Realm.h>
|
|
#include <LibJS/RustIntegration.h>
|
|
#include <LibJS/SourceCode.h>
|
|
|
|
namespace JS {
|
|
|
|
GC_DEFINE_ALLOCATOR(FunctionConstructor);
|
|
|
|
FunctionConstructor::FunctionConstructor(Realm& realm)
|
|
: NativeFunction(realm.vm().names.Function.as_string(), realm.intrinsics().function_prototype())
|
|
{
|
|
}
|
|
|
|
void FunctionConstructor::initialize(Realm& realm)
|
|
{
|
|
auto& vm = this->vm();
|
|
Base::initialize(realm);
|
|
|
|
// 20.2.2.2 Function.prototype, https://tc39.es/ecma262/#sec-function.prototype
|
|
define_direct_property(vm.names.prototype, realm.intrinsics().function_prototype(), 0);
|
|
|
|
define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
|
}
|
|
|
|
// 20.2.1.1.1 CreateDynamicFunction ( constructor, newTarget, kind, parameterArgs, bodyArg ), https://tc39.es/ecma262/#sec-createdynamicfunction
|
|
ThrowCompletionOr<GC::Ref<ECMAScriptFunctionObject>> FunctionConstructor::create_dynamic_function(VM& vm, FunctionObject& constructor, FunctionObject* new_target, FunctionKind kind, ReadonlySpan<Value> parameter_args, Value body_arg)
|
|
{
|
|
// 1. If newTarget is undefined, set newTarget to constructor.
|
|
if (new_target == nullptr)
|
|
new_target = &constructor;
|
|
|
|
StringView prefix;
|
|
GC::Ref<Object> (Intrinsics::*fallback_prototype)() = nullptr;
|
|
|
|
switch (kind) {
|
|
// 2. If kind is normal, then
|
|
case FunctionKind::Normal:
|
|
// a. Let prefix be "function".
|
|
prefix = "function"sv;
|
|
|
|
// b. Let exprSym be the grammar symbol FunctionExpression.
|
|
// c. Let bodySym be the grammar symbol FunctionBody[~Yield, ~Await].
|
|
// d. Let parameterSym be the grammar symbol FormalParameters[~Yield, ~Await].
|
|
|
|
// e. Let fallbackProto be "%Function.prototype%".
|
|
fallback_prototype = &Intrinsics::function_prototype;
|
|
break;
|
|
|
|
// 3. Else if kind is generator, then
|
|
case FunctionKind::Generator:
|
|
// a. Let prefix be "function*".
|
|
prefix = "function*"sv;
|
|
|
|
// b. Let exprSym be the grammar symbol GeneratorExpression.
|
|
// c. Let bodySym be the grammar symbol GeneratorBody.
|
|
// d. Let parameterSym be the grammar symbol FormalParameters[+Yield, ~Await].
|
|
|
|
// e. Let fallbackProto be "%GeneratorFunction.prototype%".
|
|
fallback_prototype = &Intrinsics::generator_function_prototype;
|
|
break;
|
|
|
|
// 4. Else if kind is async, then
|
|
case FunctionKind::Async:
|
|
// a. Let prefix be "async function".
|
|
prefix = "async function"sv;
|
|
|
|
// b. Let exprSym be the grammar symbol AsyncFunctionExpression.
|
|
// c. Let bodySym be the grammar symbol AsyncFunctionBody.
|
|
// d. Let parameterSym be the grammar symbol FormalParameters[~Yield, +Await].
|
|
|
|
// e. Let fallbackProto be "%AsyncFunction.prototype%".
|
|
fallback_prototype = &Intrinsics::async_function_prototype;
|
|
break;
|
|
|
|
// 5. Else,
|
|
case FunctionKind::AsyncGenerator:
|
|
// a. Assert: kind is async-generator.
|
|
|
|
// b. Let prefix be "async function*".
|
|
prefix = "async function*"sv;
|
|
|
|
// c. Let exprSym be the grammar symbol AsyncGeneratorExpression.
|
|
// d. Let bodySym be the grammar symbol AsyncGeneratorBody.
|
|
// e. Let parameterSym be the grammar symbol FormalParameters[+Yield, +Await].
|
|
|
|
// f. Let fallbackProto be "%AsyncGeneratorFunction.prototype%".
|
|
fallback_prototype = &Intrinsics::async_generator_function_prototype;
|
|
break;
|
|
|
|
default:
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
|
|
// 6. Let argCount be the number of elements in parameterArgs.
|
|
auto arg_count = parameter_args.size();
|
|
|
|
// 7. Let parameterStrings be a new empty List.
|
|
Vector<String> parameter_strings;
|
|
parameter_strings.ensure_capacity(arg_count);
|
|
|
|
// 8. For each element arg of parameterArgs, do
|
|
for (auto const& parameter_value : parameter_args) {
|
|
// a. Append ? ToString(arg) to parameterStrings.
|
|
parameter_strings.unchecked_append(TRY(parameter_value.to_string(vm)));
|
|
}
|
|
|
|
// 9. Let bodyString be ? ToString(bodyArg).
|
|
auto body_string = TRY(body_arg.to_string(vm));
|
|
|
|
// 10. Let currentRealm be the current Realm Record.
|
|
auto& realm = *vm.current_realm();
|
|
|
|
// 11. Let P be the empty String.
|
|
String parameters_string;
|
|
|
|
// 12. If argCount > 0, then
|
|
if (arg_count > 0) {
|
|
// a. Set P to parameterStrings[0].
|
|
// b. Let k be 1.
|
|
// c. Repeat, while k < argCount,
|
|
// i. Let nextArgString be parameterStrings[k].
|
|
// ii. Set P to the string-concatenation of P, "," (a comma), and nextArgString.
|
|
// iii. Set k to k + 1.
|
|
parameters_string = MUST(String::join(',', parameter_strings));
|
|
}
|
|
|
|
// 13. Let bodyParseString be the string-concatenation of 0x000A (LINE FEED), bodyString, and 0x000A (LINE FEED).
|
|
auto body_parse_string = ByteString::formatted("\n{}\n", body_string);
|
|
|
|
// 14. Let sourceString be the string-concatenation of prefix, " anonymous(", P, 0x000A (LINE FEED), ") {", bodyParseString, and "}".
|
|
// 15. Let sourceText be StringToCodePoints(sourceString).
|
|
auto source_text = ByteString::formatted("{} anonymous({}\n) {{{}}}", prefix, parameters_string, body_parse_string);
|
|
|
|
// 16. Perform ? HostEnsureCanCompileStrings(currentRealm, parameterStrings, bodyString, sourceString, FUNCTION, parameterArgs, bodyArg).
|
|
TRY(vm.host_ensure_can_compile_strings(realm, parameter_strings, body_string, source_text, CompilationType::Function, parameter_args, body_arg));
|
|
|
|
GC::Ptr<SharedFunctionInstanceData> function_data;
|
|
|
|
auto rust_compilation = RustIntegration::compile_dynamic_function(vm, source_text, parameters_string, body_parse_string, kind);
|
|
if (!rust_compilation.has_value())
|
|
return vm.throw_completion<SyntaxError>("Failed to compile dynamic function"_string);
|
|
if (rust_compilation->is_error())
|
|
return vm.throw_completion<SyntaxError>(rust_compilation->release_error());
|
|
function_data = rust_compilation->value();
|
|
|
|
// 25. Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
|
|
auto* prototype = TRY(get_prototype_from_constructor(vm, *new_target, fallback_prototype));
|
|
|
|
// 26. Let env be currentRealm.[[GlobalEnv]].
|
|
auto& environment = realm.global_environment();
|
|
|
|
// 27. Let privateEnv be null.
|
|
PrivateEnvironment* private_environment = nullptr;
|
|
|
|
auto function = ECMAScriptFunctionObject::create_from_function_data(
|
|
realm,
|
|
*function_data,
|
|
&environment,
|
|
private_environment,
|
|
*prototype);
|
|
|
|
// FIXME: Remove the name argument from create() and do this instead.
|
|
// 29. Perform SetFunctionName(F, "anonymous").
|
|
|
|
// 30. If kind is generator, then
|
|
if (kind == FunctionKind::Generator) {
|
|
// a. Let prototype be OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
|
|
prototype = Object::create_prototype(realm, realm.intrinsics().generator_function_prototype_prototype());
|
|
|
|
// b. Perform ! DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
|
function->define_direct_property(vm.names.prototype, prototype, Attribute::Writable);
|
|
}
|
|
// 31. Else if kind is asyncGenerator, then
|
|
else if (kind == FunctionKind::AsyncGenerator) {
|
|
// a. Let prototype be OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).
|
|
prototype = Object::create_prototype(realm, realm.intrinsics().async_generator_function_prototype_prototype());
|
|
|
|
// b. Perform ! DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
|
|
function->define_direct_property(vm.names.prototype, prototype, Attribute::Writable);
|
|
}
|
|
// 32. Else if kind is normal, perform MakeConstructor(F).
|
|
else if (kind == FunctionKind::Normal) {
|
|
// FIXME: Implement MakeConstructor
|
|
prototype = Object::create_prototype(realm, realm.intrinsics().object_prototype());
|
|
prototype->define_direct_property(vm.names.constructor, function, Attribute::Writable | Attribute::Configurable);
|
|
function->define_direct_property(vm.names.prototype, prototype, Attribute::Writable);
|
|
}
|
|
|
|
// 33. NOTE: Functions whose kind is async are not constructible and do not have a [[Construct]] internal method or a "prototype" property.
|
|
|
|
// 34. Return F.
|
|
return function;
|
|
}
|
|
|
|
// 20.2.1.1 Function ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-function-p1-p2-pn-body
|
|
ThrowCompletionOr<Value> FunctionConstructor::call()
|
|
{
|
|
return TRY(construct(*this));
|
|
}
|
|
|
|
// 20.2.1.1 Function ( ...parameterArgs, bodyArg ), https://tc39.es/ecma262/#sec-function-p1-p2-pn-body
|
|
ThrowCompletionOr<GC::Ref<Object>> FunctionConstructor::construct(FunctionObject& new_target)
|
|
{
|
|
auto& vm = this->vm();
|
|
|
|
ReadonlySpan<Value> arguments = vm.running_execution_context().arguments_span();
|
|
|
|
ReadonlySpan<Value> parameter_args = arguments;
|
|
if (!parameter_args.is_empty())
|
|
parameter_args = parameter_args.slice(0, parameter_args.size() - 1);
|
|
|
|
// 1. Let C be the active function object.
|
|
auto* constructor = vm.active_function_object();
|
|
|
|
// 2. If bodyArg is not present, set bodyArg to the empty String.
|
|
Value body_arg = &vm.empty_string();
|
|
if (!arguments.is_empty())
|
|
body_arg = arguments.last();
|
|
|
|
// 3. Return ? CreateDynamicFunction(C, NewTarget, normal, parameterArgs, bodyArg).
|
|
return TRY(create_dynamic_function(vm, *constructor, &new_target, FunctionKind::Normal, parameter_args, body_arg));
|
|
}
|
|
|
|
}
|