Whitespace cleanups. CRLF => LF

This commit is contained in:
Leo Balter 2019-10-08 15:40:54 -04:00 committed by Rick Waldron
parent bb6ce7e435
commit d49777de27
17 changed files with 729 additions and 898 deletions

54
LICENSE
View File

@ -1,28 +1,28 @@
The << Software identified by reference to the Ecma Standard* ("Software)">> is protected by copyright and is being The << Software identified by reference to the Ecma Standard* ("Software)">> is protected by copyright and is being
made available under the "BSD License", included below. This Software may be subject to third party rights (rights made available under the "BSD License", included below. This Software may be subject to third party rights (rights
from parties other than Ecma International), including patent rights, and no licenses under such third party rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights
are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA
CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS*. INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS*.
Copyright (C) 2012-2013 Ecma International Copyright (C) 2012-2013 Ecma International
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met: following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer. disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other materials provided with the distribution. following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from 3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE. DAMAGE.
* Ecma International Standards hereafter means Ecma International Standards as well as Ecma Technical Reports * Ecma International Standards hereafter means Ecma International Standards as well as Ecma Technical Reports

View File

@ -1,415 +1,273 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: | description: >
Compare two values structurally Compare two values structurally
defines: [assert.deepEqual] defines: [assert.deepEqual]
---*/ ---*/
// @ts-check var deepEqual = (function () {
var EQUAL = 1;
var deepEqual = (function () { var NOT_EQUAL = -1;
/** var UNKNOWN = 0;
* @typedef {0} UNKNOWN
* @typedef {1} EQUAL function deepEqual(a, b) {
* @typedef {-1} NOT_EQUAL return compareEquality(a, b) === EQUAL;
* @typedef {Map<unknown, Map<unknown, EQUAL | NOT_EQUAL>>} ComparisonCache }
*/
function compareEquality(a, b, cache) {
/** @type {EQUAL} */ return compareIf(a, b, isOptional, compareOptionality)
var EQUAL = 1; || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality)
|| compareIf(a, b, isObjectEquatable, compareObjectEquality, cache)
/** @type {NOT_EQUAL} */ || NOT_EQUAL;
var NOT_EQUAL = -1; }
/** @type {UNKNOWN} */ function compareIf(a, b, test, compare, cache) {
var UNKNOWN = 0; return !test(a)
? !test(b) ? UNKNOWN : NOT_EQUAL
/** : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache);
* @template T }
* @param {T} a
* @param {T} b function tryCompareStrictEquality(a, b) {
* @returns {boolean} return a === b ? EQUAL : UNKNOWN;
*/ }
function deepEqual(a, b) {
return compareEquality(a, b) === EQUAL; function tryCompareTypeOfEquality(a, b) {
} return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN;
}
/**
* @param {unknown} a function tryCompareToStringTagEquality(a, b) {
* @param {unknown} b var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined;
* @param {ComparisonCache} [cache] var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined;
* @returns {EQUAL | NOT_EQUAL} return aTag !== bTag ? NOT_EQUAL : UNKNOWN;
*/ }
function compareEquality(a, b, cache) {
return compareIf(a, b, isOptional, compareOptionality) function isOptional(value) {
|| compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality) return value === undefined
|| compareIf(a, b, isObjectEquatable, compareObjectEquality, cache) || value === null;
|| NOT_EQUAL; }
}
function compareOptionality(a, b) {
/** return tryCompareStrictEquality(a, b)
* @template T || NOT_EQUAL;
* @param {unknown} a }
* @param {unknown} b
* @param {(value: unknown) => value is T} test function isPrimitiveEquatable(value) {
* @param {(a: T, b: T, cache?: ComparisonCache) => EQUAL | NOT_EQUAL} compare switch (typeof value) {
* @param {ComparisonCache} [cache] case 'string':
* @returns {EQUAL | NOT_EQUAL | UNKNOWN} case 'number':
*/ case 'bigint':
function compareIf(a, b, test, compare, cache) { case 'boolean':
return !test(a) case 'symbol':
? !test(b) ? UNKNOWN : NOT_EQUAL return true;
: !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache); default:
} return isBoxed(value);
}
/** }
* @returns {EQUAL | UNKNOWN}
*/ function comparePrimitiveEquality(a, b) {
function tryCompareStrictEquality(a, b) { if (isBoxed(a)) a = a.valueOf();
return a === b ? EQUAL : UNKNOWN; if (isBoxed(b)) b = b.valueOf();
} return tryCompareStrictEquality(a, b)
|| tryCompareTypeOfEquality(a, b)
/** || compareIf(a, b, isNaNEquatable, compareNaNEquality)
* @returns {NOT_EQUAL | UNKNOWN} || NOT_EQUAL;
*/ }
function tryCompareTypeOfEquality(a, b) {
return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN; function isNaNEquatable(value) {
} return typeof value === 'number';
}
/**
* @returns {NOT_EQUAL | UNKNOWN} function compareNaNEquality(a, b) {
*/ return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL;
function tryCompareToStringTagEquality(a, b) { }
var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined;
var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined; function isObjectEquatable(value) {
return aTag !== bTag ? NOT_EQUAL : UNKNOWN; return typeof value === 'object';
} }
/** function compareObjectEquality(a, b, cache) {
* @returns {value is null | undefined} if (!cache) cache = new Map();
*/ return getCache(cache, a, b)
function isOptional(value) { || setCache(cache, a, b, EQUAL) // consider equal for now
return value === undefined || cacheComparison(a, b, tryCompareStrictEquality, cache)
|| value === null; || cacheComparison(a, b, tryCompareToStringTagEquality, cache)
} || compareIf(a, b, isValueOfEquatable, compareValueOfEquality)
|| compareIf(a, b, isToStringEquatable, compareToStringEquality)
/** || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache)
* @returns {EQUAL | NOT_EQUAL} || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache)
*/ || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
function compareOptionality(a, b) { || cacheComparison(a, b, fail, cache);
return tryCompareStrictEquality(a, b) }
|| NOT_EQUAL;
} function isBoxed(value) {
return value instanceof String
/** || value instanceof Number
* @returns {value is number | bigint | string | symbol | boolean | undefined} || value instanceof Boolean
*/ || typeof Symbol === 'function' && value instanceof Symbol
function isPrimitiveEquatable(value) { || typeof BigInt === 'function' && value instanceof BigInt;
switch (typeof value) { }
case 'string':
case 'number': function isValueOfEquatable(value) {
case 'bigint': return value instanceof Date;
case 'boolean': }
case 'symbol':
return true; function compareValueOfEquality(a, b) {
default: return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality)
return isBoxed(value); || NOT_EQUAL;
} }
}
function isToStringEquatable(value) {
/** return value instanceof RegExp;
* @returns {EQUAL | NOT_EQUAL} }
*/
function comparePrimitiveEquality(a, b) { function compareToStringEquality(a, b) {
if (isBoxed(a)) a = a.valueOf(); return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality)
if (isBoxed(b)) b = b.valueOf(); || NOT_EQUAL;
return tryCompareStrictEquality(a, b) }
|| tryCompareTypeOfEquality(a, b)
|| compareIf(a, b, isNaNEquatable, compareNaNEquality) function isArrayLikeEquatable(value) {
|| NOT_EQUAL; return (Array.isArray ? Array.isArray(value) : value instanceof Array)
} || (typeof Uint8Array === 'function' && value instanceof Uint8Array)
|| (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray)
/** || (typeof Uint16Array === 'function' && value instanceof Uint16Array)
* @returns {value is number} || (typeof Uint32Array === 'function' && value instanceof Uint32Array)
*/ || (typeof Int8Array === 'function' && value instanceof Int8Array)
function isNaNEquatable(value) { || (typeof Int16Array === 'function' && value instanceof Int16Array)
return typeof value === 'number'; || (typeof Int32Array === 'function' && value instanceof Int32Array)
} || (typeof Float32Array === 'function' && value instanceof Float32Array)
|| (typeof Float64Array === 'function' && value instanceof Float64Array)
/** || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array)
* @param {number} a || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array);
* @param {number} b }
* @returns {EQUAL | NOT_EQUAL}
*/ function compareArrayLikeEquality(a, b, cache) {
function compareNaNEquality(a, b) { if (a.length !== b.length) return NOT_EQUAL;
return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL; for (var i = 0; i < a.length; i++) {
} if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) {
return NOT_EQUAL;
/** }
* @returns {value is object} }
*/ return EQUAL;
function isObjectEquatable(value) { }
return typeof value === 'object';
} function isStructurallyEquatable(value) {
return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference
/** || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference
* @param {ComparisonCache} cache || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference
* @returns {EQUAL | NOT_EQUAL} || typeof Map === 'function' && value instanceof Map // comparable via @@iterator
*/ || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator
function compareObjectEquality(a, b, cache) { }
if (!cache) cache = new Map();
return getCache(cache, a, b) function compareStructuralEquality(a, b, cache) {
|| setCache(cache, a, b, EQUAL) // consider equal for now var aKeys = [];
|| cacheComparison(a, b, tryCompareStrictEquality, cache) for (var key in a) aKeys.push(key);
|| cacheComparison(a, b, tryCompareToStringTagEquality, cache)
|| compareIf(a, b, isValueOfEquatable, compareValueOfEquality) var bKeys = [];
|| compareIf(a, b, isToStringEquatable, compareToStringEquality) for (var key in b) bKeys.push(key);
|| compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache)
|| compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache) if (aKeys.length !== bKeys.length) {
|| compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) return NOT_EQUAL;
|| cacheComparison(a, b, fail, cache); }
}
aKeys.sort();
function isBoxed(value) { bKeys.sort();
return value instanceof String
|| value instanceof Number for (var i = 0; i < aKeys.length; i++) {
|| value instanceof Boolean var aKey = aKeys[i];
|| typeof Symbol === 'function' && value instanceof Symbol var bKey = bKeys[i];
|| typeof BigInt === 'function' && value instanceof BigInt; if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) {
} return NOT_EQUAL;
}
/** if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) {
* @returns {value is { valueOf(): any }} return NOT_EQUAL;
*/ }
function isValueOfEquatable(value) { }
return value instanceof Date;
} return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
|| EQUAL;
/** }
* @param {{ valueOf(): any }} a
* @param {{ valueOf(): any }} b function isIterableEquatable(value) {
* @returns {EQUAL | NOT_EQUAL} return typeof Symbol === 'function'
*/ && typeof value[Symbol.iterator] === 'function';
function compareValueOfEquality(a, b) { }
return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality)
|| NOT_EQUAL; function compareIteratorEquality(a, b, cache) {
} if (typeof Map === 'function' && a instanceof Map && b instanceof Map ||
typeof Set === 'function' && a instanceof Set && b instanceof Set) {
/** if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size
* @returns {value is { toString(): string }} }
*/
function isToStringEquatable(value) { var ar, br;
return value instanceof RegExp; while (true) {
} ar = a.next();
br = b.next();
/** if (ar.done) {
* @param {{ toString(): string }} a if (br.done) return EQUAL;
* @param {{ toString(): string }} b if (b.return) b.return();
* @returns {EQUAL | NOT_EQUAL} return NOT_EQUAL;
*/ }
function compareToStringEquality(a, b) { if (br.done) {
return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality) if (a.return) a.return();
|| NOT_EQUAL; return NOT_EQUAL;
} }
if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) {
/** if (a.return) a.return();
* @returns {value is ArrayLike<unknown>} if (b.return) b.return();
*/ return NOT_EQUAL;
function isArrayLikeEquatable(value) { }
return (Array.isArray ? Array.isArray(value) : value instanceof Array) }
|| (typeof Uint8Array === 'function' && value instanceof Uint8Array) }
|| (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray)
|| (typeof Uint16Array === 'function' && value instanceof Uint16Array) function compareIterableEquality(a, b, cache) {
|| (typeof Uint32Array === 'function' && value instanceof Uint32Array) return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache);
|| (typeof Int8Array === 'function' && value instanceof Int8Array) }
|| (typeof Int16Array === 'function' && value instanceof Int16Array)
|| (typeof Int32Array === 'function' && value instanceof Int32Array) function cacheComparison(a, b, compare, cache) {
|| (typeof Float32Array === 'function' && value instanceof Float32Array) var result = compare(a, b, cache);
|| (typeof Float64Array === 'function' && value instanceof Float64Array) if (cache && (result === EQUAL || result === NOT_EQUAL)) {
|| (typeof BigUint64Array === 'function' && value instanceof BigUint64Array) setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result));
|| (typeof BigInt64Array === 'function' && value instanceof BigInt64Array); }
} return result;
}
/**
* @template T function fail() {
* @param {ArrayLike<T>} a return NOT_EQUAL;
* @param {ArrayLike<T>} b }
* @param {ComparisonCache} cache
* @returns {EQUAL | NOT_EQUAL} function setCache(cache, left, right, result) {
*/ var otherCache;
function compareArrayLikeEquality(a, b, cache) {
if (a.length !== b.length) return NOT_EQUAL; otherCache = cache.get(left);
for (var i = 0; i < a.length; i++) { if (!otherCache) cache.set(left, otherCache = new Map());
if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) { otherCache.set(right, result);
return NOT_EQUAL;
} otherCache = cache.get(right);
} if (!otherCache) cache.set(right, otherCache = new Map());
return EQUAL; otherCache.set(left, result);
} }
/** function getCache(cache, left, right) {
* @template T var otherCache;
* @param {T} value /** @type {EQUAL | NOT_EQUAL | UNKNOWN | undefined} */
* @returns {value is Exclude<T, Promise | WeakMap | WeakSet | Map | Set>} var result;
*/
function isStructurallyEquatable(value) { otherCache = cache.get(left);
return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference result = otherCache && otherCache.get(right);
|| typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference if (result) return result;
|| typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference
|| typeof Map === 'function' && value instanceof Map // comparable via @@iterator otherCache = cache.get(right);
|| typeof Set === 'function' && value instanceof Set); // comparable via @@iterator result = otherCache && otherCache.get(left);
} if (result) return result;
/** return UNKNOWN;
* @param {ComparisonCache} cache }
* @returns {EQUAL | NOT_EQUAL}
*/ return deepEqual;
function compareStructuralEquality(a, b, cache) { })();
var aKeys = [];
for (var key in a) aKeys.push(key); assert.deepEqual = function (actual, expected, message) {
assert(deepEqual(actual, expected),
var bKeys = []; 'Expected ' + assert._formatValue(actual) + ' to be structurally equal to ' + assert._formatValue(expected) + '. ' + (message || ''));
for (var key in b) bKeys.push(key); };
if (aKeys.length !== bKeys.length) {
return NOT_EQUAL;
}
aKeys.sort();
bKeys.sort();
for (var i = 0; i < aKeys.length; i++) {
var aKey = aKeys[i];
var bKey = bKeys[i];
if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) {
return NOT_EQUAL;
}
if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) {
return NOT_EQUAL;
}
}
return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
|| EQUAL;
}
/**
* @returns {value is Iterable<unknown>}
*/
function isIterableEquatable(value) {
return typeof Symbol === 'function'
&& typeof value[Symbol.iterator] === 'function';
}
/**
* @template T
* @param {Iterator<T>} a
* @param {Iterator<T>} b
* @param {ComparisonCache} cache
* @returns {EQUAL | NOT_EQUAL}
*/
function compareIteratorEquality(a, b, cache) {
if (typeof Map === 'function' && a instanceof Map && b instanceof Map ||
typeof Set === 'function' && a instanceof Set && b instanceof Set) {
if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size
}
var ar, br;
while (true) {
ar = a.next();
br = b.next();
if (ar.done) {
if (br.done) return EQUAL;
if (b.return) b.return();
return NOT_EQUAL;
}
if (br.done) {
if (a.return) a.return();
return NOT_EQUAL;
}
if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) {
if (a.return) a.return();
if (b.return) b.return();
return NOT_EQUAL;
}
}
}
/**
* @template T
* @param {Iterable<T>} a
* @param {Iterable<T>} b
* @param {ComparisonCache} cache
* @returns {EQUAL | NOT_EQUAL}
*/
function compareIterableEquality(a, b, cache) {
return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache);
}
/**
* @template T
* @template {EQUAL | NOT_EQUAL | UNKNOWN} R
* @param {(a: T, b: T, circular?: ComparisonCache) => R} compare
* @param {ComparisonCache} [cache]
*/
function cacheComparison(a, b, compare, cache) {
var result = compare(a, b, cache);
if (cache && (result === EQUAL || result === NOT_EQUAL)) {
setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result));
}
return result;
}
function fail() {
return NOT_EQUAL;
}
/**
* @param {EQUAL | NOT_EQUAL} result
* @param {ComparisonCache} cache
*/
function setCache(cache, left, right, result) {
var otherCache;
otherCache = cache.get(left);
if (!otherCache) cache.set(left, otherCache = new Map());
otherCache.set(right, result);
otherCache = cache.get(right);
if (!otherCache) cache.set(right, otherCache = new Map());
otherCache.set(left, result);
}
/**
* @param {ComparisonCache} cache
*/
function getCache(cache, left, right) {
var otherCache;
/** @type {EQUAL | NOT_EQUAL | UNKNOWN | undefined} */
var result;
otherCache = cache.get(left);
result = otherCache && otherCache.get(right);
if (result) return result;
otherCache = cache.get(right);
result = otherCache && otherCache.get(left);
if (result) return result;
return UNKNOWN;
}
return deepEqual;
})();
/**
* @template T
* @param {T} actual
* @param {T} expected
* @param {string} [message]
*/
assert.deepEqual = function (actual, expected, message) {
assert(deepEqual(actual, expected),
'Expected ' + assert._formatValue(actual) + ' to be structurally equal to ' + assert._formatValue(expected) + '. ' + (message || ''));
};

