Skip to content

feat(dsl): movement actions, the map file and scena-run .osc (p8-s1) - #108

Merged
JArmandoAnaya merged 1 commit into
mainfrom
feat/p8-s1-actions-and-run
Aug 2, 2026
Merged

feat(dsl): movement actions, the map file and scena-run .osc (p8-s1)#108
JArmandoAnaya merged 1 commit into
mainfrom
feat/p8-s1-actions-and-run

Conversation

@JArmandoAnaya

Copy link
Copy Markdown
Contributor

Completes p8-s1: a DSL scenario now runs end to end.

scena-run cruise.osc --dt 0.01 --duration 12 --trace out/cruise.csv

§8.8 movement actions → IR actions

Seven have an unambiguous counterpart and lower; the runtime is the one both
frontends already share, so lowering decides only which IR action a DSL action
is.

§8.8 action IR action
assign_speed SpeedAction, Step
change_speed SpeedAction with the transition §8.8.2.18 asks for
remain_stationary SpeedAction to zero
assign_position TeleportAction to a WorldPosition
change_lane LaneChangeAction with a RelativeTargetLane
change_space_gap / change_time_gap LongitudinalDistanceAction

move, drive and walk carry no target of their own — they exist to be
shaped by §8.9 modifiers (p8-s3) — so on their own they lower to nothing.
Everything else in §8.8 is reported by name, never silently dropped.

Two readings the standard does not state, both recorded in ADR-0030:

  • dynamic_profile names a shape, rate_peak a magnitude, and neither is a
    duration.
    With no peak rate there is no number to ramp over, so the change
    is a Step (§7.4.1.2). asap is a Step from the other direction: §8.7
    declares no performance envelope, so "as soon as possible" is bounded by
    nothing.
  • change_lane needs an explicit left or right. §8.8.3.14's inside,
    outside and same need road geometry to say which way that is, and an
    unstated side would have to be chosen — which the determinism contract
    does not allow.

The do directive → a storyboard

One Story, one Act, one ManeuverGroup per phase — the group is where an actor
lives, so a group per phase keeps each invocation's actor with its actions.
serial chains a phase on its predecessor reaching completeState, which is the
trigger form §7.6.2.1.2's "starts when its predecessor ends" already has in the
runtime; parallel leaves the triggers absent (§7.6.1.1). one_of, nesting,
until, wait, emit, call and an invocation duration are reported and
belong to p8-s2.

The map file, and one resolution rule it needed

§8.5.4's map_file is read in both spellings the standard prints —
map.set_map_file("m.xodr") (Code 61) and keep(my_map.map_file == "m.xodr")
(Code 62) — and travels beside the IR in a LowerResult, mirroring
xml::Document. A road-network path is an input to the host, not kernel
state: the engine reaches roads only through IRoadQuery (ADR-0003).

The first spelling needed something the checker did not have: a bare actor
type name is a receiver in its own right.
map in Code 61 names the actor
type, because the road network is a singleton no scenario declares a field
for, and without that rule the standard's own concrete-scenario example
(Code 6) was rejected. A declared field of the same name still wins — the
receiver a reader means by a name is the declaration in front of them.

Struct-valued arguments

The DSL has no struct constructor: §7.2.2.6.7 declares list and range
constructors and nothing else. So assign_position(position: start) can only
name a declaration, and the keeps on it are where the numbers are — the same
binding table ADR-0030 already uses for an actor's own attributes, applied one
level further out. A coordinate nothing constrains is reported, not assumed.

scena-run runs .osc

The extension picks the frontend; everything past the load sees only the
Scenario IR, so the options, exit codes and trace format are unchanged.
--entry names the §7.7.2 entry point (a file with several scenarios is
reported, never guessed at) and -I adds an import search path.

Tests and docs

  • dsl_lowering_test.cpp 17 → 37: each action's mapping, the storyboard shape,
    both map-file spellings, and every deferral reported rather than dropped.
  • dsl_types_test.cpp +3: the actor-type receiver, a field shadowing it, and a
    non-actor type still getting the ordinary "that is a type, not a value".
  • scena_run_test.cpp +4: a .osc running end to end, --entry selection, a
    malformed .osc, and the DSL-named road network.
  • ADR-0030 gains decisions 6–8 and two rejected alternatives; the coverage
    matrix, the scena-run user guide and the DSL frontend README move with the
    code.
  • The parity audit now reads lower.h as well, so dsl::lower's missing
    binding is recorded with its reason instead of being invisible — the IR has
    no binding carrier until p8-s4 ([p8-s4] XML-DSL parity & DSL golden scenarios #47).

1366 gtest (+27), 194 pytest.

Closes #44

Completes p8-s1: a DSL scenario now runs end to end.

Seven §8.8 movement actions lower onto the runtime actions P2/P5 already
implement — assign_speed, change_speed, remain_stationary, assign_position,
change_lane, change_space_gap, change_time_gap. The generic move/drive/walk
carry no target of their own and lower to nothing, because they exist to be
shaped by §8.9 modifiers (p8-s3); every other §8.8 action is reported by name
rather than silently dropped.

The `do` directive becomes one Story, one Act and one ManeuverGroup per phase.
`serial` chains a phase on its predecessor reaching completeState (§7.6.2.1.2),
`parallel` leaves the triggers absent (§7.6.1.1); one_of, nesting, until, wait,
emit, call and an invocation duration are reported and belong to p8-s2.

§8.5.4's map_file is read in both spellings the standard prints —
`map.set_map_file("m.xodr")` (Code 61) and `keep(my_map.map_file == "...")`
(Code 62) — and travels beside the IR in a LowerResult, mirroring
xml::Document, because a road-network path is a host input and not kernel
state (ADR-0003).

The first spelling needed one resolution rule the checker did not have: a bare
actor type name is a receiver in its own right, since the map is a singleton no
scenario declares a field for. Without it the standard's own concrete-scenario
example (Code 6) was rejected. A declared field of the same name still wins.

scena-run picks its frontend from the extension: .osc goes to the DSL frontend,
everything else to XML, and past the load only the Scenario IR is visible.
--entry names the §7.7.2 entry point and -I adds an import search path.

ADR-0030 gains decisions 6-8; the coverage matrix, the scena-run user guide and
the DSL frontend README move with them. The parity audit now reads lower.h as
well, so dsl::lower's missing binding is recorded rather than invisible.

1366 gtest (+27), 194 pytest.
@JArmandoAnaya
JArmandoAnaya merged commit 6b4fae4 into main Aug 2, 2026
12 checks passed
@JArmandoAnaya
JArmandoAnaya deleted the feat/p8-s1-actions-and-run branch August 2, 2026 13:20
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.

[p8-s1] Lowering concrete scenarios to the IR

1 participant