Skip to content

Use Parsers 3 kernels for number parsing - #480

Draft
quinnj wants to merge 5 commits into
masterfrom
codex/parsers-3-number-migration
Draft

Use Parsers 3 kernels for number parsing#480
quinnj wants to merge 5 commits into
masterfrom
codex/parsers-3-number-migration

Conversation

@quinnj

@quinnj quinnj commented Aug 20, 2026

Copy link
Copy Markdown
Member

Summary

This draft updates JSON number parsing for Parsers 3 while retaining compatibility with Parsers 1 and 2 and Julia 1.9.

  • Keep strict JSON number grammar in JSON.jl.
  • Use span-exact Parsers 3 kernels for built-in numeric targets.
  • Keep adaptive untyped promotion: Int64 to BigInt, and Float64 overflow to BigFloat.
  • Parse typed Float32 and BigFloat values from the original token bytes. This removes intermediate Float64 rounding.
  • Add explicit CI and coverage lanes for Parsers 1.1.2 and the exact head of Rewrite Parsers around span-exact scalar kernels JuliaData/Parsers.jl#210.

This branch is stacked on #479 because it extends that number-parsing change. The first three commits come from #479. They can drop from this PR after #479 merges.

Compatibility design

The implementation selects a bounded adapter at compile time:

  • Parsers 3 uses parseint, parsebigint, parsefloat, and parsenext on exact byte spans.
  • Parsers 2 keeps its exact-span integer adapter.
  • Parsers 1 keeps its older xparse integer adapter.
  • Parsers 1 and 2 use Base for validated finite floats and wide integers. This avoids known legacy parser crashes, incorrect long-decimal results, and pooled BigInt ownership.

The package still declares Parsers = "1, 2, 3" and julia = "1.9". Parsers 3 itself requires Julia 1.10 or later, so Julia 1.9 resolves a compatible older Parsers release.

Observable corrections

  • typemin(Int64) now stays an Int64.
  • allownan=true adds configured and native special spellings. It no longer coerces every finite number to Float64.
  • Finite numbers with a leading + are rejected as non-standard JSON.
  • Negative zero keeps its sign.
  • Long finite decimals use Base-compatible rounding on the Parsers 1 and 2 compatibility paths.
  • Typed Float32 and BigFloat values no longer double-round through Float64 on Parsers 3.
  • Returned BigInt values have independent storage.

Validation

Independent tests used the exact branch commit and exact Parsers 3 pin:

  • Focused grammar, span, rounding, promotion, special-value, and ownership matrix: 657,429/657,429 across seven lanes, with zero Float64 oracle differences.
  • Parsers 1 / Julia 1.9: 61,472 passed.
  • Parsers 2 / Julia 1.9: 61,472 passed.
  • Parsers 2 / Julia 1.10: 61,472 passed.
  • Parsers 2 / Julia 1.12: 61,477 passed, including trim 6/6.
  • Parsers 3 / Julia 1.10: 61,479 passed.
  • Parsers 3 / Julia 1.12: 61,484 passed, including trim 6/6.
  • Julia 1.14 nightly: all 61,478 non-trim checks passed. JuliaC 0.3.8 alone could not trim that nightly because of unresolved new Base CancelTokenKey calls.
  • Documentation builds successfully.

Performance

Against the stacked #479 Parsers 2 baseline on Julia 1.12.6:

  • Common Int64: within noise to 6% faster.
  • Common Float64: 21% to 24% faster.
  • Wide BigInt: 14x to 18x faster, with about 32x fewer allocations.
  • Typed Float32: about 3.2x faster and correctly rounded.
  • Float64-overflow to BigFloat: within noise to 7% faster, with one fewer allocation.

Parsers 1 and 2 byte-vector float inputs require one bounded temporary String. This is an intentional compatibility cost for correct rounding and safe behavior. Parsers 3 parses the original span directly.

Dependency state

The Parsers 3 CI lane pins exact green draft head 83c7142fb714cb87261ef38eec7ab103444eb30d from JuliaData/Parsers.jl#210. This pin should move to the released Parsers 3 version before this PR merges.

Co-authored by Codex

@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.36735% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.78%. Comparing base (233d644) to head (3445472).

Files with missing lines Patch % Lines
src/parse.jl 84.21% 9 Missing ⚠️
src/lazy.jl 97.12% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #480      +/-   ##
==========================================
+ Coverage   89.99%   90.78%   +0.79%     
==========================================
  Files           7        7              
  Lines        1519     1628     +109     
==========================================
+ Hits         1367     1478     +111     
+ Misses        152      150       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant