Values
The value domain, defined in
3.0-value.watsup,
is used throughout dynamic semantics rules. The overall structure mirrors
typeIR from Section 3.2: base values correspond to base
types, data values to struct and header types, and object values to object
types. Each category is described below.
Base Values
syntax integerValue = integerLiteral
syntax boolValue = _B bool
syntax matchKindValue = MATCH_KIND '.' nameIR
syntax baseValue =
| integerValue
| boolValue
| matchKindValue
Integer values reuse the surface-syntax integerLiteral, which carries both
a bit-width and a raw integer payload: 8 W 42 is the unsigned 8-bit value 42,
and 8 S 255 is the signed 8-bit value -1. For signed integers, the payload
is always a non-negative bit pattern in the range [0, 2^w); the
two’s-complement interpretation is applied by the arithmetic operations when
needed.
Bool values wrap a boolean with the _B tag.
Match-kind values are written MATCH_KIND . nameIR, where nameIR is the
member name, such as exact or lpm.
Data Values
syntax fieldValue = value nameIR ';'
syntax structValue = STRUCT typeId `{ fieldValue* `}
syntax headerValue = HEADER typeId `{ fieldValue* `}
syntax dataValue =
| structValue
| headerValue
Data values are the runtime counterparts of structTypeIR and headerTypeIR.
Each carries its type name (typeId) and a list of field values
(fieldValue*), where each field value pairs a runtime value with the field’s
name.
The structure is symmetric with the type representation. A structTypeIR holds
fieldTypeIR* (type-name pairs), and a structValue holds fieldValue*
(value-name pairs). This parallel makes field-level operations straightforward:
to read a field, scan the fieldValue* list for the matching nameIR; to write
a field, reconstruct the list with the updated entry.
Nano-P4 treats structs and headers identically at the value level. The distinction matters only for extern operations (such as packet extraction) and validity tracking, which are not part of the core evaluation rules.
Object Values
syntax packetValue = PACKET typeId objectState
syntax tableValue = TABLE nameIR tableProperties
syntax objectValue =
| packetValue
| tableValue
Object values represent runtime state for the two object kinds that appear inside a Nano-P4 program’s evaluation.
Packet values carry an objectState, whose type is declared
extern syntax. This means the spec gives the type a name but leaves its
concrete representation to the toolchain implementation. The spec only ever
passes objectState values through extern operations (See
Section 5.5: Call & Convention - Extern Method Call);
it never inspects or constructs one directly. The typeId identifies the packet
type name.
Table values carry the table’s nameIR and its tableProperties (the key
list and action list as loaded from the program). A tableValue is created when
a control’s local table declaration is evaluated and stored in the block frame.
When tbl.apply() is called, this value is retrieved and used to drive the
lookup, as we will see in Section 5.8.
Default Values
When a variable is declared without an initializer, the interpreter must produce
a well-typed initial value. The $default function maps a typeIR to the
canonical zero value for that type:
dec $default(typeIR) : value
def $default(BIT `< w `>) = w W 0
def $default(INT `< w `>) = w S 0
def $default(BOOL) = _B false
def $default(STRUCT typeId `{ fieldTypeIR* `})
= STRUCT typeId `{ fieldValue* `}
-- if (typeIR id ';' = fieldTypeIR)*
-- if (value = $default(typeIR))*
-- if (fieldValue = value id ';')*
def $default(HEADER typeId `{ fieldTypeIR* `})
= HEADER typeId `{ fieldValue* `}
-- if (typeIR id ';' = fieldTypeIR)*
-- if (value = $default(typeIR))*
-- if (fieldValue = value id ';')*
Unsigned integers default to w W 0, signed integers to w S 0, and booleans
to _B false. For structs and headers, $default recurses field by field: it
unpacks each fieldTypeIR into a (typeIR, id) pair, computes the default
value for that type, and reassembles the result as a fieldValue. The list
comprehension syntax (... = ...)* zips the three lists in lockstep.
Note that $default has no clause for object types. Tables and packets are
never declared with uninitialized values; they are always constructed explicitly
during loading or local declaration evaluation.