feat(dsl): lower a checked DSL program to the Scenario IR (p8-s1) - #107
Merged
Conversation
.osc in, entities out. Lowering decides which DSL construct denotes which IR construct and nothing else — runtime semantics stay in the runtime, which both frontends share. Entry point (§7.7.2, implementation-defined by the standard's own words): named by qualified name or as written; a root file declaring exactly one scenario uses it without being asked, and a file declaring several is an error listing them, because guessing would make the run depend on declaration order. Participants: every entry-scenario field whose type derives from std::physical_object becomes one entity, in declaration order. vehicle/person/stationary_object classify onto the p2-s1 taxonomy; §8.7.10's animal has no counterpart there and stays unclassified rather than being misfiled as a pedestrian. Concrete values: keep(<field-path> == <constant>) in either operand order, plus §7.3.8.2 conditional inheritance. Values arrive already folded to base units, so lowering never converts — re-applying the standard's printed factors a second time is the bug ADR-0029 exists to prevent. §8.7 declares no performance limits at all, so the IR's zeros are the faithful lowering: the runtime already reads a non-positive limit as unconstrained. No numbers are invented. ADR-0030. 17 tests in dsl_lowering_test.cpp, including that lowering the same source twice gives bit-identical geometry — load time is inside the determinism contract. Refs #44 Also fixes a pre-existing bug the lowering surfaced: constant evaluation resolved `enum-name!member` only in the current namespace, never through the use list (§7.7.4.2). A scenario in `namespace demo use std` writing `vehicle_category!bus` therefore could not fold it, which silently made every enum-valued `keep` look like one that needs a solver — including in the checker's own constraint classification. Refs #44
MSVC's C4456 is a warning-as-error in CI: the inner optional in the conditional-inheritance branch reused the outer one's name. Refs #44
7 tasks
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.
The first half of p8-s1:
.oscin,ir::Scenarioout.frontends/dsl/lower.hturns a checked program into entities the existing engine accepts.
Lowering decides which DSL construct denotes which IR construct and nothing
else. Runtime semantics stay in the runtime, which both frontends share — the
architecture's rule, and the reason this is a small file.
Three decisions (ADR-0030)
The entry point is named, and a lone scenario names itself. §7.7.2 says
outright that selection "is defined by implementation", and that the latitude is
deliberate.
LowerOptions::entry_pointtakes a qualified name (demo::overtake)or the name as written. Empty means the root file's only scenario; a file
declaring several is an error that lists them. Guessing would make the run depend
on declaration order — exactly the hidden input the determinism contract exists
to remove.
entry_points()returns the same list, in declaration order, becausethat is what the file offers and a reader matches it against the file in front
of them.
A participant is a field deriving from
std::physical_object. §8.7 roots itsactor hierarchy there.
vehicle/person/stationary_objectclassify ontoADR-0010's taxonomy; anything else deriving from
physical_objectstays anunclassified participant. That last row is the interesting one: §8.7.10's
animalis a sibling actor, not a pedestrian category, and XML has nowhere toput it. An identity and a control mode is all the runtime needs of it, and a
wrong classification would be worse than none.
Concrete means
keep(field == constant). Either operand order, constant sidefolding without a solver — that is what §6.3.1.2.1's "attribute-level concrete"
means, and it is the only shape whose meaning is unambiguous without search.
§7.3.8.2's conditional inheritance (
inherits vehicle(vehicle_category == car))is read the same way, since that is the spelling §8.7's own examples use.
Two things this deliberately does not do:
physical value arrives in its base unit. Re-applying §8.14.1.3's printed
factors a second time is precisely the bug ADR-0029 exists to prevent.
the domain model has no counterpart to XML's
Performance. The IR's zeros arethe faithful lowering, because the runtime already reads a non-positive limit
as "unconstrained" (
actor_max_speed). A category nothing fixes keepsir::Vehicle's own default rather than a guess made here.A pre-existing bug this surfaced
Constant evaluation resolved
enum-name!memberonly in the currentnamespace, never through the use list (§7.7.4.2). A scenario in
namespace demo use stdwritingvehicle_category!buscould not fold it — andbecause the checker classifies constraints by whether they fold, every
enum-valued
keepwritten that way was reported as needing a solver. It wasinvisible until something had to read those values.
Fixed in
expression.cppwith the ordinary lookup order (explicit::, then thecurrent namespace, then the use list), and pinned in
dsl_expression_test.cpp.This is why the vehicle-category tests here are meaningful rather than vacuous.
Tests
dsl_lowering_test.cpp(17): entry-point selection in all four shapes, thetaxonomy mapping including the unclassified case, geometry and category binding
from both operand orders, a value written in
cmarriving in metres, theperformance-is-unconstrained rule, the empty-scenario warning, and that lowering
the same source twice gives bit-identical geometry — load time is inside the
determinism contract.
dsl_expression_test.cpp(+1) for the enum-lookup fix.1339 gtest (+18), 194 pytest.
What is left of p8-s1
The §8.8 movement-action subset,
set_map_file→ road backend, andscena-runaccepting
.osc. Split off because this half stands on its own and is worthreviewing on its own: it is where the mapping decisions live, and the action
subset is mechanical once they are settled.
Refs #44