14
harness/types.d.ts vendored
View File

@ -1,14 +0,0 @@
declare function $ERROR(text: string): void;
// Proposal: regexp-match-indices
interface RegExpExecArray {
indices: RegExpIndicesArray;
}
interface RegExpMatchArray {
indices: RegExpIndicesArray;
}
interface RegExpIndicesArray extends Array<[number, number]> {
groups?: { [group: string]: [number, number] };
}

View File

@ -1,28 +1,27 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: A matching element of indices is an Array with exactly two number properties. description: A matching element of indices is an Array with exactly two number properties.
esid: sec-getmatchindicesarray esid: sec-getmatchindicesarray
features: [regexp-match-indices] features: [regexp-match-indices]
info: | info: |
GetMatchIndicesArray ( S, match ) GetMatchIndicesArray ( S, match )
5. Return CreateArrayFromList(« _match_.[[StartIndex]], _match_.[[EndIndex]] »). 5. Return CreateArrayFromList(« _match_.[[StartIndex]], _match_.[[EndIndex]] »).
---*/ ---*/
let input = "abcd";
let input = "abcd"; let match = /b(c)/.exec(input);
let match = /b(c)/.exec(input); let indices = match.indices;
let indices = match.indices;
// `indices[0]` is an array
// `indices[0]` is an array assert.sameValue(Object.getPrototypeOf(indices[0]), Array.prototype);
assert.sameValue(Object.getPrototypeOf(indices[0]), Array.prototype); assert.sameValue(indices[0].length, 2);
assert.sameValue(indices[0].length, 2); assert.sameValue(typeof indices[0][0], "number");
assert.sameValue(typeof indices[0][0], "number"); assert.sameValue(typeof indices[0][1], "number");
assert.sameValue(typeof indices[0][1], "number");
// `indices[1]` is an array
// `indices[1]` is an array assert.sameValue(Object.getPrototypeOf(indices[1]), Array.prototype);
assert.sameValue(Object.getPrototypeOf(indices[1]), Array.prototype); assert.sameValue(indices[1].length, 2);
assert.sameValue(indices[1].length, 2); assert.sameValue(typeof indices[1][0], "number");
assert.sameValue(typeof indices[1][0], "number"); assert.sameValue(typeof indices[1][1], "number");
assert.sameValue(typeof indices[1][1], "number");

