/src/hermes/lib/VM/JSRegExpStringIterator.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) Meta Platforms, Inc. and affiliates. |
3 | | * |
4 | | * This source code is licensed under the MIT license found in the |
5 | | * LICENSE file in the root directory of this source tree. |
6 | | */ |
7 | | |
8 | | #include "hermes/VM/JSRegExpStringIterator.h" |
9 | | |
10 | | #include "hermes/VM/BuildMetadata.h" |
11 | | #include "hermes/VM/StringPrimitive.h" |
12 | | |
13 | | #include "JSLib/JSLibInternal.h" |
14 | | |
15 | | namespace hermes { |
16 | | namespace vm { |
17 | | |
18 | | //===----------------------------------------------------------------------===// |
19 | | // class JSRegExpStringIterator |
20 | | |
21 | | const ObjectVTable JSRegExpStringIterator::vt{ |
22 | | VTable( |
23 | | CellKind::JSRegExpStringIteratorKind, |
24 | | cellSize<JSRegExpStringIterator>()), |
25 | | JSRegExpStringIterator::_getOwnIndexedRangeImpl, |
26 | | JSRegExpStringIterator::_haveOwnIndexedImpl, |
27 | | JSRegExpStringIterator::_getOwnIndexedPropertyFlagsImpl, |
28 | | JSRegExpStringIterator::_getOwnIndexedImpl, |
29 | | JSRegExpStringIterator::_setOwnIndexedImpl, |
30 | | JSRegExpStringIterator::_deleteOwnIndexedImpl, |
31 | | JSRegExpStringIterator::_checkAllOwnIndexedImpl, |
32 | | }; |
33 | | |
34 | | void JSRegExpStringIteratorBuildMeta( |
35 | | const GCCell *cell, |
36 | 1 | Metadata::Builder &mb) { |
37 | 1 | mb.addJSObjectOverlapSlots( |
38 | 1 | JSObject::numOverlapSlots<JSRegExpStringIterator>()); |
39 | 1 | JSObjectBuildMeta(cell, mb); |
40 | 1 | const auto *self = static_cast<const JSRegExpStringIterator *>(cell); |
41 | 1 | mb.setVTable(&JSRegExpStringIterator::vt); |
42 | 1 | mb.addField("iteratedRegExp", &self->iteratedRegExp_); |
43 | 1 | mb.addField("iteratedString", &self->iteratedString_); |
44 | 1 | } |
45 | | |
46 | | /// ES11 21.2.5.8.1 CreateRegExpStringIterator ( R, S, global, fullUnicode ) |
47 | | PseudoHandle<JSRegExpStringIterator> JSRegExpStringIterator::create( |
48 | | Runtime &runtime, |
49 | | Handle<JSObject> R, |
50 | | Handle<StringPrimitive> S, |
51 | | bool global, |
52 | 0 | bool fullUnicode) { |
53 | 0 | auto proto = Handle<JSObject>::vmcast(&runtime.regExpStringIteratorPrototype); |
54 | |
|
55 | 0 | auto *cell = runtime.makeAFixed<JSRegExpStringIterator>( |
56 | 0 | runtime, |
57 | 0 | proto, |
58 | 0 | runtime.getHiddenClassForPrototype( |
59 | 0 | *proto, numOverlapSlots<JSRegExpStringIterator>()), |
60 | 0 | R, |
61 | 0 | S, |
62 | 0 | global, |
63 | 0 | fullUnicode); |
64 | 0 | return JSObjectInit::initToPseudoHandle(runtime, cell); |
65 | 0 | } |
66 | | |
67 | | /// ES11 21.2.7.1.1 %RegExpStringIteratorPrototype%.next ( ) 4-11 |
68 | | CallResult<HermesValue> JSRegExpStringIterator::nextElement( |
69 | | Handle<JSRegExpStringIterator> O, |
70 | 0 | Runtime &runtime) { |
71 | | // 4. If O.[[Done]] is true, then |
72 | 0 | if (O->done_) { |
73 | | // a. Return ! CreateIterResultObject(undefined, true). |
74 | 0 | return createIterResultObject(runtime, Runtime::getUndefinedValue(), true) |
75 | 0 | .getHermesValue(); |
76 | 0 | } |
77 | | // 5. Let R be O.[[IteratingRegExp]]. |
78 | 0 | auto R = runtime.makeHandle(O->iteratedRegExp_); |
79 | | // 6. Let S be O.[[IteratedString]]. |
80 | 0 | auto S = runtime.makeHandle(O->iteratedString_); |
81 | | |
82 | | // 7. Let global be O.[[Global]]. |
83 | | // 8. Let fullUnicode be O.[[Unicode]]. |
84 | | // we will just use JSRegExpStringIterator's fields for non pointer types. |
85 | | |
86 | | // 9. Let match be ? RegExpExec(R, S). |
87 | 0 | auto matchRes = regExpExec(runtime, R, S); |
88 | 0 | if (LLVM_UNLIKELY(matchRes == ExecutionStatus::EXCEPTION)) { |
89 | 0 | return ExecutionStatus::EXCEPTION; |
90 | 0 | } |
91 | 0 | auto match = matchRes.getValue(); |
92 | | |
93 | | // 10. If match is null, then |
94 | 0 | if (match.isNull()) { |
95 | | // a. Set O.[[Done]] to true. |
96 | 0 | O->done_ = true; |
97 | | // b. Return ! CreateIterResultObject(undefined, true). |
98 | 0 | return createIterResultObject(runtime, Runtime::getUndefinedValue(), true) |
99 | 0 | .getHermesValue(); |
100 | 0 | } else { |
101 | | // 11. Else, |
102 | 0 | auto matchObj = runtime.makeHandle<JSObject>(match); |
103 | | // a. If global is true, then |
104 | 0 | if (O->global_) { |
105 | | // i. Let matchStr be ? ToString(? Get(match, "0")). |
106 | 0 | Handle<> zeroHandle = HandleRootOwner::getZeroValue(); |
107 | 0 | auto propRes = JSObject::getComputed_RJS(matchObj, runtime, zeroHandle); |
108 | 0 | if (LLVM_UNLIKELY(propRes == ExecutionStatus::EXCEPTION)) { |
109 | 0 | return ExecutionStatus::EXCEPTION; |
110 | 0 | } |
111 | 0 | auto matchStrRes = |
112 | 0 | toString_RJS(runtime, runtime.makeHandle(std::move(*propRes))); |
113 | 0 | if (matchStrRes == ExecutionStatus::EXCEPTION) { |
114 | 0 | return ExecutionStatus::EXCEPTION; |
115 | 0 | } |
116 | 0 | auto matchStr = runtime.makeHandle(std::move(*matchStrRes)); |
117 | | |
118 | | // ii. If matchStr is the empty String, then |
119 | 0 | if (matchStr->getStringLength() == 0) { |
120 | | // 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")). |
121 | 0 | auto lastIndexRes = runtime.getNamed(R, PropCacheID::RegExpLastIndex); |
122 | 0 | if (lastIndexRes == ExecutionStatus::EXCEPTION) { |
123 | 0 | return ExecutionStatus::EXCEPTION; |
124 | 0 | } |
125 | 0 | auto lastIndex = runtime.makeHandle(std::move(*lastIndexRes)); |
126 | 0 | auto thisIndex = toLength(runtime, lastIndex); |
127 | 0 | if (thisIndex == ExecutionStatus::EXCEPTION) { |
128 | 0 | return ExecutionStatus::EXCEPTION; |
129 | 0 | } |
130 | | // 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, fullUnicode). |
131 | 0 | double nextIndex = advanceStringIndex( |
132 | 0 | S.get(), thisIndex->getNumberAs<uint64_t>(), O->unicode_); |
133 | | // 3. Perform ? Set(R, "lastIndex", nextIndex, true). |
134 | 0 | if (setLastIndex(R, runtime, nextIndex) == ExecutionStatus::EXCEPTION) { |
135 | 0 | return ExecutionStatus::EXCEPTION; |
136 | 0 | } |
137 | 0 | } |
138 | | // iii. Return ! CreateIterResultObject(match, false). |
139 | 0 | return createIterResultObject(runtime, matchObj, false).getHermesValue(); |
140 | 0 | } |
141 | | // b. Else, |
142 | 0 | else { |
143 | | // i. Set O.[[Done]] to true. |
144 | 0 | O->done_ = true; |
145 | | // ii. Return ! CreateIterResultObject(match, false). |
146 | 0 | return createIterResultObject(runtime, matchObj, false).getHermesValue(); |
147 | 0 | } |
148 | 0 | } |
149 | 0 | } |
150 | | |
151 | | } // namespace vm |
152 | | } // namespace hermes |