Loading Phase
Static semantics verifies that a program is well-typed and produces a
typingContext as its result. Dynamic semantics takes that context and
evaluates the program. The loading phase sits between them: it takes the
typingContext, processes each declaration to build a loadContext, and hands
the result to dynamic semantics.
Why is the loading phase necessary?
In full P4, the phase between type checking and execution is called
instantiation. Parsers, controls, and externs hold stateful components such as
register arrays, counter arrays, and tables. Writing MyParser() or
MyControl() does not just name a declaration; it allocates a live object with
its own private state. Instantiation is the pass that evaluates constructor
arguments, allocates those objects, and wires them together before any packet
arrives.
Nano-P4 has no stateful components, so true instantiation is unnecessary. But a
lighter version of the same idea is still needed: the evaluator must know which
callable bodies to invoke and which specific parser and control serve as the
entry point. Type checking is concerned with what something is, not what its
body looks like. By the time type checking finishes, the typingContext knows
that my_parser is a parser that accepts certain parameter types, but it does
not retain the body of my_parser for later execution.
The loading phase fills that gap. It walks the declarations a second time, pairs each callable body with the elaborated parameter types that type checking produced, and records which parser and control were chosen as the entry point.
What does the loading phase produce?
The loadContext holds three things that dynamic semantics needs:
CALLABLE: a map from callable identifiers to their elaborated definitions (callableDef). Each definition pairs a callable’s name and elaborated parameter list with its body, ready for the evaluator to invoke.PARSERandCONTROL: the specific parser and control declarations that were instantiated as the entry point of the NanoSwitch. Dynamic semantics starts execution from these two.
When make_evalContext is called at the start of dynamic semantics, it receives
both the typingContext (for type information) and the loadContext (for
callable bodies and entry points) and combines them into the evalContext used
throughout evaluation.
In this chapter
- Load Context: the
loadContexttype and its initialization - Loading Declarations: the rules that walk each declaration and populate the context