View File

@ -1,39 +1,38 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: The properties of the "indices" array correspond to the start/end indices of the same values in the match. description: The properties of the "indices" array correspond to the start/end indices of the same values in the match.
includes: [compareArray.js] includes: [compareArray.js]
esid: sec-makeindicesarray esid: sec-makeindicesarray
features: [regexp-match-indices] features: [regexp-match-indices]
info: | info: |
MakeIndicesArray ( S, indices, groupNames ) MakeIndicesArray ( S, indices, groupNames )
4. Let _n_ be the number of elements in _indices_. 4. Let _n_ be the number of elements in _indices_.
... ...
6. Set _A_ to ! ArrayCreate(_n_). 6. Set _A_ to ! ArrayCreate(_n_).
... ...
11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do
a. Let _matchIndices_ be _indices_[_i_]. a. Let _matchIndices_ be _indices_[_i_].
b. If _matchIndices_ is not *undefined*, then b. If _matchIndices_ is not *undefined*, then
i. Let _matchIndicesArray_ be ! GetMatchIndicesArray(_S_, _matchIndices_). i. Let _matchIndicesArray_ be ! GetMatchIndicesArray(_S_, _matchIndices_).
c. Else, c. Else,
i. Let _matchIndicesArray_ be *undefined*. i. Let _matchIndicesArray_ be *undefined*.
d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_). d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_).
... ...
---*/ ---*/
let input = "abcd";
let input = "abcd"; let match = /b(c)/.exec(input);
let match = /b(c)/.exec(input); let indices = match.indices;
let indices = match.indices;
// `indices` has the same length as match
// `indices` has the same length as match assert.sameValue(indices.length, match.length);
assert.sameValue(indices.length, match.length);
// The first element of `indices` contains the start/end indices of the match
// The first element of `indices` contains the start/end indices of the match assert.compareArray(indices[0], [1, 3]);
assert.compareArray(indices[0], [1, 3]); assert.sameValue(input.slice(indices[0][0], indices[0][1]), match[0]);
assert.sameValue(input.slice(indices[0][0], indices[0][1]), match[0]);
// The second element of `indices` contains the start/end indices of the first capture
// The second element of `indices` contains the start/end indices of the first capture assert.compareArray(indices[1], [2, 3]);
assert.compareArray(indices[1], [2, 3]); assert.sameValue(input.slice(indices[1][0], indices[1][1]), match[1]);
assert.sameValue(input.slice(indices[1][0], indices[1][1]), match[1]);

View File

@ -1,76 +1,75 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: Basic matching cases with non-unicode matches. description: Basic matching cases with non-unicode matches.
includes: [compareArray.js, propertyHelper.js, deepEqual.js] includes: [compareArray.js, propertyHelper.js, deepEqual.js]
esid: sec-regexpbuiltinexec esid: sec-regexpbuiltinexec
features: [regexp-match-indices] features: [regexp-match-indices]
info: | info: |
Runtime Semantics: RegExpBuiltinExec ( R, S ) Runtime Semantics: RegExpBuiltinExec ( R, S )
... ...
4. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex")). 4. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex")).
... ...
25. Let _indices_ be a new empty List. 25. Let _indices_ be a new empty List.
26. Let _match_ be the Match { [[StartIndex]]: _lastIndex_, [[EndIndex]]: _e_ }. 26. Let _match_ be the Match { [[StartIndex]]: _lastIndex_, [[EndIndex]]: _e_ }.
27. Add _match_ as the last element of _indices_. 27. Add _match_ as the last element of _indices_.
... ...
33. For each integer _i_ such that _i_ > 0 and _i_ <= _n_, in ascending order, do 33. For each integer _i_ such that _i_ > 0 and _i_ <= _n_, in ascending order, do
... ...
f. Else, f. Else,
i. Let _captureStart_ be _captureI_'s _startIndex_. i. Let _captureStart_ be _captureI_'s _startIndex_.
ii. Let _captureEnd_ be _captureI_'s _endIndex_. ii. Let _captureEnd_ be _captureI_'s _endIndex_.
... ...
iv. Let _capture_ be the Match { [[StartIndex]]: _captureStart_, [[EndIndex]]: _captureEnd_ }. iv. Let _capture_ be the Match { [[StartIndex]]: _captureStart_, [[EndIndex]]: _captureEnd_ }.
v. Append _capture_ to _indices_. v. Append _capture_ to _indices_.
... ...
34. Let _indicesArray_ be MakeIndicesArray( _S_, _indices_, _groupNames_). 34. Let _indicesArray_ be MakeIndicesArray( _S_, _indices_, _groupNames_).
---*/ ---*/
assert.deepEqual([[1, 2], [1, 2]], "bab".match(/(a)/).indices);
assert.deepEqual([[1, 2], [1, 2]], "bab".match(/(a)/).indices); assert.deepEqual([[0, 3], [1, 2]], "bab".match(/.(a)./).indices);
assert.deepEqual([[0, 3], [1, 2]], "bab".match(/.(a)./).indices); assert.deepEqual([[0, 3], [1, 2], [2, 3]], "bab".match(/.(a)(.)/).indices);
assert.deepEqual([[0, 3], [1, 2], [2, 3]], "bab".match(/.(a)(.)/).indices); assert.deepEqual([[0, 3], [1, 3]], "bab".match(/.(\w\w)/).indices);
assert.deepEqual([[0, 3], [1, 3]], "bab".match(/.(\w\w)/).indices); assert.deepEqual([[0, 3], [0, 3]], "bab".match(/(\w\w\w)/).indices);
assert.deepEqual([[0, 3], [0, 3]], "bab".match(/(\w\w\w)/).indices); assert.deepEqual([[0, 3], [0, 2], [2, 3]], "bab".match(/(\w\w)(\w)/).indices);
assert.deepEqual([[0, 3], [0, 2], [2, 3]], "bab".match(/(\w\w)(\w)/).indices); assert.deepEqual([[0, 2], [0, 2], undefined], "bab".match(/(\w\w)(\W)?/).indices);
assert.deepEqual([[0, 2], [0, 2], undefined], "bab".match(/(\w\w)(\W)?/).indices);
let groups = /(?<a>.)(?<b>.)(?<c>.)\k<c>\k<b>\k<a>/.exec("abccba").indices.groups;
let groups = /(?<a>.)(?<b>.)(?<c>.)\k<c>\k<b>\k<a>/.exec("abccba").indices.groups; assert.compareArray([0, 1], groups.a);
assert.compareArray([0, 1], groups.a); assert.compareArray([1, 2], groups.b);
assert.compareArray([1, 2], groups.b); assert.compareArray([2, 3], groups.c);
assert.compareArray([2, 3], groups.c); verifyProperty(groups, "a", {
verifyProperty(groups, "a", { enumerable: true,
enumerable: true, writable: true,
writable: true, configurable: true
configurable: true });
}); verifyProperty(groups, "b", {
verifyProperty(groups, "b", { enumerable: true,
enumerable: true, writable: true,
writable: true, configurable: true
configurable: true });
}); verifyProperty(groups, "c", {
verifyProperty(groups, "c", { enumerable: true,
enumerable: true, writable: true,
writable: true, configurable: true
configurable: true });
});
// "𝐁" is U+1d401 MATHEMATICAL BOLD CAPITAL B
// "𝐁" is U+1d401 MATHEMATICAL BOLD CAPITAL B // - Also representable as the code point "\u{1d401}"
// - Also representable as the code point "\u{1d401}" // - Also representable as the surrogate pair "\uD835\uDC01"
// - Also representable as the surrogate pair "\uD835\uDC01"
// Verify assumptions:
// Verify assumptions: assert.sameValue("𝐁".length, 2, 'The length of "𝐁" is 2');
assert.sameValue("𝐁".length, 2, 'The length of "𝐁" is 2'); assert.sameValue("\u{1d401}".length, 2, 'The length of "\\u{1d401}" is 2');
assert.sameValue("\u{1d401}".length, 2, 'The length of "\\u{1d401}" is 2'); assert.sameValue("\uD835\uDC01".length, 2, 'The length of "\\uD835\\uDC01" is 2');
assert.sameValue("\uD835\uDC01".length, 2, 'The length of "\\uD835\\uDC01" is 2'); assert.sameValue("𝐁".match(/./)[0].length, 1, 'The length of a single code unit match against "𝐁" is 1 (without /u flag)');
assert.sameValue("𝐁".match(/./)[0].length, 1, 'The length of a single code unit match against "𝐁" is 1 (without /u flag)'); assert.sameValue("\u{1d401}".match(/./)[0].length, 1, 'The length of a single code unit match against "\\u{1d401}" is 1 (without /u flag)');
assert.sameValue("\u{1d401}".match(/./)[0].length, 1, 'The length of a single code unit match against "\\u{1d401}" is 1 (without /u flag)'); assert.sameValue("\uD835\uDC01".match(/./)[0].length, 1, 'The length of a single code unit match against "\\ud835\\udc01" is 1 (without /u flag)');
assert.sameValue("\uD835\uDC01".match(/./)[0].length, 1, 'The length of a single code unit match against "\\ud835\\udc01" is 1 (without /u flag)');
assert.compareArray([0, 1], "𝐁".match(/./).indices[0], 'Indices for non-unicode match against "𝐁" (without /u flag)');
assert.compareArray([0, 1], "𝐁".match(/./).indices[0], 'Indices for non-unicode match against "𝐁" (without /u flag)'); assert.compareArray([0, 1], "\u{1d401}".match(/./).indices[0], 'Indices for non-unicode match against "\\u{1d401}" (without /u flag)');
assert.compareArray([0, 1], "\u{1d401}".match(/./).indices[0], 'Indices for non-unicode match against "\\u{1d401}" (without /u flag)'); assert.compareArray([0, 1], "\uD835\uDC01".match(/./).indices[0], 'Indices for non-unicode match against "\\ud835\\udc01" (without /u flag)');
assert.compareArray([0, 1], "\uD835\uDC01".match(/./).indices[0], 'Indices for non-unicode match against "\\ud835\\udc01" (without /u flag)'); assert.compareArray([0, 1], "𝐁".match(/(?<a>.)/).indices.groups.a, 'Indices for non-unicode match against "𝐁" in groups.a (without /u flag)');
assert.compareArray([0, 1], "𝐁".match(/(?<a>.)/).indices.groups.a, 'Indices for non-unicode match against "𝐁" in groups.a (without /u flag)'); assert.compareArray([0, 1], "\u{1d401}".match(/(?<a>.)/).indices.groups.a, 'Indices for non-unicode match against "\\u{1d401}" in groups.a (without /u flag)');
assert.compareArray([0, 1], "\u{1d401}".match(/(?<a>.)/).indices.groups.a, 'Indices for non-unicode match against "\\u{1d401}" in groups.a (without /u flag)'); assert.compareArray([0, 1], "\uD835\uDC01".match(/(?<a>.)/).indices.groups.a, 'Indices for non-unicode match against "\\ud835\\udc01" in groups.a (without /u flag)');
assert.compareArray([0, 1], "\uD835\uDC01".match(/(?<a>.)/).indices.groups.a, 'Indices for non-unicode match against "\\ud835\\udc01" in groups.a (without /u flag)');

