1 // ♓🌟 Piscēs ∷ function.js
2 // ====================================================================
4 // Copyright © 2022‐2023 Lady [@ Lady’s Computer].
6 // This Source Code Form is subject to the terms of the Mozilla Public
7 // License, v. 2.0. If a copy of the MPL was not distributed with this
8 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
10 import { ITERATOR
, toFunctionName
, toLength
} from "./value.js";
14 * Creates a bound function from the provided function using the
15 * provided this value and arguments list.
17 * ☡ As with `call` and `construct`, the arguments must be passed as
23 * Returns a new function which calls the provided function with its
24 * first argument as the `this` value and the remaining arguments
27 * The `length`, `name`, and prototype of the provided function will
28 * be preserved in the new one. A second argument may be used to
29 * override `length` and `name`.
34 * Returns a new function which calls the provided function with its
35 * first argument as the `this` value and the remaining arguments
38 * The `length`, `name`, and prototype of the provided function will
39 * be preserved in the new one. A second argument may be used to
40 * override `length` and `name`.
42 * ※ This is effectively an alias for `Function::call.bind`.
44 createCallableFunction
,
47 * Returns a constructor which throws whenever it is called but has
48 * the same `.name` and `.prototype` as the provided value.
50 * The `length`, `name`, `prototype`, and prototype of the provided
51 * function will be preserved in the new one. A second argument may
52 * be used to override `length`, `name`, and `prototype`.
54 createIllegalConstructor
,
56 // ☡ Because these functions are used to initialize module constants,
57 // they can’t depend on imports from elsewhere.
61 } = Function
.prototype;
62 const callBind
= Reflect
.apply(functionBind
, functionCall
, [
67 defineProperty
: defineOwnProperty
,
68 defineProperties
: defineOwnProperties
,
69 getPrototypeOf
: getPrototype
,
70 setPrototypeOf
: setPrototype
,
72 const { [ITERATOR
]: arrayIterator
} = Array
.prototype;
74 next
: arrayIteratorNext
,
75 } = getPrototype([][ITERATOR
]());
76 const argumentIterablePrototype
= {
84 call(arrayIterator
, this.args
, []),
89 const applyBaseFunction
= ($, base
, lengthDelta
= 0) => {
90 if (base
=== undefined) {
91 // No base function was provided to apply.
94 // A base function was provided; apply it.
95 const { length
, name
, prototype } = base
;
96 setPrototype($, getPrototype(base
));
97 return applyProperties($, {
98 length
: +length
+ lengthDelta
,
104 const applyProperties
= ($, override
) => {
105 if (override
=== undefined) {
106 // No properties were provided to apply.
109 // Properties were provided; apply them.
110 const { length
, name
, prototype } = override
;
111 if (!isConstructor($) || prototype === undefined) {
112 // The provided function is not a constructor or no prototype
113 // value was provided.
115 // Do not modify the prototype property of the provided
119 // The provided function is a constructor and a prototype value
122 // Change the prototype property of the provided function to
124 defineOwnProperty($, "prototype", { value
: prototype });
126 return defineOwnProperties($, {
128 value
: toLength(length
=== undefined ? $.length
: length
),
131 value
: toFunctionName(
132 name
=== undefined ? $.name
?? "" : name
,
140 bind
: ($, boundThis
, boundArgs
) =>
145 argumentIterablePrototype
,
146 { args
: { value
: boundArgs
} },
149 createArrowFunction
: ($, propertyOverride
= undefined) =>
154 argumentIterablePrototype
,
155 { args
: { value
: $s
} },
161 createCallableFunction
: ($, propertyOverride
= undefined) =>
165 const iterator
= objectCreate(
166 argumentIterablePrototype
,
167 { args
: { value
: $s
} },
169 const { value
: thisValue
} = iterator
.next();
170 return call($, thisValue
, [...iterator
]);
177 createIllegalConstructor
: ($, propertyOverride
= undefined) => {
178 const constructor = applyProperties(
181 throw new TypeError("Illegal constructor");
187 return defineOwnProperty(constructor, "prototype", {
196 * Calls the provided function with the provided this value and
199 * ☡ This is effectively an alias for `Reflect.apply`—the arguments
200 * must be passed as an arraylike.
205 * Constructs the provided function with the provided arguments list
208 * ☡ This is effectively an alias for `Reflect.construct`—the
209 * arguments must be passed as an arraylike.
213 /** Returns whether the provided value is a constructor. */
216 const { apply
, construct
} = Reflect
;
218 call
: (target
, thisArgument
, argumentsList
) =>
219 apply(target
, thisArgument
, argumentsList
),
220 construct
: (target
, argumentsList
, ...args
) =>
222 ? construct(target
, argumentsList
, args
[0])
223 : construct(target
, argumentsList
),
224 isConstructor
: ($) =>
225 completesNormally(() =>
226 // Try constructing a new object with the provided value as its
227 // `new.target`. This will throw if the provided value is not a
229 construct(function () {}, [], $)
235 * Returns whether calling the provided function with no `this` value
236 * or arguments completes normally; that is, does not throw an error.
238 * ☡ This function will throw an error if the provided argument is not
241 export const completesNormally
= ($) => {
242 if (!isCallable($)) {
243 // The provided value is not callable; this is an error.
245 `Piscēs: Cannot determine completion of noncallable value: ${$}`,
248 // The provided value is callable.
250 // Attempt to call the function and return true if this succeeds.
254 // Calling the function did not succeed; return false.
261 * Returns the provided value.
263 * ※ This function can be called as a constructor. When used in an
264 * `extends` clause and called via `super`, it will set the value of
265 * `this` to the provided value, enabling it to be extended with
266 * private class features.
268 export const identity = function ($) {
272 /** Returns whether the provided value is callable. */
273 export const isCallable
= ($) => typeof $ === "function";
276 * Returns whether the provided object inherits from the prototype of
277 * the provided function.
279 export const ordinaryHasInstance
= createCallableFunction(
280 Function
.prototype[Symbol
.hasInstance
],
281 { name
: "ordinaryHasInstance" },