• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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