Harden jsonlit and reject unsupported syntax at Compile time#15
Merged
Conversation
jsonlit:
- Fix `[N][...]T` array-type detection so `[2][]int{{1},{2}}` and
`[3][4]int{{1,2,3,4}}` survive the rewrite (recursive
`isArrayTypeFollow`).
- Accept `<-` as a slice-type prefix follow so `[]<-chan T{}` passes
through.
- Treat `)`, `]`, and `}` as type-end tokens before `{` so
`func() {}`, `List[int]{}`, and `[]interface{}{1}` are not mangled
into bare object literals.
- Track a brace stack with three states (object, any-elemented typed,
inert typed) so nested type-omitted composites like
`[][]int{{1,2},{3,4}}` and `[]struct{X int}{{1},{2}}` are left
alone, while `map[string]any{"k": {"j": 1}}` and `[]any{{"k": 1}}`
still get the inner brace rewritten.
- Preserve comments inside empty `[]` by splitting the splice into
two edits.
- Add an `internal/jsonlit/README.md` describing the approach,
bracket and brace classification, and known limitations.
- Expand the test suite and fuzz seed corpus with the previously
broken shapes.
Compile-time validator:
- Add `validate.go` that walks the parsed AST and rejects every
unsupported form (function literals, slice expressions, type
assertions, channel ops, pointer/address ops, bitwise operators,
imaginary literals, spread args, generic instantiations, fixed-
size arrays, and typed slices/maps other than `[]any` /
`map[string]any`) with `ErrCompile` and a `line:col` prefix.
- Switch `Compile` to `parser.ParseExprFrom` with a local FileSet so
validator errors carry positions like the parser's own.
- Update three existing tests that previously asserted
`ErrEvaluate` for unsupported forms to now expect `ErrCompile`,
and update `docs/reference/spec.md` accordingly.
- Keep the runtime checks as defense in depth.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Two related improvements to the front-end of
expr:jsonlit edge cases. The token-based JSON-style rewrite in
internal/jsonlithad several shapes where valid Go input either failed to parse or was silently miscompiled. Fixed by makingisArrayTypeFollowrecursive (for[N][...]T), accepting<-/)/]as type-end tokens before{(for[]<-chan T{},func() {},List[int]{},[]interface{}{1}), tracking a brace stack so nested type-omitted composites like[][]int{{1,2}}and[]struct{X int}{{1}}are left alone whilemap[string]any{"k": {"j": 1}}still gets the inner brace rewritten, and splitting the empty-[]edit into two splices so comments are preserved. Adds aninternal/jsonlit/README.mddescribing the approach, classification, and known limits.Compile-time validation. Adds a one-pass AST validator (
validate.go) invoked fromCompileimmediately after parsing. Forms expr does not evaluate (function literals, slice expressions, type assertions, channel/pointer/address ops, bitwise operators, imaginary literals, spread args, generic instantiations, fixed-size arrays, typed slices/maps other than[]any/map[string]any) now fail atCompilewithErrCompileand aline:colprefix, instead of failing atRunwithErrEvaluate. SwitchesCompiletoparser.ParseExprFromfor positioned errors. Runtime checks are kept as defense in depth.Three existing tests previously asserting
ErrEvaluatefor unsupported syntax now expectErrCompile.docs/reference/spec.mdis updated accordingly.Test plan
go test ./...passesgo test -fuzz=FuzzRewrite -fuzztime=30s ./internal/jsonlit/clean (with new seeds for the previously broken shapes)go test -fuzz=FuzzCompile -fuzztime=20s .clean (>1M execs)go test -fuzz=FuzzEval -fuzztime=20s .clean (>400k execs)validate_test.gopins each unsupported form toErrCompileplus three nested-rejection casesinternal/jsonlit/jsonlit_test.goadds explicit cases for every fixed shape🤖 Generated with Claude Code