Fix schemagen integer parser rejecting zero with negative exponents #57

Merged
andrew merged 1 commits from weaselbot/weaseljson:weaselbot/issue-56 into main 2026-07-20 18:00:37 +00:00
Member

Summary

Fixes #56. The generated parseJsonInt64 in schemagen rejected valid JSON numbers whose mathematical value is 0 but which are written with a negative exponent large enough that trailing/leading-zero trimming does not fully offset it (e.g. 0e-2, 0.0e-2, -0e-2, 0e-20).

Root cause

The if (finalExp < 0) return false; guard ran before the zero-detection branch (if (leadingZeros == digits.size()) { out = 0; return true; }). For a zero value, all significant digits get trimmed away, leaving an all-zero digits, but finalExp can still be negative, so the early return false triggered before the out = 0 branch was reached.

Fix

Reorder the two guards so the zero-detection check runs first. When the remaining digits are all zero, the value is 0 regardless of the exponent, so we accept it and set out = 0. The negative-finalExp rejection then only applies to non-zero values, which are correctly rejected as non-integral (e.g. 1e-2).

Testing

Added regression cases to SchemagenIntegerBoundaryTest covering both root and object-field integer schemas for 0e-1, 0e-2, 0.0e-2, -0e-2, 0e-20, 0.000e-5, and {"age":0e-2} / {"age":-0e-20}. Existing rejection cases (1e-2, 1.5, 0.001) remain rejected. Full schemagen test suite and the CMake/CTest suite pass.

## Summary Fixes #56. The generated `parseJsonInt64` in schemagen rejected valid JSON numbers whose mathematical value is `0` but which are written with a negative exponent large enough that trailing/leading-zero trimming does not fully offset it (e.g. `0e-2`, `0.0e-2`, `-0e-2`, `0e-20`). ## Root cause The `if (finalExp < 0) return false;` guard ran *before* the zero-detection branch (`if (leadingZeros == digits.size()) { out = 0; return true; }`). For a zero value, all significant digits get trimmed away, leaving an all-zero `digits`, but `finalExp` can still be negative, so the early `return false` triggered before the `out = 0` branch was reached. ## Fix Reorder the two guards so the zero-detection check runs first. When the remaining digits are all zero, the value is `0` regardless of the exponent, so we accept it and set `out = 0`. The negative-`finalExp` rejection then only applies to non-zero values, which are correctly rejected as non-integral (e.g. `1e-2`). ## Testing Added regression cases to `SchemagenIntegerBoundaryTest` covering both root and object-field integer schemas for `0e-1`, `0e-2`, `0.0e-2`, `-0e-2`, `0e-20`, `0.000e-5`, and `{"age":0e-2}` / `{"age":-0e-20}`. Existing rejection cases (`1e-2`, `1.5`, `0.001`) remain rejected. Full schemagen test suite and the CMake/CTest suite pass.
weaselbot added 1 commit 2026-07-20 02:01:09 +00:00
Fix schemagen integer parser rejecting zero with negative exponents
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-arm64, ubuntu-latest-arm64, true) (pull_request) Successful in 51s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-arm64, ubuntu-latest-arm64, false) (pull_request) Successful in 50s
CI / pre-commit (pull_request) Successful in 56s
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-amd64, ubuntu-latest-amd64, true) (pull_request) Successful in 1m33s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-amd64, ubuntu-latest-amd64, false) (pull_request) Successful in 1m33s
cdff634057
Move the zero-detection check in the generated parseJsonInt64 before the
finalExp < 0 guard. Previously, valid JSON numbers whose mathematical
value is 0 but written with a large negative exponent (e.g. 0e-2,
0.0e-2, -0e-2, 0e-20) were rejected because the negative-finalExp early
return ran before the all-zero-digits branch could set out = 0. Non-zero
values with negative exponents are still correctly rejected.

Closes #56
andrew merged commit 814b24efba into main 2026-07-20 18:00:37 +00:00
andrew deleted branch weaselbot/issue-56 2026-07-20 18:00:37 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: weaselab/weaseljson#57