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
} 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 * ※ This is effectively an alias for `Function::call.bind`.
32 * Returns a constructor which throws whenever it is called but has
33 * the same `.name` and `.prototype` as the provided value.
35 * If a second argument is provided, the returned constructor will
36 * use that as its prototype; otherwise, it will use the prototype of
39 makeIllegalConstructor
,
41 // ☡ Because these functions are used to initialize module constants,
42 // they can’t depend on imports from elsewhere.
46 } = Function
.prototype;
47 const callBind
= Reflect
.apply(functionBind
, functionCall
, [
52 defineProperties
: defineOwnProperties
,
53 getPrototypeOf
: getPrototype
,
54 setPrototypeOf
: setPrototype
,
56 const { [ITERATOR
]: arrayIterator
} = Array
.prototype;
58 next
: arrayIteratorNext
,
59 } = getPrototype([][ITERATOR
]());
60 const argumentIterablePrototype
= {
65 call(arrayIterator
, this.args
, []),
71 bind
: ($, boundThis
, boundArgs
) =>
76 argumentIterablePrototype
,
77 { args
: { value
: boundArgs
} },
80 makeCallable
: ($, name
= undefined) =>
81 defineOwnProperties(callBind(functionCall
, $), {
82 length
: { value
: $.length
+ 1 },
83 name
: { value
: name
?? $.name
?? "" },
85 makeIllegalConstructor
: ($, proto
= undefined) => {
86 const constructor = function () {
87 throw new TypeError("Illegal constructor");
89 if ($ == null && proto
=== undefined) {
90 // The provided argument is nullish and no explicit prototype
93 // Do not modify the prototype of the generated constructor.
96 // The provided argument is not nullish or an explicit
97 // prototype was provided.
99 // Set the prototype of the generated constructor to match.
102 proto
=== undefined ? getPrototype($) : proto
,
105 return defineOwnProperties(constructor, {
106 name
: { value
: $?.name
?? "" },
107 prototype: { value
: $?.prototype ?? {}, writable
: false },
115 * Calls the provided function with the provided this value and
118 * ☡ This is effectively an alias for `Reflect.apply`—the arguments
119 * must be passed as an arraylike.
124 * Constructs the provided function with the provided arguments list
127 * ☡ This is effectively an alias for `Reflect.construct`—the
128 * arguments must be passed as an arraylike.
132 /** Returns whether the provided value is a constructor. */
135 const { apply
, construct
} = Reflect
;
137 call
: (target
, thisArgument
, argumentsList
) =>
138 apply(target
, thisArgument
, argumentsList
),
139 construct
: (target
, argumentsList
, ...args
) =>
141 ? construct(target
, argumentsList
, args
[0])
142 : construct(target
, argumentsList
),
143 isConstructor
: ($) =>
144 completesNormally(() =>
145 // Try constructing a new object with the provided value as its
146 // `new.target`. This will throw if the provided value is not a
148 construct(function () {}, [], $)
154 * Returns whether calling the provided function with no `this` value
155 * or arguments completes normally; that is, does not throw an error.
157 * ☡ This function will throw an error if the provided argument is not
160 export const completesNormally
= ($) => {
161 if (!isCallable($)) {
162 // The provided value is not callable; this is an error.
164 `Piscēs: Cannot determine completion of noncallable value: ${$}`,
167 // The provided value is callable.
169 // Attempt to call the function and return true if this succeeds.
173 // Calling the function did not succeed; return false.
180 * Returns the provided value.
182 * ※ This function can be called as a constructor. When used in an
183 * `extends` clause and called via `super`, it will set the value of
184 * `this` to the provided value, enabling it to be extended with
185 * private class features.
187 export const identity = function ($) {
191 /** Returns whether the provided value is callable. */
192 export const isCallable
= ($) => typeof $ === "function";
195 * Returns whether the provided object inherits from the prototype of
196 * the provided function.
198 export const ordinaryHasInstance
= makeCallable(
199 Function
.prototype[Symbol
.hasInstance
],
200 "ordinaryHasInstance",