fix(parser): reject C-style radix literals (0x/0b/0o) instead of silently parsing to 0 (#337)#343
Merged
Merged
Conversation
…ntly parsing to 0 (#337) A `0x…`-style C-style hex integer literal in a property association silently parsed to `0`: the lexer split `0x40003000` into INTEGER_LIT `0` + IDENT `x40003000`, and the parser then treated the trailing identifier as a *unit*, yielding `Integer(0, unit="x40003000")` with no diagnostic — a silent wrong value for any consumer of `items --format json`. C-style radix prefixes are not valid AADL v2.3 numeric literals (AADL uses based notation `base#digits#`, e.g. `16#40003000#`). Accepting them would introduce a spar-specific dialect divergence, so — per the issue's stated preference ("a hard error is strictly better than silent 0") — spar now rejects them: - `scan_number` (lexer) recognizes a lone leading `0` glued to a radix marker (`x`/`X`, `b`/`B`, `o`/`O`) followed by a valid digit of that radix, and lexes the whole malformed run as one ERROR token. - `property_expression_primary` (grammar) attaches a targeted diagnostic on that token: "C-style radix literal is not valid AADL; use based notation, e.g. `16#…#` for hexadecimal". `spar parse` now reports the diagnostic with location and exits non-zero; `spar items` no longer emits a deceptive `Integer[0]`. Oracles (all executed; lexer + lowering + parser tests confirmed red before the fix): the C-style forms each lex as a single ERROR token, `=> 0x40003000;` no longer lowers to `Integer(0, Some(unit))`, the parser emits a diagnostic, and negative controls (`0 ns`, `0bar`, `0x`, `16#40003000#`) are unaffected; positive control `16#40003000#` lowers to `Integer(1073754112, None)`. Adds REQ-PARSER-003 (traces-to REQ-PARSER-001). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rivet verification gate✅ 20/20 passed
Filter: Failed artifacts(none) Updated automatically by |
avrabe
added a commit
that referenced
this pull request
Jul 23, 2026
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
Closes #337. A
0x…-style C-style hex integer literal in a property association silently parsed to0with no diagnostic. The lexer split0x40003000into INTEGER_LIT0+ IDENTx40003000, andproperty_expression_primarythen treated the trailing identifier as a unit, lowering the property toInteger(0, unit="x40003000"). A downstream consumer ofitems --format jsonreadingtyped_value.Integer[0]got a plausible-looking wrong value (0) with no signal.Decision: reject, don't extend the dialect
The issue offered two resolutions — accept
0x…as hex, or emit a diagnostic — and stated "a hard error is strictly better than silent 0." C-style radix prefixes are not valid AADL v2.3 numeric literals; AADL uses based notationbase#digits#(e.g.16#40003000#). Accepting0x…would introduce a spar-specific dialect divergence (cf. the interop/anti-dialect-drift concern in #246), and OSATE/Ocarina would reject it. So spar now rejects it, spec-faithfully. (0x…already appears in the tree only as opaque string content — e.g. the TSNGate_Control_ListGCL — which this change leaves untouched.)Fix
crates/spar-parser/src/lexer.rs—scan_numberrecognizes a lone leading0glued to a radix marker (x/X,b/B,o/O) followed by a valid digit of that radix, and lexes the whole malformed run as oneERRORtoken (newis_radix_digithelper).crates/spar-parser/src/grammar/properties.rs— a newERRORarm inproperty_expression_primaryattaches a targeted diagnostic on that token and recovers to the;(newis_c_style_radix_literalhelper).Observable behavior:
spar parsenow reports…:5:18: C-style radix literal is not valid AADL; use based notation, e.g.16#…#for hexadecimaland exits non-zero;spar itemsno longer emits a deceptiveInteger[0].Oracles (all executed; production guard confirmed red-flips the parser/lowering/lexer tests)
0x40003000,0X1F,0b1010,0o17,0xDEAD_BEEFeach lex as a singleERRORtoken (before the fix they split into0+ IDENT). Negative controls:0 ns→0+ns,0bar→0+bar,0x(no hex digit) →0+x,16#40003000#→ one INTEGER_LIT.=> 0x40003000;no longer lowers toInteger(0, Some(unit)); positive control=> 16#40003000#;lowers toInteger(1073754112, None).0x40003000ERRORtoken in the tree;16#40003000#parses clean.Verification
cargo test -p spar-parser -p spar-syntax -p spar-hir-def— green (parser 77, syntax 291, hir-def 472); the 5 lexer + lowering + parser oracles confirmed red before the fix.cargo fmt --checkclean;cargo clippy -p spar-parser -p spar-hir-def -p spar-syntax --all-targets -- -D warningsclean.rivet validate— PASS, 0 broken cross-refs, REQ-PARSER-003 present with resolvingtraces-to.Integer(0, Some(Name("x40003000")))reproduced), re-derived0x40003000 = 1073754112, swept 23 false-positive candidates (none), and confirmed the TSN hex-in-string GCL test stays green.Scope / honesty
Fixes the token-split silent-zero path (the reported bug) for hex and the same-class
0b/0oprefixes. It does not makespar itemsitself exit non-zero on the malformed input — that command remains a best-effort structural dump; the hard error surfaces viaspar parse/analyze. The unrelated silent-hex-in-property discussion is fully addressed by rejection here.Requirements
Adds
REQ-PARSER-003(traces-toREQ-PARSER-001), releasev0.32.0.🤖 Generated with Claude Code
Generated by Claude Code