Files
2023-08-01 13:49:46 +02:00

388 lines
14 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.RegExpCreate = RegExpCreate;
exports.RegExpAlloc = RegExpAlloc;
exports.RegExpInitialize = RegExpInitialize;
exports.RegExpExec = RegExpExec;
exports.RegExpBuiltinExec = RegExpBuiltinExec;
exports.AdvanceStringIndex = AdvanceStringIndex;
exports.EscapeRegExpPattern = EscapeRegExpPattern;
var _invariant = require("../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _index = require("../values/index.js");
var _get = require("./get.js");
var _is = require("./is.js");
var _call = require("./call.js");
var _has = require("./has.js");
var _singletons = require("../singletons.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// ECMA262 21.2.3.2.3
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
function RegExpCreate(realm, P, F) {
// 1. Let obj be ? RegExpAlloc(%RegExp%).
var obj = RegExpAlloc(realm, realm.intrinsics.RegExp);
// 2. Return ? RegExpInitialize(obj, P, F).
return RegExpInitialize(realm, obj, P, F);
}
// ECMA262 21.2.3.2.1
function RegExpAlloc(realm, newTarget) {
// 1. Let obj be ? OrdinaryCreateFromConstructor(newTarget, "%RegExpPrototype%", « [[RegExpMatcher]],
// [[OriginalSource]], [[OriginalFlags]] »).
var obj = _singletons.Create.OrdinaryCreateFromConstructor(realm, newTarget, "RegExpPrototype", {
$RegExpMatcher: undefined, // always initialized to not undefined before use
$OriginalSource: undefined, // ditto
$OriginalFlags: undefined // ditto
});
// 2. Perform ! DefinePropertyOrThrow(obj, "lastIndex", PropertyDescriptor {[[Writable]]: true,
// [[Enumerable]]: false, [[Configurable]]: false}).
_singletons.Properties.DefinePropertyOrThrow(realm, obj, "lastIndex", {
writable: true,
enumerable: false,
configurable: false
});
// 3. Return obj.
return obj;
}
// ECMA262 21.2.3.2.2
function RegExpInitialize(realm, obj, pattern, flags) {
// Note that obj is a new object, and we can thus write to internal slots
(0, _invariant2.default)(realm.isNewObject(obj));
// 1. If pattern is undefined, let P be the empty String.
var P = void 0;
if (!pattern || (0, _has.HasCompatibleType)(pattern, _index.UndefinedValue)) {
P = "";
} else {
// 2. Else, let P be ? ToString(pattern).
P = _singletons.To.ToStringPartial(realm, pattern);
}
// 3. If flags is undefined, let F be the empty String.
var F = void 0;
if (!flags || (0, _has.HasCompatibleType)(flags, _index.UndefinedValue)) {
F = "";
} else {
// 4. Else, let F be ? ToString(flags).
F = _singletons.To.ToStringPartial(realm, flags);
}
// 5. If F contains any code unit other than "g", "i", "m", "u", or "y" or if it contains the same code unit more than once, throw a SyntaxError exception.
for (var i = 0; i < F.length; ++i) {
if ("gimuy".indexOf(F.charAt(i)) < 0) {
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError, "invalid RegExp flag");
}
for (var j = i + 1; j < F.length; ++j) {
if (F.charAt(i) === F.charAt(j)) {
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError, "duplicate RegExp flag");
}
}
}
// 6. If F contains "u", let BMP be false; else let BMP be true.
var BMP = F.indexOf("u") >= 0 ? false : true;
// 7. If BMP is true, then
if (BMP) {
// a. Parse P using the grammars in 21.2.1 and interpreting each of its 16-bit elements as a Unicode BMP
// code point. UTF-16 decoding is not applied to the elements. The goal symbol for the parse is
// Pattern. Throw a SyntaxError exception if P did not conform to the grammar, if any elements of P
// were not matched by the parse, or if any Early Error conditions exist.
// b. Let patternCharacters be a List whose elements are the code unit elements of P.
} else {}
// 8. Else,
// a. Parse P using the grammars in 21.2.1 and interpreting P as UTF-16 encoded Unicode code points
// (6.1.4). The goal symbol for the parse is Pattern[U]. Throw a SyntaxError exception if P did not
// conform to the grammar, if any elements of P were not matched by the parse, or if any Early Error
// conditions exist.
// b. Let patternCharacters be a List whose elements are the code points resulting from applying UTF-16
// decoding to P's sequence of elements.
// 9. Set the value of obj's [[OriginalSource]] internal slot to P.
obj.$OriginalSource = P;
// 10. Set the value of obj's [[OriginalFlags]] internal slot to F.
obj.$OriginalFlags = F;
// 11. Set obj's [[RegExpMatcher]] internal slot to the internal procedure that evaluates the above parse of
// P by applying the semantics provided in 21.2.2 using patternCharacters as the pattern's List of
// SourceCharacter values and F as the flag parameters.
try {
var computedFlags = "y";
if (F.indexOf("i") >= 0) computedFlags += "i";
if (F.indexOf("u") >= 0) computedFlags += "u";
if (F.indexOf("m") >= 0) computedFlags += "m";
var matcher = new RegExp(P, computedFlags);
obj.$RegExpMatcher = function (S, lastIndex) {
matcher.lastIndex = lastIndex;
var match = matcher.exec(S);
if (!match) {
return null;
}
return {
endIndex: match.index + match[0].length,
captures: match
};
};
} catch (e) {
if (e instanceof SyntaxError) {
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError, "invalid RegExp");
} else throw e;
}
// 12. Perform ? Set(obj, "lastIndex", 0, true).
_singletons.Properties.Set(realm, obj, "lastIndex", realm.intrinsics.zero, true);
// 13. Return obj.
return obj;
}
// ECMA262 21.2.5.2.1
function RegExpExec(realm, R, S) {
// 1. Assert: Type(R) is Object.
(0, _invariant2.default)(R instanceof _index.ObjectValue, "Type(R) is Object");
// 2. Assert: Type(S) is String.
(0, _invariant2.default)(typeof S === "string", "Type(S) is String");
// 3. Let exec be ? Get(R, "exec").
var exec = (0, _get.Get)(realm, R, "exec");
// 4. If IsCallable(exec) is true, then
if ((0, _is.IsCallable)(realm, exec)) {
// a. Let result be ? Call(exec, R, « S »).
var result = (0, _call.Call)(realm, exec, R, [new _index.StringValue(realm, S)]);
// b. If Type(result) is neither Object or Null, throw a TypeError exception.
if (!(0, _has.HasSomeCompatibleType)(result, _index.ObjectValue, _index.NullValue)) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "Type(result) is neither Object or Null");
}
// c. Return result.
return result.throwIfNotConcrete();
}
// 5. If R does not have a [[RegExpMatcher]] internal slot, throw a TypeError exception.
if (R.$RegExpMatcher === undefined) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "R does not have a [[RegExpMatcher]] internal slot");
}
// 6. Return ? RegExpBuiltinExec(R, S).
return RegExpBuiltinExec(realm, R, S);
}
// ECMA262 21.2.5.2.2
function RegExpBuiltinExec(realm, R, S) {
// 1. Assert: R is an initialized RegExp instance.
(0, _invariant2.default)(R.$RegExpMatcher !== undefined && R.$OriginalSource !== undefined && R.$OriginalFlags !== undefined, "R is an initialized RegExp instance");
// 2. Assert: Type(S) is String.
(0, _invariant2.default)(typeof S === "string", "Type(S) is String");
// 3. Let length be the number of code units in S.
var length = S.length;
// 4. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
var lastIndex = _singletons.To.ToLength(realm, (0, _get.Get)(realm, R, "lastIndex"));
// 5. Let flags be R.[[OriginalFlags]].
var flags = R.$OriginalFlags;
(0, _invariant2.default)(typeof flags === "string");
// 6 .If flags contains "g", let global be true, else let global be false.
var global = flags.indexOf("g") >= 0 ? true : false;
// 7. If flags contains "y", let sticky be true, else let sticky be false.
var sticky = flags.indexOf("y") >= 0 ? true : false;
// 8. If global is false and sticky is false, let lastIndex be 0.
if (global === false && sticky === false) lastIndex = 0;
// 9. Let matcher be the value of R's [[RegExpMatcher]] internal slot.
var matcher = R.$RegExpMatcher;
(0, _invariant2.default)(matcher !== undefined);
// 10. If flags contains "u", let fullUnicode be true, else let fullUnicode be false.
var fullUnicode = flags.indexOf("u") >= 0 ? true : false;
// 11. Let matchSucceeded be false.
var matchSucceeded = false;
var r = null;
// 12. Repeat, while matchSucceeded is false
while (!matchSucceeded) {
// a. If lastIndex > length, then
if (lastIndex > length) {
// i. Perform ? Set(R, "lastIndex", 0, true).
_singletons.Properties.Set(realm, R, "lastIndex", realm.intrinsics.zero, true);
// ii. Return null.
return realm.intrinsics.null;
}
// b. Let r be matcher(S, lastIndex).
r = matcher(S, lastIndex);
// c. If r is failure, then
if (r == null) {
// i. If sticky is true, then
if (sticky) {
// 1. Perform ? Set(R, "lastIndex", 0, true).
_singletons.Properties.Set(realm, R, "lastIndex", realm.intrinsics.zero, true);
// 2. Return null.
return realm.intrinsics.null;
}
// ii. Let lastIndex be AdvanceStringIndex(S, lastIndex, fullUnicode).
lastIndex = AdvanceStringIndex(realm, S, lastIndex, fullUnicode);
} else {
// d. Else,
// i. Assert: r is a State.
(0, _invariant2.default)(r, "r is a State");
// ii. Set matchSucceeded to true.
matchSucceeded = true;
// (not in standard) Let lastIndex be the index of the captures
lastIndex = r.captures.index;
}
}
(0, _invariant2.default)(r != null);
// 13. Let e be r's endIndex value.
var e = r.endIndex;
// 14. If fullUnicode is true, then
if (fullUnicode) {}
// TODO #1018 a. e is an index into the Input character list, derived from S, matched by matcher. 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 length of Input, then eUTF is the number of code units in S.
// b. Let e be eUTF.
// 15. If global is true or sticky is true, then
if (global === true || sticky === true) {
// a. Perform ? Set(R, "lastIndex", e, true).
_singletons.Properties.Set(realm, R, "lastIndex", new _index.NumberValue(realm, e), true);
}
// 16. Let n be the length of r's captures List. (This is the same value as 21.2.2.1's NcapturingParens.)
var n = r.captures.length - 1;
// 17. Let A be ArrayCreate(n + 1).
var A = _singletons.Create.ArrayCreate(realm, n + 1);
// 18. Assert: The value of A's "length" property is n + 1.
var lengthOfA = (0, _get.Get)(realm, A, "length").throwIfNotConcrete();
(0, _invariant2.default)(lengthOfA instanceof _index.NumberValue);
(0, _invariant2.default)(lengthOfA.value === n + 1, 'The value of A\'s "length" property is n + 1');
// 19. Let matchIndex be lastIndex.
var matchIndex = lastIndex;
// 20. Perform ! CreateDataProperty(A, "index", matchIndex).
_singletons.Create.CreateDataProperty(realm, A, "index", new _index.NumberValue(realm, matchIndex));
// 21. Perform ! CreateDataProperty(A, "input", S).
_singletons.Create.CreateDataProperty(realm, A, "input", new _index.StringValue(realm, S));
// 22. Let matchedSubstr be the matched substring (i.e. the portion of S between offset lastIndex inclusive and offset e exclusive).
var matchedSubstr = S.substr(lastIndex, e - lastIndex);
// 23. Perform ! CreateDataProperty(A, "0", matchedSubstr).
_singletons.Create.CreateDataProperty(realm, A, "0", new _index.StringValue(realm, matchedSubstr));
// 24. For each integer i such that i > 0 and i ≤ n
for (var i = 1; i <= n; ++i) {
// a. Let captureI be ith element of r's captures List.
var captureI = r.captures[i];
var capturedValue = void 0;
// b. If captureI is undefined, let capturedValue be undefined.
if (captureI === undefined) {
capturedValue = realm.intrinsics.undefined;
} else if (fullUnicode) {
// c. Else if fullUnicode is true, then
// TODO #1018: i. Assert: captureI is a List of code points.
// ii. Let capturedValue be a string whose code units are the UTF16Encoding of the code points of captureI.
capturedValue = realm.intrinsics.undefined;
} else {
// d. Else, fullUnicode is false,
// i. Assert: captureI is a List of code units.
(0, _invariant2.default)(typeof captureI === "string");
// ii. Let capturedValue be a string consisting of the code units of captureI.
capturedValue = new _index.StringValue(realm, captureI);
}
// e. Perform ! CreateDataProperty(A, ! ToString(i), capturedValue).
_singletons.Create.CreateDataProperty(realm, A, _singletons.To.ToString(realm, new _index.NumberValue(realm, i)), capturedValue);
}
// 25. Return A.
return A;
}
function AdvanceStringIndex(realm, S, index, unicode) {
// 1. Assert: Type(S) is String.
(0, _invariant2.default)(typeof S === "string", "Type(S) is String");
// 2. Assert: index is an integer such that 0≤index≤253-1.
(0, _invariant2.default)(index >= 0 && index <= Math.pow(2, 53) - 1, "index is an integer such that 0≤index≤253-1");
// 3. Assert: Type(unicode) is Boolean.
(0, _invariant2.default)(typeof unicode === "boolean", "Type(unicode) is Boolean");
// 4. If unicode is false, return index+1.
if (unicode === false) return index + 1;
// 5. Let length be the number of code units in S.
var length = S.length;
// 6. If index+1 ≥ length, return index+1.
if (index + 1 >= length) return index + 1;
// 7. Let first be the code unit value at index index in S.
var first = S.charCodeAt(index);
// 8. If first < 0xD800 or first > 0xDBFF, return index+1.
if (first < 0xd800 || first > 0xdbff) return index + 1;
// 9. Let second be the code unit value at index index+1 in S.
var second = S.charCodeAt(index + 1);
// 10. If second < 0xDC00 or second > 0xDFFF, return index+1.
if (second < 0xdc00 || second > 0xdfff) return index + 1;
// 11. Return index+2.
return index + 2;
}
function EscapeRegExpPattern(realm, P, F) {
return P.replace("/", "/");
}
//# sourceMappingURL=regexp.js.map