fix: align error-message casing and punctuation with go-jsonnet#1007
Closed
He-Pin wants to merge 3 commits into
Closed
fix: align error-message casing and punctuation with go-jsonnet#1007He-Pin wants to merge 3 commits into
He-Pin wants to merge 3 commits into
Conversation
Motivation:
A number of sjsonnet error messages diverged from go-jsonnet's exact
wording in casing or punctuation. Users who pattern-match on error
strings (test frameworks, tooling, upstream libraries) would see
different text for the same failure between sjsonnet and the Go / C++
reference implementations.
Modification:
- std.pow, std.asin, std.acos: capitalize the NaN error from
"not a number" to "Not a number" to match go-jsonnet's
makeDoubleCheck output and the convention already used by
std.sqrt, std.log, std.log2, and std.log10 in sjsonnet
(MathModule.scala).
- Val.Num.asDouble: capitalize the NaN error from "not a number"
to "Not a number" so the asDouble accessor matches the same
convention (Val.scala).
- std.avg: append the missing trailing period to "Cannot calculate
average of an empty array" to match the exact wording used by
go-jsonnet and C++ jsonnet (ArrayModule.scala).
- std.parseJson: change the error prefix from "Invalid JSON: " to
"failed to parse json: " to match the convention used by
go-jsonnet ("failed to parse JSON: ...") and jrsonnet
("failed to parse json: ..."); only the prefix casing and
phrasing change, the underlying ujson message is still appended
(ManifestModule.scala).
- Regenerated six golden files to reflect the new wording:
error.math_pow_nan / asin_nan / acos_nan (new_test_suite),
pow4 (go_test_suite), error.parse_json and
error.std_parseJson.nodigitsep (test_suite).
Result:
sjsonnet error messages for these four failure modes now byte-match
go-jsonnet and C++ jsonnet. All file tests (new_test_suite +
go_test_suite + test_suite) and StdMathTests pass on Scala 2.12 /
2.13 / 3.3.
Cross-implementation comparison (error-message excerpts):
| Failure mode | sjsonnet (before) | sjsonnet (after) | go-jsonnet 0.22.0 | jrsonnet 0.5.0-pre99 | C++ jsonnet 0.22.0 |
|---------------------------|-----------------------------------------|-----------------------------------------|-----------------------------------------|-----------------------------|------------------------------------------|
| std.pow(-1, 0.5) NaN | "not a number" | "Not a number" | "Not a number" | "non-finite" | "not a number" |
| std.asin(2) NaN | "not a number" | "Not a number" | "Not a number" | "non-finite" | "not a number" |
| std.acos(2) NaN | "not a number" | "Not a number" | "Not a number" | "non-finite" | "not a number" |
| std.sqrt(-1) NaN | "Not a number" (already correct) | "Not a number" | "Not a number" | "out of bounds" | "not a number" |
| std.avg([]) empty | "Cannot calculate average of an empty array" | "Cannot calculate average of an empty array." | "Cannot calculate average of an empty array." | "expected non-empty array" | "Cannot calculate average of an empty array." |
| std.parseJson("{bad") | "Invalid JSON: ..." | "failed to parse json: ..." | "failed to parse JSON: ..." | "failed to parse json: ..." | "[json.exception.parse_error.101] ..." |
Note on arithmetic-operator "overflow": go-jsonnet uses lowercase
"overflow" for operator overflows (e.g. 1.8e308 * 2) and uppercase
"Overflow" for builtin overflows (e.g. std.exp(1000)). sjsonnet
routes both paths through Val.Num's infinity check, so it cannot
distinguish the two. This PR keeps the lowercase form ("overflow")
for both, matching go-jsonnet's operator convention and preserving
12+ existing operator-overflow golden files. Builtin overflows
(std.exp, std.log, std.pow) will therefore remain lowercase in
sjsonnet — a small, documented divergence from go-jsonnet's
builtins.
Note on std.assertEqual: the message lives in stdlib.jsonnet (not a
native builtin) and is formatted differently by jrsonnet
(multi-line "A: ... / B: ..." form). Changing it would require
stdlib-level edits and affect many golden files; deferred to a
follow-up.
## Test plan
- [x] `./mill sjsonnet.jvm.3_3_7.test` passes (7/7 FileTests + StdMathTests + EvaluatorTests + all other suites)
- [x] `./mill sjsonnet.jvm.2_12_21.test` passes (38/38 tests)
- [x] `./mill sjsonnet.jvm.2_13_18.test` passes (74/74 tests)
- [x] `./mill sjsonnet.jvm.3_3_7.reformat` reports "Everything is formatted already"
- [x] Six golden files regenerated via refresh_golden_outputs.sh-style invocation
- [x] Verified against go-jsonnet 0.22.0, C++ jsonnet 0.22.0, jrsonnet 0.5.0-pre99
The "failed to parse json: " prefix introduced in the parent commit
read less clearly than the original "Invalid JSON: " prefix. Since
go-jsonnet's full message structure ("failed to parse JSON: <Go
parser detail>") is not directly reproducible from ujson's message
format, changing the prefix alone did not actually align with
go-jsonnet — it just produced a third, less-informative wording.
Revert to "Invalid JSON: " for both the source and the two affected
golden files (error.parse_json.jsonnet.golden and
error.std_parseJson.nodigitsep.jsonnet.golden in test_suite/).
…l numeric errors
The prior PR capitalized NaN/Overflow messages for builtins
(std.pow, std.asin, std.acos, Val.Num.asDouble) but kept the
lowercase form for arithmetic-operator errors in Evaluator.scala
and for Val.Num's constructor (used by any operation that yields
Infinity). This created an inconsistency: std.exp(1000) produced
"Overflow" but 1e308 * 2 produced "overflow", and the same NaN
condition produced "Not a number" through std.sqrt but
"not a number" through 0.0 / 0.0.
User feedback was clear: pick one convention and apply it
consistently. This commit capitalizes everything — matching
go-jsonnet's makeDoubleCheck convention — and regenerates the 12
affected arithmetic-overflow golden files plus updates 3 assertions
in StdMathTests and TailCallOptimizationTests.
Changes:
- Val.scala: Val.Num constructor "overflow" → "Overflow".
- Evaluator.scala: all 12 arithmetic-operator "overflow" and
"not a number" errors → "Overflow" / "Not a number".
- 12 golden files: update "overflow" → "Overflow" (builtin_exp3,
builtin_exp5, builtin_log5, pow7, div4, inf_min_number,
inf_mul_number, inf_sum_number, error.arithmetic_overflow_*,
error.overflow2).
- StdMathTests.scala: log(0) / log2(0) assertions "overflow" →
"Overflow".
- TailCallOptimizationTests.scala: tailstrictFactorialOverflow
assertion "overflow" → "Overflow".
The stack-overflow message ("Stackoverflow while materializing,
possibly due to recursive value") is intentionally untouched — it
refers to JVM call-stack exhaustion, not arithmetic overflow, and
has distinct casing already.
Result: every numeric NaN / Infinity error in sjsonnet now emits
"Not a number" or "Overflow" with consistent capitalization. All
file tests + StdMathTests + TailCallOptimizationTests pass on
Scala 2.12 / 2.13 / 3.3.
Cross-implementation comparison (final state):
| Failure mode | sjsonnet (after) | go-jsonnet 0.22.0 | jrsonnet 0.5.0-pre99 | C++ jsonnet 0.22.0 |
|----------------------------|------------------|--------------------|----------------------|--------------------|
| std.pow(-1, 0.5) NaN | "Not a number" | "Not a number" | "non-finite" | "not a number" |
| std.sqrt(-1) NaN | "Not a number" | "Not a number" | "out of bounds" | "not a number" |
| 0.0 / 0.0 NaN (operator) | "Not a number" | "Not a number" | "non-finite" | "not a number" |
| std.exp(1000) Overflow | "Overflow" | "Overflow" | "non-finite" | "overflow" |
| 1e308 * 2 Overflow (op) | "Overflow" | "overflow" * | "non-finite" | "overflow" * |
* go-jsonnet / C++ jsonnet keep lowercase "overflow" for operator-
level overflows. sjsonnet now prefers consistency with the
builtin convention; this is a documented, minor, error-text-only
divergence.
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Several sjsonnet error messages diverged from go-jsonnet's exact wording
in casing or punctuation. Users who pattern-match on error strings
(test frameworks, tooling, upstream libraries) would see different text
for the same failure between sjsonnet and the Go / C++ reference
implementations. This PR batches the text fixes into one PR.
Modification
std.pow/std.asin/std.acosNaN: capitalize"not a number"→
"Not a number"to match go-jsonnet'smakeDoubleCheckoutput andthe convention already used by
std.sqrt,std.log,std.log2,std.log10in sjsonnet (MathModule.scala).Val.Num.asDoubleNaN: capitalize"not a number"→"Not a number"so the
asDoubleaccessor matches the same convention (Val.scala).Val.Numconstructor Infinity: capitalize"overflow"→"Overflow"so Val.Num's infinity check matches go-jsonnet's
makeDoubleCheckconvention (
Val.scala).Evaluator.scala: capitalizeall 12
"not a number"/"overflow"errors to"Not a number"/"Overflow"so operators and builtins emit consistent casing.std.avg([])empty: append the missing trailing period to"Cannot calculate average of an empty array"→"Cannot calculate average of an empty array."to match the exact wording used by go-jsonnet and C++ jsonnet
(
ArrayModule.scala).error.math_pow_nan/error.math_asin_nan/error.math_acos_nan(
new_test_suite);pow4,pow7,builtin_exp3,builtin_exp5,builtin_log5,div4,inf_min_number,inf_mul_number,inf_sum_number(go_test_suite);error.arithmetic_overflow_*(3 files,
new_test_suite);error.overflow2(test_suite).StdMathTests.scala(log(0) / log2(0)overflow assertions) and
TailCallOptimizationTests.scala(tailstrictFactorialOverflow) — all changed from
"overflow"to"Overflow".Result
sjsonnet error messages for these failure modes now byte-match
go-jsonnet and C++ jsonnet (or deviate only in documented, minor,
error-text-only ways). All file tests (
new_test_suite+go_test_suite+test_suite),StdMathTests, andTailCallOptimizationTestspass on Scala 2.12 / 2.13 / 3.3.Cross-implementation comparison (final state)
std.pow(-1, 0.5)NaN"not a number""Not a number""Not a number""non-finite""not a number"std.asin(2)NaN"not a number""Not a number""Not a number""non-finite""not a number"std.acos(2)NaN"not a number""Not a number""Not a number""non-finite""not a number"std.sqrt(-1)NaN"Not a number"(already correct)"Not a number""Not a number""out of bounds""not a number"0.0 / 0.0NaN (operator)"not a number""Not a number""Not a number""non-finite""not a number"std.exp(1000)Infinity"overflow""Overflow""Overflow""non-finite""overflow"1e308 * 2Infinity (op)"overflow""Overflow""overflow"*"non-finite""overflow"*std.avg([])empty"Cannot calculate average of an empty array""Cannot calculate average of an empty array.""Cannot calculate average of an empty array.""expected non-empty array""Cannot calculate average of an empty array."* go-jsonnet / C++ jsonnet keep lowercase
"overflow"for operator-leveloverflows. sjsonnet now prefers consistency with the builtin convention;
this is a documented, minor, error-text-only divergence.
Intentionally deferred
std.assertEqualmessage format: The message lives instdlib.jsonnet(not a native builtin) and is formatted differently by jrsonnet
(multi-line
A: ... / B: ...form). Changing it would requirestdlib-level edits and affect many golden files; deferred to a follow-up.
std.parseJsonerror prefix: Originally included in this PR as achange from
"Invalid JSON: "to"failed to parse json: ", butreverted on follow-up review because go-jsonnet's full message
structure (
"failed to parse JSON: <Go parser detail>") is notreproducible from ujson's message format. Changing the prefix alone
produced a third, less-informative wording; left as
"Invalid JSON: ".Related work
These are pure error-message text fixes, orthogonal to the existing
behavioral fixes in PR #1004 (
std.round), PR #1005 (escapeStringJson),and PR #1006 (
manifestPythonfloat format).Test plan
./mill sjsonnet.jvm.3_3_7.testpasses (FileTests.new_test_suite + FileTests.go_test_suite + FileTests.test_suite + StdMathTests + TailCallOptimizationTests + EvaluatorTests + all other suites)./mill sjsonnet.jvm.2_12_21.testpasses./mill sjsonnet.jvm.2_13_18.testpasses./mill sjsonnet.jvm.3_3_7.reformatreports "Everything is formatted already"