fix(core): infer whole numbers outside the target's integer range as double#2938
Conversation
|
But this needs to be language-specific, no? JS different limits than Go for example! |
|
Good point — reworked in 93b65a7.
Tests cover the comparator boundaries, Go/Python end-to-end through both parsers, and a case showing the same literal classifying differently under different ranges. 🤖 Generated with Claude Code |
|
Review result: one correctness issue remains before merge. The new The effective range therefore needs to cover fixed non-int64 targets such as Crystal and renderer-dependent widths such as CJSON's Validation otherwise passed: the PR builds cleanly, all 82 unit tests pass, and the GitHub Test workflow is successful. |
…double Instead of a fixed int64 check, each TargetLanguage now declares its supported integer range — the inclusive range of whole numbers its integer type can round-trip, as decimal strings since the boundaries exceed exact doubles. The default is int64; JavaScript-family languages (including Elm, whose Int is a JS number at runtime) are exact only within ±(2^53 - 1); Crystal renders integers as Int32; Python, Ruby, Elixir, and Pike have arbitrary-precision integers, and JSON Schema's `integer` is unbounded, so they have no limit. Some languages' integer width depends on a renderer option — cJSON's integer-size can narrow it down to int8_t — so the range is exposed as getSupportedIntegerRange(rendererOptions), and both the CLI and jsonInputForTargetLanguage pass the renderer options through when constructing JSON input. Both JSON parsers consult the range: the CLI's streaming parser checks the exact digit string, and the JSON.parse-based core parser checks the double's exact decimal value via toFixed(0), which errs toward `double` at range boundaries the double can't represent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
93b65a7 to
751ac79
Compare
|
Both fixed in 751ac79 (also rebased onto master):
New tests cover the per-language range declarations, Crystal end-to-end through the streaming parser, and cJSON under 🤖 Generated with Claude Code |
Fixes #2931.
A whole number in input JSON that lies outside the target language's integer range was always inferred as
integer, so e.g. Go gotint64for123456789012345678901234567890and the generated code failed to unmarshal the very sample it was generated from:What this does
Each
TargetLanguagenow declares its supported integer range — the inclusive range of whole numbers its integer type can round-trip, given as decimal strings because the boundaries (e.g. INT64_MAX) are not exactly representable as doubles. Whole numbers outside the range are inferred asdouble;nullmeans arbitrary-precision.Int32)integer-sizerenderer option (int64_t by default)Because cJSON's width depends on a renderer option, the range is exposed as
getSupportedIntegerRange(rendererOptions); the CLI andjsonInputForTargetLanguage(which gained an optionalrendererOptionsparameter) pass the renderer options through when constructing JSON input.Both JSON parsers consult the range:
JSON.parse-based core parser (which previously hardcoded the JS safe-integer cutoff for every language) checks the double's exact decimal value viatoFixed(0), erring towarddoubleat range boundaries the double can't represent. Side benefit: Go via the core API now keepsint64for whole numbers between 2^53 and INT64_MAX instead of widening them todouble.Testing
-0), Go, Python, and Crystal end-to-end through both parsers, cJSON underinteger-size=int16_t, per-language range declarations, and a test showing the same literal classifying differently under different ranges.float64and the generated Go unmarshals its own sample;pythonkeepsint;-l schemakeeps"type": "integer";--lang crystalturns2147483648intoFloat64;--lang cjson --integer-size int8_tturns128intodouble.🤖 Generated with Claude Code