Coverage Report

Created: 2026-05-16 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsRegExp.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2017  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Runtime.
5
 * 
6
 *   The Moddable SDK Runtime is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU Lesser General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Runtime is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU Lesser General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU Lesser General Public License
17
 *   along with the Moddable SDK Runtime.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * This file incorporates work covered by the following copyright and  
20
 * permission notice:  
21
 *
22
 *       Copyright (C) 2010-2016 Marvell International Ltd.
23
 *       Copyright (C) 2002-2010 Kinoma, Inc.
24
 *
25
 *       Licensed under the Apache License, Version 2.0 (the "License");
26
 *       you may not use this file except in compliance with the License.
27
 *       You may obtain a copy of the License at
28
 *
29
 *        http://www.apache.org/licenses/LICENSE-2.0
30
 *
31
 *       Unless required by applicable law or agreed to in writing, software
32
 *       distributed under the License is distributed on an "AS IS" BASIS,
33
 *       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34
 *       See the License for the specific language governing permissions and
35
 *       limitations under the License.
36
 */
37
38
#include "xsAll.h"
39
#ifndef mxRegExp
40
  #define mxRegExp 1
41
#endif
42
#if mxRegExp
43
static txNumber fxAdvanceStringIndex(txMachine* the, txString string, txNumber index, txBoolean unicodeFlag);
44
static txSlot* fxCheckRegExpInstance(txMachine* the, txSlot* slot);
45
static void fxExecuteRegExp(txMachine* the, txSlot* regexp, txSlot* argument);
46
#endif
47
48
static void fx_RegExp_prototype_get_flag(txMachine* the, txU4 flag);
49
static void fx_RegExp_prototype_split_aux(txMachine* the, txSlot* string, txIndex start, txIndex stop, txSlot* item);
50
51
void fxBuildRegExp(txMachine* the)
52
23.0k
{
53
23.0k
  txSlot* slot;
54
23.0k
  mxPush(mxObjectPrototype);
55
23.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
56
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_prototype_compile), 0, mxID(_compile), XS_DONT_ENUM_FLAG);
57
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_prototype_exec), 1, mxID(_exec), XS_DONT_ENUM_FLAG);
58
23.0k
  mxExecuteRegExpFunction.kind = slot->kind;
59
23.0k
  mxExecuteRegExpFunction.value = slot->value;
60
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_prototype_match), 1, mxID(_Symbol_match), XS_DONT_ENUM_FLAG);
61
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_prototype_matchAll), 1, mxID(_Symbol_matchAll), XS_DONT_ENUM_FLAG);
62
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_prototype_replace), 2, mxID(_Symbol_replace), XS_DONT_ENUM_FLAG);
63
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_prototype_search), 1, mxID(_Symbol_search), XS_DONT_ENUM_FLAG);
64
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_prototype_split), 2, mxID(_Symbol_split), XS_DONT_ENUM_FLAG);
65
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_prototype_test), 1, mxID(_test), XS_DONT_ENUM_FLAG);
66
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_prototype_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG);
67
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_RegExp_prototype_get_dotAll), C_NULL, mxID(_dotAll), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
68
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_RegExp_prototype_get_flags), C_NULL, mxID(_flags), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
69
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_RegExp_prototype_get_global), C_NULL, mxID(_global), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
70
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_RegExp_prototype_get_hasIndices), C_NULL, mxID(_hasIndices), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
71
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_RegExp_prototype_get_ignoreCase), C_NULL, mxID(_ignoreCase), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
72
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_RegExp_prototype_get_multiline), C_NULL, mxID(_multiline), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
73
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_RegExp_prototype_get_source), C_NULL, mxID(_source), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
74
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_RegExp_prototype_get_sticky), C_NULL, mxID(_sticky), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
75
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_RegExp_prototype_get_unicode), C_NULL, mxID(_unicode), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
76
23.0k
#if mxECMAScript2024
77
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_RegExp_prototype_get_unicodeSets), C_NULL, mxID(_unicodeSets), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
78
23.0k
#endif
79
23.0k
  mxRegExpPrototype = *the->stack;
80
23.0k
  slot = fxBuildHostConstructor(the, mxCallback(fx_RegExp), 2, mxID(_RegExp));
81
23.0k
  mxRegExpConstructor = *the->stack;
82
23.0k
  slot = fxLastProperty(the, slot);
83
23.0k
#if mxECMAScript2025
84
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_escape), 1, mxID(_escape), XS_DONT_ENUM_FLAG);
85
23.0k
#endif
86
23.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG);
87
23.0k
  mxPop();
88
23.0k
  fxNewHostFunction(the, mxCallback(fxInitializeRegExp), 2, XS_NO_ID, XS_NO_ID);
89
23.0k
  mxInitializeRegExpFunction = *the->stack;
90
  
91
23.0k
  mxPush(mxIteratorPrototype);
