Reference

This is the complete reference for the IRIS language: formal grammar, every primitive opcode, effect tags, and the type system.

Grammar#

The IRIS surface syntax is defined in src/iris-programs/syntax/iris_parser.iris and src/iris-programs/syntax/iris_lowerer.iris, with pre-compiled pipelines in bootstrap/*.json.

Module Structure#

module       ::= capability_decl* item*
item         ::= let_decl | type_decl | import_decl

Capability Declarations#

capability_decl ::= 'allow' '[' cap_entry (',' cap_entry)* ']'
                  | 'deny'  '[' cap_entry (',' cap_entry)* ']'
cap_entry       ::= IDENT STRING_LIT?

Let Declarations#

let_decl     ::= 'let' ['rec'] IDENT param* [':' type] [cost_annot]
                 requires_clause* ensures_clause* '=' expr

param        ::= IDENT
cost_annot   ::= '[' 'cost' ':' cost_expr ']'
requires_clause ::= 'requires' expr
ensures_clause  ::= 'ensures' expr

Type Declarations#

type_decl    ::= 'type' IDENT ['<' IDENT (',' IDENT)* '>'] '=' type
               | 'type' IDENT ['<' IDENT (',' IDENT)* '>'] '=' sum_type
               | 'type' IDENT ['<' IDENT (',' IDENT)* '>'] '=' struct_type

sum_type     ::= variant ('|' variant)*
variant      ::= UPPER_IDENT ['(' type ')']
UPPER_IDENT  ::= [A-Z] [a-zA-Z0-9_]*

struct_type  ::= '{' field (',' field)* '}'
field        ::= IDENT ':' type

Sum type declarations automatically bind constructors. Red in type Color = Red | Green | Blue becomes a value; Some in type Option = Some(Int) | None becomes a function Some : Int -> Option.

Struct type declarations define named-field product types. type Point = { x: Int, y: Int } creates a type where .x resolves to .0 and .y to .1 at compile time. Struct types are sugar over tuples.

Import Declarations#

import_decl  ::= 'import' STRING_LIT 'as' IDENT
               | 'import' HEX_HASH 'as' IDENT
STRING_LIT   ::= '"' [^"]* '"'
HEX_HASH     ::= '#' [0-9a-f]+

Path-based imports use a string literal containing a file path, resolved relative to the importing file. Hash-based imports use a #-prefixed BLAKE3 hash to identify an immutable content-addressed fragment. Both forms bind the imported module’s top-level declarations (including ADT constructors) into the importing scope.

import "stdlib/option.iris" as Opt    -- path-based
import #abc123def456 as math          -- hash-based

Types#

type         ::= 'forall' IDENT '.' type
               | type_atom '->' type
               | type_atom

type_atom    ::= '(' ')'                          -- Unit
               | '(' type (',' type)+ ')'          -- Tuple
               | '(' type ')'                      -- Parenthesized
               | '{' IDENT ':' type '|' expr '}'   -- Refinement
               | '{' field (',' field)* '}'         -- Struct type
               | IDENT '<' type (',' type)* '>'    -- Parameterized
               | IDENT                              -- Named

Cost Expressions#

cost_expr    ::= 'Unknown' | 'Zero'
               | 'Const' '(' INT ')'
               | 'Linear' '(' IDENT ')'
               | 'NLogN' '(' IDENT ')'
               | 'Polynomial' '(' IDENT ',' INT ')'
               | 'Sum' '(' cost_expr ',' cost_expr ')'

See the Type System page for how types, costs, contracts, and effects interact.

Expressions#

Precedence (lowest to highest):

  1. let ... in, if ... then ... else, match ... with, \params -> body
  2. Pipe: |>
  3. Logical OR: ||
  4. Logical AND: &&
  5. Comparison: ==, !=, <, >, <=, >=
  6. Addition: +, -
  7. Multiplication: *, /, %
  8. Unary: - (negation), ! (logical not)
  9. Application: f x y (juxtaposition)
  10. Postfix: .0, .1, … (tuple access)
  11. Atoms: literals, variables, parenthesized, tuples
expr         ::= 'let' IDENT '=' expr 'in' expr
               | 'if' expr 'then' expr 'else' expr
               | 'match' expr 'with' match_arm+
               | '\' IDENT+ '->' expr
               | pipe_expr

pipe_expr    ::= or_expr ('|>' or_expr)*
or_expr      ::= and_expr ('||' and_expr)*
and_expr     ::= cmp_expr ('&&' cmp_expr)*
cmp_expr     ::= add_expr (cmp_op add_expr)?
add_expr     ::= mul_expr (('+' | '-') mul_expr)*
mul_expr     ::= unary_expr (('*' | '/' | '%') unary_expr)*
unary_expr   ::= '-' unary_expr | '!' unary_expr | app_expr
app_expr     ::= postfix_expr atom_expr*
postfix_expr ::= atom_expr ('.' (INT | IDENT))*

atom_expr    ::= INT | FLOAT | STRING | 'true' | 'false' | IDENT
               | '(' ')'                    -- Unit
               | '(' op ')'                 -- Operator section
               | '(' expr (',' expr)+ ')'   -- Tuple
               | '(' expr ')'               -- Parenthesized
               | '{' field_init (',' field_init)* '}'  -- Struct literal

field_init   ::= IDENT '=' expr

Match Arms#

match_arm    ::= '|' pattern '->' pipe_expr
pattern      ::= '_' | IDENT | INT | 'true' | 'false'
               | UPPER_IDENT ['(' pattern ')']    -- Constructor pattern

Constructor patterns like Some(v) or None destructure sum type values bound by type declarations. Patterns are tried top-to-bottom; the first matching arm is evaluated.

Match expressions work inside any expression context, including lambda bodies. This is essential for fold callbacks and higher-order functions:

let result = fold xs 0 (\acc x ->
  match classify x with
  | Positive(n) -> acc + n
  | Negative(n) -> acc - n
  | Zero -> acc)

Operator Sections#

(+)   -- \a b -> a + b
(*)   -- \a b -> a * b
(==)  -- \a b -> a == b

Lexical Elements#

Keywords#

let  rec  in  val  type  import  as
match  with  if  then  else
forall  true  false
requires  ensures
allow  deny

Operators#

+  -  *  /  %            -- Arithmetic
==  !=  <  >  <=  >=     -- Comparison
&&  ||  !                -- Logical
|>                       -- Pipe
->                       -- Arrow (types and lambdas)
\                        -- Lambda
.                        -- Tuple access

Literals#

FormTypeExamples
Decimal integerInt0, 42, -7
Decimal floatFloat643.14, 0.5, 1e10
Double-quoted stringString"hello", "foo\nbar"
Hex hashFragmentId#abc123def456
BooleanBooltrue, false

Primitive Opcodes#

All primitives are named functions resolved by the IRIS lowerer (src/iris-programs/syntax/iris_lowerer.iris). Each maps to a (opcode, arity) pair.

Arithmetic (0x00–0x09)#

NameOpcodeAritySemantics
add0x002a + b
sub0x012a - b
mul0x022a * b
div0x032a / b (integer division, errors on zero)
mod0x042a % b
neg0x051-a
abs0x061|a|
min0x072min(a, b)
max0x082max(a, b)
pow0x092a^b

Bitwise (0x10–0x15)#

NameOpcodeAritySemantics
bitand0x102Bitwise AND
bitor0x112Bitwise OR
bitxor0x122Bitwise XOR
bitnot0x131Bitwise NOT
shl0x142Shift left
shr0x152Shift right

Comparison (0x20–0x25)#

NameOpcodeAritySemantics
eq0x202a == b
ne0x212a != b
lt0x222a < b
gt0x232a > b
le0x242a <= b
ge0x252a >= b

Higher-Order (0x30–0x32)#

NameOpcodeAritySemantics
map0x302Apply function to each element
filter0x312Keep elements satisfying predicate
zip0x322Pair elements from two collections

Conversion (0x40–0x44)#

NameOpcodeAritySemantics
int_to_float0x401Int to Float64
float_to_int0x411Float64 to Int (truncate)
bool_to_int0x441Bool to Int (false=0, true=1)

Graph Introspection (0x80–0x8D)#

NameOpcodeAritySemantics
self_graph0x800Capture own SemanticGraph as a Program value
graph_nodes0x811List all node IDs in a graph
graph_get_kind0x822Get the NodeKind of a node
graph_get_prim_op0x832Get the opcode of a Prim node
graph_set_prim_op0x843Set the opcode of a Prim node (returns modified graph)
graph_add_node_rt0x852Add a new node at runtime
graph_connect0x864Add an edge between two nodes
graph_disconnect0x873Remove an edge
graph_replace_subtree0x883Replace a subtree in the graph
graph_eval0x892Evaluate a graph with given inputs
graph_get_root0x8A1Get the root NodeId of a graph
graph_add_guard_rt0x8B4Add a Guard node at runtime
graph_add_ref_rt0x8C2Add a Ref node at runtime
graph_set_cost0x8D3Set cost annotation on a node

Meta-Evolution (0xA0)#

NameOpcodeAritySemantics
evolve_subprogram0xA03Breed a sub-program satisfying given test cases

String Operations (0xB0–0xC0)#

NameOpcodeAritySemantics
str_len0xB01String length
str_concat0xB12Concatenate two strings
str_slice0xB23Substring (start, end)
str_contains0xB32Check if string contains substring
str_split0xB42Split string by delimiter
str_join0xB52Join strings with separator
str_to_int0xB61Parse string as integer
int_to_string0xB71Convert integer to string
str_eq0xB82String equality
str_starts_with0xB92Check prefix
str_ends_with0xBA2Check suffix
str_replace0xBB3Replace all occurrences
str_trim0xBC1Trim whitespace
str_upper0xBD1Convert to uppercase
str_lower0xBE1Convert to lowercase
str_chars0xBF1Split into character Tuple
char_at0xC02Get character at index

List/Collection Operations (0xC1–0xCD)#

NameOpcodeAritySemantics
list_append0xC12Concatenate two lists
list_nth0xC22Get element at index
list_take0xC32First N elements
list_drop0xC42Drop first N elements
list_sort0xC51Sort ascending
list_dedup0xC61Remove consecutive duplicates
list_range0xC72Generate range [start, end)
map_insert0xC83Insert key-value into State map
map_get0xC92Get value by key from State map
map_remove0xCA2Remove key from State map
map_keys0xCB1Get all keys as Tuple
map_values0xCC1Get all values as Tuple
map_size0xCD1Number of entries in State map

Data Access / Introspection (0xCF, 0xD2–0xD6)#

NameOpcodeAritySemantics
map_contains_key0xCF2Check if key exists in State map (returns Bool)
tuple_get0xD22Get field from tuple by string key or int index
str_from_chars0xD31Convert Tuple of char codes (Int) to String
is_unit0xD41Check if value is Unit (returns Bool)
type_of0xD51Return Int tag identifying Value variant (0=Int, 1=Float64, 2=Bool, 3=String, 4=Tuple, 5=Unit, 6=State, 7=Graph, 8=Program, 9=Thunk, 10=Bytes, 11=Range)
str_index_of0xD62Find first occurrence of substring, returns char index or -1

Math (0xD8–0xE3)#

NameOpcodeAritySemantics
math_sqrt0xD81Square root
math_log0xD91Natural logarithm
math_exp0xDA1Exponential (e^x)
math_sin0xDB1Sine
math_cos0xDC1Cosine
math_floor0xDD1Floor
math_ceil0xDE1Ceiling
math_round0xDF1Round to nearest
math_pi0xE00Pi constant
math_e0xE10Euler’s number
random_int0xE22Random integer in [min, max]
random_float0xE30Random float in [0, 1)

Lazy Lists (0xE9–0xEC)#

NameOpcodeAritySemantics
lazy_unfold0xE92Create lazy stream from step function and seed; returns Thunk
thunk_force0xEA1Force one step: returns (element, next_thunk) or Unit
lazy_take0xEB2Materialize first N elements from a Thunk into a Tuple
lazy_map0xEC2Lazily apply function to each element of a Thunk stream

Time & Bytes (0xE4–0xE8)#

NameOpcodeAritySemantics
time_format0xE42Format timestamp
time_parse0xE52Parse time string
bytes_from_ints0xE61Convert Tuple of ints to Bytes
bytes_concat0xE72Concatenate two Bytes
bytes_len0xE81Length of Bytes

Effect Tags#

Effects are performed through Effect nodes. In surface syntax, effect functions resolve to these tags.

Standard Effects (0x00–0x0D)#

TagNameSignature
0x00PrintValue -> Unit
0x01ReadLine() -> Bytes
0x02HttpGetString -> Bytes
0x03HttpPostString, Bytes -> Bytes
0x04FileReadString -> Bytes
0x05FileWriteString, Bytes -> Unit
0x06DbQueryString -> Tuple
0x07DbExecuteString -> Int
0x08SleepInt -> Unit
0x09Timestamp() -> Int
0x0ARandom() -> Int
0x0BLogString -> Unit
0x0CSendMessageString, Value -> Unit
0x0DRecvMessageString -> Value

Raw I/O (0x10–0x1F)#

TagNameSignature
0x10TcpConnectString, Int -> Int
0x11TcpReadInt, Int -> Bytes
0x12TcpWriteInt, Bytes -> Int
0x13TcpCloseInt -> Unit
0x14TcpListenInt -> Int
0x15TcpAcceptInt -> Int
0x16FileOpenString, Int -> Int
0x17FileReadBytesInt, Int -> Bytes
0x18FileWriteBytesInt, Bytes -> Int
0x19FileCloseInt -> Unit
0x1AFileStatString -> Tuple
0x1BDirListString -> Tuple
0x1CEnvGetString -> String
0x1DClockNs() -> Int
0x1ERandomBytesInt -> Bytes
0x1FSleepMsInt -> Unit

Threading & Atomics (0x20–0x28)#

TagNameSignature
0x20ThreadSpawnProgram -> Future
0x21ThreadJoinFuture -> Value
0x22AtomicReadString -> Value
0x23AtomicWriteString, Value -> Unit
0x24AtomicSwapString, Value -> Value
0x25AtomicAddString, Int -> Value
0x26RwLockReadString -> Value
0x27RwLockWriteString, Value -> Unit
0x28RwLockReleaseString -> Unit

JIT & FFI (0x29–0x2B)#

TagNameSignature
0x29MmapExecBytes -> Int
0x2ACallNativeInt, Tuple -> Int
0x2BFfiCallString, String, Tuple -> Value

Type System#

Primitive Types#

TypeDescription
Int64-bit signed integer
Nat64-bit unsigned natural number
Float6464-bit IEEE 754 floating point
Float3232-bit IEEE 754 floating point
BoolBoolean (true/false)
StringUTF-8 string
BytesByte vector
UnitUnit type (no value)

Composite Types#

TypeDefDescription
Product(Vec<TypeId>)Tuple / struct
Sum(Vec<(Tag, TypeId)>)Tagged union
Arrow(TypeId, TypeId, CostBound)Function with cost annotation
Recursive(BoundVar, TypeId)mu X. F(X) recursive type
ForAll(BoundVar, TypeId)Polymorphic type
Refined(TypeId, RefinementPredicate)Refinement type {x: T | P}
NeuralGuard(TypeId, TypeId, GuardSpec, CostBound)Neural computation type
Exists(BoundVar, TypeId)Existential type
Vec(TypeId, SizeTerm)Sized vector
HWParam(TypeId, HardwareProfile)Hardware-parameterized type

Algebraic Data Types#

Sum types are declared with type and define constructors that produce tagged values:

type_decl   ::= 'type' IDENT '=' constructor ('|' constructor)*
constructor ::= IDENT '(' type ')' | IDENT

Nullary constructors like None or Red are values. Constructors with a payload like Some(Int) are functions of type Int -> Option. Constructors are first-class: they can be passed to higher-order functions, returned from expressions, and used across import boundaries.

type Option = Some(Int) | None
type Color  = Red | Green | Blue

let colors = (Red, Green, Blue)
let wrapped = map (1, 2, 3) Some   -- (Some(1), Some(2), Some(3))

Struct Types#

Struct types are sugar over product types. A struct declaration assigns field names to tuple positions:

struct_type  ::= '{' field (',' field)* '}'
field        ::= IDENT ':' type

At compile time, struct construction { x = 3, y = 4 } becomes Tuple(3, 4), and field access .x resolves to positional .0. The runtime never sees field names, only tuples and integer projections.

type Point = { x: Int, y: Int }
let p : Point = { x = 10, y = 20 }   -- Tuple(10, 20)
let sum = p.x + p.y                   -- p.0 + p.1 → 30

Runtime Values#

VariantDescription
Int(i64)Integer
Nat(u64)Natural number
Float64(f64)64-bit float
Float32(f32)32-bit float
Bool(bool)Boolean
String(String)UTF-8 string
Bytes(Vec<u8>)Byte vector
UnitUnit value
Tuple(Vec<Value>)Tuple / list
Tagged(u16, Box<Value>)Tagged variant
State(StateStore)Key-value map
Program(Box<SemanticGraph>)Reified program (for self-modification)
Thunk(Arc<SemanticGraph>, Box<Value>)Lazy stream (step function + state)
Future(FutureHandle)Handle to concurrent computation