ReviewOS

zig-utils/zig-js

Intl.NumberFormat: emit BigInt numeric part boundaries

#567
Closed chris opened this 9 days ago ·
9 days ago

Parent: #475 Related: #564, #565

Problem

Intl.NumberFormat.prototype.formatToParts currently special-cases BigInt by formatting the whole value through bigIntFormatWithResolved and emitting one literal part. A focused probe formats 12345678901234567890n as the correct visible text but reports no integer/group structure; system JavaScriptCore emits numeric part boundaries. Range consumers also need the same exact structural model rather than an opaque literal.

Scope

  • Feed exact BigInt digits through the shared ordered NumberFormat emitter without converting through f64.
  • Apply grouping, localized digits, signs/accounting, currency/unit/percent placement, and notation/rounding behavior permitted for BigInt while retaining exact integer magnitude.
  • Make format, formatToParts, formatRange, and formatRangeToParts share the same BigInt structure and range-affix logic.

No-workaround rules

No f64 conversion, value-length cutoff, ungrouped special case, opaque literal part, locale recognition, duplicated formatting algorithm, or borrowed bytes that outlive their owner.

Acceptance

  • Focused exact-text and exact-part oracles cover zero, signs, very large magnitudes, grouping schemes, non-Latin digits, currency/unit/percent, compact/scientific notation, and ranges.
  • BigInt format equals joined formatToParts, with spec-correct part types and sources.
  • Relevant Intl402 and BigInt locale subtrees gain missing cases with no regressions.
  • OOM, bounded heap, moving GC, no-GIL, TSan, allocation evidence, and full units pass.
9 days ago

Frozen the BigInt structural boundary in aa3cf4d0 (bench(intl): isolate BigInt structural formatting (#567)).

The four controls isolate format, formatToParts, formatRange, and formatRangeToParts across exact large magnitudes, non-Latin digits / Indic grouping, affixes, notation, and rounding. At 4 jobs / 5 samples, pre-fix zig-js checksums are 31,584 / 21,200 / 79,312 / 1,121,984; the JavaScriptCore oracle is 108,704 / 952,064 / 118,528 / 2,929,264.

The range control also confirmed an independent symptom of the same root cause: nfNumericArg converts BigInt through f64, so distinct 20-digit endpoints can collapse to the same rounded range. The implementation will retain the original mathematical values and feed exact decimal digits into the shared structural emitter.

9 days ago

#567 is complete via the frozen consumer boundary aa3cf4d0 and the exact structural implementation 5d255fec.

BigInt now enters the same ordered NumberFormat emitter as Number without binary64 conversion. format, formatToParts, formatRange, formatRangeToParts, and BigInt.prototype.toLocaleString share exact arbitrary-precision grouping, localized digits, sign/accounting, currency/unit/percent affixes, compact/scientific/engineering notation, rounding modes/increments, and range source attribution. Distinct 20-digit endpoints remain distinct.

Validation: Intl402 3,341/3,341; focused formatRange 11/11, formatRangeToParts 10/10, BigInt toLocaleString 11/11; focused TSan 9/9; full units 1,648 pass / 1 skip / 0 fail / 0 leak. The four representative checksums move from 31,584 / 21,200 / 79,312 / 1,121,984 to 108,224 / 952,048 / 117,904 / 3,318,576, and invocation attribution records zero lock contentions.

The oracle also exposed a separate non-BigInt locale-data gap for German currencyDisplay:"name"; that generated-CLDR work is tracked in #569 rather than being hidden in this fix.

Sign in to comment on this issue.