Compare commits

..
1 Commits
Author SHA1 Message Date
weaselbot b9dfb3becc schemagen: parse integer fallback exactly for decimal/exponent forms
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-arm64, ubuntu-latest-arm64, true) (pull_request) Successful in 1m0s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-arm64, ubuntu-latest-arm64, false) (pull_request) Successful in 58s
CI / pre-commit (pull_request) Failing after 52s
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-amd64, ubuntu-latest-amd64, true) (pull_request) Successful in 1m29s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-amd64, ubuntu-latest-amd64, false) (pull_request) Successful in 1m24s
Replace the double-based fallback in generated integer slots with a
string-to-int64 parser that handles decimal points and exponents
without losing precision near the int64 boundaries.

The old path used std::from_chars<double> and compared against
±9223372036854775808.0, which rounds the int64 max and min so that
valid values are rejected and out-of-range negatives are accepted.

The new helper:
- Parses sign, integer part, optional fraction, and optional exponent.
- Strips trailing zeros to cancel fractional places.
- Rejects non-integral values and overflow using exact uint64_t
  arithmetic.

Adds regression tests covering root integer and object-field integer
boundary values, including the cases from issue #19.
2026-06-23 18:36:37 -04:00
2 changed files with 5 additions and 17 deletions
+2 -8
View File
@@ -324,9 +324,7 @@ class SchemagenIntegerBoundaryTest(unittest.TestCase):
self.assertEqual(run.returncode, 0, msg=run.stdout + run.stderr)
def _build_cases_array(self, name, entries):
lines = [
f" struct {name}Case {{ const char *s; WeaselJsonStatus expected; long long v; }};"
]
lines = [f" struct {name}Case {{ const char *s; WeaselJsonStatus expected; long long v; }};"]
lines.append(f" {name}Case {name}_cases[] = {{")
for s, exp, v in entries:
val = f"{v}LL" if isinstance(v, int) else v
@@ -395,11 +393,7 @@ class SchemagenIntegerBoundaryTest(unittest.TestCase):
('{"age":1e3}', "WeaselJson_OK", 1000),
('{"age":2.0}', "WeaselJson_OK", 2),
('{"age":0.001}', "WeaselJson_REJECT", 0),
(
'{"age":-9223372036854775808.0}',
"WeaselJson_OK",
"-9223372036854775807LL - 1",
),
('{"age":-9223372036854775808.0}', "WeaselJson_OK", "-9223372036854775807LL - 1"),
]
cases_src = self._build_cases_array("object", cases)
harness = textwrap.dedent(
+3 -9
View File
@@ -1001,15 +1001,9 @@ private:
mag *= 10;
}}
if (mag > limit) return false;
if (neg) {{
if (mag == kMaxNeg) {{
out = INT64_MIN;
}} else {{
out = -static_cast<int64_t>(mag);
}}
}} else {{
out = static_cast<int64_t>(mag);
}}
__int128 signedMag = static_cast<__int128>(mag);
if (neg) signedMag = -signedMag;
out = static_cast<int64_t>(signedMag);
return true;
}}