"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