feat(parser): reject a feature named in/out — reserved words (#420) - #437
Merged
Conversation
Category-1 (grammar-level permissiveness) item from #420: spar accepted a feature — in practice a port — named with the AS-5506B Annex A reserved word `in` or `out`, e.g. `in : in event port;`. `in`/`out` cannot be identifiers, so this was a too-permissive gap admitting invalid AADL a user's model could carry. OSATE 2.18.0 rejects it at the grammar level ("no viable alternative at input 'in'", recorded on #420). The acceptance came through the general keyword-as-name path (`at_name` reads any keyword followed by `:` as a declaration name). `feature()` now special-cases `IN_KW`/`OUT_KW` in the feature-name position, emitting a reserved-word diagnostic while still consuming the token so the rest of the declaration parses and the tree round-trips. Scope is exactly the feature-name position; `in`/`out` in their legal roles (direction `in`/`out`/`in out`, `in modes`, `in binding`) and keyword-as-name for other keywords are untouched. Oracle (inline, no external tool needed): crates/spar-syntax/tests/parser_tests.rs — port_named_in_is_rejected / port_named_out_is_rejected assert the diagnostic; port_named_in_still_round_trips asserts losslessness. Non-vacuity is executed: before the fix all three rejection inputs parsed with zero errors; the discriminating partner port_named_inp_outp_still_accepted (ports `inp`/`outp`) parses cleanly both before and after, so the check keys on the name being reserved and nothing else. No first-party file flips: the graded conformance suites (osate_agreement.rs too-permissive floor 53, too-strict 0; three_way_conformance.rs) hold their ceilings, and no vendored/first-party .aadl names a feature `in`/`out` (grep over test-data/interop returns 0). Adds REQ-PLUGFEST-PORTNAME-INOUT-001 (implemented, traces-to REQ-PLUGFEST-006). Honestly deferred: the reverse-direction discipline pins such a rule with a test-data/negative fixture carrying MEASURED OSATE and Ocarina verdicts (the two graded baselines are asserted set-equal). This environment has neither oracle, and a baseline row must be measured not assumed, so the corpus fixture + its two baseline rows are left to a run/maintainer with both tools. Does not close #420. 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 |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Merged
avrabe
added a commit
that referenced
this pull request
Aug 22, 2026
Version bump for v0.42.0. Feature landed in #437 (#420 category-1): spar now rejects a feature/port named with the AS-5506B Annex A reserved word `in` or `out` (a too-permissive grammar gap OSATE rejects at the grammar level). Cargo.toml / Cargo.lock (23 workspace crates) / vscode-spar/package.json 0.41.0 -> 0.42.0; REQ-PLUGFEST-PORTNAME-INOUT-001 promoted to verified (release v0.42.0). Co-authored-by: Claude <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.
What
Category-1 (grammar-level permissiveness) item from #420: spar accepted a feature — in practice a port — named with the AS-5506B Annex A reserved word
inorout, e.g.in/outcannot be identifiers, so this is a too-permissive gap: spar admitted invalid AADL a user's model could carry. OSATE 2.18.0 rejects it at the grammar level (no viable alternative at input 'in', recorded on #420).How
The acceptance came through the general keyword-as-name path (
Parser::at_namereads any keyword followed by:as a declaration name).feature()(crates/spar-parser/src/grammar/features.rs) now special-casesIN_KW/OUT_KWin the feature-name position, emittingwhile still consuming the token so the rest of the declaration parses and the tree round-trips (the reject is a diagnostic, not a rewrite). Scope is exactly the name position —
in/outin their legal roles (feature directionin/out/in out,in modes,in binding) and keyword-as-name for other keywords are untouched.Oracle & non-vacuity (executed, not asserted)
Inline in
crates/spar-syntax/tests/parser_tests.rs— no external tool needed:port_named_in_is_rejected,port_named_out_is_rejected— assert the diagnostic.port_named_in_still_round_trips— asserts losslessness.port_named_inp_outp_still_accepted— the discriminating partner: identical but for the port namesinp/outp(ordinary identifiers). It parses cleanly both before and after, so the check keys on the name being a reserved word and nothing else.Verified against the built test binary: before the fix all three rejection inputs parsed with zero errors; reverting the
features.rsbranch re-greens them, proving they bite.No regression to the graded conformance floor
osate_agreement.rs(too-permissive floor 53, too-strict 0) andthree_way_conformance.rsre-run and hold their ceilings — no first-party file flips verdict.FIRST_PARTY_MODELSunchanged (120); no vendored/first-party.aadlnames a featurein/out(grep -rniE '^[[:space:]]*(in|out)[[:space:]]*:' test-data/interop→ 0).cargo fmt --all -- --check,cargo clippy --workspace --all-targets -- -D warnings, and the fullspar-syntax/ corpus / roundtrip suites pass locally.Requirement & honest scope
Adds
REQ-PLUGFEST-PORTNAME-INOUT-001(implemented, traces-toREQ-PLUGFEST-006).Deferred, disclosed: the reverse-direction discipline pins such a rule with a
test-data/negative/**fixture carrying measured OSATE and Ocarina verdicts (the two graded baselines are asserted set-equal and must cover every first-party file). This automated environment has neither a downloaded OSATE nor Ocarina, and a baseline row must be measured, never assumed, so the corpus fixture + its two baseline rows are left to a run/maintainer with both oracles. The inline tests fully pin the behaviour meanwhile.Does not close #420 (many category-1 items remain), and does not claim
in/outis the last reserved word spar admits as an identifier — other name positions (subcomponent/connection) are not audited here.An independent clean-room subagent re-derived non-vacuity, scope, the graded invariants, the grep-0 corroboration, and the REQ's honesty — all PASS, no over-claim.
🤖 Generated with Claude Code
Generated by Claude Code