Skip to content

feat(dsl): scena-check, the DSL checking CLI (p7-s5) - #104

Merged
JArmandoAnaya merged 1 commit into
mainfrom
feat/p7-s5-scena-check
Aug 2, 2026
Merged

feat(dsl): scena-check, the DSL checking CLI (p7-s5)#104
JArmandoAnaya merged 1 commit into
mainfrom
feat/p7-s5-scena-check

Conversation

@JArmandoAnaya

Copy link
Copy Markdown
Contributor

First half of slice 43i. tools/scena-check — load a .osc file, follow its
imports, report what the checker finds.

$ scena-check my_scenario.osc
my_scenario.osc: ok, 412 types across 3 files

A thin consumer of scena::dsl::check_file with no language semantics of its
own. It links the DSL frontend alone: checking a DSL file needs no engine, no
road backend and no XML frontend.

Exit codes

0 ok, 2 usage, 3 the source did not check, 4 the input could not be
read.

3 and 4 are deliberately distinct. Scena's status model separates a defect
in the content from the host handing the library something unusable, and the
exit codes follow that line — a file full of type errors is the scenario's
problem, an unreadable path is the invocation's, and a build script can branch
on which.

A diagnostic gap the CLI made obvious

Resolver and expression diagnostics carried a line and a column but no file.
That is fine inside a test that checks one string, and useless in a checker: a
Program spans every file its root imported, so a diagnostic from an imported
file was indistinguishable from one in the file you passed.

Scope and ExpressionContext now carry the source file; the three resolver
emitters and expression typing's fail stamp it. dsl_import_test.cpp gains
ADiagnosticNamesTheFileItCameFrom, which builds a two-file program with an
error in each and asserts both that no diagnostic has an empty file and that
each names the right one.

This is why the slice was worth splitting — the gap is only visible once
something has to print the diagnostics for a human.

Tests

18 subprocess cases, reusing scena-run's harness with its portability fixes
intact: the cmd.exe outer-quote wrapping and the POSIX exit-status unpacking.
They cover every exit code, the diagnostic shape and position, search-path
ordering (two copies of a module, resolved differently depending on -I
order), file and module imports, --strict promoting a warning, --quiet
staying silent while still exiting non-zero, --no-standard-library, the three
usage errors, multi-diagnostic recovery, and byte-identical output across two
runs.

One pins something specific to this frontend: a DSL diagnostic prints no
bracketed rule id, because the DSL standard defines no asam.net: rule
identifiers. The section reference in the message is the citation.

1304 gtest (+19: 18 CLI + 1 import), 184 pytest.

Docs: docs/user-guide/scena-check.md and an index entry.

What is left on #43

43i-2: the C ABI scn_check_dsl, the Python check_dsl, the parity audit
update and an example. That PR carries Closes #43.

Refs #43

Adds `tools/scena-check`: load a .osc file, follow its imports, report what
the checker finds. A thin consumer of `scena::dsl::check_file` with no
language semantics of its own, linking the DSL frontend alone — checking a
DSL file needs no engine, no road backend and no XML frontend.

Options: -I/--search-path (repeatable, searched in order),
--no-standard-library, --strict, --quiet. Exit codes follow scena-run's
convention and the Status model's own split: 0 ok, 2 usage, 3 the source did
not check, 4 the input could not be read. A defect in the content and the host
handing us something unusable are different failures, and a build script can
act on the difference.

Diagnostics print in the same one-per-line shape scena-run uses, so a script
that parses one tool's output can parse the other's. A DSL diagnostic prints
no bracketed rule id, because the DSL standard defines none — the section
reference in the message is the citation, and a test pins that no rule id
appears.

Fixes a diagnostic gap the CLI made obvious: resolver and expression
diagnostics carried a line and column but no file. A Program spans every file
its root imported, so a line number alone does not locate anything — a
diagnostic from an imported file was indistinguishable from one in the file
you passed. `Scope` and `ExpressionContext` now carry the source file, the
three resolver emitters and expression typing's `fail` stamp it, and
`dsl_import_test.cpp` pins that a two-file program attributes each diagnostic
to the file it came from.

Tests drive the built binary as a subprocess, reusing scena-run's harness with
its portability fixes intact: the cmd.exe outer-quote wrapping and the POSIX
exit-status unpacking. 18 cases covering the exit codes, the diagnostic shape
and position, search-path ordering, module and file imports, --strict,
--quiet, --no-standard-library, the usage errors, multi-diagnostic recovery,
and determinism of the output.

Docs: docs/user-guide/scena-check.md and an index entry.

1304 gtest (+19), 184 pytest.

Refs #43
@JArmandoAnaya
JArmandoAnaya merged commit 203f44e into main Aug 2, 2026
12 checks passed
@JArmandoAnaya
JArmandoAnaya deleted the feat/p7-s5-scena-check branch August 2, 2026 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant