@scriptc/cli-darwin-x64 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/THIRD_PARTY_NOTICES +1 -1
- package/dist/bin/scriptc +0 -0
- package/dist/bin/scriptc.json +1 -1
- package/dist/lib/declarations/scriptc-node-fallback.d.ts +915 -215
- package/dist/lib/declarations/scriptc-overrides.d.ts +5 -1
- package/dist/lib/declarations/scriptc.d.ts +22 -2
- package/dist/lib/llvm/bin/scriptc-llvm-codegen +0 -0
- package/dist/lib/llvm/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/runtime-pack.json +215 -215
- package/dist/lib/runtime-sources/package.json +1 -1
- package/dist/lib/runtime-sources/src/scr_array.c +317 -40
- package/dist/lib/runtime-sources/src/scr_async.test.ts +16 -6
- package/dist/lib/runtime-sources/src/scr_bigint.c +15 -0
- package/dist/lib/runtime-sources/src/scr_bytes.c +437 -216
- package/dist/lib/runtime-sources/src/scr_bytes.test.c +85 -0
- package/dist/lib/runtime-sources/src/scr_bytes_io.c +0 -34
- package/dist/lib/runtime-sources/src/scr_copying.c +12 -2
- package/dist/lib/runtime-sources/src/scr_cycle.c +84 -60
- package/dist/lib/runtime-sources/src/scr_json.c +494 -161
- package/dist/lib/runtime-sources/src/scr_json.test.c +323 -1
- package/dist/lib/runtime-sources/src/scr_json.test.ts +58 -25
- package/dist/lib/runtime-sources/src/scr_key.h +68 -0
- package/dist/lib/runtime-sources/src/scr_lib.c +177 -89
- package/dist/lib/runtime-sources/src/scr_map.c +268 -96
- package/dist/lib/runtime-sources/src/scr_number.c +2 -4
- package/dist/lib/runtime-sources/src/scr_numeric.h +25 -0
- package/dist/lib/runtime-sources/src/scr_numeric.test.c +37 -0
- package/dist/lib/runtime-sources/src/scr_numeric.test.ts +33 -0
- package/dist/lib/runtime-sources/src/scr_regex.c +255 -145
- package/dist/lib/runtime-sources/src/scr_runtime.h +76 -19
- package/dist/lib/runtime-sources/src/scr_string.c +184 -42
- package/package.json +1 -1
|
@@ -13,10 +13,9 @@
|
|
|
13
13
|
* lre_compile rejects aborts with a clear
|
|
14
14
|
* message (Node throws SyntaxError at parse time — documented divergence;
|
|
15
15
|
* rare, since tsc's parser has already syntax-checked the literal).
|
|
16
|
-
* -
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* like Node. Correctness-first: the conversion is O(n) per call.
|
|
16
|
+
* - ASCII subjects borrow their existing bytes; other subjects use a
|
|
17
|
+
* per-call UTF-16 conversion. Both engine representations report UTF-16
|
|
18
|
+
* code-unit indices, matching .length/slice/charCodeAt.
|
|
20
19
|
* - Match loops mirror quickjs.c's own (JS_RegExpDelete /
|
|
21
20
|
* js_regexp_Symbol_replace): capture buffers are sized by
|
|
22
21
|
* lre_get_alloc_count (NOT capture_count*2 — the executor writes
|
|
@@ -304,6 +303,8 @@ ScrStr *scr_regex_to_string(ScrRegex *re) {
|
|
|
304
303
|
/* Subject as freshly-malloc'd UTF-16 code units (strings are well-formed
|
|
305
304
|
* UTF-8, so no validation). Unit count ≤ byte count. */
|
|
306
305
|
static uint16_t *scr_to_utf16(const ScrStr *s, int *plen) {
|
|
306
|
+
if (s->len > (size_t)INT32_MAX - 1 || s->len > SIZE_MAX / sizeof(uint16_t))
|
|
307
|
+
scr_regex_oom();
|
|
307
308
|
uint16_t *u = malloc((s->len ? s->len : 1) * sizeof(uint16_t));
|
|
308
309
|
if (!u) scr_regex_oom();
|
|
309
310
|
int n = 0;
|
|
@@ -339,53 +340,98 @@ static uint16_t *scr_to_utf16(const ScrStr *s, int *plen) {
|
|
|
339
340
|
return u;
|
|
340
341
|
}
|
|
341
342
|
|
|
342
|
-
/*
|
|
343
|
-
*
|
|
344
|
-
|
|
345
|
-
*
|
|
343
|
+
/* Decode one UTF-16 code point. A boundary that splits a surrogate pair
|
|
344
|
+
* produces U+FFFD, as in the runtime's string slicing contract. */
|
|
345
|
+
static uint32_t scr_regex_codepoint(const uint16_t *units, int *index, int end) {
|
|
346
|
+
uint32_t cp = units[(*index)++];
|
|
347
|
+
if (cp >= 0xD800 && cp < 0xDC00 && *index < end &&
|
|
348
|
+
units[*index] >= 0xDC00 && units[*index] < 0xE000)
|
|
349
|
+
return 0x10000 + ((cp - 0xD800) << 10) + (units[(*index)++] - 0xDC00);
|
|
350
|
+
return cp >= 0xD800 && cp < 0xE000 ? 0xFFFD : cp;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
static size_t scr_regex_encode(char *out, uint32_t cp) {
|
|
354
|
+
if (cp < 0x80) {
|
|
355
|
+
out[0] = (char)cp;
|
|
356
|
+
return 1;
|
|
357
|
+
}
|
|
358
|
+
if (cp < 0x800) {
|
|
359
|
+
out[0] = (char)(0xC0 | (cp >> 6));
|
|
360
|
+
out[1] = (char)(0x80 | (cp & 0x3F));
|
|
361
|
+
return 2;
|
|
362
|
+
}
|
|
363
|
+
if (cp < 0x10000) {
|
|
364
|
+
out[0] = (char)(0xE0 | (cp >> 12));
|
|
365
|
+
out[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
|
|
366
|
+
out[2] = (char)(0x80 | (cp & 0x3F));
|
|
367
|
+
return 3;
|
|
368
|
+
}
|
|
369
|
+
out[0] = (char)(0xF0 | (cp >> 18));
|
|
370
|
+
out[1] = (char)(0x80 | ((cp >> 12) & 0x3F));
|
|
371
|
+
out[2] = (char)(0x80 | ((cp >> 6) & 0x3F));
|
|
372
|
+
out[3] = (char)(0x80 | (cp & 0x3F));
|
|
373
|
+
return 4;
|
|
374
|
+
}
|
|
375
|
+
|
|
346
376
|
static void scr_jb_put_utf16(ScrJsonBuf *b, const uint16_t *u, int start, int end) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
} else if (cp >= 0xD800 && cp < 0xE000) {
|
|
354
|
-
cp = 0xFFFD;
|
|
355
|
-
}
|
|
356
|
-
if (cp < 0x80) {
|
|
357
|
-
scr_jb_putc(b, (char)cp);
|
|
358
|
-
} else if (cp < 0x800) {
|
|
359
|
-
scr_jb_putc(b, (char)(0xC0 | (cp >> 6)));
|
|
360
|
-
scr_jb_putc(b, (char)(0x80 | (cp & 0x3F)));
|
|
361
|
-
} else if (cp < 0x10000) {
|
|
362
|
-
scr_jb_putc(b, (char)(0xE0 | (cp >> 12)));
|
|
363
|
-
scr_jb_putc(b, (char)(0x80 | ((cp >> 6) & 0x3F)));
|
|
364
|
-
scr_jb_putc(b, (char)(0x80 | (cp & 0x3F)));
|
|
365
|
-
} else {
|
|
366
|
-
scr_jb_putc(b, (char)(0xF0 | (cp >> 18)));
|
|
367
|
-
scr_jb_putc(b, (char)(0x80 | ((cp >> 12) & 0x3F)));
|
|
368
|
-
scr_jb_putc(b, (char)(0x80 | ((cp >> 6) & 0x3F)));
|
|
369
|
-
scr_jb_putc(b, (char)(0x80 | (cp & 0x3F)));
|
|
377
|
+
char bytes[256];
|
|
378
|
+
size_t used = 0;
|
|
379
|
+
for (int i = start; i < end;) {
|
|
380
|
+
if (used > sizeof bytes - 4) {
|
|
381
|
+
scr_jb_write(b, bytes, used);
|
|
382
|
+
used = 0;
|
|
370
383
|
}
|
|
384
|
+
used += scr_regex_encode(bytes + used, scr_regex_codepoint(u, &i, end));
|
|
371
385
|
}
|
|
386
|
+
scr_jb_write(b, bytes, used);
|
|
372
387
|
}
|
|
373
388
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
389
|
+
/* Matching owns only the converted subject and oversized register buffer.
|
|
390
|
+
* The caller keeps the original immutable string alive. ASCII bytes are
|
|
391
|
+
* already the engine's one-byte representation, even under /u or /i. */
|
|
392
|
+
typedef struct ScrRegexInput {
|
|
393
|
+
const uint8_t *data;
|
|
394
|
+
uint16_t *utf16;
|
|
395
|
+
int len;
|
|
396
|
+
int wide;
|
|
397
|
+
uint8_t **capture;
|
|
398
|
+
uint8_t *registers[32];
|
|
399
|
+
} ScrRegexInput;
|
|
400
|
+
|
|
401
|
+
static bool scr_text_ascii(const ScrStr *s) {
|
|
402
|
+
size_t i = 0;
|
|
403
|
+
for (; s->len - i >= sizeof(uint64_t); i += sizeof(uint64_t)) {
|
|
404
|
+
uint64_t word;
|
|
405
|
+
memcpy(&word, s->data + i, sizeof word);
|
|
406
|
+
if (word & UINT64_C(0x8080808080808080)) return false;
|
|
407
|
+
}
|
|
408
|
+
for (; i < s->len; i++) {
|
|
409
|
+
if ((unsigned char)s->data[i] >= 0x80) return false;
|
|
410
|
+
}
|
|
411
|
+
return true;
|
|
379
412
|
}
|
|
380
413
|
|
|
381
|
-
|
|
414
|
+
static void scr_regex_input_init(ScrRegexInput *input, const uint8_t *bc,
|
|
415
|
+
const ScrStr *s) {
|
|
416
|
+
if (s->len > (size_t)INT32_MAX - 1) scr_regex_oom();
|
|
417
|
+
input->wide = !scr_text_ascii(s);
|
|
418
|
+
input->utf16 = input->wide ? scr_to_utf16(s, &input->len) : NULL;
|
|
419
|
+
input->data = input->wide ? (const uint8_t *)input->utf16 : (const uint8_t *)s->data;
|
|
420
|
+
if (!input->wide) input->len = (int)s->len;
|
|
421
|
+
/* The executor writes temporary registers beyond the capture pairs. */
|
|
422
|
+
int count = lre_get_alloc_count(bc);
|
|
423
|
+
input->capture = count <= 32 ? input->registers : malloc((size_t)count * sizeof(uint8_t *));
|
|
424
|
+
if (!input->capture) scr_regex_oom();
|
|
425
|
+
}
|
|
382
426
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
427
|
+
static void scr_regex_input_dispose(ScrRegexInput *input) {
|
|
428
|
+
if (input->capture != input->registers) free(input->capture);
|
|
429
|
+
free(input->utf16);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
static int scr_exec(ScrRegexInput *input, const uint8_t *bc, int index) {
|
|
433
|
+
int rc = lre_exec(input->capture, bc, input->data, index, input->len,
|
|
434
|
+
input->wide, lre_opaque());
|
|
389
435
|
if (rc < 0) {
|
|
390
436
|
fflush(stdout);
|
|
391
437
|
scr_trap("scriptc: regular expression execution failed\n");
|
|
@@ -393,24 +439,43 @@ static int scr_exec(uint8_t **capture, const uint8_t *bc, const uint16_t *u,
|
|
|
393
439
|
return rc;
|
|
394
440
|
}
|
|
395
441
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
if (
|
|
403
|
-
|
|
442
|
+
static int scr_capture_index(const ScrRegexInput *input, const uint8_t *capture) {
|
|
443
|
+
return (int)((capture - input->data) >> input->wide);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
static void scr_regex_put_span(ScrJsonBuf *b, const ScrRegexInput *input,
|
|
447
|
+
int start, int end) {
|
|
448
|
+
if (input->wide) scr_jb_put_utf16(b, input->utf16, start, end);
|
|
449
|
+
else scr_jb_write(b, (const char *)input->data + start, (size_t)(end - start));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
static ScrStr *scr_regex_span(const ScrRegexInput *input, int start, int end) {
|
|
453
|
+
if (!input->wide)
|
|
454
|
+
return scr_str_new((const char *)input->data + start, (size_t)(end - start));
|
|
455
|
+
/* Captures have a known span: allocate its exact UTF-8 length instead
|
|
456
|
+
* of inheriting a general builder's size hint from an earlier document. */
|
|
457
|
+
size_t bytes = 0;
|
|
458
|
+
for (int i = start; i < end;) {
|
|
459
|
+
uint32_t cp = scr_regex_codepoint(input->utf16, &i, end);
|
|
460
|
+
size_t width = cp < 0x80 ? 1 : cp < 0x800 ? 2 : cp < 0x10000 ? 3 : 4;
|
|
461
|
+
if (width > SIZE_MAX - sizeof(ScrStr) - 1 - bytes) scr_regex_oom();
|
|
462
|
+
bytes += width;
|
|
463
|
+
}
|
|
464
|
+
ScrStr *out = scr_str_alloc_raw(bytes, bytes);
|
|
465
|
+
size_t offset = 0;
|
|
466
|
+
for (int i = start; i < end;)
|
|
467
|
+
offset += scr_regex_encode(out->data + offset, scr_regex_codepoint(input->utf16, &i, end));
|
|
468
|
+
out->data[bytes] = '\0';
|
|
469
|
+
return out;
|
|
404
470
|
}
|
|
405
471
|
|
|
406
472
|
/* ECMA-262 AdvanceStringIndex: past a whole surrogate pair under /u, one
|
|
407
|
-
* code unit otherwise
|
|
408
|
-
*
|
|
409
|
-
|
|
410
|
-
if (unicode && i + 1 < len &&
|
|
411
|
-
u[i + 1] >= 0xDC00 && u[i + 1] < 0xE000)
|
|
473
|
+
* code unit otherwise. ASCII cannot contain a surrogate pair. */
|
|
474
|
+
static int scr_advance(const ScrRegexInput *input, int i, bool unicode) {
|
|
475
|
+
const uint16_t *u = input->utf16;
|
|
476
|
+
if (unicode && input->wide && i + 1 < input->len &&
|
|
477
|
+
u[i] >= 0xD800 && u[i] < 0xDC00 && u[i + 1] >= 0xDC00 && u[i + 1] < 0xE000)
|
|
412
478
|
return i + 2;
|
|
413
|
-
}
|
|
414
479
|
return i + 1;
|
|
415
480
|
}
|
|
416
481
|
|
|
@@ -420,13 +485,6 @@ void scr_regex_reset_last_index(ScrRegex *re, double index) {
|
|
|
420
485
|
re->last_index = index;
|
|
421
486
|
}
|
|
422
487
|
|
|
423
|
-
bool scr_regex_test(ScrRegex *re, ScrStr *s) {
|
|
424
|
-
ScrArr *result = scr_regex_exec(s, re);
|
|
425
|
-
bool matched = result != NULL;
|
|
426
|
-
scr_arr_release(result);
|
|
427
|
-
return matched;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
488
|
static int scr_regex_start(ScrRegex *re, int len) {
|
|
431
489
|
double index = re->last_index;
|
|
432
490
|
if (isnan(index) || index <= 0) return 0;
|
|
@@ -434,6 +492,20 @@ static int scr_regex_start(ScrRegex *re, int len) {
|
|
|
434
492
|
return (int)floor(index);
|
|
435
493
|
}
|
|
436
494
|
|
|
495
|
+
/* A predicate needs only boundaries; it never materializes result strings. */
|
|
496
|
+
bool scr_regex_test(ScrRegex *re, ScrStr *s) {
|
|
497
|
+
uint8_t *bc = scr_regex_bc(re);
|
|
498
|
+
ScrRegexInput input;
|
|
499
|
+
scr_regex_input_init(&input, bc, s);
|
|
500
|
+
bool stateful = (lre_get_flags(bc) & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) != 0;
|
|
501
|
+
int pos = stateful ? scr_regex_start(re, input.len) : 0;
|
|
502
|
+
int rc = pos < 0 ? 0 : scr_exec(&input, bc, pos);
|
|
503
|
+
if (stateful) re->last_index = rc == 1
|
|
504
|
+
? (double)scr_capture_index(&input, input.capture[1]) : 0;
|
|
505
|
+
scr_regex_input_dispose(&input);
|
|
506
|
+
return rc == 1;
|
|
507
|
+
}
|
|
508
|
+
|
|
437
509
|
/* ── match ────────────────────────────────────────────────────────────── */
|
|
438
510
|
|
|
439
511
|
/* re.exec(s): a fresh string[] of [whole match, ...captures], or NULL
|
|
@@ -444,20 +516,20 @@ static int scr_regex_start(ScrRegex *re, int len) {
|
|
|
444
516
|
ScrArr *scr_regex_exec(ScrStr *s, ScrRegex *re) {
|
|
445
517
|
uint8_t *bc = scr_regex_bc(re);
|
|
446
518
|
bool stateful = (lre_get_flags(bc) & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) != 0;
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
519
|
+
ScrRegexInput input;
|
|
520
|
+
scr_regex_input_init(&input, bc, s);
|
|
521
|
+
int len = input.len;
|
|
522
|
+
uint8_t **capture = input.capture;
|
|
450
523
|
int pos = stateful ? scr_regex_start(re, len) : 0;
|
|
451
|
-
int rc = pos < 0 ? 0 : scr_exec(
|
|
524
|
+
int rc = pos < 0 ? 0 : scr_exec(&input, bc, pos);
|
|
452
525
|
if (stateful) re->last_index = rc == 1
|
|
453
|
-
? (double)(
|
|
526
|
+
? (double)scr_capture_index(&input, capture[1]) : 0;
|
|
454
527
|
ScrArr *out = NULL;
|
|
455
528
|
if (rc == 1) {
|
|
456
|
-
const uint8_t *ubase = (const uint8_t *)u;
|
|
457
529
|
int count = lre_get_capture_count(bc);
|
|
458
530
|
out = scr_arr_new(SCR_ELEM_STR, (size_t)count);
|
|
459
531
|
out->metadata = scr_dyn_new_obj();
|
|
460
|
-
scr_dyn_obj_set(out->metadata, "index", 5, scr_dyn_new_num((double)(
|
|
532
|
+
scr_dyn_obj_set(out->metadata, "index", 5, scr_dyn_new_num((double)scr_capture_index(&input, capture[0])));
|
|
461
533
|
scr_dyn_obj_set(out->metadata, "input", 5, scr_dyn_new_str(s));
|
|
462
534
|
for (int k = 0; k < count; k++) {
|
|
463
535
|
const uint8_t *cs = capture[2 * k], *ce = capture[2 * k + 1];
|
|
@@ -465,12 +537,11 @@ ScrArr *scr_regex_exec(ScrStr *s, ScrRegex *re) {
|
|
|
465
537
|
scr_arr_set_undefined(out, (double)out->len);
|
|
466
538
|
} else {
|
|
467
539
|
scr_arr_push_ref(
|
|
468
|
-
out,
|
|
540
|
+
out, scr_regex_span(&input, scr_capture_index(&input, cs), scr_capture_index(&input, ce)));
|
|
469
541
|
}
|
|
470
542
|
}
|
|
471
543
|
}
|
|
472
|
-
|
|
473
|
-
free(u);
|
|
544
|
+
scr_regex_input_dispose(&input);
|
|
474
545
|
return out; /* +1, or NULL (no match) */
|
|
475
546
|
}
|
|
476
547
|
|
|
@@ -485,22 +556,21 @@ ScrArr *scr_regex_match(ScrStr *s, ScrRegex *re) {
|
|
|
485
556
|
if (!(flags & LRE_FLAG_GLOBAL)) return scr_regex_exec(s, re);
|
|
486
557
|
re->last_index = 0;
|
|
487
558
|
bool unicode = (flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
559
|
+
ScrRegexInput input;
|
|
560
|
+
scr_regex_input_init(&input, bc, s);
|
|
561
|
+
int len = input.len;
|
|
562
|
+
uint8_t **capture = input.capture;
|
|
492
563
|
ScrArr *out = NULL;
|
|
493
564
|
int pos = scr_regex_start(re, len);
|
|
494
565
|
if (pos < 0) pos = len + 1;
|
|
495
|
-
while (pos <= len && scr_exec(
|
|
496
|
-
int start = (
|
|
497
|
-
int end = (
|
|
566
|
+
while (pos <= len && scr_exec(&input, bc, pos) == 1) {
|
|
567
|
+
int start = scr_capture_index(&input, capture[0]);
|
|
568
|
+
int end = scr_capture_index(&input, capture[1]);
|
|
498
569
|
if (!out) out = scr_arr_new(SCR_ELEM_STR, 4);
|
|
499
|
-
scr_arr_push_ref(out,
|
|
500
|
-
pos = start == end ? scr_advance(
|
|
570
|
+
scr_arr_push_ref(out, scr_regex_span(&input, start, end));
|
|
571
|
+
pos = start == end ? scr_advance(&input, end, unicode) : end;
|
|
501
572
|
}
|
|
502
|
-
|
|
503
|
-
free(u);
|
|
573
|
+
scr_regex_input_dispose(&input);
|
|
504
574
|
return out;
|
|
505
575
|
}
|
|
506
576
|
|
|
@@ -513,14 +583,13 @@ ScrArr *scr_regex_match(ScrStr *s, ScrRegex *re) {
|
|
|
513
583
|
* bytecode omits the implicit forward scan) — exactly Node. */
|
|
514
584
|
double scr_regex_search(ScrStr *s, ScrRegex *re) {
|
|
515
585
|
uint8_t *bc = scr_regex_bc(re);
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
uint8_t **capture =
|
|
519
|
-
int rc = scr_exec(
|
|
586
|
+
ScrRegexInput input;
|
|
587
|
+
scr_regex_input_init(&input, bc, s);
|
|
588
|
+
uint8_t **capture = input.capture;
|
|
589
|
+
int rc = scr_exec(&input, bc, 0);
|
|
520
590
|
double out = -1;
|
|
521
|
-
if (rc == 1) out = (double)(
|
|
522
|
-
|
|
523
|
-
free(u);
|
|
591
|
+
if (rc == 1) out = (double)scr_capture_index(&input, capture[0]);
|
|
592
|
+
scr_regex_input_dispose(&input);
|
|
524
593
|
return out;
|
|
525
594
|
}
|
|
526
595
|
|
|
@@ -544,17 +613,17 @@ static ScrArr *scr_regex_match_all_core(ScrStr *s, ScrRegex *re, ScrArr *indices
|
|
|
544
613
|
}
|
|
545
614
|
bool unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
|
|
546
615
|
int capture_count = lre_get_capture_count(bc);
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
616
|
+
ScrRegexInput input;
|
|
617
|
+
scr_regex_input_init(&input, bc, s);
|
|
618
|
+
int len = input.len;
|
|
619
|
+
uint8_t **capture = input.capture;
|
|
551
620
|
ScrArr *out = scr_arr_new(SCR_ELEM_ARR, 4);
|
|
552
621
|
int pos = scr_regex_start(re, len);
|
|
553
622
|
if (pos < 0) pos = len + 1;
|
|
554
623
|
while (pos <= len) {
|
|
555
|
-
if (scr_exec(
|
|
556
|
-
int start = (
|
|
557
|
-
int end = (
|
|
624
|
+
if (scr_exec(&input, bc, pos) != 1) break;
|
|
625
|
+
int start = scr_capture_index(&input, capture[0]);
|
|
626
|
+
int end = scr_capture_index(&input, capture[1]);
|
|
558
627
|
ScrArr *row = scr_arr_new(SCR_ELEM_STR, (size_t)capture_count);
|
|
559
628
|
for (int k = 0; k < capture_count; k++) {
|
|
560
629
|
const uint8_t *cs = capture[2 * k], *ce = capture[2 * k + 1];
|
|
@@ -562,15 +631,14 @@ static ScrArr *scr_regex_match_all_core(ScrStr *s, ScrRegex *re, ScrArr *indices
|
|
|
562
631
|
scr_arr_set_undefined(row, (double)row->len);
|
|
563
632
|
} else {
|
|
564
633
|
scr_arr_push_ref(
|
|
565
|
-
row,
|
|
634
|
+
row, scr_regex_span(&input, scr_capture_index(&input, cs), scr_capture_index(&input, ce)));
|
|
566
635
|
}
|
|
567
636
|
}
|
|
568
637
|
scr_arr_push_ref(out, row);
|
|
569
638
|
if (indices != NULL) scr_arr_push_f64(indices, (double)start);
|
|
570
|
-
pos = end == start ? scr_advance(
|
|
639
|
+
pos = end == start ? scr_advance(&input, end, unicode) : end;
|
|
571
640
|
}
|
|
572
|
-
|
|
573
|
-
free(u);
|
|
641
|
+
scr_regex_input_dispose(&input);
|
|
574
642
|
return out; /* +1 (possibly empty — Node's no-match drain is []) */
|
|
575
643
|
}
|
|
576
644
|
|
|
@@ -598,17 +666,18 @@ ScrArr *scr_regex_match_all_into(ScrStr *s, ScrRegex *re, ScrArr *indices) {
|
|
|
598
666
|
* — also Node's unterminated-'$<name' answer either way. The template is
|
|
599
667
|
* scanned byte-wise: every '$' directive is ASCII, and UTF-8 continuation
|
|
600
668
|
* bytes can never alias it. */
|
|
601
|
-
static void scr_put_substitution(ScrJsonBuf *b, const
|
|
669
|
+
static void scr_put_substitution(ScrJsonBuf *b, const ScrRegexInput *input,
|
|
602
670
|
int start, int end, uint8_t **capture,
|
|
603
671
|
int capture_count, const char *groupnames,
|
|
604
672
|
const ScrStr *rep) {
|
|
605
|
-
const uint8_t *ubase = (const uint8_t *)u;
|
|
606
673
|
size_t i = 0;
|
|
607
674
|
while (i < rep->len) {
|
|
608
675
|
char c = rep->data[i];
|
|
609
676
|
if (c != '$' || i + 1 >= rep->len) {
|
|
610
|
-
|
|
611
|
-
|
|
677
|
+
const char *next = memchr(rep->data + i + 1, '$', rep->len - i - 1);
|
|
678
|
+
size_t end = next ? (size_t)(next - rep->data) : rep->len;
|
|
679
|
+
scr_jb_write(b, rep->data + i, end - i);
|
|
680
|
+
i = end;
|
|
612
681
|
continue;
|
|
613
682
|
}
|
|
614
683
|
char c1 = rep->data[i + 1];
|
|
@@ -616,13 +685,13 @@ static void scr_put_substitution(ScrJsonBuf *b, const uint16_t *u, int len,
|
|
|
616
685
|
scr_jb_putc(b, '$');
|
|
617
686
|
i += 2;
|
|
618
687
|
} else if (c1 == '&') {
|
|
619
|
-
|
|
688
|
+
scr_regex_put_span(b, input, start, end);
|
|
620
689
|
i += 2;
|
|
621
690
|
} else if (c1 == '`') {
|
|
622
|
-
|
|
691
|
+
scr_regex_put_span(b, input, 0, start);
|
|
623
692
|
i += 2;
|
|
624
693
|
} else if (c1 == '\'') {
|
|
625
|
-
|
|
694
|
+
scr_regex_put_span(b, input, end, input->len);
|
|
626
695
|
i += 2;
|
|
627
696
|
} else if (c1 >= '0' && c1 <= '9') {
|
|
628
697
|
int k = c1 - '0';
|
|
@@ -637,7 +706,7 @@ static void scr_put_substitution(ScrJsonBuf *b, const uint16_t *u, int len,
|
|
|
637
706
|
if (k >= 1 && k < capture_count) {
|
|
638
707
|
const uint8_t *cs = capture[2 * k], *ce = capture[2 * k + 1];
|
|
639
708
|
if (cs && ce) {
|
|
640
|
-
|
|
709
|
+
scr_regex_put_span(b, input, scr_capture_index(input, cs), scr_capture_index(input, ce));
|
|
641
710
|
}
|
|
642
711
|
i += adv;
|
|
643
712
|
} else {
|
|
@@ -663,7 +732,7 @@ static void scr_put_substitution(ScrJsonBuf *b, const uint16_t *u, int len,
|
|
|
663
732
|
if (glen == name_len && memcmp(p, name, name_len) == 0) {
|
|
664
733
|
const uint8_t *cs = capture[2 * k], *ce = capture[2 * k + 1];
|
|
665
734
|
if (cs && ce) {
|
|
666
|
-
|
|
735
|
+
scr_regex_put_span(b, input, scr_capture_index(input, cs), scr_capture_index(input, ce));
|
|
667
736
|
break; /* at most one duplicate participates */
|
|
668
737
|
}
|
|
669
738
|
}
|
|
@@ -688,31 +757,34 @@ static ScrStr *scr_replace_impl(ScrStr *s, ScrRegex *re, ScrStr *rep) {
|
|
|
688
757
|
bool unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
|
|
689
758
|
int capture_count = lre_get_capture_count(bc);
|
|
690
759
|
const char *groupnames = lre_get_groupnames(bc);
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
760
|
+
ScrRegexInput input;
|
|
761
|
+
scr_regex_input_init(&input, bc, s);
|
|
762
|
+
int len = input.len;
|
|
763
|
+
uint8_t **capture = input.capture;
|
|
695
764
|
ScrJsonBuf b;
|
|
696
765
|
scr_jb_init(&b);
|
|
697
766
|
if (global) re->last_index = 0;
|
|
698
767
|
int next = 0, pos = sticky ? scr_regex_start(re, len) : 0;
|
|
699
768
|
if (pos < 0) pos = len + 1;
|
|
700
769
|
if (sticky && !global) re->last_index = 0;
|
|
770
|
+
bool matched = false;
|
|
771
|
+
bool literal = memchr(rep->data, '$', rep->len) == NULL;
|
|
701
772
|
while (pos <= len) {
|
|
702
|
-
if (scr_exec(
|
|
703
|
-
|
|
704
|
-
int
|
|
773
|
+
if (scr_exec(&input, bc, pos) != 1) break;
|
|
774
|
+
matched = true;
|
|
775
|
+
int start = scr_capture_index(&input, capture[0]);
|
|
776
|
+
int end = scr_capture_index(&input, capture[1]);
|
|
705
777
|
if (sticky && !global) re->last_index = end;
|
|
706
|
-
|
|
707
|
-
|
|
778
|
+
scr_regex_put_span(&b, &input, next, start);
|
|
779
|
+
if (literal) scr_jb_put_str(&b, rep);
|
|
780
|
+
else scr_put_substitution(&b, &input, start, end, capture, capture_count, groupnames, rep);
|
|
708
781
|
next = end;
|
|
709
782
|
if (!global) break;
|
|
710
|
-
pos = end == start ? scr_advance(
|
|
783
|
+
pos = end == start ? scr_advance(&input, end, unicode) : end;
|
|
711
784
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
return scr_jb_finish(&b);
|
|
785
|
+
if (matched) scr_regex_put_span(&b, &input, next, len);
|
|
786
|
+
scr_regex_input_dispose(&input);
|
|
787
|
+
return matched ? scr_jb_finish(&b) : scr_str_retain(s);
|
|
716
788
|
}
|
|
717
789
|
|
|
718
790
|
ScrStr *scr_regex_replace(ScrStr *s, ScrRegex *re, ScrStr *rep) {
|
|
@@ -795,10 +867,10 @@ ScrArr *scr_regex_split_limit(ScrStr *s, ScrRegex *re, double limit_num) {
|
|
|
795
867
|
int re_flags = lre_get_flags(bc);
|
|
796
868
|
bool unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
|
|
797
869
|
bool sticky = (re_flags & LRE_FLAG_STICKY) != 0;
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
870
|
+
ScrRegexInput input;
|
|
871
|
+
scr_regex_input_init(&input, bc, s);
|
|
872
|
+
int len = input.len;
|
|
873
|
+
uint8_t **capture = input.capture;
|
|
802
874
|
ScrArr *out = scr_arr_new(SCR_ELEM_STR, 0);
|
|
803
875
|
|
|
804
876
|
/* ECMA-262 22.2.6.14 (Symbol.split). The spec probes every
|
|
@@ -808,31 +880,30 @@ ScrArr *scr_regex_split_limit(ScrStr *s, ScrRegex *re, double limit_num) {
|
|
|
808
880
|
* loop. A genuinely sticky pattern keeps the spec's probe-and-advance. */
|
|
809
881
|
if (len == 0) {
|
|
810
882
|
/* Empty subject: one probe — a match yields [], no match yields [""]. */
|
|
811
|
-
if (scr_exec(
|
|
883
|
+
if (scr_exec(&input, bc, 0) != 1) {
|
|
812
884
|
scr_arr_push_ref(out, scr_str_new("", 0));
|
|
813
885
|
}
|
|
814
|
-
|
|
815
|
-
free(u);
|
|
886
|
+
scr_regex_input_dispose(&input);
|
|
816
887
|
return out;
|
|
817
888
|
}
|
|
818
889
|
int p = 0, q = 0;
|
|
819
890
|
while (q < len) {
|
|
820
|
-
if (scr_exec(
|
|
891
|
+
if (scr_exec(&input, bc, q) != 1) {
|
|
821
892
|
if (!sticky) break; /* no match anywhere right of q */
|
|
822
|
-
q = scr_advance(
|
|
893
|
+
q = scr_advance(&input, q, unicode);
|
|
823
894
|
continue;
|
|
824
895
|
}
|
|
825
|
-
int start = (
|
|
826
|
-
int end = (
|
|
896
|
+
int start = scr_capture_index(&input, capture[0]);
|
|
897
|
+
int end = scr_capture_index(&input, capture[1]);
|
|
827
898
|
/* The sticky algorithm never probes the position after the subject.
|
|
828
899
|
* A forward search can find a zero-width match there; exclude it. */
|
|
829
900
|
if (start == len) break;
|
|
830
901
|
if (end == p) {
|
|
831
902
|
/* Zero-length match adjacent to the previous split point: advance
|
|
832
903
|
* (start == q == p here — the search cannot skip a match). */
|
|
833
|
-
q = scr_advance(
|
|
904
|
+
q = scr_advance(&input, start, unicode);
|
|
834
905
|
} else {
|
|
835
|
-
scr_arr_push_ref(out,
|
|
906
|
+
scr_arr_push_ref(out, scr_regex_span(&input, p, start));
|
|
836
907
|
if (out->len == limit) goto done;
|
|
837
908
|
for (int group = 1; group < capture_count; group++) {
|
|
838
909
|
const uint8_t *from = capture[2 * group];
|
|
@@ -842,8 +913,8 @@ ScrArr *scr_regex_split_limit(ScrStr *s, ScrRegex *re, double limit_num) {
|
|
|
842
913
|
// distinct from both empty strings and holes.
|
|
843
914
|
scr_arr_set_undefined(out, (double)out->len);
|
|
844
915
|
} else {
|
|
845
|
-
scr_arr_push_ref(out,
|
|
846
|
-
(
|
|
916
|
+
scr_arr_push_ref(out, scr_regex_span(&input,
|
|
917
|
+
scr_capture_index(&input, from), scr_capture_index(&input, to)));
|
|
847
918
|
}
|
|
848
919
|
if (out->len == limit) goto done;
|
|
849
920
|
}
|
|
@@ -851,10 +922,9 @@ ScrArr *scr_regex_split_limit(ScrStr *s, ScrRegex *re, double limit_num) {
|
|
|
851
922
|
q = p;
|
|
852
923
|
}
|
|
853
924
|
}
|
|
854
|
-
scr_arr_push_ref(out,
|
|
925
|
+
scr_arr_push_ref(out, scr_regex_span(&input, p, len));
|
|
855
926
|
done:
|
|
856
|
-
|
|
857
|
-
free(u);
|
|
927
|
+
scr_regex_input_dispose(&input);
|
|
858
928
|
return out;
|
|
859
929
|
}
|
|
860
930
|
|
|
@@ -955,10 +1025,38 @@ static void scr_case_put_cp(ScrJsonBuf *b, uint32_t cp) {
|
|
|
955
1025
|
}
|
|
956
1026
|
|
|
957
1027
|
static ScrStr *scr_str_case_conv(const ScrStr *s, int to_lower) {
|
|
1028
|
+
unsigned char first = to_lower ? 'A' : 'a';
|
|
1029
|
+
unsigned char last = to_lower ? 'Z' : 'z';
|
|
1030
|
+
if (scr_text_ascii(s)) {
|
|
1031
|
+
size_t changed = 0;
|
|
1032
|
+
while (changed < s->len &&
|
|
1033
|
+
((unsigned char)s->data[changed] < first || (unsigned char)s->data[changed] > last))
|
|
1034
|
+
changed++;
|
|
1035
|
+
if (changed == s->len) return scr_str_retain((ScrStr *)s);
|
|
1036
|
+
ScrStr *out = scr_str_alloc_raw(s->len, s->len);
|
|
1037
|
+
memcpy(out->data, s->data, changed);
|
|
1038
|
+
for (size_t i = changed; i < s->len; i++) {
|
|
1039
|
+
unsigned char c = (unsigned char)s->data[i];
|
|
1040
|
+
out->data[i] = (char)(c >= first && c <= last ? c ^ 0x20 : c);
|
|
1041
|
+
}
|
|
1042
|
+
out->data[s->len] = '\0';
|
|
1043
|
+
return out;
|
|
1044
|
+
}
|
|
958
1045
|
ScrJsonBuf b;
|
|
959
1046
|
scr_jb_init(&b);
|
|
960
1047
|
uint32_t res[LRE_CC_RES_LEN_MAX];
|
|
961
1048
|
for (size_t i = 0; i < s->len;) {
|
|
1049
|
+
if ((unsigned char)s->data[i] < 0x80) {
|
|
1050
|
+
size_t start = i;
|
|
1051
|
+
while (i < s->len && (unsigned char)s->data[i] < 0x80) i++;
|
|
1052
|
+
size_t output = b.len;
|
|
1053
|
+
scr_jb_write(&b, s->data + start, i - start);
|
|
1054
|
+
for (size_t j = output; j < b.len; j++) {
|
|
1055
|
+
unsigned char c = (unsigned char)b.data[j];
|
|
1056
|
+
if (c >= first && c <= last) b.data[j] = (char)(c ^ 0x20);
|
|
1057
|
+
}
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
962
1060
|
size_t adv;
|
|
963
1061
|
uint32_t c = scr_case_decode(s->data + i, &adv);
|
|
964
1062
|
int l;
|
|
@@ -994,6 +1092,9 @@ ScrStr *scr_str_normalize(const ScrStr *s, const ScrStr *form) {
|
|
|
994
1092
|
scr_throw_error(SCR_ERR_RANGE, scr_str_new(message, sizeof message - 1));
|
|
995
1093
|
return NULL;
|
|
996
1094
|
}
|
|
1095
|
+
/* Every ASCII string is already normalized in all four forms. Validate
|
|
1096
|
+
* the form first: even an empty subject must reject an invalid form. */
|
|
1097
|
+
if (scr_text_ascii(s)) return scr_str_retain((ScrStr *)s);
|
|
997
1098
|
if (s->len > INT32_MAX / sizeof(uint32_t)) scr_regex_oom();
|
|
998
1099
|
uint32_t *input = malloc((s->len + 1) * sizeof(uint32_t));
|
|
999
1100
|
if (!input) scr_regex_oom();
|
|
@@ -1170,7 +1271,16 @@ ScrRegex *scr_regex_new(ScrStr *pattern, ScrStr *flags) {
|
|
|
1170
1271
|
}
|
|
1171
1272
|
re->rc = 1;
|
|
1172
1273
|
re->source = pattern->len > 0 ? scr_str_retain(pattern) : scr_str_new("(?:)", 4);
|
|
1173
|
-
|
|
1274
|
+
/* Public flags use getter order, independently of constructor spelling.
|
|
1275
|
+
* Validate first so duplicates and invalid flags retain their errors. */
|
|
1276
|
+
char canonical[6];
|
|
1277
|
+
size_t flag_count = 0;
|
|
1278
|
+
const char *order = "gimsuy";
|
|
1279
|
+
for (unsigned i = 0; i < 6; i++) {
|
|
1280
|
+
if (seen_flags & (1u << i)) canonical[flag_count++] = order[i];
|
|
1281
|
+
}
|
|
1282
|
+
re->flags = flag_count == flags->len && memcmp(canonical, flags->data, flag_count) == 0
|
|
1283
|
+
? scr_str_retain(flags) : scr_str_new(canonical, flag_count);
|
|
1174
1284
|
/* Eager compile — the literal path stays lazy (its failure is an
|
|
1175
1285
|
* abort; tsc already parsed those patterns). */
|
|
1176
1286
|
int lre_flags = scr_lre_flags(re->flags);
|