How Scenic is Compiled

The process of compiling a Scenic program into a Scenario object can be split into several phases. Understanding what each phase does is useful if you plan to modify the Scenic language.

For more details on Phases 1 and 2 (parsing Scenic and converting it into Python), see the Guide to the Scenic Parser & Compiler.

Phase 1: Scenic Parser

In this phase the program is parsed using the Scenic parser. The parser is generated from a PEG grammar (scenic.gram) using the Pegen parser generator. The parser generates an abstract syntax tree (Scenic AST) for the program. Scenic AST is a superset of Python AST defined in ast.py and has additional nodes for representing Scenic-specific constructs.

Phase 2: Scenic Compiler

In this phase, the Scenic AST is transformed into a Python AST. The Scenic Compiler walks the Scenic AST and replaces Scenic-specific nodes with corresponding Python AST nodes.

Phase 3: AST Compilation

Compile the Python AST down to a Python code object.

Phase 4: Python Execution

In this phase the Python code object compiled in Phase 3 is executed. When run, the definitions of objects, global parameters, requirements, behaviors, etc. produce Python data structures used internally by Scenic to keep track of the distributions, functions, coroutines, etc. used in their definitions. For example, a random value will evaluate to a Distribution object storing information about which distribution it is drawn from; actually sampling from that distribution will not occur until after the compilation process (when calling Scenario.generate). A require statement will likewise produce a closure which can be used at sampling time to check whether its condition is satisfied or not.

Note that since this phase only happens once, at compile time and not sampling time, top-level code in a Scenic program [1] is only executed once even when sampling many scenes from it. This is done deliberately, in order to generate a static representation of the semantics of the Scenic program which can be used for sampling without needing to re-run the entire program.

Phase 5: Scenario Construction

In this phase the various pieces of the internal representation of the program resulting from Phase 4 are bundled into a Scenario object and returned to the user. This phase is also where the program is analyzed and pruning techniques applied to optimize the scenario for later sampling.

Sampling and Executing Scenarios

Sampling scenes and executing dynamic simulations from them are not part of the compilation process [2]. For documentation on how those are done, see Scenario.generate and scenic.core.simulators respectively.

Footnotes