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

Variable Declarations

VarDecl ::= ident ':' Type ';'
Type    ::= BaseType ('[' ArrayLen ']')?
BaseType ::= PrimitiveType | StructName

A variable declaration introduces one named value at PD-global scope or inside an event body. The ident: Type; form is the only shape supported today; an initialiser (ident: Type = expr;) is reserved but not yet parsed.

🚧 Initialiser syntax (= expr) is reserved but unparsed — see #105. For now, initialise locals from inside the body, and globals from the imported source’s init() function (see Boot Initialisation).

Scopes

Variables can appear in three positions inside a .fi file:

  • Global — at the top level of the file, alongside Mapping and import declarations. Globals are visible everywhere in the PD, read/write inside event bodies.
  • Event local — inside a computation event body, from its declaration to the end of the event (the next top-level item, since there is no explicit terminator keyword).
  • Process variable — inside a process body: a parameter (proc Drain(pkt: Slot), read-only, in scope for the whole body), a declaration x: T; (in scope for the rest of its sequence), or a receive binder c?x (in scope for the rest of its prefix).

A name in a body is looked up among that body’s own variables first, then the program’s globals, then the system’s constants:

body variable → global → constant

Event and process variables never see each other: a process value reaches an event only as a carrier. Shadowing a global, a mapping or a constant is a warning; declaring a name twice in one body while the first is still in scope is an error. Carriers are read-only — see Event Declarations.

Primitive types

The primitive types accepted in declarations are:

GroupTokens
Signed integersint, int8, int16, int32, int64
Unsigned integersuint, uint8, uint16, uint32, uint64
Booleanbool
Byte aliasbyte (8-bit)
AddressAddress

int and uint are aliases of int64 and uint64 on every target. byte is an alias for uint8. There is no void type — every declared variable has a concrete, storable type.

Struct types and arrays

pkt: Slot           // user-defined struct — declared in the .fis data layer
buf: uint8[16]       // fixed-size array — length is a literal or const name

Any identifier that isn’t a recognised primitive keyword is treated as a struct type name, resolved against the .fis struct declarations during name resolution (unknown names are rejected there, not at parse time). Fiducia has no pointer types — there is no ptr<T> syntax.

Examples

// Global declarations, top of a .fi file.
counter: int;
ready: bool;
last_irq_ts: uint64;

// Local declarations inside an event body.
evt handle_packet.|size: int|:
    local_buf: uint8[64];     // local
    ok: bool;                 // local
    local_buf = eth.alloc();  // assignment uses globals/locals/carriers

Validation

  • A variable name is unique within its enclosing scope (multiple globals with the same name are rejected; a body variable may shadow a global, with a warning).
  • The type must be a recognised primitive, Address, a fixed-size array of one, or a struct name that resolves to a real .fis struct declaration.