]> Lady’s Gitweb - Pisces/blobdiff - string.js
Add methods for own entries and values to object.js
[Pisces] / string.js
index 6d4d2290d59582e07c1d342f043305723f124761..e8126d14fa44be9155723de05b4720403ee327f9 100644 (file)
--- a/string.js
+++ b/string.js
@@ -19,10 +19,14 @@ import {
   stringIteratorFunction,
 } from "./iterable.js";
 import {
+  defineOwnDataProperty,
   defineOwnProperties,
   getOwnPropertyDescriptors,
+  objectCreate,
+  setPropertyValues,
   setPrototype,
 } from "./object.js";
+import { sameValue, toLength, UNDEFINED } from "./value.js";
 
 const RE = RegExp;
 const { prototype: rePrototype } = RE;
@@ -93,7 +97,7 @@ export const {
      * expression with `^(?:` and `)$` if you don’t want nongreedy
      * regular expressions to fail when shorter matches are possible.
      */
-    constructor(source, name = undefined, constraint = null) {
+    constructor(source, name = UNDEFINED, constraint = null) {
       super(
         ($) => {
           if (typeof $ !== "string") {
@@ -138,17 +142,19 @@ export const {
         return defineOwnProperties(
           setPrototype(this, matcherPrototype),
           {
-            lastIndex: {
+            lastIndex: setPropertyValues(objectCreate(null), {
               configurable: false,
               enumerable: false,
               value: 0,
               writable: false,
-            },
-            name: {
-              value: name != null
+            }),
+            name: defineOwnDataProperty(
+              objectCreate(null),
+              "value",
+              name != null
                 ? `${name}`
                 : `Matcher(${call(reToString, regExp, [])})`,
-            },
+            ),
           },
         );
       }
@@ -246,21 +252,31 @@ export const {
     }
   };
 
-  const matcherConstructor = defineOwnProperties(
+  const matcherConstructor = Object.defineProperties(
     class extends RegExp {
       constructor(...args) {
         return new Matcher(...args);
       }
     },
     {
-      name: { value: "Matcher" },
-      length: { value: 1 },
+      name: defineOwnDataProperty(
+        Object.create(null),
+        "value",
+        "Matcher",
+      ),
+      length: defineOwnDataProperty(Object.create(null), "value", 1),
     },
   );
   const matcherPrototype = defineOwnProperties(
     matcherConstructor.prototype,
     getOwnPropertyDescriptors(Matcher.prototype),
-    { constructor: { value: matcherConstructor } },
+    {
+      constructor: defineOwnDataProperty(
+        Object.create(null),
+        "value",
+        matcherConstructor,
+      ),
+    },
   );
 
   return { Matcher: matcherConstructor };
@@ -299,6 +315,25 @@ export const {
   };
 })();
 
+/**
+ * Returns −0 if the provided argument is "-0"; returns a number
+ * representing the index if the provided argument is a canonical
+ * numeric index string; otherwise, returns undefined.
+ *
+ * There is no clamping of the numeric index, but note that numbers
+ * above 2^53 − 1 are not safe nor valid integer indices.
+ */
+export const canonicalNumericIndexString = ($) => {
+  if (typeof $ !== "string") {
+    return UNDEFINED;
+  } else if ($ === "-0") {
+    return -0;
+  } else {
+    const n = +$;
+    return $ === `${n}` ? n : UNDEFINED;
+  }
+};
+
 export const {
   /**
    * Returns an iterator over the codepoints in the string representation
@@ -375,19 +410,30 @@ export const {
 export const getCharacter = ($, pos) => {
   const codepoint = getCodepoint($, pos);
   return codepoint == null
-    ? undefined
+    ? UNDEFINED
     : stringFromCodepoints(codepoint);
 };
 
-/**
- * Returns the code unit at the provided position in the string
- * representation of the provided value according to the algorithm of
- * `String::charAt`, except that out‐of‐bounds values return undefined
- * in place of nan.
- */
 export const {
+  /**
+   * Returns the code unit at the provided position in the string
+   * representation of the provided value according to the algorithm of
+   * `String::charAt`, except that out‐of‐bounds values return undefined
+   * in place of nan.
+   */
   getCodeUnit,
 
+  /**
+   * Returns a string created from the provided code units.
+   *
+   * ※ This is effectively an alias for `String.fromCharCode`, but
+   * with the same error behaviour as `String.fromCodePoint`.
+   *
+   * ☡ This function throws an error if provided with an argument which
+   * is not an integral number from 0 to FFFF₁₆ inclusive.
+   */
+  stringFromCodeUnits,
+
   /**
    * Returns the result of catenating the string representations of the
    * provided values, returning a new string according to the algorithm
@@ -400,18 +446,45 @@ export const {
    */
   stringCatenate,
 } = (() => {
+  const { fromCharCode } = String;
   const { charCodeAt, concat } = String.prototype;
-  const { isNaN: isNan } = Number;
+  const {
+    isInteger: isIntegralNumber,
+    isNaN: isNan,
+  } = Number;
 
   return {
     getCodeUnit: ($, n) => {
       const codeUnit = call(charCodeAt, $, [n]);
-      return isNan(codeUnit) ? undefined : codeUnit;
+      return isNan(codeUnit) ? UNDEFINED : codeUnit;
     },
-    stringCatenate: defineOwnProperties(
+    stringCatenate: Object.defineProperties(
       (...args) => call(concat, "", args),
       { name: { value: "stringCatenate" }, length: { value: 2 } },
     ),
+    stringFromCodeUnits: Object.defineProperties(
+      (...codeUnits) => {
+        for (let index = 0; index < codeUnits.length; ++index) {
+          // Iterate over each provided code unit and throw if it is
+          // out of range.
+          const nextCU = +codeUnits[index];
+          if (
+            !isIntegralNumber(nextCU) || nextCU < 0 || nextCU > 0xFFFF
+          ) {
+            // The code unit is not an integral number between 0 and
+            // 0xFFFF.
+            throw new RangeError(
+              `Piscēs: Code unit out of range: ${nextCU}.`,
+            );
+          } else {
+            // The code unit is acceptable.
+            /* do nothing */
+          }
+        }
+        return call(fromCharCode, UNDEFINED, codeUnits);
+      },
+      { name: { value: "stringFromCodeUnits" }, length: { value: 1 } },
+    ),
   };
 })();
 
@@ -445,6 +518,34 @@ export const getLastSubstringIndex = createCallableFunction(
   { name: "getLastSubstringIndex" },
 );
 
+/** Returns whether the provided value is an array index. */
+export const isArrayIndexString = ($) => {
+  const value = canonicalNumericIndexString($);
+  if (value !== UNDEFINED) {
+    // The provided value is a canonical numeric index string; return
+    // whether it is in range for array indices.
+    return sameValue(value, 0) ||
+      value === toLength(value) && value > 0 && value < -1 >>> 0;
+  } else {
+    // The provided value is not a canonical numeric index string.
+    return false;
+  }
+};
+
+/** Returns whether the provided value is an integer index string. */
+export const isIntegerIndexString = ($) => {
+  const value = canonicalNumericIndexString($);
+  if (value !== UNDEFINED) {
+    // The provided value is a canonical numeric index string; return
+    // whether it is in range for integer indices.
+    return sameValue(value, 0) ||
+      value === toLength(value) && value > 0;
+  } else {
+    // The provided value is not a canonical numeric index string.
+    return false;
+  }
+};
+
 /**
  * Returns the result of joining the provided iterable.
  *
@@ -458,7 +559,7 @@ export const join = (() => {
     call(
       arrayJoin,
       [...$],
-      [separator === undefined ? "," : `${separator}`],
+      [separator === UNDEFINED ? "," : `${separator}`],
     );
   return join;
 })();
@@ -473,48 +574,6 @@ export const rawString = createArrowFunction(String.raw, {
   name: "rawString",
 });
 
-export const {
-  /**
-   * Returns a string created from the provided code units.
-   *
-   * ※ This is effectively an alias for `String.fromCharCode`, but
-   * with the same error behaviour as `String.fromCodePoint`.
-   *
-   * ☡ This function throws an error if provided with an argument which
-   * is not an integral number from 0 to FFFF₁₆ inclusive.
-   */
-  stringFromCodeUnits,
-} = (() => {
-  const { fromCharCode } = String;
-  const { isInteger: isIntegralNumber } = Number;
-
-  return {
-    stringFromCodeUnits: defineOwnProperties(
-      (...codeUnits) => {
-        for (let index = 0; index < codeUnits.length; ++index) {
-          // Iterate over each provided code unit and throw if it is
-          // out of range.
-          const nextCU = +codeUnits[index];
-          if (
-            !isIntegralNumber(nextCU) || nextCU < 0 || nextCU > 0xFFFF
-          ) {
-            // The code unit is not an integral number between 0 and
-            // 0xFFFF.
-            throw new RangeError(
-              `Piscēs: Code unit out of range: ${nextCU}.`,
-            );
-          } else {
-            // The code unit is acceptable.
-            /* do nothing */
-          }
-        }
-        return call(fromCharCode, undefined, codeUnits);
-      },
-      { name: { value: "stringFromCodeUnits" }, length: { value: 1 } },
-    ),
-  };
-})();
-
 /**
  * Returns a string created from the provided codepoints.
  *
This page took 0.02839 seconds and 4 git commands to generate.