92
23.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
93
23.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_RegExp_prototype_matchAll_next), 0, mxID(_next), XS_DONT_ENUM_FLAG);
94
23.0k
  slot = fxNextStringXProperty(the, slot, "RegExp String Iterator", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
95
23.0k
  mxPull(mxRegExpStringIteratorPrototype);
96
97
23.0k
  mxPop();
98
23.0k
}
99
100
#if mxRegExp
101
txNumber fxAdvanceStringIndex(txMachine* the, txString string, txNumber index, txBoolean unicodeFlag)
102
7.74M
{
103
7.74M
#if mxCESU8
104
7.74M
  if (unicodeFlag) {
105
6.74M
    txInteger character;
106
6.74M
    txSize offset = fxCacheUnicodeLength(the, string);
107
6.74M
    if (index >= offset)
108
34.6k
      return index + 1;
109
6.71M
    offset = fxCacheUnicodeToUTF8Offset(the, string, (txInteger)index);
110
6.71M
    offset = mxPtrDiff(mxStringByteDecode(string + offset, &character) - string);
111
6.71M
    if (character == C_EOF)
112
0
      return index + 1;
113
6.71M
    return fxCacheUTF8ToUnicodeOffset(the, string, offset);
114
6.71M
  }
115
993k
#endif
116
993k
  return index + 1;
117
7.74M
}
118
119
txSlot* fxCheckRegExpInstance(txMachine* the, txSlot* slot)
120
9.04M
{
121
9.04M
  if (slot->kind == XS_REFERENCE_KIND) {
122
9.04M
    slot = slot->value.reference;
123
9.04M
    if ((slot->next) && (slot->next->flag & XS_INTERNAL_FLAG) && (slot->next->kind == XS_REGEXP_KIND))
124
9.04M
      return slot;
125
9.04M
  }
126
9.04M
  mxTypeError("this: not a RegExp instance");
127
0
  return C_NULL;
128
9.04M
}
129
130
void fxExecuteRegExp(txMachine* the, txSlot* regexp, txSlot* argument)
131
9.50M
{
132
9.50M
  mxPushSlot(regexp);
133
9.50M
  mxDub();
134
9.50M
  mxGetID(mxID(_exec));
135
9.50M
  if ((the->stack->kind != XS_REFERENCE_KIND) || (!mxIsFunction(the->stack->value.reference))) {
136
33
    the->stack->kind = mxExecuteRegExpFunction.kind;
137
33
    the->stack->value = mxExecuteRegExpFunction.value;
138
33
  }
139
9.50M
  mxCall();
140
9.50M
  mxPushSlot(argument);
141
9.50M
  mxRunCount(1);
142
9.50M
  if ((the->stack->kind != XS_NULL_KIND) && (the->stack->kind != XS_REFERENCE_KIND))
143
11
    mxTypeError("invalid exec result");
144
9.50M
}
145
#endif
146
147
void fxInitializeRegExp(txMachine* the) 
148
622k
{
149
622k
#if mxRegExp
150
622k
  txSlot* instance = fxToInstance(the, mxThis);
151
622k
  txSlot* regexp = instance->next;
152
622k
  txSlot* key = regexp->next;
153
622k
  txString pattern;
154
622k
  txString modifier;
155
156
622k
  if (mxArgv(0)->kind == XS_UNDEFINED_KIND)
157
6.87k
    *mxArgv(0) = mxEmptyString;
158
615k
  else
159
615k
    fxToString(the, mxArgv(0));
160
622k
  if (mxArgv(1)->kind == XS_UNDEFINED_KIND)
161
84.8k
    *mxArgv(1) = mxEmptyString;
162
537k
  else
163
537k
    fxToString(the, mxArgv(1));
164
622k
    key->kind = (mxArgv(0)->kind == XS_STRING_X_KIND) ? XS_KEY_X_KIND : XS_KEY_KIND;
165
622k
    pattern = key->value.key.string = mxArgv(0)->value.string;
166
622k
  modifier = mxArgv(1)->value.string;
167
622k
  if (!fxCompileRegExp(the, pattern, modifier, &regexp->value.regexp.code, &regexp->value.regexp.data, the->nameBuffer, sizeof(the->nameBuffer)))
168
34.6k
    mxSyntaxError("invalid regular expression: %s", the->nameBuffer);
169
587k
  *mxResult = *mxThis;
170
587k
#endif
171
587k
}
172
173
txBoolean fxIsRegExp(txMachine* the, txSlot* slot)
174
539k
{
175
539k
#if mxRegExp
176
539k
    if (mxIsReference(slot)) {
177
57.8k
        txSlot* instance = slot->value.reference;
178
57.8k
        mxPushSlot(slot);
179
57.8k
        mxGetID(mxID(_Symbol_match));
180
57.8k
        if (the->stack->kind != XS_UNDEFINED_KIND)
181
53.7k
            return fxToBoolean(the, the->stack++);
182
4.13k
        mxPop();
183
4.13k
        if ((instance->next) && (instance->next->flag & XS_INTERNAL_FLAG) && (instance->next->kind == XS_REGEXP_KIND))
184
0
            return 1;
185
4.13k
    }
186
485k
#endif
187
485k
  return 0;
188
539k
}
189
190
txSlot* fxNewRegExpInstance(txMachine* the)
191
622k
{
192
622k
#if mxRegExp
193
622k
  txSlot* instance;
194
622k
  txSlot* property;
195
622k
  instance = fxNewObjectInstance(the);
196
197
622k
  property = instance->next = fxNewSlot(the);
198
622k
  property->flag = XS_INTERNAL_FLAG;
199
622k
  property->kind = XS_REGEXP_KIND;
200
622k
  property->value.regexp.code = C_NULL;
201
622k
  property->value.regexp.data = C_NULL;
202
203
622k
  property = property->next = fxNewSlot(the);
204
622k
  property->flag = XS_INTERNAL_FLAG;
205
622k
  property->kind = (mxEmptyString.kind == XS_STRING_X_KIND) ? XS_KEY_X_KIND : XS_KEY_KIND;
206
622k
  property->value.key.string = mxEmptyString.value.string;
207
622k
  property->value.key.sum = 0;
208
209
622k
  property = fxNextIntegerProperty(the, property, 0, mxID(_lastIndex), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG);
210
  
211
622k
  return instance;
212
#else
213
  return NULL;
214
#endif
215
622k
}
216
217
void fx_RegExp(txMachine* the)
218
541k
{
219
541k
#if mxRegExp
220
541k
  txSlot* pattern = ((mxArgc > 0) && (mxArgv(0)->kind != XS_UNDEFINED_KIND)) ? mxArgv(0) : C_NULL;
221
541k
  txSlot* flags = ((mxArgc > 1) && (mxArgv(1)->kind != XS_UNDEFINED_KIND)) ? mxArgv(1) : C_NULL;
222
541k
  txBoolean patternIsRegExp = (pattern && fxIsRegExp(the, pattern)) ? 1 : 0;
223
  
224
541k
  if (!mxHasTarget) {
225
13.0k
    if (patternIsRegExp && !flags) {
226
19
      mxPushSlot(pattern);
227
19
      mxGetID(mxID(_constructor));
228
19
      if ((the->stack->kind == mxFunction->kind) && (the->stack->value.reference == mxFunction->value.reference)) {
229
11
        mxPop();
230
11
        *mxResult = *pattern;
231
11
        return;
232
11
      }
233
8
      mxPop();
234
8
    }
235
13.0k
    mxPushSlot(mxFunction);
236
13.0k
  }
237
528k
  else {
238
528k
    mxPushSlot(mxTarget);
239
528k
  }
240
541k
  fxGetPrototypeFromConstructor(the, &mxRegExpPrototype);
241
541k
  fxNewRegExpInstance(the);
242
541k
  mxPush(mxInitializeRegExpFunction);
243
541k
  mxCall();
244
541k
  if (patternIsRegExp) {
245
53.5k
    mxPushSlot(pattern);
246
53.5k
    mxGetID(mxID(_source));
247
53.5k
    if (flags)
248
53.5k
      mxPushSlot(flags);
249
13
    else {
250
13
      mxPushSlot(pattern);
251
13
      mxGetID(mxID(_flags));
252
13
    }
253
53.5k
  }
254
488k
  else {
255
488k
    if (pattern)
256
482k
      mxPushSlot(pattern);
257
5.57k
    else
258
5.57k
      mxPushUndefined();
259
488k
    if (flags)
260
478k
      mxPushSlot(flags);
261
9.41k
    else
262
9.41k
      mxPushUndefined();
263
488k
  }
264
541k
  mxRunCount(2);
265
541k
  mxPullSlot(mxResult);
266
#else
267
  mxUnknownError("not built-in");
268
#endif
269
541k
}
270
271
void fx_RegExp_prototype_get_flag(txMachine* the, txU4 flag)
272
4.57M
{
273
4.57M
#if mxRegExp
274
4.57M
  txSlot* slot = mxThis;
275
4.57M
  if (slot->kind == XS_REFERENCE_KIND) {
276
4.57M
    slot = slot->value.reference;
277
4.57M
    if (slot == mxRegExpPrototype.value.reference)
278
3.03k
      return;
279
4.57M
    slot = slot->next;
280
4.57M
    if ((slot) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_REGEXP_KIND)) {
281
4.52M
      txInteger flags = slot->value.regexp.code[0];
282
4.52M
      mxResult->value.boolean = (flags & flag) ? 1 : 0;
283
4.52M
      mxResult->kind = XS_BOOLEAN_KIND;
284
4.52M
      return;
285
4.52M
    }
286
4.57M
  }
287
4.57M
  mxTypeError("this: not an object");
