Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ add_subdirectory(frontends/xml)
add_subdirectory(frontends/dsl)
add_subdirectory(roads/opendrive)
add_subdirectory(tools/scena-run)
add_subdirectory(tools/scena-check)

if(SCN_BUILD_CAPI)
add_subdirectory(capi)
Expand Down
3 changes: 3 additions & 0 deletions docs/user-guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ The user guide grows sprint by sprint along the
- [`scena-run`](scena-run.md) — the headless CLI: options and exit codes, the
round-trip-exact trace format, replaying a host-controlled entity, and the
golden suite harness.
- [`scena-check`](scena-check.md) — the OpenSCENARIO DSL checker: options and
exit codes, the diagnostic format, resolving imports and search paths, and
what "checked clean" does and does not cover.
- [Python quickstart](python.md) — installing, loading and running a scenario,
building one in memory, observing a run, driving entities from the host with a
`SimulatorGateway` subclass, the GIL and reentrancy policy, and the parity
Expand Down
122 changes: 122 additions & 0 deletions docs/user-guide/scena-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# `scena-check` — checking OpenSCENARIO DSL

`scena-check` loads an OpenSCENARIO DSL file, follows its imports, and reports
what the checker finds. It does not execute anything: DSL execution is a later
milestone, and a file that checks clean here is one the frontend understood, not
one that will necessarily run.

```
scena-check my_scenario.osc
```

```
my_scenario.osc: ok, 412 types across 3 files
```

## Options

| Option | Meaning |
| --- | --- |
| `-I`, `--search-path <dir>` | A directory to resolve module imports against. Repeatable; searched in the order given. |
| `--no-standard-library` | Do not load the bundled `osc.standard` library. |
| `--strict` | Exit non-zero when there are warnings, not only errors. |
| `--quiet` | Do not print diagnostics. |
| `-h`, `--help` | Usage text. |

## Exit codes

| Code | Meaning |
| --- | --- |
| `0` | The file checked. There may still have been warnings — see `--strict`. |
| `2` | The command line was wrong. |
| `3` | The source did not check: it has errors, an import did not resolve, or `--strict` was given and there were warnings. |
| `4` | The input could not be read. |

`3` and `4` are deliberately different. Scena's status model separates a defect
in the content from the host handing the library something it cannot use, and
the exit codes follow that line: a file full of type errors is your scenario's
problem, an unreadable path is your invocation's. A build script can act on the
difference.

## Diagnostics

One diagnostic per line, in the same shape [`scena-run`](scena-run.md) prints, so
a script that parses one tool's output can parse the other's:

```
error: my_scenario.osc:14:9: unknown type 'vehicel' (§7.7.4.2)
warning: my_scenario.osc:31:5: this constraint needs a solver; v0.0.1 resolves fixed values only (§7.3.11, ADR-0004)
```

The file is always named, including for a diagnostic that came from an imported
file rather than from the one you passed — a program spans every file its root
imported, so a line number on its own would not locate anything.

Every diagnostic cites the section of the standard it comes from. Unlike the XML
frontend's, a DSL diagnostic carries no bracketed rule identifier: the DSL
standard defines no `asam.net:` rule ids, so the section reference in the message
is the citation.

Error recovery is contractual. A malformed declaration does not cost its
siblings, so one run reports as much as it can rather than stopping at the first
problem.

## Imports

Both of the reference forms in the standard work.

A **file reference** is resolved relative to the file that wrote it:

```
import "shared/common.osc"
```

A **module reference** maps `a.b.c` to `a/b/c.osc` and is looked for under each
`--search-path`, in the order you gave them:

```
import shared.common
```

```
scena-check main.osc -I ./lib -I ./vendor/lib
```

A file referenced twice is imported once, keyed on its canonical path. A diamond
therefore declares its shared types once, and an import cycle terminates instead
of erroring.

References beginning with `osc` are reserved by the standard and never reach the
search path; an unknown one is reported rather than looked up as a module of
yours.

## The standard library

The `osc.standard` library is bundled — it is not files on disk, so there is
nothing to install or point at. Its physical types are available without an
import, because they are what gives a literal like `30kph` a type at all; the
domain model needs an explicit import:

```
import osc.standard.all
namespace demo use std, stdtypes

scenario overtake:
ego: vehicle
target: lane
keep(target.lane_type == lane_type!driving)
keep(target.width == 3.5m)
```

`--no-standard-library` turns even the implicit part off, which is useful when
checking a file that is meant to stand alone.

## What "checked clean" covers

The checker resolves names, types every expression, and validates constraints
and coverage declarations against the standard's rules. Constraints it cannot
resolve to fixed values are reported as warnings rather than errors — solving
them needs a constraint solver, which is out of scope for v0.0.1 — so a clean
exit means "well-formed and understood", not "solved".

Run with `--strict` in CI if you want those warnings to fail the build.
4 changes: 4 additions & 0 deletions frontends/dsl/include/scena/dsl/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ struct ExpressionContext {
/// The namespace the expression was written in, for resolving type names in
/// `is()`, `as()` and enum references.
std::string name_space;
/// The source file the expression was written in. A `Program` spans every
/// file its root imported, so a line number alone does not locate a
/// diagnostic — `scena-check` needs the file to point at.
std::string file;
/// The namespaces the enclosing `namespace ... use` clause makes visible.
std::vector<std::string> uses;
/// Names bound by the construct the expression sits in rather than by the
Expand Down
Loading
Loading