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