288
4.57M
#endif
289
4.57M
}
290
291
void fx_RegExp_prototype_get_flags(txMachine* the)
292
566k
{
293
566k
#if mxRegExp
294
566k
  char flags[9];
295
566k
  txIndex index = 0;
296
566k
  if (mxThis->kind != XS_REFERENCE_KIND)
297
12
    mxTypeError("this: not an object");
298
566k
  mxPushSlot(mxThis);
299
566k
  mxGetID(mxID(_hasIndices));
300
566k
  if (fxToBoolean(the, the->stack++))
301
6.73k
    flags[index++] = 'd';
302
566k
  mxPushSlot(mxThis);
303
566k
  mxGetID(mxID(_global));
304
566k
  if (fxToBoolean(the, the->stack++))
305
349k
    flags[index++] = 'g';
306
566k
  mxPushSlot(mxThis);
307
566k
  mxGetID(mxID(_ignoreCase));
308
566k
  if (fxToBoolean(the, the->stack++))
309
134k
    flags[index++] = 'i';
310
566k
  mxPushSlot(mxThis);
311
566k
  mxGetID(mxID(_multiline));
312
566k
  if (fxToBoolean(the, the->stack++))
313
3.35k
    flags[index++] = 'm';
314
566k
  mxPushSlot(mxThis);
315
566k
  mxGetID(mxID(_dotAll));
316
566k
  if (fxToBoolean(the, the->stack++))
317
38.8k
    flags[index++] = 's';
318
566k
  mxPushSlot(mxThis);
319
566k
  mxGetID(mxID(_unicode));
320
566k
  if (fxToBoolean(the, the->stack++))
321
107k
    flags[index++] = 'u';
322
566k
#if mxECMAScript2024
323
566k
  mxPushSlot(mxThis);
324
566k
  mxGetID(mxID(_unicodeSets));
325
566k
  if (fxToBoolean(the, the->stack++))
326
83.8k
    flags[index++] = 'v';
327
566k
#endif
328
566k
  mxPushSlot(mxThis);
329
566k
  mxGetID(mxID(_sticky));
330
566k
  if (fxToBoolean(the, the->stack++))
331
10.2k
    flags[index++] = 'y';
332
566k
  flags[index] = 0;
333
566k
  fxCopyStringC(the, mxResult, flags);
334
566k
#endif
335
566k
}
336
337
void fx_RegExp_prototype_get_dotAll(txMachine* the)
338
566k
{
339
566k
#if mxRegExp
340
566k
  fx_RegExp_prototype_get_flag(the, XS_REGEXP_S);
341
566k
#endif
342
566k
}
343
344
void fx_RegExp_prototype_get_global(txMachine* the)
345
566k
{
346
566k
#if mxRegExp
347
566k
  fx_RegExp_prototype_get_flag(the, XS_REGEXP_G);
348
566k
#endif
349
566k
}
350
351
void fx_RegExp_prototype_get_hasIndices(txMachine* the)
352
566k
{
353
566k
#if mxRegExp
354
566k
  fx_RegExp_prototype_get_flag(the, XS_REGEXP_D);
355
566k
#endif
356
566k
}
357
358
void fx_RegExp_prototype_get_ignoreCase(txMachine* the)
359
613k
{
360
613k
#if mxRegExp
361
613k
  fx_RegExp_prototype_get_flag(the, XS_REGEXP_I);
362
613k
#endif
363
613k
}
364
365
void fx_RegExp_prototype_get_multiline(txMachine* the)
366
566k
{
367
566k
#if mxRegExp
368
566k
  fx_RegExp_prototype_get_flag(the, XS_REGEXP_M);
369
566k
#endif
370
566k
}
371
372
void fx_RegExp_prototype_get_source(txMachine* the)
373
284k
{
374
284k
#if mxRegExp
375
284k
  txSlot* slot = mxThis;
376
284k
  if (slot->kind == XS_REFERENCE_KIND) {
377
284k
    slot = slot->value.reference;
378
284k
    if (slot == mxRegExpPrototype.value.reference) {
379
377
      *mxResult = mxEmptyRegExp;
380
377
      return;
381
377
    }
382
284k
    slot = slot->next;
383
284k
    if ((slot) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_REGEXP_KIND)) {
384
276k
      txString pattern;
385
276k
      txInteger escape = 0;
386
276k
      txInteger count = 0;
387
276k
      txU1 c, d, *s, *r;
388
276k
            slot = slot->next;
389
276k
      pattern = slot->value.key.string;
390
276k
      if (*pattern == 0) {
391
1.38k
        *mxResult = mxEmptyRegExp;
392
1.38k
        return;
393
1.38k
      }
394
275k
      s = (txU1*)pattern;
395
275k
      d = 0;
396
36.5M
      while ((c = *s++)) {
397
36.2M
        if ((c == '/') && (d != '\\'))
398
37.5k
          escape++;
399
36.2M
        else if ((c == 10) || (c == 13)/* || (c == '/')*/)
400
2.04k
          escape++;
401
36.2M
        else if ((c == 0xE2) && (s[0] == 0x80) && ((s[1] == 0xA8) || (s[1] == 0xA9))) /* LS || PS */
402
3.13k
          escape += 3;
403
36.2M
        d = c;
404
36.2M
        count++;
405
36.2M
      }
406
275k
      if (escape) {
407
13.0k
        mxResult->value.string = fxNewChunk(the, count + escape + 1);
408
13.0k
        mxResult->kind = XS_STRING_KIND;
409
13.0k
        s = (txU1*)slot->value.key.string;
410
13.0k
        r = (txU1*)mxResult->value.string;
411
13.0k
        d = 0;
412
10.3M
        while ((c = *s++)) {
413
10.2M
          if ((c == '/') && (d != '\\')) {
414
37.5k
            *r++ = '\\'; *r++ = '/';
415
37.5k
          }
416
10.2M
          else if (c == 10) {
417
1.97k
            *r++ = '\\'; *r++ = 'n';
418
1.97k
          }
419
10.2M
          else if (c == 13) {
420
73
            *r++ = '\\'; *r++ = 'r';
421
73
          }
422
10.2M
          else if ((c == 0xE2) && (s[0] == 0x80) && (s[1] == 0xA8)) {
423
1.69k
            *r++ = '\\'; *r++ = 'u'; *r++ = '2'; *r++ = '0'; *r++ = '2'; *r++ = '8';
424
1.69k
            s += 2;
425
1.69k
          }
426
10.2M
          else if ((c == 0xE2) && (s[0] == 0x80) && (s[1] == 0xA9)) {
427
1.43k
            *r++ = '\\'; *r++ = 'u'; *r++ = '2'; *r++ = '0'; *r++ = '2'; *r++ = '9';
428
1.43k
            s += 2;
429
1.43k
          }
430
10.2M
          else {
431
10.2M
            *r++ = c; 
432
10.2M
          }
433
10.2M
          d = c;
434
10.2M
        }
435
13.0k
        *r = 0;
436
13.0k
      }
437
262k
      else {
438
262k
        mxResult->value.string = slot->value.string;
439
262k
        mxResult->kind = (slot->kind == XS_KEY_X_KIND) ? XS_STRING_X_KIND : XS_STRING_KIND;
440
262k
      }
441
275k
      return;
442
276k
    }
443
284k
  }
444
284k
  mxTypeError("this: not a RegExp instance");
