Coverage Report

Created: 2025-12-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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