Serenity Operating System
1/*
2 * Copyright (c) 2020-2022, Linus Groh <linusg@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <LibJS/Lexer.h>
8#include <LibJS/Parser.h>
9#include <LibJS/Runtime/AbstractOperations.h>
10#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
11#include <LibJS/Runtime/Error.h>
12#include <LibJS/Runtime/FunctionConstructor.h>
13#include <LibJS/Runtime/FunctionObject.h>
14#include <LibJS/Runtime/GeneratorPrototype.h>
15#include <LibJS/Runtime/GlobalEnvironment.h>
16#include <LibJS/Runtime/GlobalObject.h>
17#include <LibJS/Runtime/Realm.h>
18
19namespace JS {
20
21FunctionConstructor::FunctionConstructor(Realm& realm)
22 : NativeFunction(realm.vm().names.Function.as_string(), *realm.intrinsics().function_prototype())
23{
24}
25
26ThrowCompletionOr<void> FunctionConstructor::initialize(Realm& realm)
27{
28 auto& vm = this->vm();
29 MUST_OR_THROW_OOM(NativeFunction::initialize(realm));
30
31 // 20.2.2.2 Function.prototype, https://tc39.es/ecma262/#sec-function.prototype
32 define_direct_property(vm.names.prototype, realm.intrinsics().function_prototype(), 0);
33
34 define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
35
36 return {};
37}
38
39// 20.2.1.1.1 CreateDynamicFunction ( constructor, newTarget, kind, args ), https://tc39.es/ecma262/#sec-createdynamicfunction
40ThrowCompletionOr<ECMAScriptFunctionObject*> FunctionConstructor::create_dynamic_function(VM& vm, FunctionObject& constructor, FunctionObject* new_target, FunctionKind kind, MarkedVector<Value> const& args)
41{
42 // 1. Let currentRealm be the current Realm Record.
43 auto& current_realm = *vm.current_realm();
44
45 // 2. Perform ? HostEnsureCanCompileStrings(currentRealm).
46 TRY(vm.host_ensure_can_compile_strings(current_realm));
47
48 // 3. If newTarget is undefined, set newTarget to constructor.
49 if (new_target == nullptr)
50 new_target = &constructor;
51
52 StringView prefix;
53 Object* (Intrinsics::*fallback_prototype)() = nullptr;
54
55 switch (kind) {
56 // 4. If kind is normal, then
57 case FunctionKind::Normal:
58 // a. Let prefix be "function".
59 prefix = "function"sv;
60
61 // b. Let exprSym be the grammar symbol FunctionExpression.
62 // c. Let bodySym be the grammar symbol FunctionBody[~Yield, ~Await].
63 // d. Let parameterSym be the grammar symbol FormalParameters[~Yield, ~Await].
64
65 // e. Let fallbackProto be "%Function.prototype%".
66 fallback_prototype = &Intrinsics::function_prototype;
67 break;
68
69 // 5. Else if kind is generator, then
70 case FunctionKind::Generator:
71 // a. Let prefix be "function*".
72 prefix = "function*"sv;
73
74 // b. Let exprSym be the grammar symbol GeneratorExpression.
75 // c. Let bodySym be the grammar symbol GeneratorBody.
76 // d. Let parameterSym be the grammar symbol FormalParameters[+Yield, ~Await].
77
78 // e. Let fallbackProto be "%GeneratorFunction.prototype%".
79 fallback_prototype = &Intrinsics::generator_function_prototype;
80 break;
81
82 // 6. Else if kind is async, then
83 case FunctionKind::Async:
84 // a. Let prefix be "async function".
85 prefix = "async function"sv;
86
87 // b. Let exprSym be the grammar symbol AsyncFunctionExpression.
88 // c. Let bodySym be the grammar symbol AsyncFunctionBody.
89 // d. Let parameterSym be the grammar symbol FormalParameters[~Yield, +Await].
90
91 // e. Let fallbackProto be "%AsyncFunction.prototype%".
92 fallback_prototype = &Intrinsics::async_function_prototype;
93 break;
94
95 // 7. Else,
96 case FunctionKind::AsyncGenerator:
97 // a. Assert: kind is asyncGenerator.
98
99 // b. Let prefix be "async function*".
100 prefix = "async function*"sv;
101
102 // c. Let exprSym be the grammar symbol AsyncGeneratorExpression.
103 // d. Let bodySym be the grammar symbol AsyncGeneratorBody.
104 // e. Let parameterSym be the grammar symbol FormalParameters[+Yield, +Await].
105
106 // f. Let fallbackProto be "%AsyncGeneratorFunction.prototype%".
107 fallback_prototype = &Intrinsics::async_generator_function_prototype;
108 break;
109
110 default:
111 VERIFY_NOT_REACHED();
112 }
113
114 // 8. Let argCount be the number of elements in args.
115 auto arg_count = args.size();
116
117 // 9. Let P be the empty String.
118 DeprecatedString parameters_string = "";
119
120 Optional<Value> body_arg;
121
122 // 10. If argCount = 0, let bodyArg be the empty String.
123 if (arg_count == 0) {
124 // Optimization: Instead of creating a PrimitiveString here, we just check if body_arg is empty in step 16.
125 }
126 // 11. Else if argCount = 1, let bodyArg be args[0].
127 else if (arg_count == 1) {
128 body_arg = args[0];
129 }
130 // 12. Else,
131 else {
132 // a. Assert: argCount > 1.
133 VERIFY(arg_count > 1);
134
135 // b. Let firstArg be args[0].
136 // c. Set P to ? ToString(firstArg).
137 // NOTE: Also done in the loop. We start at 0 instead and then join() with a comma.
138
139 // d. Let k be 1.
140 size_t k = 0;
141
142 // e. Repeat, while k < argCount - 1,
143 Vector<DeprecatedString> parameters;
144 for (; k < arg_count - 1; ++k) {
145 // i. Let nextArg be args[k].
146 auto next_arg = args[k];
147
148 // ii. Let nextArgString be ? ToString(nextArg).
149 // iii. Set P to the string-concatenation of P, "," (a comma), and nextArgString.
150 parameters.append(TRY(next_arg.to_deprecated_string(vm)));
151
152 // iv. Set k to k + 1.
153 }
154 parameters_string = DeprecatedString::join(',', parameters);
155
156 // f. Let bodyArg be args[k].
157 body_arg = args[k];
158 }
159
160 // 13. Let bodyString be the string-concatenation of 0x000A (LINE FEED), ? ToString(bodyArg), and 0x000A (LINE FEED).
161 auto body_string = DeprecatedString::formatted("\n{}\n", body_arg.has_value() ? TRY(body_arg->to_deprecated_string(vm)) : "");
162
163 // 14. Let sourceString be the string-concatenation of prefix, " anonymous(", P, 0x000A (LINE FEED), ") {", bodyString, and "}".
164 // 15. Let sourceText be StringToCodePoints(sourceString).
165 auto source_text = DeprecatedString::formatted("{} anonymous({}\n) {{{}}}", prefix, parameters_string, body_string);
166
167 u8 parse_options = FunctionNodeParseOptions::CheckForFunctionAndName;
168 if (kind == FunctionKind::Async || kind == FunctionKind::AsyncGenerator)
169 parse_options |= FunctionNodeParseOptions::IsAsyncFunction;
170 if (kind == FunctionKind::Generator || kind == FunctionKind::AsyncGenerator)
171 parse_options |= FunctionNodeParseOptions::IsGeneratorFunction;
172
173 // 16. Let parameters be ParseText(StringToCodePoints(P), parameterSym).
174 i32 function_length = 0;
175 auto parameters_parser = Parser { Lexer { parameters_string } };
176 auto parameters = parameters_parser.parse_formal_parameters(function_length, parse_options);
177
178 // 17. If parameters is a List of errors, throw a SyntaxError exception.
179 if (parameters_parser.has_errors()) {
180 auto error = parameters_parser.errors()[0];
181 return vm.throw_completion<SyntaxError>(TRY_OR_THROW_OOM(vm, error.to_string()));
182 }
183
184 // 18. Let body be ParseText(StringToCodePoints(bodyString), bodySym).
185 bool contains_direct_call_to_eval = false;
186 auto body_parser = Parser { Lexer { body_string } };
187 // Set up some parser state to accept things like return await, and yield in the plain function body.
188 body_parser.m_state.in_function_context = true;
189 if ((parse_options & FunctionNodeParseOptions::IsAsyncFunction) != 0)
190 body_parser.m_state.await_expression_is_valid = true;
191 if ((parse_options & FunctionNodeParseOptions::IsGeneratorFunction) != 0)
192 body_parser.m_state.in_generator_function_context = true;
193 (void)body_parser.parse_function_body(parameters, kind, contains_direct_call_to_eval);
194
195 // 19. If body is a List of errors, throw a SyntaxError exception.
196 if (body_parser.has_errors()) {
197 auto error = body_parser.errors()[0];
198 return vm.throw_completion<SyntaxError>(TRY_OR_THROW_OOM(vm, error.to_string()));
199 }
200
201 // 20. NOTE: The parameters and body are parsed separately to ensure that each is valid alone. For example, new Function("/*", "*/ ) {") is not legal.
202 // 21. NOTE: If this step is reached, sourceText must have the syntax of exprSym (although the reverse implication does not hold). The purpose of the next two steps is to enforce any Early Error rules which apply to exprSym directly.
203
204 // 22. Let expr be ParseText(sourceText, exprSym).
205 auto source_parser = Parser { Lexer { source_text } };
206 // This doesn't need any parse_options, it determines those & the function type based on the tokens that were found.
207 auto expr = source_parser.parse_function_node<FunctionExpression>();
208
209 // 23. If expr is a List of errors, throw a SyntaxError exception.
210 if (source_parser.has_errors()) {
211 auto error = source_parser.errors()[0];
212 return vm.throw_completion<SyntaxError>(TRY_OR_THROW_OOM(vm, error.to_string()));
213 }
214
215 // 24. Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
216 auto* prototype = TRY(get_prototype_from_constructor(vm, *new_target, fallback_prototype));
217
218 // 25. Let realmF be the current Realm Record.
219 auto& realm = *vm.current_realm();
220
221 // 26. Let env be realmF.[[GlobalEnv]].
222 auto& environment = realm.global_environment();
223
224 // 27. Let privateEnv be null.
225 PrivateEnvironment* private_environment = nullptr;
226
227 // 28. Let F be OrdinaryFunctionCreate(proto, sourceText, parameters, body, non-lexical-this, env, privateEnv).
228 auto function = ECMAScriptFunctionObject::create(realm, "anonymous", *prototype, move(source_text), expr->body(), expr->parameters(), expr->function_length(), &environment, private_environment, expr->kind(), expr->is_strict_mode(), expr->might_need_arguments_object(), contains_direct_call_to_eval);
229
230 // FIXME: Remove the name argument from create() and do this instead.
231 // 29. Perform SetFunctionName(F, "anonymous").
232
233 // 30. If kind is generator, then
234 if (kind == FunctionKind::Generator) {
235 // a. Let prototype be OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
236 prototype = Object::create(realm, realm.intrinsics().generator_function_prototype_prototype());
237
238 // b. Perform ! DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
239 function->define_direct_property(vm.names.prototype, prototype, Attribute::Writable);
240 }
241 // 31. Else if kind is asyncGenerator, then
242 else if (kind == FunctionKind::AsyncGenerator) {
243 // a. Let prototype be OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).
244 prototype = Object::create(realm, realm.intrinsics().async_generator_function_prototype_prototype());
245
246 // b. Perform ! DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
247 function->define_direct_property(vm.names.prototype, prototype, Attribute::Writable);
248 }
249 // 32. Else if kind is normal, perform MakeConstructor(F).
250 else if (kind == FunctionKind::Normal) {
251 // FIXME: Implement MakeConstructor
252 prototype = Object::create(realm, realm.intrinsics().object_prototype());
253 prototype->define_direct_property(vm.names.constructor, function, Attribute::Writable | Attribute::Configurable);
254 function->define_direct_property(vm.names.prototype, prototype, Attribute::Writable);
255 }
256
257 // 33. NOTE: Functions whose kind is async are not constructible and do not have a [[Construct]] internal method or a "prototype" property.
258
259 // 34. Return F.
260 return function.ptr();
261}
262
263// 20.2.1.1 Function ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-function-p1-p2-pn-body
264ThrowCompletionOr<Value> FunctionConstructor::call()
265{
266 return TRY(construct(*this));
267}
268
269// 20.2.1.1 Function ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-function-p1-p2-pn-body
270ThrowCompletionOr<NonnullGCPtr<Object>> FunctionConstructor::construct(FunctionObject& new_target)
271{
272 auto& vm = this->vm();
273
274 // 1. Let C be the active function object.
275 auto* constructor = vm.active_function_object();
276
277 // 2. Let args be the argumentsList that was passed to this function by [[Call]] or [[Construct]].
278 auto& args = vm.running_execution_context().arguments;
279
280 // 3. Return ? CreateDynamicFunction(C, NewTarget, normal, args).
281 return *TRY(create_dynamic_function(vm, *constructor, &new_target, FunctionKind::Normal, args));
282}
283
284}