View File

@ -1,30 +1,29 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: The properties of the "indices" array are created with CreateDataProperty. description: The properties of the "indices" array are created with CreateDataProperty.
includes: [propertyHelper.js] includes: [propertyHelper.js]
esid: sec-makeindicesarray esid: sec-makeindicesarray
features: [regexp-match-indices] features: [regexp-match-indices]
info: | info: |
MakeIndicesArray ( S, indices, groupNames ) MakeIndicesArray ( S, indices, groupNames )
11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do
d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_). d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_).
---*/ ---*/
let input = "abcd";
let input = "abcd"; let match = /b(c)/.exec(input);
let match = /b(c)/.exec(input); let indices = match.indices;
let indices = match.indices;
verifyProperty(indices, '0', {
verifyProperty(indices, '0', { enumerable: true,
enumerable: true, configurable: true,
configurable: true, writable: true
writable: true });
});
verifyProperty(indices, '1', {
verifyProperty(indices, '1', { enumerable: true,
enumerable: true, configurable: true,
configurable: true, writable: true
writable: true });
});

View File

@ -1,85 +1,84 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: Basic matching cases with non-unicode matches. description: Basic matching cases with non-unicode matches.
includes: [compareArray.js, propertyHelper.js, deepEqual.js] includes: [compareArray.js, propertyHelper.js, deepEqual.js]
esid: sec-regexpbuiltinexec esid: sec-regexpbuiltinexec
features: [regexp-match-indices] features: [regexp-match-indices]
info: | info: |
Runtime Semantics: RegExpBuiltinExec ( R, S ) Runtime Semantics: RegExpBuiltinExec ( R, S )
... ...
4. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex")). 4. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex")).
... ...
16. If _fullUnicode_ is *true*, set _e_ to ! GetStringIndex(_S_, _Input_, _e_). 16. If _fullUnicode_ is *true*, set _e_ to ! GetStringIndex(_S_, _Input_, _e_).
... ...
25. Let _indices_ be a new empty List. 25. Let _indices_ be a new empty List.
26. Let _match_ be the Match { [[StartIndex]]: _lastIndex_, [[EndIndex]]: _e_ }. 26. Let _match_ be the Match { [[StartIndex]]: _lastIndex_, [[EndIndex]]: _e_ }.
27. Add _match_ as the last element of _indices_. 27. Add _match_ as the last element of _indices_.
... ...
33. For each integer _i_ such that _i_ > 0 and _i_ <= _n_, in ascending order, do 33. For each integer _i_ such that _i_ > 0 and _i_ <= _n_, in ascending order, do
... ...
f. Else, f. Else,
i. Let _captureStart_ be _captureI_'s _startIndex_. i. Let _captureStart_ be _captureI_'s _startIndex_.
ii. Let _captureEnd_ be _captureI_'s _endIndex_. ii. Let _captureEnd_ be _captureI_'s _endIndex_.
iii. If _fullUnicode_ is *true*, then iii. If _fullUnicode_ is *true*, then
1. Set _captureStart_ to ! GetStringIndex(_S_, _Input_, _captureStart_). 1. Set _captureStart_ to ! GetStringIndex(_S_, _Input_, _captureStart_).
1. Set _captureEnd_ to ! GetStringIndex(_S_, _Input_, _captureEnd_). 1. Set _captureEnd_ to ! GetStringIndex(_S_, _Input_, _captureEnd_).
iv. Let _capture_ be the Match { [[StartIndex]]: _captureStart_, [[EndIndex]]: _captureEnd_ }. iv. Let _capture_ be the Match { [[StartIndex]]: _captureStart_, [[EndIndex]]: _captureEnd_ }.
v. Append _capture_ to _indices_. v. Append _capture_ to _indices_.
... ...
34. Let _indicesArray_ be MakeIndicesArray( _S_, _indices_, _groupNames_). 34. Let _indicesArray_ be MakeIndicesArray( _S_, _indices_, _groupNames_).
GetStringIndex ( S, Input, e ) GetStringIndex ( S, Input, e )
... ...
4. Let _eUTF_ be the smallest index into _S_ that corresponds to the character at element _e_ of _Input_. If _e_ is greater than or equal to the number of elements in _Input_, then _eUTF_ is the number of code units in _S_. 4. Let _eUTF_ be the smallest index into _S_ that corresponds to the character at element _e_ of _Input_. If _e_ is greater than or equal to the number of elements in _Input_, then _eUTF_ is the number of code units in _S_.
5. Return _eUTF_. 5. Return _eUTF_.
---*/ ---*/
assert.deepEqual([[1, 2], [1, 2]], "bab".match(/(a)/u).indices);
assert.deepEqual([[1, 2], [1, 2]], "bab".match(/(a)/u).indices); assert.deepEqual([[0, 3], [1, 2]], "bab".match(/.(a)./u).indices);
assert.deepEqual([[0, 3], [1, 2]], "bab".match(/.(a)./u).indices); assert.deepEqual([[0, 3], [1, 2], [2, 3]], "bab".match(/.(a)(.)/u).indices);
assert.deepEqual([[0, 3], [1, 2], [2, 3]], "bab".match(/.(a)(.)/u).indices); assert.deepEqual([[0, 3], [1, 3]], "bab".match(/.(\w\w)/u).indices);
assert.deepEqual([[0, 3], [1, 3]], "bab".match(/.(\w\w)/u).indices); assert.deepEqual([[0, 3], [0, 3]], "bab".match(/(\w\w\w)/u).indices);
assert.deepEqual([[0, 3], [0, 3]], "bab".match(/(\w\w\w)/u).indices); assert.deepEqual([[0, 3], [0, 2], [2, 3]], "bab".match(/(\w\w)(\w)/u).indices);
assert.deepEqual([[0, 3], [0, 2], [2, 3]], "bab".match(/(\w\w)(\w)/u).indices); assert.deepEqual([[0, 2], [0, 2], undefined], "bab".match(/(\w\w)(\W)?/u).indices);
assert.deepEqual([[0, 2], [0, 2], undefined], "bab".match(/(\w\w)(\W)?/u).indices);
let groups = /(?<a>.)(?<b>.)(?<c>.)\k<c>\k<b>\k<a>/u.exec("abccba").indices.groups;
let groups = /(?<a>.)(?<b>.)(?<c>.)\k<c>\k<b>\k<a>/u.exec("abccba").indices.groups; assert.compareArray([0, 1], groups.a);
assert.compareArray([0, 1], groups.a); assert.compareArray([1, 2], groups.b);
assert.compareArray([1, 2], groups.b); assert.compareArray([2, 3], groups.c);
assert.compareArray([2, 3], groups.c); verifyProperty(groups, "a", {
verifyProperty(groups, "a", { enumerable: true,
enumerable: true, writable: true,
writable: true, configurable: true
configurable: true });
}); verifyProperty(groups, "b", {
verifyProperty(groups, "b", { enumerable: true,
enumerable: true, writable: true,
writable: true, configurable: true
configurable: true });
}); verifyProperty(groups, "c", {
verifyProperty(groups, "c", { enumerable: true,
enumerable: true, writable: true,
writable: true, configurable: true
configurable: true });
});
// "𝐁" is U+1d401 MATHEMATICAL BOLD CAPITAL B
// "𝐁" is U+1d401 MATHEMATICAL BOLD CAPITAL B // - Also representable as the code point "\u{1d401}"
// - Also representable as the code point "\u{1d401}" // - Also representable as the surrogate pair "\uD835\uDC01"
// - Also representable as the surrogate pair "\uD835\uDC01"
// Verify assumptions:
// Verify assumptions: assert.sameValue("𝐁".length, 2, 'The length of "𝐁" is 2');
assert.sameValue("𝐁".length, 2, 'The length of "𝐁" is 2'); assert.sameValue("\u{1d401}".length, 2, 'The length of "\\u{1d401}" is 2');
assert.sameValue("\u{1d401}".length, 2, 'The length of "\\u{1d401}" is 2'); assert.sameValue("\uD835\uDC01".length, 2, 'The length of "\\uD835\\uDC01" is 2');
assert.sameValue("\uD835\uDC01".length, 2, 'The length of "\\uD835\\uDC01" is 2'); assert.sameValue(2, "𝐁".match(/./u)[0].length, 'The length of a single code point match against "𝐁" is 2 (with /u flag)');
assert.sameValue(2, "𝐁".match(/./u)[0].length, 'The length of a single code point match against "𝐁" is 2 (with /u flag)'); assert.sameValue(2, "\u{1d401}".match(/./u)[0].length, 'The length of a single code point match against "\\u{1d401}" is 2 (with /u flag)');
assert.sameValue(2, "\u{1d401}".match(/./u)[0].length, 'The length of a single code point match against "\\u{1d401}" is 2 (with /u flag)'); assert.sameValue(2, "\uD835\uDC01".match(/./u)[0].length, 'The length of a single code point match against "\\ud835\\udc01" is 2 (with /u flag)');
assert.sameValue(2, "\uD835\uDC01".match(/./u)[0].length, 'The length of a single code point match against "\\ud835\\udc01" is 2 (with /u flag)');
assert.compareArray([0, 2], "𝐁".match(/./u).indices[0], 'Indices for unicode match against "𝐁" (with /u flag)');
assert.compareArray([0, 2], "𝐁".match(/./u).indices[0], 'Indices for unicode match against "𝐁" (with /u flag)'); assert.compareArray([0, 2], "\u{1d401}".match(/./u).indices[0], 'Indices for unicode match against \\u{1d401} (with /u flag)');
assert.compareArray([0, 2], "\u{1d401}".match(/./u).indices[0], 'Indices for unicode match against \\u{1d401} (with /u flag)'); assert.compareArray([0, 2], "\uD835\uDC01".match(/./u).indices[0], 'Indices for unicode match against \\ud835\\udc01 (with /u flag)');
assert.compareArray([0, 2], "\uD835\uDC01".match(/./u).indices[0], 'Indices for unicode match against \\ud835\\udc01 (with /u flag)'); assert.compareArray([0, 2], "𝐁".match(/(?<a>.)/u).indices.groups.a, 'Indices for unicode match against 𝐁 in groups.a (with /u flag)');
assert.compareArray([0, 2], "𝐁".match(/(?<a>.)/u).indices.groups.a, 'Indices for unicode match against 𝐁 in groups.a (with /u flag)'); assert.compareArray([0, 2], "\u{1d401}".match(/(?<a>.)/u).indices.groups.a, 'Indices for unicode match against \\u{1d401} in groups.a (with /u flag)');
assert.compareArray([0, 2], "\u{1d401}".match(/(?<a>.)/u).indices.groups.a, 'Indices for unicode match against \\u{1d401} in groups.a (with /u flag)'); assert.compareArray([0, 2], "\uD835\uDC01".match(/(?<a>.)/u).indices.groups.a, 'Indices for unicode match against \\ud835\\udc01 in groups.a (with /u flag)');
assert.compareArray([0, 2], "\uD835\uDC01".match(/(?<a>.)/u).indices.groups.a, 'Indices for unicode match against \\ud835\\udc01 in groups.a (with /u flag)');

View File

@ -1,21 +1,20 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: Basic matching cases with non-unicode matches. description: Basic matching cases with non-unicode matches.
includes: [compareArray.js] includes: [compareArray.js]
esid: sec-makeindicesarray esid: sec-makeindicesarray
features: [regexp-match-indices] features: [regexp-match-indices]
---*/ ---*/
assert.compareArray([1, 2], /(?<π>a)/u.exec("bab").indices.groups.π);
assert.compareArray([1, 2], /(?<π>a)/u.exec("bab").indices.groups.π); assert.compareArray([1, 2], /(?<\u{03C0}>a)/u.exec("bab").indices.groups.π);
assert.compareArray([1, 2], /(?<\u{03C0}>a)/u.exec("bab").indices.groups.π); assert.compareArray([1, 2], /(?<π>a)/u.exec("bab").indices.groups.\u03C0);
assert.compareArray([1, 2], /(?<π>a)/u.exec("bab").indices.groups.\u03C0); assert.compareArray([1, 2], /(?<\u{03C0}>a)/u.exec("bab").indices.groups.\u03C0);
assert.compareArray([1, 2], /(?<\u{03C0}>a)/u.exec("bab").indices.groups.\u03C0); assert.compareArray([1, 2], /(?<$>a)/u.exec("bab").indices.groups.$);
assert.compareArray([1, 2], /(?<$>a)/u.exec("bab").indices.groups.$); assert.compareArray([1, 2], /(?<_>a)/u.exec("bab").indices.groups._);
assert.compareArray([1, 2], /(?<_>a)/u.exec("bab").indices.groups._); assert.compareArray([1, 2], /(?<$𐒤>a)/u.exec("bab").indices.groups.$𐒤);
assert.compareArray([1, 2], /(?<$𐒤>a)/u.exec("bab").indices.groups.$𐒤); assert.compareArray([1, 2], /(?<_\u200C>a)/u.exec("bab").indices.groups._\u200C);
assert.compareArray([1, 2], /(?<_\u200C>a)/u.exec("bab").indices.groups._\u200C); assert.compareArray([1, 2], /(?<_\u200D>a)/u.exec("bab").indices.groups._\u200D);
assert.compareArray([1, 2], /(?<_\u200D>a)/u.exec("bab").indices.groups._\u200D); assert.compareArray([1, 2], /(?<ಠ_ಠ>a)/u.exec("bab").indices.groups._ಠ);
assert.compareArray([1, 2], /(?<ಠ_ಠ>a)/u.exec("bab").indices.groups._ಠ);

View File

@ -1,33 +1,32 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: An unmatched capture in a match corresponds to an unmatched capture in "indices" description: An unmatched capture in a match corresponds to an unmatched capture in "indices"
esid: sec-makeindicesarray esid: sec-makeindicesarray
features: [regexp-match-indices] features: [regexp-match-indices]
info: | info: |
MakeIndicesArray ( S, indices, groupNames ) MakeIndicesArray ( S, indices, groupNames )
4. Let _n_ be the number of elements in _indices_. 4. Let _n_ be the number of elements in _indices_.
... ...
6. Set _A_ to ! ArrayCreate(_n_). 6. Set _A_ to ! ArrayCreate(_n_).
... ...
11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do
a. Let _matchIndices_ be _indices_[_i_]. a. Let _matchIndices_ be _indices_[_i_].
b. If _matchIndices_ is not *undefined*, then b. If _matchIndices_ is not *undefined*, then
i. Let _matchIndicesArray_ be ! GetMatchIndicesArray(_S_, _matchIndices_). i. Let _matchIndicesArray_ be ! GetMatchIndicesArray(_S_, _matchIndices_).
c. Else, c. Else,
i. Let _matchIndicesArray_ be *undefined*. i. Let _matchIndicesArray_ be *undefined*.
d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_). d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_).
... ...
---*/ ---*/
let input = "abd";
let input = "abd"; let match = /b(c)?/.exec(input);
let match = /b(c)?/.exec(input); let indices = match.indices;
let indices = match.indices;
// `indices` has the same length as match
// `indices` has the same length as match assert.sameValue(indices.length, match.length);
assert.sameValue(indices.length, match.length);
// The second element of `indices` should be undefined.
// The second element of `indices` should be undefined. assert.sameValue(indices[1], undefined);
assert.sameValue(indices[1], undefined);

View File

@ -1,19 +1,18 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: The "indices" property is an Array. description: The "indices" property is an Array.
esid: sec-makeindicesarray esid: sec-makeindicesarray
features: [regexp-match-indices] features: [regexp-match-indices]
info: | info: |
MakeIndicesArray ( S, indices, groupNames ) MakeIndicesArray ( S, indices, groupNames )
6. Set _A_ to ! ArrayCreate(_n_). 6. Set _A_ to ! ArrayCreate(_n_).
---*/ ---*/
let match = /a/.exec("a");
let match = /a/.exec("a"); let indices = match.indices;
let indices = match.indices;
// `indices` is an array
// `indices` is an array assert.sameValue(Object.getPrototypeOf(indices), Array.prototype);
assert.sameValue(Object.getPrototypeOf(indices), Array.prototype);
assert(Array.isArray(indices)); assert(Array.isArray(indices));

View File

