• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include 'src/builtins/builtins-regexp-gen.h'
6
7namespace regexp {
8
9extern transitioning macro
10RegExpMatchAllAssembler::CreateRegExpStringIterator(
11    NativeContext, Object, String, bool, bool): JSAny;
12
13@export
14transitioning macro RegExpPrototypeMatchAllImpl(implicit context: Context)(
15    nativeContext: NativeContext, receiver: JSAny, string: JSAny): JSAny {
16  // 1. Let R be the this value.
17  // 2. If Type(R) is not Object, throw a TypeError exception.
18  ThrowIfNotJSReceiver(
19      receiver, MessageTemplate::kIncompatibleMethodReceiver,
20      'RegExp.prototype.@@matchAll');
21  const receiver = UnsafeCast<JSReceiver>(receiver);
22
23  // 3. Let S be ? ToString(O).
24  const string: String = ToString_Inline(string);
25
26  let matcher: Object;
27  let global: bool;
28  let unicode: bool;
29
30  // 'FastJSRegExp' uses the strict fast path check because following code
31  // uses the flags property.
32  // TODO(jgruber): Handle slow flag accesses on the fast path and make this
33  // permissive.
34  typeswitch (receiver) {
35    case (fastRegExp: FastJSRegExp): {
36      const source = fastRegExp.source;
37
38      // 4. Let C be ? SpeciesConstructor(R, %RegExp%).
39      // 5. Let flags be ? ToString(? Get(R, "flags")).
40      // 6. Let matcher be ? Construct(C, « R, flags »).
41      const flags: String = FastFlagsGetter(fastRegExp);
42      matcher = RegExpCreate(nativeContext, source, flags);
43      const matcherRegExp = UnsafeCast<JSRegExp>(matcher);
44      dcheck(IsFastRegExpPermissive(matcherRegExp));
45
46      // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
47      // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
48      const fastRegExp = UnsafeCast<FastJSRegExp>(receiver);
49      FastStoreLastIndex(matcherRegExp, fastRegExp.lastIndex);
50
51      // 9. If flags contains "g", let global be true.
52      // 10. Else, let global be false.
53      global = FastFlagGetter(matcherRegExp, Flag::kGlobal);
54
55      // 11. If flags contains "u", let fullUnicode be true.
56      // 12. Else, let fullUnicode be false.
57      unicode = FastFlagGetter(matcherRegExp, Flag::kUnicode);
58    }
59    case (Object): {
60      // 4. Let C be ? SpeciesConstructor(R, %RegExp%).
61      const regexpFun = LoadRegExpFunction(nativeContext);
62      const speciesConstructor =
63          UnsafeCast<Constructor>(SpeciesConstructor(receiver, regexpFun));
64
65      // 5. Let flags be ? ToString(? Get(R, "flags")).
66      const flags = GetProperty(receiver, 'flags');
67      const flagsString = ToString_Inline(flags);
68
69      // 6. Let matcher be ? Construct(C, « R, flags »).
70      matcher = Construct(speciesConstructor, receiver, flagsString);
71
72      // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
73      const lastIndex: Number = ToLength_Inline(SlowLoadLastIndex(receiver));
74
75      // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
76      SlowStoreLastIndex(UnsafeCast<JSReceiver>(matcher), lastIndex);
77
78      // 9. If flags contains "g", let global be true.
79      // 10. Else, let global be false.
80      const globalCharString: String = StringConstant('g');
81      const globalIndex: Smi = StringIndexOf(flagsString, globalCharString, 0);
82      global = globalIndex != -1;
83
84      // 11. If flags contains "u", let fullUnicode be true.
85      // 12. Else, let fullUnicode be false.
86      const unicodeCharString = StringConstant('u');
87      const unicodeIndex: Smi =
88          StringIndexOf(flagsString, unicodeCharString, 0);
89      unicode = unicodeIndex != -1;
90    }
91  }
92
93  // 13. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode).
94  return CreateRegExpStringIterator(
95      nativeContext, matcher, string, global, unicode);
96}
97
98// https://tc39.github.io/proposal-string-matchall/
99// RegExp.prototype [ @@matchAll ] ( string )
100transitioning javascript builtin RegExpPrototypeMatchAll(
101    js-implicit context: NativeContext, receiver: JSAny)(string: JSAny): JSAny {
102  return RegExpPrototypeMatchAllImpl(context, receiver, string);
103}
104
105// https://tc39.github.io/proposal-string-matchall/
106// %RegExpStringIteratorPrototype%.next ( )
107transitioning javascript builtin RegExpStringIteratorPrototypeNext(
108    js-implicit context: NativeContext, receiver: JSAny)(): JSAny {
109  // 1. Let O be the this value.
110  // 2. If Type(O) is not Object, throw a TypeError exception.
111  // 3. If O does not have all of the internal slots of a RegExp String
112  // Iterator Object Instance (see 5.3), throw a TypeError exception.
113  const methodName: constexpr string = '%RegExpStringIterator%.prototype.next';
114  const receiver = Cast<JSRegExpStringIterator>(receiver) otherwise
115  ThrowTypeError(
116      MessageTemplate::kIncompatibleMethodReceiver, methodName, receiver);
117
118  try {
119    // 4. If O.[[Done]] is true, then
120    //   a. Return ! CreateIterResultObject(undefined, true).
121    const flags: SmiTagged<JSRegExpStringIteratorFlags> = receiver.flags;
122    if (flags.done) goto ReturnEmptyDoneResult;
123
124    // 5. Let R be O.[[iteratingRegExp]].
125    const iteratingRegExp: JSReceiver = receiver.iterating_reg_exp;
126
127    // 6. Let S be O.[[IteratedString]].
128    const iteratingString: String = receiver.iterated_string;
129
130    // 7. Let global be O.[[Global]].
131    // 8. Let fullUnicode be O.[[Unicode]].
132    // 9. Let match be ? RegExpExec(R, S).
133    let match: Object;
134    let isFastRegExp: bool = false;
135    try {
136      if (IsFastRegExpPermissive(iteratingRegExp)) {
137        const regexp = UnsafeCast<JSRegExp>(iteratingRegExp);
138        const lastIndex = LoadLastIndexAsLength(regexp, true);
139        const matchIndices: RegExpMatchInfo =
140            RegExpPrototypeExecBodyWithoutResultFast(
141                regexp, iteratingString, lastIndex)
142            otherwise IfNoMatch;
143        match = ConstructNewResultFromMatchInfo(
144            regexp, matchIndices, iteratingString, lastIndex);
145        isFastRegExp = true;
146      } else {
147        match = RegExpExec(iteratingRegExp, iteratingString);
148        if (match == Null) {
149          goto IfNoMatch;
150        }
151      }
152      // 11. Else,
153      // b. Else, handle non-global case first.
154      if (!flags.global) {
155        // i. Set O.[[Done]] to true.
156        receiver.flags.done = true;
157
158        // ii. Return ! CreateIterResultObject(match, false).
159        return AllocateJSIteratorResult(UnsafeCast<JSAny>(match), False);
160      }
161      // a. If global is true,
162      dcheck(flags.global);
163      if (isFastRegExp) {
164        // i. Let matchStr be ? ToString(? Get(match, "0")).
165        const match = UnsafeCast<JSRegExpResult>(match);
166        const resultFixedArray = UnsafeCast<FixedArray>(match.elements);
167        const matchStr = UnsafeCast<String>(resultFixedArray.objects[0]);
168
169        // When iterating_regexp is fast, we assume it stays fast even after
170        // accessing the first match from the RegExp result.
171        dcheck(IsFastRegExpPermissive(iteratingRegExp));
172        const iteratingRegExp = UnsafeCast<JSRegExp>(iteratingRegExp);
173        if (matchStr == kEmptyString) {
174          // 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
175          const thisIndex: Smi = FastLoadLastIndex(iteratingRegExp);
176
177          // 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex,
178          // fullUnicode).
179          const nextIndex: Smi =
180              AdvanceStringIndexFast(iteratingString, thisIndex, flags.unicode);
181
182          // 3. Perform ? Set(R, "lastIndex", nextIndex, true).
183          FastStoreLastIndex(iteratingRegExp, nextIndex);
184        }
185
186        // iii. Return ! CreateIterResultObject(match, false).
187        return AllocateJSIteratorResult(match, False);
188      }
189      dcheck(!isFastRegExp);
190      // i. Let matchStr be ? ToString(? Get(match, "0")).
191      const match = UnsafeCast<JSAny>(match);
192      const matchStr = ToString_Inline(GetProperty(match, SmiConstant(0)));
193
194      if (matchStr == kEmptyString) {
195        // 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
196        const lastIndex: JSAny = SlowLoadLastIndex(iteratingRegExp);
197        const thisIndex: Number = ToLength_Inline(lastIndex);
198
199        // 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex,
200        // fullUnicode).
201        const nextIndex: Number =
202            AdvanceStringIndexSlow(iteratingString, thisIndex, flags.unicode);
203
204        // 3. Perform ? Set(R, "lastIndex", nextIndex, true).
205        SlowStoreLastIndex(iteratingRegExp, nextIndex);
206      }
207      // iii. Return ! CreateIterResultObject(match, false).
208      return AllocateJSIteratorResult(match, False);
209    }
210    // 10. If match is null, then
211    label IfNoMatch {
212      // a. Set O.[[Done]] to true.
213      receiver.flags.done = true;
214
215      // b. Return ! CreateIterResultObject(undefined, true).
216      goto ReturnEmptyDoneResult;
217    }
218  } label ReturnEmptyDoneResult {
219    return AllocateJSIteratorResult(Undefined, True);
220  }
221}
222}
223