• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 #include "plugins/ets/runtime/regexp/regexp.h"
33 
34 namespace ark::ets::intrinsics {
35 using RegExpParser = ark::RegExpParser;
36 using RegExpExecutor = ark::ets::RegExpExecutor;
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 *LAST_INDEX_FIELD_NAME = "lastIndex";
45 constexpr const char *FLAGS_FIELD_NAME = "flags_";
46 constexpr std::array<const char *, LAST_PAREN_FIELDS_COUNT> PAREN_FIELD_NAMES = {"",    "$1_", "$2_", "$3_", "$4_",
47                                                                                  "$5_", "$6_", "$7_", "$8_", "$9_"};
48 constexpr const char *LAST_MATCH_FIELD_NAME = "lastMatch_";
49 constexpr const char *INPUT_STATIC_FIELD_NAME = "input_";
50 constexpr const char *LAST_PAREN_FIELD_NAME = "lastParen_";
51 constexpr const char *LEFT_CONTEXT_FIELD_NAME = "leftContext_";
52 constexpr const char *RIGHT_CONTEXT_FIELD_NAME = "rightContext_";
53 
54 constexpr const char *RESULT_CLASS_NAME = "Lescompat/RegExpExecArray;";
55 constexpr const char *INDEX_FIELD_NAME = "index";
56 constexpr const char *INPUT_FIELD_NAME = "input";
57 constexpr const char *INDICES_FIELD_NAME = "indices";
58 constexpr const char *RESULT_FIELD_NAME = "result_";
59 constexpr const char *IS_CORRECT_FIELD_NAME = "isCorrect";
60 constexpr const char *GROUPS_FIELD_NAME = "groupsRaw_";
61 
62 constexpr const auto REG_EXP_PARSER_EXT_FLAG_EXT_UNICODE = (1U << 7U);
63 
64 constexpr const uint32_t INDICES_DIMENSIONS_NUM = 2;
65 
CastToBitMask(EtsString * checkStr)66 uint32_t CastToBitMask(EtsString *checkStr)
67 {
68     uint32_t flagsBits = 0;
69     uint32_t flagsBitsTemp = 0;
70     for (int i = 0; i < checkStr->GetLength(); i++) {
71         switch (checkStr->At(i)) {
72             case 'd':
73                 flagsBitsTemp = RegExpParser::FLAG_HASINDICES;
74                 break;
75             case 'g':
76                 flagsBitsTemp = RegExpParser::FLAG_GLOBAL;
77                 break;
78             case 'i':
79                 flagsBitsTemp = RegExpParser::FLAG_IGNORECASE;
80                 break;
81             case 'm':
82                 flagsBitsTemp = RegExpParser::FLAG_MULTILINE;
83                 break;
84             case 's':
85                 flagsBitsTemp = RegExpParser::FLAG_DOTALL;
86                 break;
87             case 'u':
88                 flagsBitsTemp = RegExpParser::FLAG_UTF16;
89                 break;
90             case 'y':
91                 flagsBitsTemp = RegExpParser::FLAG_STICKY;
92                 break;
93             case 'v':
94                 flagsBitsTemp = REG_EXP_PARSER_EXT_FLAG_EXT_UNICODE;
95                 break;
96             default: {
97                 auto *thread = ManagedThread::GetCurrent();
98                 auto ctx = PandaEtsVM::GetCurrent()->GetLanguageContext();
99                 std::string message = "invalid regular expression flags";
100                 ark::ThrowException(ctx, thread, utf::CStringAsMutf8("Lstd/core/IllegalArgumentException;"),
101                                     utf::CStringAsMutf8(message.c_str()));
102                 return 0;
103             }
104         }
105         if ((flagsBits & flagsBitsTemp) != 0) {
106             auto *thread = ManagedThread::GetCurrent();
107             auto ctx = PandaEtsVM::GetCurrent()->GetLanguageContext();
108             std::string message = "invalid regular expression flags";
109             ark::ThrowException(ctx, thread, utf::CStringAsMutf8("Lstd/core/IllegalArgumentException;"),
110                                 utf::CStringAsMutf8(message.c_str()));
111             return 0;
112         }
113         flagsBits |= flagsBitsTemp;
114     }
115     return flagsBits;
116 }
117 
118 struct ExecuteOptions {
119     EtsInt lastIndex;
120     bool hasIndices;
121     bool hasSlashU;
122 };
123 
124 }  // namespace
125 
SetFlags(EtsObject * regexpObject,EtsString * checkStr)126 void SetFlags(EtsObject *regexpObject, EtsString *checkStr)
127 {
128     auto *coroutine = EtsCoroutine::GetCurrent();
129     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
130     VMHandle<EtsObject> regexp(coroutine, regexpObject->GetCoreType());
131 
132     auto *regexpClass = regexp->GetClass();
133     EtsField *flagsField = regexpClass->GetDeclaredFieldIDByName(FLAGS_FIELD_NAME);
134 
135     auto flags = checkStr->GetMutf8();
136     std::sort(flags.begin(), flags.end());
137     VMHandle<EtsString> newFlags(coroutine, EtsString::CreateFromMUtf8(flags.c_str())->GetCoreType());
138     regexp->SetFieldObject(flagsField, newFlags->AsObject());
139 }
140 
SetGroupNames(EtsObject * regexpObject,const RegExpParser & parser)141 void SetGroupNames(EtsObject *regexpObject, const RegExpParser &parser)
142 {
143     auto *coroutine = EtsCoroutine::GetCurrent();
144     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
145     VMHandle<EtsObject> regexp(coroutine, regexpObject->GetCoreType());
146     auto *regexpClass = regexp->GetClass();
147 
148     auto *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
149     auto *stringClass = classLinker->GetClassRoot(EtsClassRoot::STRING);
150 
151     auto groupName = parser.GetGroupNames();
152     EtsObjectArray *etsGroupNames = EtsObjectArray::Create(stringClass, groupName.size());
153     VMHandle<EtsObjectArray> arrHandle(coroutine, etsGroupNames->GetCoreType());
154 
155     EtsField *groupNamesField = regexpClass->GetDeclaredFieldIDByName(GROUP_NAMES_FIELD_NAME);
156     for (size_t i = 0; i < groupName.size(); ++i) {
157         VMHandle<EtsString> str(coroutine,
158                                 EtsString::CreateFromMUtf8(groupName[i].c_str(), groupName[i].size())->GetCoreType());
159         arrHandle.GetPtr()->Set(i, str->AsObject());
160     }
161     regexp.GetPtr()->SetFieldObject(groupNamesField, arrHandle.GetPtr()->AsObject());
162 }
163 
EscompatRegExpCompile(EtsObject * regexpObj)164 extern "C" EtsObject *EscompatRegExpCompile(EtsObject *regexpObj)
165 {
166     // NOTE(kparshukov): remove #20259
167     auto *coroutine = EtsCoroutine::GetCurrent();
168     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
169 
170     VMHandle<EtsObject> regexp(coroutine, regexpObj->GetCoreType());
171     return regexp.GetPtr();
172 }
173 
EscompatRegExpParse(EtsString * pattern)174 extern "C" EtsString *EscompatRegExpParse(EtsString *pattern)
175 {
176     RegExpParser parse = RegExpParser();
177     auto patternstr = ark::PandaStringToStd(pattern->GetUtf8());
178     parse.Init(const_cast<char *>(reinterpret_cast<const char *>(patternstr.c_str())), patternstr.length(), 0);
179     parse.Parse();
180     if (parse.IsError()) {
181         auto errormsg = ark::PandaStringToStd(parse.GetErrorMsg());
182         return EtsString::CreateFromMUtf8(errormsg.c_str(), errormsg.length());
183     }
184     return nullptr;
185 }
186 
SetSuccessfulMatchLegacyProperties(EtsClass * type,const EtsObject * regexpExecArrayObj,EtsString * inputStrObj,uint32_t index)187 void SetSuccessfulMatchLegacyProperties(EtsClass *type, const EtsObject *regexpExecArrayObj, EtsString *inputStrObj,
188                                         uint32_t index)
189 {
190     auto *coroutine = EtsCoroutine::GetCurrent();
191     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
192 
193     EtsClass *resultClass = regexpExecArrayObj->GetClass();
194     auto *resultField = resultClass->GetDeclaredFieldIDByName(RESULT_FIELD_NAME);
195     VMHandle<EtsObjectArray> matches(coroutine, regexpExecArrayObj->GetFieldObject(resultField)->GetCoreType());
196     ASSERT(matches->GetLength() != 0);
197 
198     VMHandle<EtsString> inputStr(coroutine, inputStrObj->GetCoreType());
199     VMHandle<EtsString> emptyString(coroutine, EtsString::CreateNewEmptyString()->GetCoreType());
200 
201     EtsField *lastMatchField = type->GetStaticFieldIDByName(LAST_MATCH_FIELD_NAME);
202     type->SetStaticFieldObject(lastMatchField, matches->Get(0U));
203     for (size_t i = 1; i < LAST_PAREN_FIELDS_COUNT; ++i) {
204         EtsField *parenField = type->GetStaticFieldIDByName(PAREN_FIELD_NAMES[i]);
205         if (i < matches->GetLength()) {
206             type->SetStaticFieldObject(parenField, matches->Get(i));
207         } else {
208             type->SetStaticFieldObject(parenField, emptyString->AsObject());
209         }
210     }
211 
212     EtsField *inputField = type->GetStaticFieldIDByName(INPUT_STATIC_FIELD_NAME);
213     type->SetStaticFieldObject(inputField, inputStr->AsObject());
214 
215     EtsField *lastParenField = type->GetStaticFieldIDByName(LAST_PAREN_FIELD_NAME);
216     if (matches->GetLength() > 1) {
217         type->SetStaticFieldObject(lastParenField, matches->Get(matches->GetLength() - 1U));
218     } else {
219         type->SetStaticFieldObject(lastParenField, emptyString->AsObject());
220     }
221 
222     EtsField *leftContextField = type->GetStaticFieldIDByName(LEFT_CONTEXT_FIELD_NAME);
223     EtsString *prefix = EtsString::FastSubString(inputStr.GetPtr(), 0, index);
224     type->SetStaticFieldObject(leftContextField, prefix->AsObject());
225 
226     EtsField *rightContextField = type->GetStaticFieldIDByName(RIGHT_CONTEXT_FIELD_NAME);
227     auto suffixBegin = index + EtsString::FromEtsObject(matches->Get(0U))->GetLength();
228     EtsString *suffix = EtsString::FastSubString(inputStr.GetPtr(), suffixBegin, inputStr->GetLength() - suffixBegin);
229     type->SetStaticFieldObject(rightContextField, suffix->AsObject());
230 }
231 
SetUnsuccessfulMatchLegacyProperties(EtsClass * type)232 void SetUnsuccessfulMatchLegacyProperties(EtsClass *type)
233 {
234     auto *coroutine = EtsCoroutine::GetCurrent();
235     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
236     VMHandle<EtsString> emptyString(coroutine, EtsString::CreateNewEmptyString()->GetCoreType());
237 
238     {
239         EtsField *lastMatchField = type->GetStaticFieldIDByName(LAST_MATCH_FIELD_NAME);
240         type->SetStaticFieldObject(lastMatchField, emptyString->AsObject());
241     }
242     for (size_t i = 1; i < LAST_PAREN_FIELDS_COUNT; ++i) {
243         EtsField *lastParenField = type->GetStaticFieldIDByName(PAREN_FIELD_NAMES[i]);
244         type->SetStaticFieldObject(lastParenField, emptyString->AsObject());
245     }
246 }
247 
ExtractString(EtsString * from,const bool asUtf16)248 PandaVector<uint8_t> ExtractString(EtsString *from, const bool asUtf16)
249 {
250     auto *coroutine = EtsCoroutine::GetCurrent();
251     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
252     VMHandle<EtsString> inputStr(coroutine, from->GetCoreType());
253     PandaVector<uint8_t> result;
254     if (asUtf16) {
255         const auto size = inputStr.GetPtr()->GetLength();
256         PandaVector<uint16_t> u16Buffer(size);
257         inputStr.GetPtr()->CopyDataUtf16(u16Buffer.data(), size);
258         auto strBuffer = reinterpret_cast<uint8_t *>(u16Buffer.data());
259         const auto newSize = size * 2;
260         for (int i = 0; i < newSize; i++) {
261             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
262             result.push_back(strBuffer[i]);
263         }
264         result.emplace_back(0U);
265         result.emplace_back(0U);
266     } else {
267         const size_t vecLen = inputStr.GetPtr()->GetLength();
268         result.resize(vecLen);
269         const auto data = inputStr.GetPtr()->GetDataMUtf8();
270         for (size_t i = 0U; i < vecLen; i++) {
271             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
272             result[i] = data[i];
273         }
274         result.emplace_back(0U);
275     }
276     return result;
277 }
278 
Execute(EtsString * pattern,EtsString * flags,EtsString * inputStrObj,ExecuteOptions options)279 RegExpExecResult Execute(EtsString *pattern, EtsString *flags, EtsString *inputStrObj, ExecuteOptions options)
280 {
281     auto *coroutine = EtsCoroutine::GetCurrent();
282     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
283     VMHandle<EtsString> patternHandle(coroutine, pattern->GetCoreType());
284     VMHandle<EtsString> flagsHandle(coroutine, flags->GetCoreType());
285     VMHandle<EtsString> inputStr(coroutine, inputStrObj->GetCoreType());
286 
287     const auto stringLength = inputStr.GetPtr()->GetLength();
288     const bool isUtf16Str = inputStr->IsUtf16();
289     const bool isUtf16Pattern = patternHandle->IsUtf16();
290     auto re = EtsRegExp();
291     re.SetFlags(flagsHandle.GetPtr());
292 
293     const bool isUtf16 = options.hasSlashU || isUtf16Str || isUtf16Pattern || re.IsUtf16();
294 
295     auto str = ExtractString(inputStr.GetPtr(), isUtf16);
296     auto patternStr = ExtractString(patternHandle.GetPtr(), isUtf16);
297     auto compiled = re.Compile(patternStr, isUtf16, patternHandle.GetPtr()->GetLength());
298     if (!compiled) {
299         RegExpExecResult badResult;
300         badResult.isSuccess = false;
301         return badResult;
302     }
303 
304     auto result = re.Execute(str, stringLength, options.lastIndex);
305     re.Destroy();
306     if (!options.hasIndices) {
307         result.indices.clear();
308     }
309     return result;
310 }
311 
SetResultField(EtsObject * regexpExecArrayObj,const PandaVector<std::pair<bool,PandaString>> & matches,bool isWide)312 void SetResultField(EtsObject *regexpExecArrayObj, const PandaVector<std::pair<bool, PandaString>> &matches,
313                     bool isWide)
314 {
315     auto *coroutine = EtsCoroutine::GetCurrent();
316     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
317     VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
318     EtsClass *resultClass = regexpExecArray->GetClass();
319 
320     auto *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
321     auto *stringClass = classLinker->GetClassRoot(EtsClassRoot::STRING);
322 
323     auto *resultField = resultClass->GetDeclaredFieldIDByName(RESULT_FIELD_NAME);
324     VMHandle<EtsObjectArray> resultArray(coroutine, EtsObjectArray::Create(stringClass, matches.size())->GetCoreType());
325     VMHandle<EtsString> match;
326     for (size_t i = 0; i < matches.size(); ++i) {
327         if (isWide) {
328             match = VMHandle<EtsString>(
329                 coroutine, EtsString::CreateFromUtf16(reinterpret_cast<const ets_char *>(matches[i].second.c_str()),
330                                                       matches[i].second.length() / RegExpExecutor::WIDE_CHAR_SIZE)
331                                ->GetCoreType());
332         } else {
333             match = VMHandle<EtsString>(
334                 coroutine, EtsString::CreateFromUtf8(reinterpret_cast<const char *>(matches[i].second.c_str()),
335                                                      matches[i].second.length())
336                                ->GetCoreType());
337         }
338         resultArray->Set(i, match->AsObject());
339     }
340     regexpExecArray->SetFieldObject(resultField, resultArray->AsObject());
341 }
342 
SetIndicesField(EtsObject * regexpExecArrayObj,const PandaVector<std::pair<uint32_t,uint32_t>> & indices,bool hasIndices)343 void SetIndicesField(EtsObject *regexpExecArrayObj, const PandaVector<std::pair<uint32_t, uint32_t>> &indices,
344                      bool hasIndices)
345 {
346     auto *coroutine = EtsCoroutine::GetCurrent();
347     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
348     VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
349     auto *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
350 
351     EtsClass *resultClass = regexpExecArray->GetClass();
352     auto *indicesField = resultClass->GetDeclaredFieldIDByName(INDICES_FIELD_NAME);
353 
354     if (!hasIndices) {
355         VMHandle<EtsDoubleArray> defaultVal(coroutine, EtsDoubleArray::Create(0)->GetCoreType());
356         regexpExecArray->SetFieldObject(indicesField, defaultVal->AsObject());
357         return;
358     }
359 
360     VMHandle<EtsObjectArray> indicesArray(
361         coroutine,
362         EtsObjectArray::Create(classLinker->GetClassRoot(EtsClassRoot::DOUBLE_ARRAY), indices.size())->GetCoreType());
363     for (size_t i = 0; i < indices.size(); ++i) {
364         VMHandle<EtsDoubleArray> index(coroutine, EtsDoubleArray::Create(INDICES_DIMENSIONS_NUM)->GetCoreType());
365         index->Set(0, static_cast<EtsDouble>(indices[i].first));
366         index->Set(1, static_cast<EtsDouble>(indices[i].second));
367         indicesArray->Set(i, index->AsObject());
368     }
369     regexpExecArray->SetFieldObject(indicesField, indicesArray->AsObject());
370 }
371 
SetIsCorrectField(EtsObject * regexpExecArrayObj,bool value)372 void SetIsCorrectField(EtsObject *regexpExecArrayObj, bool value)
373 {
374     auto *coroutine = EtsCoroutine::GetCurrent();
375     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
376     VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
377     EtsClass *resultClass = regexpExecArray->GetClass();
378     auto *resultCorrectField = resultClass->GetDeclaredFieldIDByName(IS_CORRECT_FIELD_NAME);
379 
380     regexpExecArray->SetFieldPrimitive<EtsBoolean>(resultCorrectField, ToEtsBoolean(value));
381 }
382 
SetInputField(EtsObject * regexpExecArrayObj,EtsString * inputStrObj)383 void SetInputField(EtsObject *regexpExecArrayObj, EtsString *inputStrObj)
384 {
385     auto *coroutine = EtsCoroutine::GetCurrent();
386     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
387     VMHandle<EtsString> inputStr(coroutine, inputStrObj->GetCoreType());
388     VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
389     EtsClass *resultClass = regexpExecArray->GetClass();
390     auto *inputField = resultClass->GetDeclaredFieldIDByName(INPUT_FIELD_NAME);
391 
392     regexpExecArray->SetFieldObject(inputField, inputStr->AsObject());
393 }
394 
SetIndexField(EtsObject * regexpExecArrayObj,uint32_t index)395 void SetIndexField(EtsObject *regexpExecArrayObj, uint32_t index)
396 {
397     auto *coroutine = EtsCoroutine::GetCurrent();
398     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
399     VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
400     EtsClass *resultClass = regexpExecArray->GetClass();
401 
402     auto *indexField = resultClass->GetDeclaredFieldIDByName(INDEX_FIELD_NAME);
403     regexpExecArray->SetFieldPrimitive<EtsDouble>(indexField, static_cast<EtsDouble>(index));
404 }
405 
SetLastIndexField(EtsObject * regexp,EtsField * lastIndexField,bool global,bool sticky,EtsDouble value)406 void SetLastIndexField(EtsObject *regexp, EtsField *lastIndexField, bool global, bool sticky, EtsDouble value)
407 {
408     if (!global && !sticky) {
409         return;
410     }
411     regexp->SetFieldPrimitive<EtsDouble>(lastIndexField, value);
412 }
413 
SetGroupsField(EtsObject * regexpExecArrayObj,const std::map<PandaString,std::pair<int32_t,int32_t>> & groups)414 void SetGroupsField(EtsObject *regexpExecArrayObj, const std::map<PandaString, std::pair<int32_t, int32_t>> &groups)
415 {
416     auto *coroutine = EtsCoroutine::GetCurrent();
417     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
418     VMHandle<EtsObject> regexpExecArray(coroutine, regexpExecArrayObj->GetCoreType());
419     EtsClass *resultClass = regexpExecArray->GetClass();
420     auto *groupsField = resultClass->GetDeclaredFieldIDByName(GROUPS_FIELD_NAME);
421     PandaString data;
422     for (const auto &[key, value] : groups) {
423         data += key + "," + ToPandaString(value.first) + "," + ToPandaString(value.second) + ";";
424     }
425 
426     EtsString *groupsStr = EtsString::CreateFromMUtf8(data.c_str(), data.size());
427     regexpExecArray->SetFieldObject(groupsField, groupsStr->AsObject());
428 }
429 
EscompatRegExpExec(EtsObject * obj,EtsString * patternStr,EtsString * flagsStr,EtsString * str,EtsBoolean hasSlashU)430 extern "C" EtsObject *EscompatRegExpExec(EtsObject *obj, EtsString *patternStr, EtsString *flagsStr, EtsString *str,
431                                          EtsBoolean hasSlashU)
432 {
433     auto *coroutine = EtsCoroutine::GetCurrent();
434     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
435 
436     auto *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
437 
438     VMHandle<EtsObject> regexp(coroutine, obj->GetCoreType());
439     VMHandle<EtsString> pattern(coroutine, patternStr->GetCoreType());
440     VMHandle<EtsString> flags(coroutine, flagsStr->GetCoreType());
441     VMHandle<EtsString> strHandle(coroutine, str->GetCoreType());
442     auto *regexpResultArrayClass = classLinker->GetClass(RESULT_CLASS_NAME);
443     VMHandle<EtsObject> regexpExecArrayObject(coroutine, EtsObject::Create(regexpResultArrayClass)->GetCoreType());
444 
445     auto *regexpClass = regexp->GetClass();
446 
447     EtsField *lastIndexField = regexpClass->GetDeclaredFieldIDByName(LAST_INDEX_FIELD_NAME);
448     auto lastIdx = static_cast<int32_t>(regexp.GetPtr()->GetFieldPrimitive<EtsDouble>(lastIndexField));
449     auto flagsBits = static_cast<uint8_t>(CastToBitMask(flags.GetPtr()));
450 
451     bool global = (flagsBits & RegExpParser::FLAG_GLOBAL) > 0;
452     bool sticky = (flagsBits & RegExpParser::FLAG_STICKY) > 0;
453     bool hasIndices = (flagsBits & RegExpParser::FLAG_HASINDICES) > 0;
454     if ((!global && !sticky) || lastIdx < 0) {
455         lastIdx = 0;
456     }
457     EtsInt strLen = strHandle->GetLength();
458     if (lastIdx > strLen) {
459         SetLastIndexField(regexp.GetPtr(), lastIndexField, global, sticky, 0.0);
460         SetUnsuccessfulMatchLegacyProperties(regexpClass);
461         SetIsCorrectField(regexpExecArrayObject.GetPtr(), false);
462         return regexpExecArrayObject.GetPtr();
463     }
464 
465     auto execResult = Execute(pattern.GetPtr(), flags.GetPtr(), strHandle.GetPtr(),
466                               ExecuteOptions {lastIdx, hasIndices, static_cast<bool>(hasSlashU)});
467     if (!execResult.isSuccess) {
468         SetLastIndexField(regexp.GetPtr(), lastIndexField, global, sticky, 0.0);
469         SetUnsuccessfulMatchLegacyProperties(regexpClass);
470         SetIsCorrectField(regexpExecArrayObject.GetPtr(), false);
471         return regexpExecArrayObject.GetPtr();
472     }
473 
474     SetLastIndexField(regexp.GetPtr(), lastIndexField, global, sticky, static_cast<EtsDouble>(execResult.endIndex));
475     SetIsCorrectField(regexpExecArrayObject.GetPtr(), true);
476     SetIndexField(regexpExecArrayObject.GetPtr(), execResult.index);
477     SetInputField(regexpExecArrayObject.GetPtr(), strHandle.GetPtr());
478     SetResultField(regexpExecArrayObject.GetPtr(), execResult.captures, execResult.isWide);
479     SetSuccessfulMatchLegacyProperties(regexpClass, regexpExecArrayObject.GetPtr(), strHandle.GetPtr(),
480                                        execResult.index);
481     SetIndicesField(regexpExecArrayObject.GetPtr(), execResult.indices, hasIndices);
482     SetGroupsField(regexpExecArrayObject.GetPtr(), execResult.namedGroups);
483     return regexpExecArrayObject.GetPtr();
484 }
485 }  // namespace ark::ets::intrinsics
486