1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <cstdint>
16 #include <iterator>
17 #include "ets_class_root.h"
18 #include "ets_vm.h"
19 #include "include/mem/panda_containers.h"
20 #include "macros.h"
21 #include "mem/vm_handle.h"
22 #include "plugins/ets/runtime/regexp/regexp_executor.h"
23 #include "plugins/ets/runtime/types/ets_array.h"
24 #include "plugins/ets/runtime/types/ets_string.h"
25 #include "plugins/ets/runtime/types/ets_field.h"
26 #include "runtime/regexp/ecmascript/regexp_parser.h"
27 #include "runtime/include/mem/panda_string.h"
28 #include "runtime/handle_scope-inl.h"
29 #include "types/ets_object.h"
30 #include "types/ets_primitives.h"
31 #include <array>
32
33 namespace ark::ets::intrinsics {
34 using RegExpParser = ark::RegExpParser;
35 using RegExpExecutor = ark::ets::RegExpExecutor;
36 using RegExpMatchResult = ark::RegExpMatchResult<PandaString>;
37 using Array = ark::coretypes::Array;
38
39 namespace {
40
41 constexpr const int LAST_PAREN_FIELDS_COUNT = 10;
42
43 constexpr const char *GROUP_NAMES_FIELD_NAME = "groupNames";
44 constexpr const char *BUFFER_FIELD_NAME = "buffer";
45 constexpr const char *LAST_INDEX_FIELD_NAME = "lastIndex";
46 constexpr const char *PATTERN_FIELD_NAME = "pattern_";
47 constexpr const char *FLAGS_FIELD_NAME = "flags_";
48 constexpr std::array<const char *, LAST_PAREN_FIELDS_COUNT> PAREN_FIELD_NAMES = {"", "$1_", "$2_", "$3_", "$4_",
49 "$5_", "$6_", "$7_", "$8_", "$9_"};
50 constexpr const char *LAST_MATCH_FIELD_NAME = "lastMatch_";
51 constexpr const char *INPUT_STATIC_FIELD_NAME = "input_";
52 constexpr const char *LAST_PAREN_FIELD_NAME = "lastParen_";
53 constexpr const char *LEFT_CONTEXT_FIELD_NAME = "leftContext_";
54 constexpr const char *RIGHT_CONTEXT_FIELD_NAME = "rightContext_";
55
56 constexpr const char *RESULT_CLASS_NAME = "Lescompat/RegExpExecArray;";
57 constexpr const char *INDEX_FIELD_NAME = "index";
58 constexpr const char *INPUT_FIELD_NAME = "input";
59 constexpr const char *INDICES_FIELD_NAME = "indices";
60 constexpr const char *RESULT_FIELD_NAME = "result";
61 constexpr const char *IS_CORRECT_FIELD_NAME = "isCorrect";
62
63 constexpr const uint32_t INDICES_DIMENSIONS_NUM = 2;
64
GetFieldObjectByName(EtsObject * object,const char * name)65 EtsObject *GetFieldObjectByName(EtsObject *object, const char *name)
66 {
67 auto *cls = object->GetClass();
68 EtsField *field = cls->GetDeclaredFieldIDByName(name);
69 ASSERT(field != nullptr);
70 return object->GetFieldObject(field);
71 }
72
CastToBitMask(EtsString * checkStr)73 uint32_t CastToBitMask(EtsString *checkStr)
74 {
75 uint32_t flagsBits = 0;
76 uint32_t flagsBitsTemp = 0;
77 for (int i = 0; i < checkStr->GetLength(); i++) {
78 switch (checkStr->At(i)) {
79 case 'd':
80 flagsBitsTemp = RegExpParser::FLAG_HASINDICES;
81 break;
82 case 'g':
83 flagsBitsTemp = RegExpParser::FLAG_GLOBAL;
84 break;
85 case 'i':
86 flagsBitsTemp = RegExpParser::FLAG_IGNORECASE;
87 break;
88 case 'm':
89 flagsBitsTemp = RegExpParser::FLAG_MULTILINE;
90 break;
91 case 's':
92 flagsBitsTemp = RegExpParser::FLAG_DOTALL;
93 break;
94 case 'u':
95 flagsBitsTemp = RegExpParser::FLAG_UTF16;
96 break;
97 case 'y':
98 flagsBitsTemp = RegExpParser::FLAG_STICKY;
99 break;
100 default: {
101 auto *thread = ManagedThread::GetCurrent();
102 auto ctx = PandaEtsVM::GetCurrent()->GetLanguageContext();
103 std::string message = "invalid regular expression flags";
104 ark::ThrowException(ctx, thread, utf::CStringAsMutf8("Lstd/core/IllegalArgumentException;"),
105 utf::CStringAsMutf8(message.c_str()));
106 return 0;
107 }
108 }
109 if ((flagsBits & flagsBitsTemp) != 0) {
110 auto *thread = ManagedThread::GetCurrent();
111 auto ctx = PandaEtsVM::GetCurrent()->GetLanguageContext();
112 std::string message = "invalid regular expression flags";
113 ark::ThrowException(ctx, thread, utf::CStringAsMutf8("Lstd/core/IllegalArgumentException;"),
114 utf::CStringAsMutf8(message.c_str()));
115 return 0;
116 }
117 flagsBits |= flagsBitsTemp;
118 }
119 return flagsBits;
120 }
121 } // namespace
122
SetFlags(EtsObject * regexpObject,EtsString * checkStr)123 void SetFlags(EtsObject *regexpObject, EtsString *checkStr)
124 {
125 auto *coroutine = EtsCoroutine::GetCurrent();
126 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
127 VMHandle<EtsObject> regexp(coroutine, regexpObject->GetCoreType());
128
129 auto *regexpClass = regexp->GetClass();
130 EtsField *flagsField = regexpClass->GetDeclaredFieldIDByName(FLAGS_FIELD_NAME);
131
132 auto flags = checkStr->GetMutf8();
133 std::sort(flags.begin(), flags.end());
134 VMHandle<EtsString> newFlags(coroutine, EtsString::CreateFromMUtf8(flags.c_str())->GetCoreType());
135 regexp->SetFieldObject(flagsField, newFlags->AsObject());
136 }
137
SetBuffer(EtsObject * regexpObject,const RegExpParser & parser)138 void SetBuffer(EtsObject *regexpObject, const RegExpParser &parser)
139 {
140 auto *coroutine = EtsCoroutine::GetCurrent();
141 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
142 VMHandle<EtsObject> regexp(coroutine, regexpObject->GetCoreType());
143 auto *regexpClass = regexp->GetClass();
144
145 auto bufferSize = parser.GetOriginBufferSize();
146 auto *buffer = parser.GetOriginBuffer();
147 EtsField *bufferField = regexpClass->GetDeclaredFieldIDByName(BUFFER_FIELD_NAME);
148 VMHandle<EtsByteArray> etsBuffer(coroutine, EtsByteArray::Create(bufferSize)->GetCoreType());
149 for (size_t i = 0; i < bufferSize; ++i) {
150 etsBuffer->Set(i, buffer[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
151 }
152 regexp.GetPtr()->SetFieldObject(bufferField, etsBuffer->AsObject());
153 }
154
SetGroupNames(EtsObject * regexpObject,const RegExpParser & parser)155 void SetGroupNames(EtsObject *regexpObject, const RegExpParser &parser)
156 {
157 auto *coroutine = EtsCoroutine::GetCurrent();
158 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
159 VMHandle<EtsObject> regexp(coroutine, regexpObject->GetCoreType());
160 auto *regexpClass = regexp->GetClass();
161
162 auto *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
163 auto *stringClass = classLinker->GetClassRoot(EtsClassRoot::STRING);
164
165 auto groupName = parser.GetGroupNames();
166 EtsObjectArray *etsGroupNames = EtsObjectArray::Create(stringClass, groupName.size());
167 VMHandle<EtsObjectArray> arrHandle(coroutine, etsGroupNames->GetCoreType());
168
169 EtsField *groupNamesField = regexpClass->GetDeclaredFieldIDByName(GROUP_NAMES_FIELD_NAME);
170 for (size_t i = 0; i < groupName.size(); ++i) {
171 VMHandle<EtsString> str(coroutine,
172 EtsString::CreateFromMUtf8(groupName[i].c_str(), groupName[i].size())->GetCoreType());
173 arrHandle.GetPtr()->Set(i, str->AsObject());
174 }
175 regexp.GetPtr()->SetFieldObject(groupNamesField, arrHandle.GetPtr()->AsObject());
176 }
177
EscompatRegExpCompile(EtsObject * regexpObj)178 extern "C" EtsObject *EscompatRegExpCompile(EtsObject *regexpObj)
179 {
180 auto *coroutine = EtsCoroutine::GetCurrent();
181 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
182
183 VMHandle<EtsObject> regexp(coroutine, regexpObj->GetCoreType());
184
185 EtsString *patternStrObj = EtsString::FromEtsObject(GetFieldObjectByName(regexp.GetPtr(), PATTERN_FIELD_NAME));
186 VMHandle<EtsString> patternStr(coroutine, patternStrObj->GetCoreType());
187
188 auto flags = EtsHandle<EtsString>(
189 coroutine, EtsString::FromEtsObject(GetFieldObjectByName(regexp.GetPtr(), FLAGS_FIELD_NAME)));
190 auto flagsBits = static_cast<uint8_t>(CastToBitMask(flags.GetPtr()));
191 SetFlags(regexp.GetPtr(), flags.GetPtr());
192
193 RegExpParser parser = RegExpParser();
194 PandaString pattern = ConvertToString(patternStr->GetCoreType());
195
196 parser.Init(const_cast<char *>(reinterpret_cast<const char *>(pattern.c_str())), pattern.size(), flagsBits);
197 parser.Parse();
198
199 SetGroupNames(regexp.GetPtr(), parser);
200 SetBuffer(regexp.GetPtr(), parser);
201
202 return regexp.GetPtr();
203 }
204
SetSuccessfulMatchLegacyProperties(EtsClass * type,const EtsObject * regexpExecArrayObj,EtsString * inputStrObj,uint32_t index)205 void SetSuccessfulMatchLegacyProperties(EtsClass *type, const EtsObject *regexpExecArrayObj, EtsString *inputStrObj,
206 uint32_t index)
207 {
208 auto *coroutine = EtsCoroutine::GetCurrent();
209 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
210
211 EtsClass *resultClass = regexpExecArrayObj->GetClass();
212 auto *resultField = resultClass->GetDeclaredFieldIDByName(RESULT_FIELD_NAME);
213 VMHandle<EtsObjectArray> matches(coroutine, regexpExecArrayObj->GetFieldObject(resultField)->GetCoreType());
214 ASSERT(matches->GetLength() != 0);
215
216 VMHandle<EtsString> inputStr(coroutine, inputStrObj->GetCoreType());
217 VMHandle<EtsString> emptyString(coroutine, EtsString::CreateNewEmptyString()->GetCoreType());
218
219 EtsField *lastMatchField = type->GetStaticFieldIDByName(LAST_MATCH_FIELD_NAME);
220 type->SetStaticFieldObject(lastMatchField, matches->Get(0U));
221 for (size_t i = 1; i < LAST_PAREN_FIELDS_COUNT; ++i) {
222 EtsField *parenField = type->GetStaticFieldIDByName(PAREN_FIELD_NAMES[i]);
223 if (i < matches->GetLength()) {
224 type->SetStaticFieldObject(parenField, matches->Get(i));
225 } else {
226 type->SetStaticFieldObject(parenField, emptyString->AsObject());
227 }
228 }
229
230 EtsField *inputField = type->GetStaticFieldIDByName(INPUT_STATIC_FIELD_NAME);
231 type->SetStaticFieldObject(inputField, inputStr->AsObject());
232
233 EtsField *lastParenField = type->GetStaticFieldIDByName(LAST_PAREN_FIELD_NAME);
234 if (matches->GetLength() > 1) {
235 type->SetStaticFieldObject(lastParenField, matches->Get(matches->GetLength() - 1U));
236 } else {
237 type->SetStaticFieldObject(lastParenField, emptyString->AsObject());
238 }
239
240 EtsField *leftContextField = type->GetStaticFieldIDByName(LEFT_CONTEXT_FIELD_NAME);
241 EtsString *prefix = EtsString::FastSubString(inputStr.GetPtr(), 0, index);
242 type->SetStaticFieldObject(leftContextField, prefix->AsObject());
243
244 EtsField *rightContextField = type->GetStaticFieldIDByName(RIGHT_CONTEXT_FIELD_NAME);
245 auto suffixBegin = index + EtsString::FromEtsObject(matches->Get(0U))->GetLength();
246 EtsString *suffix = EtsString::FastSubString(inputStr.GetPtr(), suffixBegin, inputStr->GetLength() - suffixBegin);
247 type->SetStaticFieldObject(rightContextField, suffix->AsObject());
248 }
249
SetUnsuccessfulMatchLegacyProperties(EtsClass * type)250 void SetUnsuccessfulMatchLegacyProperties(EtsClass *type)
251 {
252 auto *coroutine = EtsCoroutine::GetCurrent();
253 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
254 VMHandle<EtsString> emptyString(coroutine, EtsString::CreateNewEmptyString()->GetCoreType());
255
256 {
257 EtsField *lastMatchField = type->GetStaticFieldIDByName(LAST_MATCH_FIELD_NAME);
258 type->SetStaticFieldObject(lastMatchField, emptyString->AsObject());
259 }
260 for (size_t i = 1; i < LAST_PAREN_FIELDS_COUNT; ++i) {
261 EtsField *lastParenField = type->GetStaticFieldIDByName(PAREN_FIELD_NAMES[i]);
262 type->SetStaticFieldObject(lastParenField, emptyString->AsObject());
263 }
264 }
265
Execute(EtsObject * regexpObj,EtsString * inputStrObj,EtsInt stringLength,EtsInt lastIndex,bool hasIndices)266 RegExpMatchResult Execute(EtsObject *regexpObj, EtsString *inputStrObj, EtsInt stringLength, EtsInt lastIndex,
267 bool hasIndices)
268 {
269 auto *coroutine = EtsCoroutine::GetCurrent();
270 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
271
272 VMHandle<EtsString> inputStr(coroutine, inputStrObj->GetCoreType());
273 VMHandle<EtsObject> regexp(coroutine, regexpObj->GetCoreType());
274 RegExpExecutor executor = RegExpExecutor();
275 PandaVector<uint8_t> u8Buffer;
276 PandaVector<uint16_t> u16Buffer;
277 const uint8_t *strBuffer;
278 bool isUtf16 = inputStr->IsUtf16();
279 if (isUtf16) {
280 u16Buffer = PandaVector<uint16_t>(stringLength);
281 inputStr->CopyDataUtf16(u16Buffer.data(), stringLength);
282 strBuffer = reinterpret_cast<uint8_t *>(u16Buffer.data());
283 } else {
284 u8Buffer = PandaVector<uint8_t>(stringLength + 1);
285 inputStr->CopyDataMUtf8(u8Buffer.data(), stringLength + 1, true);
286 strBuffer = u8Buffer.data();
287 }
288
289 auto *etsBuffer = reinterpret_cast<EtsByteArray *>(GetFieldObjectByName(regexp.GetPtr(), BUFFER_FIELD_NAME));
290 auto *buffer = reinterpret_cast<uint8_t *>(etsBuffer->GetData<int8_t>());
291 bool ret = executor.Execute(strBuffer, lastIndex, stringLength, buffer, isUtf16);
292 return executor.GetResult(ret, hasIndices);
293 }
294
SetResultField(EtsObject * regexpExecArrayObj,const PandaVector<std::pair<bool,PandaString>> & matches,bool isWide)295 void SetResultField(EtsObject *regexpExecArrayObj, const PandaVector<std::pair<bool, PandaString>> &matches,
296 bool isWide)
297 {
298 auto *coroutine = EtsCoroutine::GetCurrent();
299 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
300 VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
301 EtsClass *resultClass = regexpExecArray->GetClass();
302
303 auto *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
304 auto *stringClass = classLinker->GetClassRoot(EtsClassRoot::STRING);
305
306 auto *resultField = resultClass->GetDeclaredFieldIDByName(RESULT_FIELD_NAME);
307 VMHandle<EtsObjectArray> resultArray(coroutine, EtsObjectArray::Create(stringClass, matches.size())->GetCoreType());
308 VMHandle<EtsString> match;
309 for (size_t i = 0; i < matches.size(); ++i) {
310 if (isWide) {
311 match = VMHandle<EtsString>(
312 coroutine, EtsString::CreateFromUtf16(reinterpret_cast<const ets_char *>(matches[i].second.c_str()),
313 matches[i].second.length() / RegExpExecutor::WIDE_CHAR_SIZE)
314 ->GetCoreType());
315 } else {
316 match = VMHandle<EtsString>(
317 coroutine, EtsString::CreateFromUtf8(reinterpret_cast<const char *>(matches[i].second.c_str()),
318 matches[i].second.length())
319 ->GetCoreType());
320 }
321 resultArray->Set(i, match->AsObject());
322 }
323 regexpExecArray->SetFieldObject(resultField, resultArray->AsObject());
324 }
325
SetIndicesField(EtsObject * regexpExecArrayObj,const PandaVector<std::pair<uint32_t,uint32_t>> & indices,bool hasIndices)326 void SetIndicesField(EtsObject *regexpExecArrayObj, const PandaVector<std::pair<uint32_t, uint32_t>> &indices,
327 bool hasIndices)
328 {
329 auto *coroutine = EtsCoroutine::GetCurrent();
330 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
331 VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
332 auto *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
333
334 EtsClass *resultClass = regexpExecArray->GetClass();
335 auto *indicesField = resultClass->GetDeclaredFieldIDByName(INDICES_FIELD_NAME);
336
337 if (!hasIndices) {
338 VMHandle<EtsDoubleArray> defaultVal(coroutine, EtsDoubleArray::Create(0)->GetCoreType());
339 regexpExecArray->SetFieldObject(indicesField, defaultVal->AsObject());
340 return;
341 }
342
343 VMHandle<EtsObjectArray> indicesArray(
344 coroutine,
345 EtsObjectArray::Create(classLinker->GetClassRoot(EtsClassRoot::DOUBLE_ARRAY), indices.size())->GetCoreType());
346 for (size_t i = 0; i < indices.size(); ++i) {
347 VMHandle<EtsDoubleArray> index(coroutine, EtsDoubleArray::Create(INDICES_DIMENSIONS_NUM)->GetCoreType());
348 index->Set(0, static_cast<EtsDouble>(indices[i].first));
349 index->Set(1, static_cast<EtsDouble>(indices[i].second));
350 indicesArray->Set(i, index->AsObject());
351 }
352 regexpExecArray->SetFieldObject(indicesField, indicesArray->AsObject());
353 }
354
SetIsCorrectField(EtsObject * regexpExecArrayObj,bool value)355 void SetIsCorrectField(EtsObject *regexpExecArrayObj, bool value)
356 {
357 auto *coroutine = EtsCoroutine::GetCurrent();
358 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
359 VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
360 EtsClass *resultClass = regexpExecArray->GetClass();
361 auto *resultCorrectField = resultClass->GetDeclaredFieldIDByName(IS_CORRECT_FIELD_NAME);
362
363 regexpExecArray->SetFieldPrimitive<bool>(resultCorrectField, value);
364 }
365
SetInputField(EtsObject * regexpExecArrayObj,EtsString * inputStrObj)366 void SetInputField(EtsObject *regexpExecArrayObj, EtsString *inputStrObj)
367 {
368 auto *coroutine = EtsCoroutine::GetCurrent();
369 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
370 VMHandle<EtsString> inputStr(coroutine, inputStrObj->GetCoreType());
371 VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
372 EtsClass *resultClass = regexpExecArray->GetClass();
373 auto *inputField = resultClass->GetDeclaredFieldIDByName(INPUT_FIELD_NAME);
374
375 regexpExecArray->SetFieldObject(inputField, inputStr->AsObject());
376 }
377
SetIndexField(EtsObject * regexpExecArrayObj,uint32_t index)378 void SetIndexField(EtsObject *regexpExecArrayObj, uint32_t index)
379 {
380 auto *coroutine = EtsCoroutine::GetCurrent();
381 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
382 VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
383 EtsClass *resultClass = regexpExecArray->GetClass();
384
385 auto *indexField = resultClass->GetDeclaredFieldIDByName(INDEX_FIELD_NAME);
386 regexpExecArray->SetFieldPrimitive<EtsDouble>(indexField, static_cast<EtsDouble>(index));
387 }
388
SetLastIndexField(EtsObject * regexp,EtsField * lastIndexField,bool global,bool sticky,EtsDouble value)389 void SetLastIndexField(EtsObject *regexp, EtsField *lastIndexField, bool global, bool sticky, EtsDouble value)
390 {
391 if (!global && !sticky) {
392 return;
393 }
394 regexp->SetFieldPrimitive<EtsDouble>(lastIndexField, value);
395 }
396
EscompatRegExpExec(EtsObject * obj,EtsString * str)397 extern "C" EtsObject *EscompatRegExpExec(EtsObject *obj, EtsString *str)
398 {
399 auto *coroutine = EtsCoroutine::GetCurrent();
400 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
401
402 auto *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
403
404 VMHandle<EtsObject> regexp(coroutine, obj->GetCoreType());
405 VMHandle<EtsString> strHandle(coroutine, str->GetCoreType());
406 auto *regexpExecArrayClass = classLinker->GetClass(RESULT_CLASS_NAME);
407 VMHandle<EtsObject> regexpExecArrayObject(coroutine, EtsObject::Create(regexpExecArrayClass)->GetCoreType());
408
409 auto *regexpClass = regexp->GetClass();
410
411 EtsField *lastIndexField = regexpClass->GetDeclaredFieldIDByName(LAST_INDEX_FIELD_NAME);
412 auto lastIndex = static_cast<int32_t>(regexp.GetPtr()->GetFieldPrimitive<EtsDouble>(lastIndexField));
413 EtsString *flags = EtsString::FromEtsObject(GetFieldObjectByName(regexp.GetPtr(), FLAGS_FIELD_NAME));
414 auto flagsBits = static_cast<uint8_t>(CastToBitMask(flags));
415
416 bool global = (flagsBits & RegExpParser::FLAG_GLOBAL) > 0;
417 bool sticky = (flagsBits & RegExpParser::FLAG_STICKY) > 0;
418 bool hasIndices = (flagsBits & RegExpParser::FLAG_HASINDICES) > 0;
419 if (!global && !sticky) {
420 lastIndex = 0;
421 }
422 EtsInt stringLength = strHandle->GetLength();
423 if (lastIndex > stringLength) {
424 SetLastIndexField(regexp.GetPtr(), lastIndexField, global, sticky, 0.0);
425 SetUnsuccessfulMatchLegacyProperties(regexpClass);
426 SetIsCorrectField(regexpExecArrayObject.GetPtr(), false);
427 return regexpExecArrayObject.GetPtr();
428 }
429
430 auto execResult = Execute(regexp.GetPtr(), strHandle.GetPtr(), stringLength, lastIndex, hasIndices);
431 if (!execResult.isSuccess) {
432 SetLastIndexField(regexp.GetPtr(), lastIndexField, global, sticky, 0.0);
433 SetUnsuccessfulMatchLegacyProperties(regexpClass);
434 SetIsCorrectField(regexpExecArrayObject.GetPtr(), false);
435 return regexpExecArrayObject.GetPtr();
436 }
437
438 SetLastIndexField(regexp.GetPtr(), lastIndexField, global, sticky, static_cast<EtsDouble>(execResult.endIndex));
439 SetIsCorrectField(regexpExecArrayObject.GetPtr(), true);
440 SetIndexField(regexpExecArrayObject.GetPtr(), execResult.index);
441 SetInputField(regexpExecArrayObject.GetPtr(), strHandle.GetPtr());
442 SetResultField(regexpExecArrayObject.GetPtr(), execResult.captures, execResult.isWide);
443 SetSuccessfulMatchLegacyProperties(regexpClass, regexpExecArrayObject.GetPtr(), strHandle.GetPtr(),
444 execResult.index);
445 SetIndicesField(regexpExecArrayObject.GetPtr(), execResult.indices, hasIndices);
446 return regexpExecArrayObject.GetPtr();
447 }
448 } // namespace ark::ets::intrinsics
449