@ -1,30 +1,29 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: The "indices" property is created with DefinePropertyOrThrow description: The "indices" property is created with DefinePropertyOrThrow
includes: [propertyHelper.js] includes: [propertyHelper.js]
esid: sec-regexpbuiltinexec esid: sec-regexpbuiltinexec
features: [regexp-match-indices] features: [regexp-match-indices]
info: | info: |
Runtime Semantics: RegExpBuiltinExec ( R, S ) Runtime Semantics: RegExpBuiltinExec ( R, S )
34. Let _indicesArray_ be MakeIndicesArray(_S_, _indices_, _groupNames_). 34. Let _indicesArray_ be MakeIndicesArray(_S_, _indices_, _groupNames_).
35. Perform ! DefinePropertyOrThrow(_A_, `"indices"`, PropertyDescriptor { [[Value]]: _indicesArray_, [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }). 35. Perform ! DefinePropertyOrThrow(_A_, `"indices"`, PropertyDescriptor { [[Value]]: _indicesArray_, [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }).
---*/ ---*/
// `indices` is created with Define, not Set.
// `indices` is created with Define, not Set. let counter = 0;
let counter = 0; Object.defineProperty(Array.prototype, "indices", {
Object.defineProperty(Array.prototype, "indices", { set() { counter++; }
set() { counter++; } });
});
let match = /a/.exec("a");
let match = /a/.exec("a"); assert.sameValue(counter, 0);
assert.sameValue(counter, 0);
// `indices` is a non-writable, non-enumerable, and configurable data-property.
// `indices` is a non-writable, non-enumerable, and configurable data-property. verifyProperty(match, 'indices', {
verifyProperty(match, 'indices', { writable: true,
writable: true, enumerable: true,
enumerable: true, configurable: true
configurable: true });
});

View File

@ -1,15 +1,14 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: > description: >
array values compare correctly. array values compare correctly.
includes: [deepEqual.js] includes: [deepEqual.js]
---*/ ---*/
assert.deepEqual([], []);
assert.deepEqual([], []); assert.deepEqual([1, "a", true], [1, "a", true]);
assert.deepEqual([1, "a", true], [1, "a", true]);
assert.throws(Test262Error, function () { assert.deepEqual([], [1]); });
assert.throws(Test262Error, function () { assert.deepEqual([], [1]); }); assert.throws(Test262Error, function () { assert.deepEqual([1, "a", true], [1, "a", false]); });
assert.throws(Test262Error, function () { assert.deepEqual([1, "a", true], [1, "a", false]); });

View File

@ -1,18 +1,17 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: > description: >
values compare correctly with circular references. values compare correctly with circular references.
includes: [deepEqual.js] includes: [deepEqual.js]
---*/ ---*/
var a = { x: 1 };
var a = { x: 1 }; var b = { x: 1 };
var b = { x: 1 }; a.a = a;
a.a = a; a.b = b;
a.b = b; b.a = b;
b.a = b; b.b = a;
b.b = a;
assert.deepEqual(a, b);
assert.deepEqual(a, b);

View File

@ -1,14 +1,13 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: > description: >
values compare correctly. values compare correctly.
includes: [deepEqual.js] includes: [deepEqual.js]
---*/ ---*/
assert.deepEqual({ a: { x: 1 }, b: [true] }, { a: { x: 1 }, b: [true] });
assert.deepEqual({ a: { x: 1 }, b: [true] }, { a: { x: 1 }, b: [true] });
assert.throws(Test262Error, function () { assert.deepEqual({}, { a: { x: 1 }, b: [true] }); });
assert.throws(Test262Error, function () { assert.deepEqual({}, { a: { x: 1 }, b: [true] }); }); assert.throws(Test262Error, function () { assert.deepEqual({ a: { x: 1 }, b: [true] }, { a: { x: 1 }, b: [false] }); });
assert.throws(Test262Error, function () { assert.deepEqual({ a: { x: 1 }, b: [true] }, { a: { x: 1 }, b: [false] }); });

View File

@ -1,20 +1,19 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: > description: >
map/set values compare correctly. map/set values compare correctly.
includes: [deepEqual.js] includes: [deepEqual.js]
---*/ ---*/
assert.deepEqual(new Set(), new Set());
assert.deepEqual(new Set(), new Set()); assert.deepEqual(new Set([1, "a", true]), new Set([1, "a", true]));
assert.deepEqual(new Set([1, "a", true]), new Set([1, "a", true])); assert.deepEqual(new Map(), new Map());
assert.deepEqual(new Map(), new Map()); assert.deepEqual(new Map([[1, "a"], ["b", true]]), new Map([[1, "a"], ["b", true]]));
assert.deepEqual(new Map([[1, "a"], ["b", true]]), new Map([[1, "a"], ["b", true]]));
assert.throws(Test262Error, function () { assert.deepEqual(new Set([]), new Set([1])); });
assert.throws(Test262Error, function () { assert.deepEqual(new Set([]), new Set([1])); }); assert.throws(Test262Error, function () { assert.deepEqual(new Set([1, "a", true]), new Set([1, "a", false])); });
assert.throws(Test262Error, function () { assert.deepEqual(new Set([1, "a", true]), new Set([1, "a", false])); }); assert.throws(Test262Error, function () { assert.deepEqual(new Map([]), new Map([[1, "a"], ["b", true]])); });
assert.throws(Test262Error, function () { assert.deepEqual(new Map([]), new Map([[1, "a"], ["b", true]])); }); assert.throws(Test262Error, function () { assert.deepEqual(new Map([[1, "a"], ["b", true]]), new Map([[1, "a"], ["b", false]])); });
assert.throws(Test262Error, function () { assert.deepEqual(new Map([[1, "a"], ["b", true]]), new Map([[1, "a"], ["b", false]])); }); assert.throws(Test262Error, function () { assert.deepEqual(new Map([[1, "a"], ["b", true]]), new Set([[1, "a"], ["b", false]])); });
assert.throws(Test262Error, function () { assert.deepEqual(new Map([[1, "a"], ["b", true]]), new Set([[1, "a"], ["b", false]])); });

View File

@ -1,15 +1,15 @@
// Copyright 2019 Ron Buckton. All rights reserved. // Copyright 2019 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file. // This code is governed by the BSD license found in the LICENSE file.
/*--- /*---
description: > description: >
object values compare correctly. object values compare correctly.
includes: [deepEqual.js] includes: [deepEqual.js]
---*/ ---*/
assert.deepEqual({}, {}); assert.deepEqual({}, {});
assert.deepEqual({ a: 1, b: true }, { a: 1, b: true }); assert.deepEqual({ a: 1, b: true }, { a: 1, b: true });
assert.throws(Test262Error, function () { assert.deepEqual({}, { a: 1, b: true }); }); assert.throws(Test262Error, function () { assert.deepEqual({}, { a: 1, b: true }); });
assert.throws(Test262Error, function () { assert.deepEqual({ a: 1, b: true }, { a: 1, b: false }); }); assert.throws(Test262Error, function () { assert.deepEqual({ a: 1, b: true }, { a: 1, b: false }); });