]> Lady’s Gitweb - Pisces/commitdiff
Build function.js on top of object.js infra
authorLady <redacted>
Sat, 25 Nov 2023 18:01:45 +0000 (13:01 -0500)
committerLady <redacted>
Sat, 25 Nov 2023 18:01:45 +0000 (13:01 -0500)
This allows us to be a little safer about our property descriptors.

function.js

index 10a3f89fd2bdf6c79257db0307457e0bbec9a0ce..71e4d098d41dfbad04e954dfd42c06d552af1a38 100644 (file)
@@ -7,7 +7,23 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
 
-import { ITERATOR, toFunctionName, toLength, type } from "./value.js";
+import {
+  ITERATOR,
+  toFunctionName,
+  toLength,
+  type,
+  UNDEFINED,
+} from "./value.js";
+import {
+  defineOwnDataProperty,
+  defineOwnProperties,
+  defineOwnProperty,
+  getOwnPropertyDescriptor,
+  getPrototype,
+  objectCreate,
+  setPropertyValues,
+  setPrototype,
+} from "./object.js";
 
 export const {
   /**
@@ -87,14 +103,6 @@ export const {
   } = functionPrototype;
   const objectConstructor = Object;
   const proxyConstructor = Proxy;
-  const {
-    create: objectCreate,
-    defineProperty: defineOwnProperty,
-    defineProperties: defineOwnProperties,
-    getOwnPropertyDescriptor,
-    getPrototypeOf: getPrototype,
-    setPrototypeOf: setPrototype,
-  } = Object;
   const {
     apply: reflectApply,
     construct: reflectConstruct,
@@ -121,7 +129,7 @@ export const {
     },
   };
   const applyBaseFunction = ($, base, lengthDelta = 0) => {
-    if (base === undefined) {
+    if (base === UNDEFINED) {
       // No base function was provided to apply.
       return $;
     } else {
@@ -140,15 +148,15 @@ export const {
     }
   };
   const applyProperties = ($, override) => {
-    if (override === undefined) {
+    if (override === UNDEFINED) {
       // No properties were provided to apply.
       return $;
     } else {
       // Properties were provided; apply them.
       const { length, name, prototype } = override;
       if (
-        !getOwnPropertyDescriptor($, "prototype")?.writable ||
-        prototype === undefined
+        prototype === UNDEFINED ||
+        !getOwnPropertyDescriptor($, "prototype")?.writable
       ) {
         // The provided function has no `.prototype`, its prototype is
         // not writable, or no prototype value was provided.
@@ -162,17 +170,27 @@ export const {
         //
         // Change the prototype property of the provided function to
         // match.
-        defineOwnProperty($, "prototype", { value: prototype });
+        defineOwnProperty(
+          $,
+          "prototype",
+          defineOwnDataProperty(
+            objectCreate(null),
+            "value",
+            prototype,
+          ),
+        );
       }
       return defineOwnProperties($, {
-        length: {
-          value: toLength(length === undefined ? $.length : length),
-        },
-        name: {
-          value: toFunctionName(
-            name === undefined ? $.name ?? "" : name,
-          ),
-        },
+        length: defineOwnDataProperty(
+          objectCreate(null),
+          "value",
+          toLength(length === UNDEFINED ? $.length : length),
+        ),
+        name: defineOwnDataProperty(
+          objectCreate(null),
+          "value",
+          toFunctionName(name === UNDEFINED ? $.name ?? "" : name),
+        ),
       });
     }
   };
@@ -182,26 +200,28 @@ export const {
       callBind(
         $,
         boundThis,
-        ...objectCreate(
-          argumentIterablePrototype,
-          { args: { value: boundArgs } },
+        ...defineOwnDataProperty(
+          objectCreate(argumentIterablePrototype),
+          "args",
+          boundArgs,
         ),
       ),
-    createArrowFunction: ($, propertyOverride = undefined) =>
+    createArrowFunction: ($, propertyOverride = UNDEFINED) =>
       applyProperties(
         applyBaseFunction(
-          (...$s) => reflectApply($, undefined, $s),
+          (...$s) => reflectApply($, UNDEFINED, $s),
           $,
         ),
         propertyOverride,
       ),
-    createCallableFunction: ($, propertyOverride = undefined) =>
+    createCallableFunction: ($, propertyOverride = UNDEFINED) =>
       applyProperties(
         applyBaseFunction(
           (...$s) => {
-            const iterator = objectCreate(
-              argumentIterablePrototype,
-              { args: { value: $s } },
+            const iterator = defineOwnDataProperty(
+              objectCreate(argumentIterablePrototype),
+              "args",
+              $s,
             )[ITERATOR]();
             const { value: thisValue } = iterator.next();
             return reflectApply($, thisValue, [...iterator]);
@@ -211,7 +231,7 @@ export const {
         ),
         propertyOverride,
       ),
-    createIllegalConstructor: ($, propertyOverride = undefined) =>
+    createIllegalConstructor: ($, propertyOverride = UNDEFINED) =>
       defineOwnProperty(
         applyProperties(
           applyBaseFunction(
@@ -228,36 +248,46 @@ export const {
     createProxyConstructor: (
       handler,
       $,
-      newTarget = undefined,
-      propertyOverride = undefined,
+      newTarget = UNDEFINED,
+      propertyOverride = UNDEFINED,
     ) => {
-      const constructor = $ === undefined ? objectConstructor : $;
-      const target = newTarget === undefined ? constructor : newTarget;
+      const constructor = $ === UNDEFINED ? objectConstructor : $;
+      const target = newTarget === UNDEFINED ? constructor : newTarget;
       const len = toLength(constructor.length);
       if (!(type(handler) === "object")) {
+        // The provided handler is not an object; this is an error.
         throw new TypeError(
           `Piscēs: Proxy handler must be an object, but got: ${handler}.`,
         );
       } else if (!isConstructor(constructor)) {
+        // The provided constructor is not a constructor; this is an
+        // error.
         throw new TypeError(
           "Piscēs: Cannot create proxy constructor from nonconstructible value.",
         );
       } else if (!isConstructor(target)) {
+        // The provided new target is not a constructor; this is an
+        // error.
         throw new TypeError(
           "Piscēs: New target must be a constructor.",
         );
       } else {
+        // The arguments are acceptable.
         return applyProperties(
           defineOwnProperties(
             setPrototype(
               function C(...$s) {
-                if (new.target === undefined) {
+                if (new.target === UNDEFINED) {
+                  // The constructor was not called with new; this is
+                  // an error.
                   throw new TypeError(
                     `Piscēs: ${
                       C.name ?? "Proxy"
                     } must be called with new.`,
                   );
                 } else {
+                  // The constructor was called with new; return the
+                  // appropriate proxy.
                   const O = reflectConstruct(
                     constructor,
                     $s,
@@ -269,19 +299,23 @@ export const {
               proxyConstructor,
             ),
             {
-              length: { value: len },
-              name: {
-                value: `${
-                  toFunctionName(constructor.name ?? "")
-                }Proxy`,
-              },
-              prototype: {
+              length: defineOwnDataProperty(
+                objectCreate(null),
+                "value",
+                len,
+              ),
+              name: defineOwnDataProperty(
+                objectCreate(null),
+                "value",
+                `${toFunctionName(constructor.name ?? "")}Proxy`,
+              ),
+              prototype: setPropertyValues(objectCreate(null), {
                 configurable: false,
                 enumerable: false,
-                value: undefined,
+                value: UNDEFINED,
                 writable: false,
-              },
-              revocable: {
+              }),
+              revocable: setPropertyValues(objectCreate(null), {
                 configurable: true,
                 enumerable: false,
                 value: defineOwnProperties(
@@ -294,12 +328,20 @@ export const {
                     return revocable(O, handler);
                   },
                   {
-                    length: { value: len },
-                    name: { value: "revocable" },
+                    length: defineOwnDataProperty(
+                      objectCreate(null),
+                      "value",
+                      len,
+                    ),
+                    name: defineOwnDataProperty(
+                      objectCreate(null),
+                      "value",
+                      "revocable",
+                    ),
                   },
                 ),
                 writable: true,
-              },
+              }),
             },
           ),
           propertyOverride,
This page took 0.03001 seconds and 4 git commands to generate.