@scriptc/runtime 0.0.10 → 0.0.12

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/src/scr_regex.c CHANGED
@@ -484,13 +484,20 @@ ScrArr *scr_regex_match_all_into(ScrStr *s, ScrRegex *re, ScrArr *indices) {
484
484
  * replacements are frontend-fenced): $$, $&, $` and $', $1..$99 (two digits
485
485
  * win when in range — the refined ES2019 rule quickjs implements), with
486
486
  * out-of-range references left literal and unmatched groups substituting
487
- * empty. $<name> stays literal: named capture groups are frontend-fenced,
488
- * so namedCaptures is always undefined here (the spec's literal case).
489
- * The template is scanned byte-wise: every '$' directive is ASCII, and
490
- * UTF-8 continuation bytes can never alias it. */
487
+ * empty. $<name> resolves against the pattern's named capture groups
488
+ * (lre_get_groupnames one NUL-terminated name per capture, "" for
489
+ * unnamed): the first PARTICIPATING capture with that name substitutes
490
+ * (ES2025 duplicates live in distinct alternatives, so at most one
491
+ * participates); a nonexistent or nonparticipating name substitutes
492
+ * empty (the spec's Get→undefined→"" path, Node-exact). When the pattern
493
+ * has NO named groups, namedCaptures is undefined and '$<' stays literal
494
+ * — also Node's unterminated-'$<name' answer either way. The template is
495
+ * scanned byte-wise: every '$' directive is ASCII, and UTF-8 continuation
496
+ * bytes can never alias it. */
491
497
  static void scr_put_substitution(ScrJsonBuf *b, const uint16_t *u, int len,
492
498
  int start, int end, uint8_t **capture,
493
- int capture_count, const ScrStr *rep) {
499
+ int capture_count, const char *groupnames,
500
+ const ScrStr *rep) {
494
501
  const uint8_t *ubase = (const uint8_t *)u;
495
502
  size_t i = 0;
496
503
  while (i < rep->len) {
@@ -534,6 +541,31 @@ static void scr_put_substitution(ScrJsonBuf *b, const uint16_t *u, int len,
534
541
  scr_jb_putc(b, '$');
535
542
  i++;
536
543
  }
544
+ } else if (c1 == '<' && groupnames != NULL) {
545
+ /* $<name>: scan for '>'; absent, the '$' is literal (the rest
546
+ * re-scans verbatim — GetSubstitution's not-found answer). */
547
+ size_t gt = i + 2;
548
+ while (gt < rep->len && rep->data[gt] != '>') gt++;
549
+ if (gt >= rep->len) {
550
+ scr_jb_putc(b, '$');
551
+ i++;
552
+ continue;
553
+ }
554
+ const char *name = rep->data + i + 2;
555
+ size_t name_len = gt - (i + 2);
556
+ const char *p = groupnames; /* capture_count-1 entries: name NUL scope */
557
+ for (int k = 1; k < capture_count; k++) {
558
+ size_t glen = strlen(p);
559
+ if (glen == name_len && memcmp(p, name, name_len) == 0) {
560
+ const uint8_t *cs = capture[2 * k], *ce = capture[2 * k + 1];
561
+ if (cs && ce) {
562
+ scr_jb_put_utf16(b, u, (int)((cs - ubase) >> 1), (int)((ce - ubase) >> 1));
563
+ break; /* at most one duplicate participates */
564
+ }
565
+ }
566
+ p += glen + LRE_GROUP_NAME_TRAILER_LEN;
567
+ }
568
+ i = gt + 1;
537
569
  } else {
538
570
  scr_jb_putc(b, '$');
539
571
  i++;
@@ -550,6 +582,7 @@ static ScrStr *scr_replace_impl(ScrStr *s, ScrRegex *re, ScrStr *rep) {
550
582
  bool global = (re_flags & LRE_FLAG_GLOBAL) != 0;
551
583
  bool unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
552
584
  int capture_count = lre_get_capture_count(bc);
585
+ const char *groupnames = lre_get_groupnames(bc);
553
586
  int len;
554
587
  uint16_t *u = scr_to_utf16(s, &len);
555
588
  uint8_t **capture = scr_capture_alloc(bc);
@@ -562,7 +595,7 @@ static ScrStr *scr_replace_impl(ScrStr *s, ScrRegex *re, ScrStr *rep) {
562
595
  int start = (int)((capture[0] - ubase) >> 1);
563
596
  int end = (int)((capture[1] - ubase) >> 1);
564
597
  scr_jb_put_utf16(&b, u, next, start);
565
- scr_put_substitution(&b, u, len, start, end, capture, capture_count, rep);
598
+ scr_put_substitution(&b, u, len, start, end, capture, capture_count, groupnames, rep);
566
599
  next = end;
567
600
  if (!global) break;
568
601
  pos = end == start ? scr_advance(u, len, end, unicode) : end;