Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.