445
284k
#endif
446
284k
}
447
448
void fx_RegExp_prototype_get_sticky(txMachine* the)
449
566k
{
450
566k
#if mxRegExp
451
566k
  fx_RegExp_prototype_get_flag(the, XS_REGEXP_Y);
452
566k
#endif
453
566k
}
454
455
void fx_RegExp_prototype_get_unicode(txMachine* the)
456
566k
{
457
566k
#if mxRegExp
458
566k
  fx_RegExp_prototype_get_flag(the, XS_REGEXP_U);
459
566k
#endif
460
566k
}
461
462
void fx_RegExp_prototype_get_unicodeSets(txMachine* the)
463
566k
{
464
566k
#if mxRegExp
465
566k
  fx_RegExp_prototype_get_flag(the, XS_REGEXP_V);
466
566k
#endif
467
566k
}
468
469
void fx_RegExp_prototype_compile(txMachine* the)
470
0
{
471
0
#if mxRegExp
472
0
  *mxResult = *mxThis;
473
0
#endif
474
0
}
475
476
void fx_RegExp_prototype_exec(txMachine* the)
477
9.04M
{
478
9.04M
#if mxRegExp
479
9.04M
  txSlot* instance = fxCheckRegExpInstance(the, mxThis);
480
9.04M
  txSlot* regexp = instance->next;
481
9.04M
  txSlot* argument;
482
9.04M
  txSlot* temporary;
483
9.04M
  txNumber lastIndex;
484
9.04M
  txInteger flags;
485
9.04M
  txBoolean globalFlag;
486
9.04M
  txBoolean namedFlag;
487
9.04M
  txBoolean stickyFlag;
488
9.04M
  txBoolean hasIndicesFlag;
489
9.04M
  txInteger offset;
490
491
9.04M
  if (mxArgc > 0)
492
9.04M
    mxPushSlot(mxArgv(0));
493
1.76k
  else
494
1.76k
    mxPushUndefined();
495
9.04M
  fxToString(the, the->stack);
496
9.04M
  argument = the->stack;
497
  
498
9.04M
  if (regexp->value.regexp.data == C_NULL) {
499
0
    mxTemporary(temporary);
500
0
    temporary->value.regexp.code = C_NULL;
501
0
    temporary->value.regexp.data = fxAllocateRegExpData(the, regexp->value.regexp.code);
502
0
    temporary->kind = XS_REGEXP_KIND;
503
0
  }
504
9.04M
  else
505
9.04M
    temporary = regexp;
506
507
9.04M
  mxPushSlot(mxThis);
508
9.04M
  mxGetID(mxID(_lastIndex));
509
9.04M
  lastIndex = fxToLength(the, the->stack);
510
9.04M
  mxPop();
511
9.04M
  if (lastIndex > 0x7FFFFFFF)
512
31
    lastIndex = 0x7FFFFFFF;
513
514
9.04M
  flags = regexp->value.regexp.code[0];
515
9.04M
  globalFlag = (flags & XS_REGEXP_G) ? 1 : 0;
516
9.04M
  namedFlag = (flags & XS_REGEXP_N) ? 1 : 0;
517
9.04M
  stickyFlag = (flags & XS_REGEXP_Y) ? 1 : 0;
518
9.04M
  hasIndicesFlag = (flags & XS_REGEXP_D) ? 1 : 0;
519
9.04M
  offset = (globalFlag || stickyFlag) ? fxCacheUnicodeToUTF8Offset(the, argument->value.string, (txInteger)lastIndex) : 0;
520
9.04M
  if ((offset >= 0) && fxMatchRegExp(the, regexp->value.regexp.code, temporary->value.regexp.data, argument->value.string, offset)) {
521
4.86M
    txSlot* resultArray;
522
4.86M
    txSlot* resultItem;
523
4.86M
    txSlot* indicesArray;
524
4.86M
    txSlot* indicesItem;
525
4.86M
    txSlot* resultObject;
526
4.86M
    txSlot* resultProperty;
527
4.86M
    txSlot* indicesObject;
528
4.86M
    txSlot* indicesProperty;
529
4.86M
    txInteger captureCount;
530
4.86M
    txInteger nameCount;
531
4.86M
    txInteger captureIndex;
532
4.86M
    txInteger nameIndex;
533
4.86M
    txInteger length;
534
4.86M
    if (globalFlag || stickyFlag) {
535
4.77M
      offset = fxCacheUTF8ToUnicodeOffset(the, argument->value.string, temporary->value.regexp.data[1]);
536
4.77M
      mxPushInteger(offset);
537
4.77M
      mxPushSlot(mxThis);
538
4.77M
      mxSetID(mxID(_lastIndex));
539
4.77M
      mxPop();
540
4.77M
    }
541
4.86M
    captureCount = regexp->value.regexp.code[1];
542
4.86M
    nameCount = regexp->value.regexp.code[2];
543
4.86M
    mxPush(mxArrayPrototype);
544
4.86M
    resultArray = fxNewArrayInstance(the);
545
4.86M
    resultItem = fxLastProperty(the, resultArray);
546
11.8M
    for (captureIndex = 0; captureIndex < captureCount; captureIndex++) {
547
6.99M
      txInteger start = temporary->value.regexp.data[2 * captureIndex];
548
6.99M
      resultItem = resultItem->next = fxNewSlot(the);
549
6.99M
      if (start >= 0) {
550
6.87M
        txInteger end = temporary->value.regexp.data[(2 * captureIndex) + 1];
551
6.87M
        length = end - start;
552
6.87M
        resultItem->value.string = (txString)fxNewChunk(the, length + 1);
553
6.87M
        c_memcpy(resultItem->value.string, argument->value.string + start, length);
554
6.87M
        resultItem->value.string[length] = 0;
555
6.87M
        resultItem->kind = XS_STRING_KIND;
556
6.87M
      }
557
6.99M
      resultArray->next->value.array.length++;
558
6.99M
    }
559
4.86M
    fxCacheArray(the, resultArray);
560
4.86M
    resultItem = fxLastProperty(the, resultArray);
561
4.86M
    resultItem = resultItem->next = fxNewSlot(the);
562
4.86M
    resultItem->ID = mxID(_index);
563
4.86M
    resultItem->kind = XS_INTEGER_KIND;
564
4.86M
    resultItem->value.integer = fxCacheUTF8ToUnicodeOffset(the, argument->value.string, temporary->value.regexp.data[0]);
565
4.86M
    resultItem = resultItem->next = fxNewSlot(the);
566
4.86M
    resultItem->ID = mxID(_input);
567
4.86M
    resultItem->value.string = argument->value.string;
568
4.86M
    resultItem->kind = argument->kind;
569
4.86M
    resultItem = resultItem->next = fxNewSlot(the);
570
4.86M
    resultItem->ID = mxID(_groups);
571
4.86M
    if (namedFlag) {
572
2.11k
      resultObject = fxNewInstance(the);
573
2.11k
      resultProperty = fxLastProperty(the, resultObject);
574
6.15k
      for (nameIndex = 0; nameIndex < nameCount; nameIndex++) {
575
4.03k
        txID name = (txID)(regexp->value.regexp.code[5 + nameIndex]);
576
4.03k
        resultProperty = resultProperty->next = fxNewSlot(the);
577
4.03k
        resultProperty->ID = name;
578
4.03k
        captureIndex = regexp->value.regexp.data[(2 * captureCount) + nameIndex];
579
4.03k
        if (captureIndex >= 0) {
580
3.02k
          mxPushReference(resultArray);
581
3.02k
          mxGetIndex(captureIndex);
582
3.02k
          mxPullSlot(resultProperty);
583
3.02k
        }
584
4.03k
      }
585
2.11k
      mxPullSlot(resultItem);
586
2.11k
    }  
587
4.86M
    if (hasIndicesFlag) {
588
20.1k
      mxPush(mxArrayPrototype);
589
20.1k
      indicesArray = fxNewArrayInstance(the);
590
20.1k
      indicesItem = fxLastProperty(the, indicesArray);
591
60.3k
      for (captureIndex = 0; captureIndex < captureCount; captureIndex++) {
592
40.2k
        txInteger start = temporary->value.regexp.data[2 * captureIndex];
593
40.2k
        indicesItem = indicesItem->next = fxNewSlot(the);
594
40.2k
        if (start >= 0) {
595
37.7k
          txInteger end = temporary->value.regexp.data[(2 * captureIndex) + 1];
596
37.7k
          length = end - start;
597
37.7k
          start = fxCacheUTF8ToUnicodeOffset(the, argument->value.string, start);
598
37.7k
          end = start + fxUTF8ToUnicodeOffset(argument->value.string + start, length);
599
37.7k
          mxPushInteger(start);
600
37.7k
          mxPushInteger(end);
601
37.7k
          fxConstructArrayEntry(the, indicesItem);
602
37.7k
        }
603
40.2k
        indicesArray->next->value.array.length++;
604
40.2k
      }
605
20.1k
      fxCacheArray(the, indicesArray);
606
20.1k
      indicesItem = fxLastProperty(the, indicesArray);
607
20.1k
      indicesItem = indicesItem->next = fxNewSlot(the);
608
20.1k
      indicesItem->ID = mxID(_groups);
609
20.1k
      if (namedFlag) {
610
4
        indicesObject = fxNewInstance(the);
611
4
        indicesProperty = fxLastProperty(the, indicesObject);
612
13
        for (nameIndex = 0; nameIndex < nameCount; nameIndex++) {
613
9
          txID name = (txID)(regexp->value.regexp.code[5 + nameIndex]);
614
9
          indicesProperty = indicesProperty->next = fxNewSlot(the);
615
9
          indicesProperty->ID = name;
616
9
          captureIndex = regexp->value.regexp.data[(2 * captureCount) + nameIndex];
617
9
          if (captureIndex >= 0) {
618
6
            mxPushReference(indicesArray);
619
6
            mxGetIndex(captureIndex);
620
6
            mxPullSlot(indicesProperty);
621
6
          }
622
9
        }
623
4
        mxPullSlot(indicesItem);
624
4
      }
625
20.1k
      resultItem = resultItem->next = fxNewSlot(the);
626
20.1k
      resultItem->ID = mxID(_indices);
627
20.1k
      mxPullSlot(resultItem);
628
20.1k
    }
629
4.86M
  }
630
4.17M
  else {
631
4.17M
    if (globalFlag || stickyFlag) {
632
4.11M
      mxPushInteger(0);
633
4.11M
      mxPushSlot(mxThis);
634
4.11M
      mxSetID(mxID(_lastIndex));
635
4.11M
      mxPop();
636
4.11M
    }
637
4.17M
    mxPushNull();
638
4.17M
  }
639
9.04M
  mxPullSlot(mxResult);
640
9.04M
#endif
641
9.04M
}
642
643
void fx_RegExp_prototype_match(txMachine* the)
644
189k
{
645
189k
#if mxRegExp
646
189k
  txSlot* argument;
647
189k
  txSlot* flags;
648
189k
  fxToInstance(the, mxThis);
649
189k
  if (mxArgc == 0)
650
10
    mxPushUndefined();
651
189k
  else
652
189k
    mxPushSlot(mxArgv(0));
653
189k
  argument = the->stack;
654
189k
  fxToString(the, argument);
655
189k
  mxPushSlot(mxThis);
656
189k
  mxGetID(mxID(_flags));
657
189k
  flags = the->stack;
658
189k
  if (c_strchr(fxToString(the, flags), 'g')) {
659
122k
    txIndex count = 0;
660
122k
    txBoolean unicodeFlag = (c_strchr(fxToString(the, flags), 'u') || c_strchr(fxToString(the, flags), 'v')) ? 1 : 0;
661
122k
    mxPushInteger(0);
662
122k
    mxPushSlot(mxThis);
663
122k
    mxSetID(mxID(_lastIndex));
664
122k
    mxPop();
665
122k
    mxPush(mxArrayPrototype);
666
122k
    fxNewArrayInstance(the);
667
122k
    mxPullSlot(mxResult);
668
3.22M
    for (;;) {
669
3.22M
      fxExecuteRegExp(the, mxThis, argument);
670
3.22M
      if (the->stack->kind == XS_NULL_KIND) {
671
122k
        if (count == 0)
672
37.4k
          mxPullSlot(mxResult);
673
85.0k
        else
674
85.0k
          mxPop();
675
122k
        break;
676
122k
      }
677
3.10M
      mxGetIndex(0);
678
3.10M
            fxToString(the, the->stack);
679
3.10M
      mxPushSlot(mxResult);
680
3.10M
      mxDefineIndex(count, 0, XS_GET_ONLY);
681
3.10M
      if (c_isEmpty(the->stack->value.string)) {
682
2.19M
        mxPushSlot(mxThis);
683
2.19M
        mxGetID(mxID(_lastIndex));
684
2.19M
        fxToLength(the, the->stack);
685
2.19M
        the->stack->value.number = fxAdvanceStringIndex(the, argument->value.string, the->stack->value.number, unicodeFlag);
686
2.19M
        mxPushSlot(mxThis);
687
2.19M
        mxSetID(mxID(_lastIndex));
688
2.19M
        mxPop();
689
2.19M
      }
690
3.10M
      mxPop();
691
3.10M
      count++;
692
3.10M
            mxCheckMetering();
693
3.10M
    }
694
122k
  }
695
66.7k
  else {
696
66.7k
    fxExecuteRegExp(the, mxThis, argument);
697
66.7k
    mxPullSlot(mxResult);
698
66.7k
  }
699
189k
  mxPop();
700
189k
  mxPop();
701
189k
#endif
702
189k
}
703
704
void fx_RegExp_prototype_matchAll(txMachine* the)
705
4.85k
{
706
4.85k
#if mxRegExp
707
4.85k
  txSlot* argument;
708
4.85k
  txBoolean globalFlag = 0;
709
4.85k
  txBoolean unicodeFlag = 0;
710
4.85k
  txSlot* matcher;
711
4.85k
  txSlot* iterator;
712
4.85k
  txSlot* property;
713
  
714
4.85k
  if (!mxIsReference(mxThis))
715
8
    mxTypeError("this: not an object");
716
4.84k
  if (mxArgc == 0)
717
0
    mxPushUndefined();
718
4.84k
  else
719
4.84k
    mxPushSlot(mxArgv(0));
720
4.84k
  argument = the->stack;
721
4.84k
  fxToString(the, argument);
722
  
723
4.84k
  mxPushSlot(mxThis);
724
4.84k
  mxGetID(mxID(_constructor));
725
4.84k
  fxToSpeciesConstructor(the, &mxRegExpConstructor);
726
4.84k
  mxNew(); 
727
4.84k
  mxPushSlot(mxThis);
728
4.84k
  mxPushSlot(mxThis);
729
4.84k
  mxGetID(mxID(_flags));
730
4.84k
  if (c_strchr(fxToString(the, the->stack), 'g'))
731
4.83k
    globalFlag = 1;
732
4.84k
  if (c_strchr(fxToString(the, the->stack), 'u') || c_strchr(fxToString(the, the->stack), 'v'))
733
1
    unicodeFlag = 1;
734
4.84k
  mxRunCount(2);
735
4.84k
  matcher = the->stack;
736
  
737
4.84k
  mxPushSlot(mxThis);
738
4.84k
  mxGetID(mxID(_lastIndex));
739
4.84k
  fxToInteger(the, the->stack);
740
4.84k
  mxPushSlot(matcher);
741
4.84k
  mxSetID(mxID(_lastIndex));
742
  
743
4.84k
  mxPush(mxRegExpStringIteratorPrototype);
744
4.84k
  iterator = fxNewIteratorInstance(the, matcher, mxID(_RegExp));
745
4.84k
  property = fxLastProperty(the, iterator);
746
4.84k
  property->kind = argument->kind;
747
4.84k
  property->value = argument->value;
748
4.84k
  property = fxNextBooleanProperty(the, property, globalFlag, XS_NO_ID, XS_INTERNAL_FLAG);
749
4.84k
  property = fxNextBooleanProperty(the, property, unicodeFlag, XS_NO_ID, XS_INTERNAL_FLAG);
750
4.84k
  property = fxNextBooleanProperty(the, property, 0, XS_NO_ID, XS_INTERNAL_FLAG);
751
4.84k
  mxPullSlot(mxResult);
752
4.84k
#endif
753
4.84k
}
754
755
void fx_RegExp_prototype_matchAll_next(txMachine* the)
756
10.3k
{
757
10.3k
#if mxRegExp
758
10.3k
  txSlot* iterator = fxCheckIteratorInstance(the, mxThis, mxID(_RegExp));
759
10.3k
  txSlot* result = iterator->next;
760
10.3k
  txSlot* value = fxCheckIteratorResult(the, result);
761
10.3k
  txSlot* done = value->next;
762
10.3k
  txSlot* matcher = result->next;
763
10.3k
  txSlot* argument = matcher->next;
764
10.3k
  txSlot* global = argument->next;
765
10.3k
  txSlot* unicode = global->next;
766
10.3k
  txSlot* complete = unicode->next;
767
10.3k
  txSlot* match;
768
10.3k
  if (complete->value.boolean) {
769
1
    value->kind = XS_UNDEFINED_KIND;
770
1
    done->value.boolean = 1;
771
1
  }
772
10.3k
  else {
773
10.3k
    fxExecuteRegExp(the, matcher, argument);
774
10.3k
    match = the->stack;
775
10.3k
    if (match->kind == XS_NULL_KIND) {
776
3.95k
      value->kind = XS_UNDEFINED_KIND;
777
3.95k
      done->value.boolean = 1;
778
3.95k
            complete->value.boolean = 1;
779
3.95k
    }
780
6.35k
    else if (global->value.boolean) {
781
6.34k
      mxPushSlot(match);
782
6.34k
      mxGetIndex(0);
783
6.34k
      fxToString(the, the->stack);
784
6.34k
      if (c_isEmpty(the->stack->value.string)) {
785
3
        mxPushSlot(matcher);
786
3
        mxGetID(mxID(_lastIndex));
787
3
        fxToLength(the, the->stack);
788
3
        the->stack->value.number = fxAdvanceStringIndex(the, argument->value.string, the->stack->value.number, unicode->value.boolean);
789
3
        mxPushSlot(matcher);
790
3
        mxSetID(mxID(_lastIndex));
791
3
        mxPop();
792
3
      }
793
6.34k
      mxPop();
794
6.34k
      value->kind = match->kind;
795
6.34k
      value->value = match->value;
796
6.34k
      done->value.boolean = 0;
797
6.34k
    }
798
9
    else {
799
9
      value->kind = match->kind;
800
9
      value->value = match->value;
801
9
      done->value.boolean = 0;
802
9
      complete->value.boolean = 1;
803
9
    }
804
10.3k
    mxPop();
805
10.3k
  }
806
10.3k
  mxResult->kind = result->kind;
807
10.3k
  mxResult->value = result->value;
808
10.3k
#endif
809
10.3k
}
810
811
void fx_RegExp_prototype_replace(txMachine* the)
812
99.8k
{
813
99.8k
#if mxRegExp
814
99.8k
  txSlot* argument;
815
99.8k
  txSlot* function = C_NULL;;
816
99.8k
  txSlot* replacement = C_NULL;;
817
99.8k
  txSlot* flags;
818
99.8k
  txBoolean globalFlag = 0;
819
99.8k
  txBoolean unicodeFlag = 0;
820
99.8k
  txSlot* list;
821
99.8k
  txSlot* item;
822
99.8k
  txSize size; 
823
99.8k
  txSize utf8Size; 
824
99.8k
  txInteger former; 
825
99.8k
  txSlot* result;
826
99.8k
  txSlot* matched;
827
99.8k
  txSize matchLength; 
828
99.8k
  txInteger c, i;
829
99.8k
  txInteger position; 
830
99.8k
  fxToInstance(the, mxThis);
831
99.8k
  if (mxArgc <= 0)
832
10
    mxPushUndefined();
833
99.8k
  else
834
99.8k
    mxPushSlot(mxArgv(0));
835
99.8k
  argument = the->stack;
836
99.8k
  fxToString(the, argument);
837
99.8k
  if (mxArgc <= 1)
838
50
    mxPushUndefined();
839
99.8k
  else
840
99.8k
    mxPushSlot(mxArgv(1));
841
99.8k
  if (mxIsReference(the->stack) && mxIsFunction(the->stack->value.reference))
842
29.7k
    function = the->stack;
843
70.1k
  else {   
844
70.1k
    replacement = the->stack;
845
70.1k
    fxToString(the, replacement);
846
70.1k
  }
847
99.8k
  mxPushSlot(mxThis);
848
99.8k
  mxGetID(mxID(_flags));
849
99.8k
  flags = the->stack;
850
99.8k
  if (c_strchr(fxToString(the, flags), 'g'))
851
99.3k
    globalFlag = 1;
852
99.8k
  if (globalFlag) {
853
99.3k
    if (c_strchr(fxToString(the, flags), 'u') || c_strchr(fxToString(the, flags), 'v'))
854
12.9k
      unicodeFlag = 1;
855
99.3k
    mxPushInteger(0);
856
99.3k
    mxPushSlot(mxThis);
857
99.3k
    mxSetID(mxID(_lastIndex));
858
99.3k
    mxPop();
859
99.3k
  }
860
99.8k
  list = item = fxNewInstance(the);
861
99.8k
  mxPushSlot(list);
862
99.8k
  size = fxCacheUnicodeLength(the, argument->value.string);
863
99.8k
  utf8Size = fxCacheUTF8Length(the, argument->value.string);
864
99.8k
  former = 0;
865
2.29M
  for (;;) {
866
2.29M
    fxExecuteRegExp(the, mxThis, argument);
867
2.29M
    if (the->stack->kind == XS_NULL_KIND) {
868
99.4k
      mxPop();
869
99.4k
      break;
870
99.4k
    }
871
2.19M
    result = the->stack;
872
    
873
2.19M
    mxPushSlot(result);
874
2.19M
    mxGetID(mxID(_index));
875
2.19M
    position = fxToInteger(the, the->stack);
876
2.19M
    mxPop();
877
2.19M
    if (position < 0) position = 0;
878
2.14M
    else if (position > size) position = size;
879
    
880
2.19M
    if (former < position) {
881
1.56M
      item = item->next = fxNewSlot(the);
882
1.56M
      fx_RegExp_prototype_split_aux(the, argument, former, position, item);
883
1.56M
    }
884
885
2.19M
        if (former <= position) {
886
1.99M
            mxPushSlot(result);
887
1.99M
            mxGetIndex(0);
888
1.99M
            fxToString(the, the->stack);
889
1.99M
            matched = the->stack;
890
1.99M
            matchLength = fxUnicodeLength(matched->value.string, C_NULL);
891
892
1.99M
            mxPushSlot(result);
893
1.99M
            mxGetID(mxID(_length));
894
1.99M
            c = fxToInteger(the, the->stack);
895
1.99M
      mxPop();
896
897
1.99M
            if (function) {
898
143k
                mxPushUndefined();
899
143k
                mxPushSlot(function);
900
143k
              mxCall();
901
143k
            }
902
1.99M
            mxPushSlot(matched);
903
4.07M
            for (i = 1; i < c; i++) {
904
2.07M
                mxPushSlot(result);
905
2.07M
                mxGetIndex(i);
906
2.07M
                if (the->stack->kind != XS_UNDEFINED_KIND)
907
1.97M
                  fxToString(the, the->stack);
908
2.07M
            }
909
1.99M
            if (function) {
910
143k
                mxPushInteger(position);
911
143k
        mxPushSlot(argument);
912
143k
        mxPushSlot(result);
913
143k
        mxGetID(mxID(_groups));
914
143k
        if (mxIsUndefined(the->stack)) {
915
143k
          mxPop();
916
143k
          mxRunCount(3 + i - 1);
917
143k
        }
918
25
        else {
919
25
          mxRunCount(4 + i - 1);
920
25
        }
921
143k
                fxToString(the, the->stack);
922
143k
                item = item->next = fxNewSlot(the);
923
143k
                mxPullSlot(item);
924
143k
            }
925
1.85M
            else {
926
1.85M
        mxPushSlot(result);
927
1.85M
        mxGetID(mxID(_groups));
928
1.85M
        if (!mxIsUndefined(the->stack))
929
1.12k
          fxToInstance(the, the->stack);
930
1.85M
        fxPushSubstitutionString(the, argument, utf8Size, fxCacheUnicodeToUTF8Offset(the, argument->value.string, position), matched, mxStringLength(matched->value.string), i - 1, the->stack + 1, the->stack, replacement);
931
1.85M
                item = item->next = fxNewSlot(the);
932
1.85M
                mxPullSlot(item);
933
1.85M
                the->stack += 1 + i;      
934
1.85M
            }
935
1.99M
            former = position + matchLength;
936
            
937
1.99M
            mxPop(); // matched
938
1.99M
        }
939
201k
        else
940
201k
            matchLength = 0;
941
            
942
2.19M
    if (!globalFlag)
943
394
      break;
944
      
945
2.19M
    if (0 == matchLength) {
946
1.68M
      mxPushSlot(mxThis);
947
1.68M
      mxGetID(mxID(_lastIndex));
948
1.68M
      fxToLength(the, the->stack);
949
1.68M
      the->stack->value.number = fxAdvanceStringIndex(the, argument->value.string, the->stack->value.number, unicodeFlag);
950
1.68M
      mxPushSlot(mxThis);
951
1.68M
      mxSetID(mxID(_lastIndex));
952
1.68M
      mxPop();
953
1.68M
    }
954
2.19M
    mxPop();
955
2.19M
         mxCheckMetering();
956
2.19M
  }
957
99.8k
  if (former < size) {
958
50.6k
    item = item->next = fxNewSlot(the);
959
50.6k
    fx_RegExp_prototype_split_aux(the, argument, former, size, item);
960
50.6k
  }
961
99.8k
  size = 0;
962
99.8k
  item = list->next;
963
3.70M
  while (item) {
964
3.60M
    item->value.key.sum = mxStringLength(item->value.string);
965
3.60M
        size = fxAddChunkSizes(the, size, item->value.key.sum);
966
3.60M
    item = item->next;
967
3.60M
  }
968
99.8k
    size = fxAddChunkSizes(the, size, 1);
969
99.8k
  mxResult->value.string = (txString)fxNewChunk(the, size);
970
99.8k
  size = 0;
971
99.8k
  item = list->next;
972
3.70M
  while (item) {
973
3.60M
    c_memcpy(mxResult->value.string + size, item->value.string, item->value.key.sum);
974
3.60M
    size += item->value.key.sum;
975
3.60M
    item = item->next;
976
3.60M
  }
977
99.8k
  mxResult->value.string[size] = 0;
978
99.8k
  mxResult->kind = XS_STRING_KIND;
979
99.8k
  mxPop();
980
99.8k
  mxPop();
981
99.8k
  mxPop();
982
99.8k
#endif
983
99.8k
}
984
985
void fx_RegExp_prototype_search(txMachine* the)
986
76
{
987
76
#if mxRegExp
988
76
  txSlot* argument;
989
76
  txSlot* lastIndex;
990
76
  fxToInstance(the, mxThis);
991
76
  if (mxArgc == 0)
992
23
    mxPushUndefined();
993
53
  else
994
53
    mxPushSlot(mxArgv(0));
995
76
  argument = the->stack;
996
76
  fxToString(the, argument);
997
76
  mxPushSlot(mxThis);
998
76
  mxGetID(mxID(_lastIndex));
999
76
  lastIndex = the->stack;
1000
  
1001
76
  mxPushInteger(0);
1002
76
  if (!fxIsSameValue(the, the->stack, lastIndex, 0)) {
1003
24
    mxPushInteger(0);
1004
24
    mxPushSlot(mxThis);
1005
24
    mxSetID(mxID(_lastIndex));
1006
24
    mxPop();
1007
24
  }
1008
76
  mxPop();
1009
  
1010
76
  fxExecuteRegExp(the, mxThis, argument);
1011
76
  if (the->stack->kind == XS_NULL_KIND) {
1012
25
    the->stack->kind = XS_INTEGER_KIND;
1013
25
    the->stack->value.integer = -1;
1014
25
  }
1015
51
  else
1016
51
    mxGetID(mxID(_index));
1017
76
  mxPullSlot(mxResult);
1018
  
1019
76
  mxPushSlot(mxThis);
1020
76
  mxGetID(mxID(_lastIndex));
1021
76
  if (!fxIsSameValue(the, the->stack, lastIndex, 0)) {
1022
12
    mxPushSlot(lastIndex);
1023
12
    mxPushSlot(mxThis);
1024
12
    mxSetID(mxID(_lastIndex));
1025
12
    mxPop();
1026
12
  }
1027
76
  mxPop();
1028
  
1029
76
  mxPop();
1030
76
#endif
1031
76
}
1032
1033
void fx_RegExp_prototype_split(txMachine* the)
1034
48.8k
{
1035
48.8k
#if mxRegExp
1036
48.8k
  txSlot* argument;
1037
48.8k
  txIndex limit;
1038
48.8k
  txString flags;
1039
48.8k
  txBoolean unicodeFlag = 0;
1040
48.8k
  txSlot* splitter;
1041
48.8k
  txSlot* array;
1042
48.8k
  txSlot* item;
1043
48.8k
  txInteger size, p, q, e, c, i;
1044
  
1045
48.8k
  if (!mxIsReference(mxThis))
1046
13
    mxTypeError("this: not an object");
1047
48.8k
  if (mxArgc == 0)
1048
14
    mxPushUndefined();
1049
48.8k
  else
1050
48.8k
    mxPushSlot(mxArgv(0));
1051
48.8k
  argument = the->stack;
1052
48.8k
  fxToString(the, argument);
1053
48.8k
  limit = ((mxArgc > 1) && (!mxIsUndefined(mxArgv(1)))) ? fxToUnsigned(the, mxArgv(1)) : 0xFFFFFFFF;
1054
  
1055
48.8k
  mxPushSlot(mxThis);
1056
48.8k
  mxGetID(mxID(_constructor));
1057
48.8k
  fxToSpeciesConstructor(the, &mxRegExpConstructor);
1058
48.8k
  mxNew(); 
1059
48.8k
  mxPushSlot(mxThis);
1060
48.8k
  mxPushSlot(mxThis);
1061
48.8k
  mxGetID(mxID(_flags));
1062
48.8k
  flags = fxToString(the, the->stack);
1063
48.8k
  if (c_strchr(flags, 'u') || c_strchr(flags, 'v'))
1064
45.0k
    unicodeFlag = 1;
1065
48.8k
  if (!c_strchr(flags, 'y')) {
1066
38.5k
    mxPushStringC("y");
1067
38.5k
    fxConcatString(the, the->stack + 1, the->stack);
1068
38.5k
    mxPop();
1069
38.5k
  }
1070
48.8k
  mxRunCount(2);
1071
48.8k
  splitter = the->stack;
1072
  
1073
48.8k
  mxPush(mxArrayPrototype);
1074
48.8k
  array = fxNewArrayInstance(the);
1075
48.8k
  mxPullSlot(mxResult);
1076
48.8k
  item = fxLastProperty(the, array);
1077
48.8k
  if (!limit)
1078
229
    goto bail;
1079
48.6k
  size = fxUnicodeLength(argument->value.string, C_NULL);
1080
48.6k
  if (size == 0) {
1081
1.59k
    fxExecuteRegExp(the, splitter, argument);
1082
1.59k
    if (the->stack->kind == XS_NULL_KIND) {
1083
878
      item = item->next = fxNewSlot(the);
1084
878
      item->value.string = mxEmptyString.value.string;
1085
878
      item->kind = mxEmptyString.kind;
1086
878
      array->next->value.array.length++;
1087
878
    }
1088
1.59k
    mxPop();
1089
1.59k
    goto bail;
1090
1.59k
  }
1091
47.0k
  p = q = 0;
1092
3.95M
  while (q < size) {
1093
3.90M
    mxPushInteger(q);
1094
3.90M
    mxPushSlot(splitter);
1095
3.90M
    mxSetID(mxID(_lastIndex));
1096
3.90M
    mxPop();
1097
3.90M
    fxExecuteRegExp(the, splitter, argument);
1098
3.90M
    if (the->stack->kind == XS_NULL_KIND) {
1099
3.85M
      q = (txInteger)fxAdvanceStringIndex(the, argument->value.string, q, unicodeFlag);
1100
3.85M
    }
1101
50.9k
    else {
1102
50.9k
      mxPushSlot(splitter);
1103
50.9k
      mxGetID(mxID(_lastIndex));
1104
50.9k
      e = fxToInteger(the, the->stack);
1105
50.9k
      mxPop();
1106
50.9k
      if (e == p) {
1107
9.61k
        q = (txInteger)fxAdvanceStringIndex(the, argument->value.string, q, unicodeFlag);
1108
9.61k
      }
1109
41.3k
      else {
1110
41.3k
        txSlot* result = the->stack;
1111
41.3k
        item = item->next = fxNewSlot(the);
1112
41.3k
        fx_RegExp_prototype_split_aux(the, argument, p, q, item);
1113
41.3k
        array->next->value.array.length++;
1114
41.3k
        if (array->next->value.array.length == limit)
1115
13
          goto bail;
1116
41.2k
        p = e;
1117
41.2k
        mxPushSlot(result);
1118
41.2k
        mxGetID(mxID(_length));
1119
41.2k
        c = fxToInteger(the, the->stack);
1120
41.2k
        mxPop();
1121
41.2k
        c--; if (c < 0) c = 0;
1122
41.2k
        i = 1;
1123
80.5k
        while (i <= c) {
1124
39.2k
          mxPushSlot(result);
1125
39.2k
          mxGetIndex(i);
1126
39.2k
          item = item->next = fxNewSlot(the);
1127
39.2k
          mxPullSlot(item);
1128
39.2k
          array->next->value.array.length++;
1129
39.2k
          if (array->next->value.array.length == limit)
1130
1
            goto bail;
1131
39.2k
          i++;
1132
39.2k
        }
1133
41.2k
        q = p;
1134
41.2k
      }
1135
50.9k
    }
1136
3.90M
    mxPop();
1137
3.90M
    mxCheckMetering();
1138
3.90M
  }
1139
  //if (p < 0)
1140
  //  p = 0;
1141
47.0k
  item = item->next = fxNewSlot(the);
1142
47.0k
  fx_RegExp_prototype_split_aux(the, argument, p, size, item);
1143
47.0k
  array->next->value.array.length++;
1144
48.7k
bail:
1145
48.7k
  fxCacheArray(the, array);
1146
48.7k
  mxPop();
1147
48.7k
  mxPop();
1148
48.7k
  mxPop();
1149
48.7k
#endif
1150
48.7k
}
1151
1152
void fx_RegExp_prototype_split_aux(txMachine* the, txSlot* string, txIndex start, txIndex stop, txSlot* item)
1153
1.70M
{
1154
1.70M
#if mxRegExp
1155
1.70M
  txInteger offset = fxCacheUnicodeToUTF8Offset(the, string->value.string, start);
1156
1.70M
  txInteger length = fxUnicodeToUTF8Offset(string->value.string + offset, stop - start);
1157
1.70M
  if ((offset >= 0) && (length > 0)) {
1158
1.68M
    item->value.string = (txString)fxNewChunk(the, length + 1);
1159
1.68M
    c_memcpy(item->value.string, string->value.string + offset, length);
1160
1.68M
    item->value.string[length] = 0;
1161
1.68M
    item->kind = XS_STRING_KIND;
1162
1.68M
  }
1163
24.8k
  else {
1164
24.8k
    item->value.string = mxEmptyString.value.string;
1165
24.8k
    item->kind = mxEmptyString.kind;
1166
24.8k
  }
1167
1.70M
#endif
1168
1.70M
}
1169
1170
void fx_RegExp_prototype_test(txMachine* the)
1171
383
{
1172
383
#if mxRegExp
1173
383
  fxToInstance(the, mxThis);
1174
383
  if (mxArgc > 0)
1175
382
    mxPushSlot(mxArgv(0));
1176
1
  else
1177
1
    mxPushUndefined();
1178
383
  fxToString(the, the->stack);
1179
383
  fxExecuteRegExp(the, mxThis, the->stack);
1180
383
  mxResult->value.boolean = (the->stack->kind != XS_NULL_KIND) ? 1 : 0;
1181
383
  mxResult->kind = XS_BOOLEAN_KIND;
1182
383
  mxPop();
1183
383
#endif
1184
383
}
1185
1186
void fx_RegExp_prototype_toString(txMachine* the)
1187
247k
{
1188
247k
#if mxRegExp
1189
247k
  fxToInstance(the, mxThis);
1190
247k
  fxStringX(the, mxResult, "/");
1191
247k
  mxPushSlot(mxThis);
1192
247k
  mxGetID(mxID(_source));
1193
247k
  fxToString(the, the->stack);
1194
247k
  fxConcatString(the, mxResult, the->stack);
1195
247k
  mxPop();
1196
247k
  fxConcatStringC(the, mxResult, "/");
1197
247k
  mxPushSlot(mxThis);
1198
247k
  mxGetID(mxID(_flags));
1199
247k
  fxToString(the, the->stack);
1200
247k
  fxConcatString(the, mxResult, the->stack);
1201
247k
  mxPop();
1202
247k
#endif
1203
247k
}