Envzn Intermediate Representation (EvIR) — Specification and Lowering

Generated — do not edit by hand. This document is produced by a generator from the compiler's own spec-trace, which it emits as it traces every construct. Regenerate after any trace change; the companion ENVZN_CONSTITUTION.md (Article II) summarises it and must stay in sync.

Envzn compiles through its own intermediate representation, the EvIR. The front end tokenizes and parses source into an AST and analyzes it; the analyzed tree is then built into EvIR nodes (build_ir), and the EvIR is lowered to C++20 (compiler/evir/emitter.py), which clang++ turns into a native executable. Section A specifies the EvIR node set in fourteen logical groups; Section B records how each node lowers to C++, covering all 531 traced mappings.


Section A — The EvIR

The node set of the Envzn intermediate representation, grouped by role. Every concrete node defined in compiler/evir/nodes.py appears in exactly one group; the abstract roots IrExpr and IrStmt are category framing, not elements.

Part A.i — Literals and constants

The leaf value nodes — the constants a program writes directly. Each carries its resolved type and lowers to the corresponding C++ literal or kernel value; the absence leaves (EMPTY, none) carry no payload and stand for an unoccupied class or pipe slot.

Part A.ii — References and access paths

The nodes that name an existing value rather than compute a new one — reads of locals, the receiver, data fields, and indexed elements. Each resolves to a place the surrounding node reads from or writes to, and the access form (owning handle, borrow, value-array slot) decides how it lowers.

Part A.iii — Operators and conversions

Computation over values: the arithmetic, comparison, bitwise, and logical operators, and the explicit AS / INTO conversions together with the CONVERSIONS hosts that define them. Conversions are always explicit and checked; there is no implicit cast.

Part A.iv — Calls, construction, and lambdas

The nodes that invoke behaviour or build instances — resolved method and static calls, heap construction through INIT and SUPER, and lambdas. Overload resolution is settled before lowering, so each call node already names its concrete target.

Part A.v — Bindings and assignment

The nodes that introduce or update storage. The binding operator carried by each one — copy, move, or non-owning reference — is part of its meaning and decides whether the right-hand value is copied, moved, or borrowed as it lowers.

Part A.vi — Control flow

The structured-control nodes — blocks, conditionals, loops, MATCH, and compile-time type narrowing — together with the clause and arm components they are built from. Control flow is always reducible; there is no arbitrary jump.

Part A.vii — Returns and expression statements

How a method hands values back and how an expression runs for its effect. The return nodes carry the single-, comma-, and pipe-XOR-shaped results, applying any required clone or move as the value leaves the callee.

Part A.viii — Recoverable failure and presence

The STATUS / pipe-XOR machinery and the presence tests. These nodes express the language's recoverable-failure vocabulary — consuming a pipe-XOR call in an IF or WHILE, reading its success or failure slots, and testing STATUS or class-value presence — kept strictly apart from the unrecoverable path.

Part A.ix — Unrecoverable failure and assertions

The PANIC / RECOVER path for unrecoverable error, and the ASSERT family for programmer-error checks that halt. Distinct from the recoverable STATUS vocabulary of the previous group: these unwind or abort rather than return a value.

Part A.x — Concurrency

The structured-concurrency nodes: the CONCURRENT scope that joins before it unwinds, the PARALLEL task launched within it, and the SYNCHRONIZED critical section. Each lowers onto the C++ threading runtime with its lifetime guarantees intact.

Part A.xi — Program structure

The declaration nodes that give a module its shape — classes, namespaces, interfaces, structs, groups, enums — and the members within them: methods, signatures, parameters, and fields. These are the top-level nodes a module is a sequence of.

Part A.xii — Foreign and unsafe

The typed foreign-function boundary and the UNSAFE gate around raw-handle access. The FOREIGN and BIND nodes reach genuine C symbols with their types stated; UNSAFE marks the only scope in which a raw foreign handle may be read.

Part A.xiii — Debug instrumentation

The debug-only capture nodes. They are present in the IR under a debug build and elided otherwise, and never change the meaning of the program they observe.

Part A.xiv — Types and lifetime

The type representation every node carries, and the scope-exit destruction markers that drive deterministic cleanup. ResolvedType is the resolved type a node was given by the analyzer; IrDrop records where an owned value's life ends on the NORMAL path, and IrCleanupPad records the same for the EXCEPTIONAL one.


Section B — Lowering EvIR to C++

How each EvIR node lowers to C++20, organised by the same fourteen groups. Each row is one traced mapping from that spec-trace: the node, the variant or concept that distinguishes it, the C++ shape it emits, and the governing constitution reference. Structural sub-nodes (clauses, arms, slots) carry no standalone lowering and are noted inline under their parent group.

Part B.i — Literals and constants

IrIntLit — an integer literal, typed by the analyzer (the context-free default is int64)

Variant / concept C++ lowering Const.
integer literal 5 I.D.ii
int literal 128bit (((unsigned __int128)68719476736ull << 64) \| (unsigned __int128)0ull)
int literal plain 1234
int literal unsigned ull 9223372036854775808ull

IrFloatLit — a floating-point literal (default float64)

Variant / concept C++ lowering Const.
float literal 3.5 I.D.ii
float literal 1.41

IrBoolLit — a boolean literal — TRUE or FALSE

Variant / concept C++ lowering Const.
boolean literal true I.D.i, I.C
bool literal false U'\n'
bool literal true true

IrCharLit — a char32 code-point literal

Variant / concept C++ lowering Const.
char literal U'x' I.D.i, I.C
char literal escape U'z'
char literal printable U'A'
char literal universal U'A'

IrStringLit — an interned immutable String literal

Variant / concept C++ lowering Const.
string literal ENVZN::_ValueArray<char32_t>{0x68, 0x69} I.D.vii, I.C
string literal make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0xA})
string literal empty make_ev_unique<String>(ENVZN::_ValueArray<char32_t>())

IrArrayLit — an array literal, [a, b, c]

Variant / concept C++ lowering Const.
array literal ENVZN::_ValueArray<T>{ <e0>, <e1>, ... }

IrStatusLit — a STATUS literal — SUCCESS, PARTIAL_SUCCESS, or FAILURE(message, code)

Variant / concept C++ lowering Const.
cstring literal "boom"
status message _STATUS_FAILURE("oops")
status msg encode ENVZN::_utf8_from_string(this->failReason)
status msg pipe move std::move(std::get<1>(__pipe_1).message)
status success _STATUS_SUCCESS()
status with code _STATUS_FAILURE("boom", 42)
status empty message _STATUS_SUCCESS()

IrEmpty — the EMPTY absence value of a class-typed slot

Variant / concept C++ lowering Const.
empty literal {}

IrNone — the none value of an unoccupied pipe / optional slot

Variant / concept C++ lowering Const.
none literal nullptr

Defined in the IR, lowering not yet spec-traced (node present in compiler/evir/nodes.py; see compiler/evir/emitter.py for current emission): IrBinaryLit.

Part B.ii — References and access paths

IrVarRef — a read of a local, parameter, or constant

Variant / concept C++ lowering Const.
rvalue read of var n I.F, I.F.i
constant field scalar static constexpr double ZERO = 0.0;
constant field string inline static const String GREETING{ENVZN::_ValueArray<char32_t>{0x68, 0x65, 0x6C, 0x6C, 0x6F}};
constant field value array static constexpr ENVZN::_ValueArrayConst<uint8_t, 6> masks = {{ 255, 127, 63, 31, 15, 7 }};
constant value float32 suffix 3.14f
constant value float64 int promote 0.0
constant value string codepoints 0x68, 0x65, 0x6C, 0x6C, 0x6F
constant value struct braceinit {4, Stage::END}
field enum case State::END
kernel foreign constant const int32_t _ev_fbc_F_OK = F_OK;
varref constant qualified Math::PI
varref narrowed handle joined
varref plain pDay
constant value float32 int promote result
constant value string empty result
enum bare result
struct nested enum result
varref narrowed optional class result
varref narrowed value optional result

IrSelf — the receiver SELF inside a method

Variant / concept C++ lowering Const.
self ref this

IrFieldRead — a data-field read through . (owning, reference, or chain receiver)

Variant / concept C++ lowering Const.
chain receiver owning field (*this->left)
chain receiver reference field (*this->src)
field array capacity (scratch.capacity())
field array length (f.length())
field constant qualified Constants::ANSWER
field foreign constant _ev_fbc_SOCK_STREAM
field foreign handle (p)->ai_next
field recv pointer deref strip this->inner->v
field self this->s
field text length (url->length())
field value q.key
field var pointer h->key

IrIndex — an indexed access coll[i] over an array, value-array, or collection

Variant / concept C++ lowering Const.
chain receiver handle storage (*got)
index default s[t]
index fixed array sbo[0]
index op index b->__op_index__(i)
assign from index move this->data[index]
index array subscript this->data[index]
index pipe slot error this->data[index]
index text op index this->data[index]

IrMultiIndex — a dense N-D subscript a[i, j, …] — fused column-major access on the EvNdArray companion; the element may be an OBJECT, whose cell is an owning handle

Variant / concept C++ lowering Const.
ndarray a(i, j) I.J

Part B.iii — Operators and conversions

IrBinary — a binary operator — arithmetic, comparison, bitwise, shift, or BEQUALS

Variant / concept C++ lowering Const.
binary bit equals float64 (std::bit_cast<uint64_t>(a) == std::bit_cast<uint64_t>(c))
binary bitwise shift (a & b)
binary default (i + a)
binary floordiv ENVZN::_ev_floordiv<int32_t>(7, 2)
binary lrotate std::rotl(x, k)
binary operator method dispatch _ev_unique<ENVZN::TimeDuration>(a->__op_plus__(b))
binary set algebra rewrap _ev_unique<Set<int32_t, _ev_unique<DefaultHasher<int32_t>>>>(a->unionWith(b))
power float pow std::pow(static_cast<double>(2), static_cast<double>((-1)))
power integer ipow ev_ipow(static_cast<int32_t>(3), static_cast<int32_t>(2))
value operand handle deref (*x)
value operand subscript cast static_cast<double>(f[0])
binary bit equals float32 (this->length + 1)
binary bit equals int (this->length + 1)
binary coalesce (this->length + 1)
binary coalesce empty (this->length + 1)
binary hash combine (this->length + 1)
binary rrotate (this->length + 1)
binary set algebra (this->length + 1)
binary wrapping ev_wrapmul_u64(a, b) I.F.ii(a.iv)

IrUnary — a unary operator — negate, NOT, BNOT, factorial, increment/decrement

Variant / concept C++ lowering Const.
unary bitwise not (~a)
unary default (-7)
unary factorial ev_factorial(5)
unary postdecrement (i--)
unary postincrement (i++)
unary preincrement (++i)
unary predecrement (!(i == j))

IrConvert — an AS / INTO conversion at a use site

Variant / concept C++ lowering Const.
conv fn pipe slot bool value{};
convert class wrap _ev_unique<String>(CharConverter::_cv_into__char8__String(c8))
enum to int cast static_cast<int32_t>(cat)
convert no conversion _ev_unique<String>(NumberConverter::_cv_into__int32__String(index))
complex ComplexConversions::_cv_into__complex__float64(realC) I.D.viii, I.D.i(g)
complex _ev_unique<String>(ComplexConversions::_cv_into__complex__String(pc)) I.D.viii
number NumberConversions::_cv_as__number__int32(n7) I.D.viii

IrPrimCast — a primitive numeric cast (static_cast<T>) — the int/float-arm coercion behind number construction and widening

Variant / concept C++ lowering Const.
number int static_cast<int64_t>(3) I.D.i(g)

IrCoerce — an IMPLICIT scalar conversion the analyzer admitted, stated on the IR (Phase 4d.1) — kind (compiler.coercion.CoerceKind) names WHICH clause (widen, reinterpret, a provably-safe narrow, an octet range check or offset shim, a folded constant) admitted the crossing with no explicit AS/INTO

Variant / concept C++ lowering Const.
widen {value} (WIDEN/REINTERPRET/NARROW_*/CONST_FITS into a non-binary dest, bare — 4d.1 identity lowering); a binary dest: static_cast<binary>(… I.F / I.D.i(c.i) / §28.3

IrConversions — a CONVERSIONS host declaring the AS/INTO operators for a type

Variant / concept C++ lowering Const.
conversions host namespace ProbeConv { /* AS/INTO operator free functions */ } I.D.viii

IrConversionOp — a single AS or INTO operator definition

Variant / concept C++ lowering Const.
conversion operator String into_String(Color v) { ... } // free fn in host namespace I.D.viii

IrOpaqueOp — an opaque[T]->wrap / ->unwrap static-dispatch operation

Variant / concept C++ lowering Const.
opaque wrap _opq_wrap<int32_t>(n) // payload boxed behind void* I.D.v

Defined in the IR, lowering not yet spec-traced (node present in compiler/evir/nodes.py; see compiler/evir/emitter.py for current emission): IrDuplicate, IrGetPointee, IrAddressOf, IrDeref, IrElementRef, IrRefOf, IrPipeSlotRef, IrMutRefCast, IrWeakLock.

Part B.iv — Calls, construction, and lambdas

IrCall — a method or namespace/static call, overload resolved by argument types

Variant / concept C++ lowering Const.
call arg handle deref *pk2
class return wrap _ev_unique<String>(clone())
foreign arg opaque array (void*)((sniHost).data())
foreign arg passthrough R_OK
foreign arg string reinterpret_cast<const char*>(ENVZN::_utf8_from_string(s).data())
foreign arg unsafe handle static_cast<void*>(this->native)
foreign arg value array (hay).data()
foreign bind arg load outparam &res
foreign bind arg opaque peek _opq_peek<SSL*>(this->ssl)
foreign bind call load buffer ([&]() -> int32_t { int32_t _tmp_0_cap = (slot).capacity(); char8_t* _tmp_0 = new char8_t[_tmp_0_cap]; int32_t _r = ::read(0, _tmp_0, 1); …
foreign bind call plain ::cos(x)
foreign bind call string callee owned ([&]() -> _ev_unique<String> { const char* _r = ::gai_strerror(rc); return _r ? ENVZN::_string_from_utf8(_r) : _ev_unique<String>(); }())
foreign bind call string caller owned ([&]() -> _ev_unique<String> { const char* _r = ::ev_path_list_dir(reinterpret_cast<const char*>(ENVZN::_utf8_from_string(this->value).dat…
method inline splice ({ auto&& _inl_101_recv = (data); (_inl_101_recv->_data); })
method inline trailing move (std::move(_inl_3_v));
method inline void guard (void)0;
methodcall arg adopt clone _ev_adopt_clone<_ev_unique<HttpHeader>>(hc->clone())
methodcall arg constref clone _ev_unique<Person>(p->clone())
methodcall arg move std::move(a)
methodcall arg template move std::move(w)
methodcall array clear this->data.clear()
methodcall array length (r6.length())
methodcall array remove arr.remove(0)
methodcall conversion helper isDigit(c)
methodcall conversion helper class wrap _ev_unique<String>(decimalDigits(v))
methodcall cxx member this->native.join()
methodcall format arg class tostring _ev_unique<String>((bob) ? (bob)->toString() : ENVZN::_string_from_utf8("EMPTY").release())
methodcall format arg dynbytebuffer _ev_unique<ByteBuffer>((dbb).toByteBuffer())
methodcall format arg dynstring _ev_unique<String>((name).toString())
methodcall format arg unrenderable ENVZN::_string_from_utf8("[??]")
methodcall namespace IntUtil::square(7)
methodcall namespace class wrap _ev_unique<String>(IntUtil::label(42))
methodcall opaque deepcopy _opq_clone(args[idx])
methodcall opaque loaded value.loaded()
methodcall opaque unwrap _opq_unwrap<bool>(value)
methodcall opaque unwrap class _opq_unwrap_class<String>(value)
methodcall self implicit burn()
methodcall string format formatter _ev_unique<String>(Formatter().format(make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0x24, 0x31}), _opq_pack(cv)))
methodcall string format wrap _ev_unique<String>(tmpl->formatWith(BinaryMode::HEX_SPACED, args))
methodcall string isempty (em->isEmpty())
methodcall variadic opaque pack ds.at(4)
string arg handle deref *e
call arg opaque move _ev_unique<ArrayIterator<T>>(iterator())
foreign arg bytebuffer _ev_unique<ArrayIterator<T>>(iterator())
methodcall arg interface upcast _ev_unique<ArrayIterator<T>>(iterator())
methodcall array capacity _ev_unique<ArrayIterator<T>>(iterator())
methodcall array iterator synth _ev_unique<ArrayIterator<T>>(iterator())
methodcall foreign legacy _ev_unique<ArrayIterator<T>>(iterator())
methodcall generic _ev_unique<ArrayIterator<T>>(iterator())
methodcall opaque wrap _ev_unique<ArrayIterator<T>>(iterator())
methodcall super _ev_unique<ArrayIterator<T>>(iterator())
complex Complex(Number(static_cast<int64_t>(3)), Number(static_cast<int64_t>(4))).__op_plus__(Complex(Number(static_cast<int64_t>(5)), Number(stat… I.D.i(g)
complex Complex(Number(static_cast<int64_t>(3)), Number(static_cast<int64_t>(4))).__op_minus__(Complex(Number(static_cast<int64_t>(1)), Number(sta… I.D.i(g)
complex Complex(Number(static_cast<int64_t>(1)), Number(static_cast<int64_t>(2))).__op_times__(Complex(Number(static_cast<int64_t>(3)), Number(sta… I.D.i(g)
complex Complex(Number(static_cast<int64_t>(1)), Number(static_cast<int64_t>(0))).__op_divide__(Complex(Number(static_cast<int64_t>(0)), Number(st… I.D.i(g)
complex Complex(Number(static_cast<int64_t>(3)), Number(static_cast<int64_t>(4))).negate() I.D.i(g)
complex sum.equals(Complex(Number(static_cast<int64_t>(8)), Number(static_cast<int64_t>(6)))) I.D.i(g), I.F.ii.c
complex c.real() I.D.i(g)
complex c.imaginary() I.D.i(g)
complex c.conjugate() I.D.i(g)
complex c.magnitude() I.D.i(g)
complex Complex(Number(static_cast<int64_t>(1)), Number(static_cast<int64_t>(0))).phase() I.D.i(g)
number drift.isClose(Number(static_cast<double>(0.3)), 1.5e-08, 1e-12) I.F.ii.c
number sum.equals(Number(static_cast<int64_t>(7))) I.D.i(g), I.F.ii.c
number n.kind() I.D.i(g)

IrCreate — a heap-class CREATE — allocation reached through an owning handle

Variant / concept C++ lowering Const.
construct heap class make_ev_unique<Widget>(5) I.F.iii, I.K.v, II.D
call arg byref local nums
call arg move std::move(r)
create class make_ev_unique<Box>()
create qualified class make_ev_unique<Logger::NullSink>()
create struct FloatingDecimal64()
create value class DynamicString()
create arg struct constref clone make_ev_unique<ArrayIterator<T>>(this->data)
create arg struct move make_ev_unique<ArrayIterator<T>>(this->data)
create qualified struct make_ev_unique<ArrayIterator<T>>(this->data)
create qualified struct pod make_ev_unique<ArrayIterator<T>>(this->data)
create struct pod make_ev_unique<ArrayIterator<T>>(this->data)
complex Complex(Number(static_cast<int64_t>(5)), Number(static_cast<int64_t>(2))) I.C(f), I.D.i(g)
number int Number(static_cast<int64_t>(3)) I.D.i(g)
number float Number(static_cast<double>(3.14)) I.D.i(g)

IrNdAlloc — an implicit dense N-D construction float64[m,n] / float64[3,4]ENVZN::EvNdArray<elem, RANK>(dims…), a selector resolving to _NdArray (blittable) or _NdObjectArray (object)

Variant / concept C++ lowering Const.
ndarray ENVZN::EvNdArray<double, 2, ENVZN::EvArrayMode::_GROWABLE>(m, n) I.J

IrNdWiden — a fixed→spine N-D widening — a compile-time fixed-shape array (EvNdArrayFixed) materialized as a runtime spine EvNdArray<elem, RANK> when it flows into a float64[,] binding; total, one-directional

Variant / concept C++ lowering Const.
ndarray ENVZN::EvNdArray<elem, RANK, _GROWABLE>(<fixed>) — kernel converting ctor, element-wise (clone for object cells); NOT a memcpy I.J.i

IrInit — an INIT constructor — its initializer list and body

Variant / concept C++ lowering Const.
constructor (INIT) Probe(const ENVZN::EvArray<_ev_unique<String>>& argv) { } I.K.v

IrLambda — a lambda — expression form, block form, or no-parameter task body

Variant / concept C++ lowering Const.
lambda block [&](<params>) { /* body */ }
lambda expr [&](<params>) { /* body */ }

Sub-nodes (structural components, lowered as part of their parent — no standalone form): IrSuperInit — a SUPER(...) call, emitted in the IrInit initializer list.

Part B.v — Bindings and assignment

IrLet — a local declaration with its binding operator (=, :=, =@)

Variant / concept C++ lowering Const.
local var, no init int32_t n = 5; I.E, II.N
primitive copy var->var int32_t m = n; I.G, I.J.ii
move-init local <owner><<Class>> w = <init>; I.G, I.I.i, I.J.ii
refsource array cell const String* piece0 = _ev_ref_of(r9[0]);
refsource field class m->left.get()
refsource field param _ev_ref_of(e->key)
refsource pipe slot const ENVZN::EvArray<char8_t>* got = &std::get<0>(__pipe_2);
refsource self param _ev_ref_of(this->key)
refsource self reference field this->active
refsource var storage refvar const_cast<std::remove_const_t<std::remove_reference_t<decltype(source)>>*>(&source)
vardecl constant scalar static constexpr uint64_t n_div_5 = 3689348814741910323;
vardecl default _ev_unique<Person> noOne = {};
vardecl fixed array nogrow ENVZN::EvArray<DynamicString> fixed(12, true);
vardecl foreign handle default struct addrinfo * res = nullptr;
vardecl from field move _ev_unique<RBNode<K, V>> x = std::move(h->left);
vardecl from var move _ev_unique<Payload> second = std::move(first);
vardecl general Pair q = p;
vardecl handle mode const int32_t* v = box->value();
vardecl interface upcast call _ev_unique<Cloneable> c = _ev_unique<Cloneable>(original->clone());
vardecl interface upcast create _ev_unique<Dictionary<__int128, int32_t, _ev_unique<DefaultHasher<__int128>>>> d = _ev_unique<Dictionary<__int128, int32_t, _ev_unique<Def…
vardecl parametric adopt clone K k2 = _ev_adopt_clone<K>(key->clone());
vardecl reference deref int32_t v = *(b->value());
vardecl storage capacity ENVZN::EvArray<char32_t> b = char32(16);
vardecl value class init DynamicString a = DynamicString();
refsource array element _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
refsource field storage _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
refsource field value _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
refsource iter ref _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
refsource none _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
refsource self _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
refsource var param _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
refsource var storage _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
refsource var value _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
vardecl constant array _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
vardecl constant string _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
vardecl from cell clone _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
vardecl from cell move _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
vardecl from index value _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
vardecl from refvar clone _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
vardecl group deref _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
vardecl optional field clone _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);
vardecl value class default _ev_unique<ArrayIterator<T>> result = make_ev_unique<ArrayIterator<T>>(this->data);

IrAssign — an assignment to an existing local, field, or reference

Variant / concept C++ lowering Const.
reassign primitive n = 5; I.G, I.I.i, I.J.ii
assign chain default spec.width = 0;
assign chain field move h->right = std::move(x->left);
assign chain var move x->left = std::move(h);
assign default ok = false;
assign from cell move value = std::move(this->data.mutable_data()[0]);
assign from field move value = std::move(popped->value);
assign handle deref v = *(r);
assign handle flip local = holder->storedRef();
assign handle rebind handle = this->guarded.get();
assign interface upcast call it = _ev_unique<ReferenceIterator<V>>((({ auto&& _inl_87_recv = (other); (std::move(_ev_unique<ReferenceIterator<V>>(_inl_87_recv->data->i…
assign mutref writethrough m = 99;
assign parametric adopt clone k2 = _ev_adopt_clone<K>(this->key->clone());
assign string field clone result = _ev_unique<String>((this->source)->clone());
assign uptr move result = std::move(paths);
class init field default this->id = i;
init param scalar this->inner = make_ev_unique<Inner>(7);
refsource self storage &this->data
refsource var class this->src = s.get();
self assign chain default this->holder->node->isRed = true;
self assign chain field move this->head->next = std::move(taken->next);
self assign chain var move this->head->next = std::move(newNode);
self assign constref clone this->label = _ev_unique<String>(label->clone());
self assign default this->i = 0;
self assign move this->head = h;
self assign opaque wrap this->ctx = _opq_wrap<SSL_CTX*>(::SSL_CTX_new(::TLS_client_method()));
self assign reference this->src = s.get();
self assign string constref clone this->name = n;
self assign strong smr this->core = core;
assign chain reference this->length = (this->length + 1);
assign chain string move this->length = (this->length + 1);
assign copy construct this->length = (this->length + 1);
assign deref copy this->length = (this->length + 1);
assign parametric move this->length = (this->length + 1);
self assign array this->length = (this->length + 1);
self assign chain reference this->length = (this->length + 1);
self assign parametric adopt clone this->length = (this->length + 1);
self assign string move this->length = (this->length + 1);

IrMultiAssign — a multi-value assignment from a comma- or pipe-shaped return

Variant / concept C++ lowering Const.
multiassign extra existing p0 = std::get<1>(_ret_5);
multiassign extra typed auto _ret_1 = d->lookup(make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0x6E, 0x6F, 0x70, 0x65})); int32_t v = std::get<0>(_ret_1); _E…
multiassign first existing prodHi = std::get<0>(_ret_4);
multiassign first typed auto _ret_1 = d->lookup(make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0x6E, 0x6F, 0x70, 0x65})); int32_t v = std::get<0>(_ret_1); _E…
multiassign slot get auto _ret_0 = labels->lookup(alpha); int32_t va = std::get<0>(_ret_0); _EvStatus sa = std::get<1>(_ret_0);
multiassign slot move get auto _ret_0 = _ev_unique<ENVZN::String>(d->remove(make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0x61}))); _ev_unique<String> rk = st…
multiassign tuple temp auto _ret_0 = d->lookup(b); int32_t got = std::get<0>(_ret_0); _EvStatus gs = std::get<1>(_ret_0);
multiassign extra ref auto _ret_4 = umul128(a, b);
multiassign first ref auto _ret_4 = umul128(a, b);

IrIndexAssign — an indexed write coll[i] = v (move or clone, per form)

Variant / concept C++ lowering Const.
indexed assign class clone result[rlen] = _ev_unique<String>(tail->clone());
indexed assign default ab[0] = 65;
indexed assign parametric move this->data[(j + 1)] = std::move(key);
indexed assign none this->data[(this->data.length())] = b;

Part B.vi — Control flow

IrBlock — a brace-delimited statement sequence and its scope

Variant / concept C++ lowering Const.
block stmt { _ev_unique<ArrayIterator<int32_t>> iter = _ev_unique<ENVZN::ArrayIterator<int32_t>>(scores->iterator()); while (iter->next()) { const in…

IrIf — a conditional with its then / else-if / else clauses

Variant / concept C++ lowering Const.
if stmt if (s) { if (d) { if (v) { if (i) { Stdio.printline(make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0x73, 0x74, 0x72, 0x69, 0x6E, 0x67…

IrLoop — a loop — counted FOR, range FOR IN, WHILE, or LOOP

Variant / concept C++ lowering Const.
for counted for (int32_t i = 1; i < 6; ++i) { _EvStatus s = pool->submit(make_ev_unique<SquareJob>(i, results)); }
forin concrete iterator [' {', ' auto _ev_iter = src.iterator();', ' while (_ev_iter->hasNext()) {']
repeat loop [' for (int32_t _rep_6 = 0; _rep_6 < (18); ++_rep_6) {']
while loop while (m > 0) { char32_t d = (48 + (m % 10)); tmp.prepend(d); m = (m / 10); }
cstyle for while ((i + 3) <= n) {
dowhile loop while ((i + 3) <= n) {
foreach range for while ((i + 3) <= n) {
forin range for while ((i + 3) <= n) {
forin virtual iterator while ((i + 3) <= n) {
loop iter while ((i + 3) <= n) {
until loop while ((i + 3) <= n) {

IrNdForEach — a dense N-D coordinate walk FOR (i, j) IN grid — nested loops, contiguous axis innermost

Variant / concept C++ lowering Const.
ndarray nested for-loops, axis 0 innermost (column-major) I.J

IrBreak — a BREAK out of the enclosing loop

Variant / concept C++ lowering Const.
break stmt break;

IrContinue — a CONTINUE to the next iteration

Variant / concept C++ lowering Const.
continue stmt (emits — first-gen C++ not captured for this row)

IrMatch — a MATCH over a class, STATUS, or enum with exhaustive arms

Variant / concept C++ lowering Const.
status match bind _ev_unique<String> msg = ENVZN::_string_from_utf8(s.message);
status match cond s.kind == _EvStatus::StatusKind::SUCCESS
valuematch enum qualify if (d == Direction::NORTH) { ok = false; } else if (d == Direction::EAST) { } else if (d == Direction::SOUTH) { ok = false; } else if (d =…
valuematch equality if (d == Direction::NORTH) { ok = false; } else if (d == Direction::EAST) { } else if (d == Direction::SOUTH) { ok = false; } else if (d =…
match group bind (emits — first-gen C++ not captured for this row)
match group when (emits — first-gen C++ not captured for this row)
match optional bind (emits — first-gen C++ not captured for this row)
match optional none (emits — first-gen C++ not captured for this row)
match optional when (emits — first-gen C++ not captured for this row)
match weak bind (emits — first-gen C++ not captured for this row)
match weak none (emits — first-gen C++ not captured for this row)
match weak when (emits — first-gen C++ not captured for this row)
valuematch condition (emits — first-gen C++ not captured for this row)

IrWhenImplements — a compile-time WHEN ... IMPLEMENTS type-narrowing block

Variant / concept C++ lowering Const.
when implements block if constexpr (std::is_base_of_v<Cloneable, T>) {\n /* then arm */\n} else {\n /* else arm */\n}
when implements cond class if constexpr (std::is_base_of_v<I, T>) {\n /* then arm */\n} else {\n /* else arm */\n}
when implements cond group if constexpr (std::is_base_of_v<I, T>) {\n /* then arm */\n} else {\n /* else arm */\n}
when implements cond implements if constexpr (std::is_base_of_v<I, T>) {\n /* then arm */\n} else {\n /* else arm */\n}
when implements cond inoperative if constexpr (std::is_base_of_v<I, T>) {\n /* then arm */\n} else {\n /* else arm */\n}
when implements cond primitive if constexpr (std::is_base_of_v<I, T>) {\n /* then arm */\n} else {\n /* else arm */\n}
when implements cond primitive set if constexpr (std::is_base_of_v<I, T>) {\n /* then arm */\n} else {\n /* else arm */\n}

Sub-nodes (structural components, lowered as part of their parent — no standalone form): IrClause — a condition-and-body clause, lowered within its IrIf / IrWhenImplements; IrMatchArm — a WHEN arm, lowered within its IrMatch.

Part B.vii — Returns and expression statements

IrReturn — a RETURN, applying any required clone or move to the value as it leaves

Variant / concept C++ lowering Const.
auto clone class field return _STATUS_SUCCESS();
auto clone header return _STATUS_SUCCESS();
auto clone return return _STATUS_SUCCESS();
auto clone value return _STATUS_SUCCESS();
class default ctor return _STATUS_SUCCESS();
class field plain return combine(sh, sr);
class field reference return _STATUS_FAILURE("WorkerPool round-trip produced the wrong sum");
class header bare return _STATUS_SUCCESS();
class header bases return _STATUS_FAILURE("cloneInheritanceSmoke step 1");
class init ctor return _STATUS_FAILURE("bug103Smoke: inlined bare-name CallStmt lost receiver");
class init ctor empty return _STATUS_SUCCESS();
class init super return _STATUS_FAILURE("cloneInheritanceSmoke step 1");
conversions namespace return _STATUS_SUCCESS();
cpp name method keyword return _STATUS_SUCCESS();
init param array return _STATUS_FAILURE("subscription did not outlive its broker");
init param heap return _STATUS_FAILURE("at least one assertion failed");
init param heap mutable return _STATUS_FAILURE("refSmoke step 1");
interface destructor return combine(sh, sr);
interface header return combine(sh, sr);
interface method pure virtual return combine(sh, sr);
interface ret class pointer return combine(sh, sr);
method return slot class _ev_unique<String> result;
method return slot reference return this->guarded;
method return slot value return true;
method sig class pointer return _STATUS_SUCCESS();
method sig multireturn tuple return true;
method signature return _STATUS_FAILURE("bug103Smoke: inlined bare-name CallStmt lost receiver");
pipe return tuple return std::make_tuple(v, s);
refsource self class return this->stored;
refsource self value return this->inner;
return clone field return make_ev_unique<String>(*this->name).release();
return clone release return e.release();
return clone value class return new DynamicString(std::move(result));
return plain return i;
return reference return this->inner;
return void return;
struct copy assign return pr.key->equals(make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0x6E, 0x61, 0x6D, 0x65}));
struct copy ctor return pr.key->equals(make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0x6E, 0x61, 0x6D, 0x65}));
struct default ctor return pr.key->equals(make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0x6E, 0x61, 0x6D, 0x65}));
struct field return _STATUS_SUCCESS();
struct header return pr.key->equals(make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0x6E, 0x61, 0x6D, 0x65}));
struct move defaults return pr.key->equals(make_ev_unique<String>(ENVZN::_ValueArray<char32_t>{0x6E, 0x61, 0x6D, 0x65}));
struct nested group return _STATUS_SUCCESS();
struct value ctor return _STATUS_SUCCESS();
auto clone array return result;
return clone field optional return result;
return clone local optional return result;

IrMultiReturn — a return populating several slots (comma or pipe-XOR shape)

Variant / concept C++ lowering Const.
interface ret multireturn return std::make_tuple(<v1>, <v2>, ...);
multireturn tuple return std::make_tuple(<v1>, <v2>, ...);

IrExprStmt — an expression evaluated for its effect as a statement

Variant / concept C++ lowering Const.
call arg class passthrough testValueAccess(r);
expr stmt (i++);
stmt call bump();
string arg move pass(label);

Sub-nodes (structural components, lowered as part of their parent — no standalone form): IrMultiSlot — a return slot, lowered within its IrMultiReturn tuple.

Part B.viii — Recoverable failure and presence

IrPipeIf — an IF whose condition is a fallible pipe-XOR producer (a pipe-returning call, a fallible AS/INTO, a SETS_ERRNO FOREIGN call, or a collection/__op_index__ mirror subscript), narrowing $= / $! in its branches. A bare value-array T[]/T[N]/T[N+] subscript is NOT a producer — it is a direct bounds-checked read — so IF arr[i] THEN over a value array is an ordinary boolean IrIf, not this node

Variant / concept C++ lowering Const.
call arg reference return deref {\n auto __pipe_1 = v->find(needle->data);\n if (std::get<1>(__pipe_1).kind == _EvStatus::StatusKind::SUCCESS) {\n /* then: $RETURNED = st…
convert call { auto __pipe_3 = NumberConverter::_cv_into__String__int64(n64); if (std::get<1>(__pipe_3).kind == _EvStatus::StatusKind::SUCCESS) { v64 =…
foreign bind call sets errno ([&]() -> std::tuple<int32_t, _EvStatus> { auto _r = ::fsync(this->fd); if (_r == -1) { int _e = errno; return {_r, _STATUS_FAILURE(std::s…
if pipe { auto __pipe_1 = s->pop(); if (std::get<1>(__pipe_1).kind == _EvStatus::StatusKind::SUCCESS) { int32_t v = std::get<0>(__pipe_1); r->expe…
if pipe convert { auto __pipe_3 = NumberConverter::_cv_into__String__int64(n64); if (std::get<1>(__pipe_3).kind == _EvStatus::StatusKind::SUCCESS) { v64 =…
pipe call variadic pack { auto __pipe_1 = s->pop(); if (std::get<1>(__pipe_1).kind == _EvStatus::StatusKind::SUCCESS) { int32_t v = std::get<0>(__pipe_1); r->expe…

IrPipeWhile — a WHILE driven by a pipe-XOR call

Variant / concept C++ lowering Const.
while pipe while (true) {\n auto __pipe_1 = it->next();\n if (!(std::get<1>(__pipe_1).kind == _EvStatus::StatusKind::SUCCESS)) break;\n const _ev_und…
while pipe fallback while (true) {

IrPipeRead — a read of a pipe result slot — $=, $=[i], $!, $#

Variant / concept C++ lowering Const.
pipe result errcode std::get<1>(__pipe_5).code
pipe result status ENVZN::_string_from_utf8(std::get<1>(__pipe_1).message)
pipe slot move std::move(std::get<0>(__pipe_3))
pipe slot reference std::get<0>(__pipe_7)
pipe slot value std::get<0>(__pipe_7)
pipe call bare std::get<0>(__pipe_1)
pipe result error std::get<0>(__pipe_1)

IrIsStatus — an IS SUCCESS / IS FAILURE / IS PARTIAL_SUCCESS test

Variant / concept C++ lowering Const.
is status (s.kind == _EvStatus::StatusKind::FAILURE)

IrIsValid — an IS VALID / IS NOT VALID presence test on a class value

Variant / concept C++ lowering Const.
isvalid class optional (h == nullptr)
isvalid foreign handle (p != nullptr)
isvalid param present (!_ev_is_present(value))
isvalid handle or ref (this->head->next == nullptr)
isvalid value optional (this->head->next == nullptr)

Part B.ix — Unrecoverable failure and assertions

IrPanic — a PANIC of an Error subclass

Variant / concept C++ lowering Const.
throw stmt throw <Class>(<args>);

IrTry — a TRY with its RECOVER and FINALLY clauses

Variant / concept C++ lowering Const.
entry main try {\n /* body */\n} catch (const <E>& <name>) {\n /* catch */\n}
try catch try {\n /* body */\n} catch (const <E>& <name>) {\n /* catch */\n}
try catch clause try {\n /* body */\n} catch (const <E>& <name>) {\n /* catch */\n}
try catch finally try {\n /* body */\n} catch (const <E>& <name>) {\n /* catch */\n}
try finally try {\n /* body */\n} catch (const <E>& <name>) {\n /* catch */\n}

IrAssert — an ASSERT / ASSERT! programmer-error check (halts on failure)

Variant / concept C++ lowering Const.
assert statement if (!(n == 5)) { std::abort(); } // message elided I.M

Sub-nodes (structural components, lowered as part of their parent — no standalone form): IrRecover — a RECOVER clause, lowered within its IrTry.

Defined in the IR, lowering not yet spec-traced (node present in compiler/evir/nodes.py; see compiler/evir/emitter.py for current emission): IrUnreachable.

Part B.x — Concurrency

IrConcurrent — a CONCURRENT structured-scope block (RAII join-before-unwind)

Variant / concept C++ lowering Const.
concurrent scope {\n ENVZN::_ev_scope __ev_scope_N;\n /* body (PARALLEL → __ev_scope_N.spawn) */\n}

IrParallel — a PARALLEL task launch within a CONCURRENT scope

Variant / concept C++ lowering Const.
parallel spawn __ev_scope_N.spawn([&]() {\n /* task body */\n});
parallel unreachable __ev_scope_N.spawn([&]() {\n /* task body */\n});

IrSynchronized — a SYNCHRONIZED(lock) critical section

Variant / concept C++ lowering Const.
sync target owned {\n std::lock_guard<std::mutex> __ev_sync_1(this->lock->_native);\n /* body */\n}
sync target self {\n std::lock_guard<std::mutex> __ev_sync_N(<mutex>._native);\n /* body */\n}
synchronized block {\n std::lock_guard<std::mutex> __ev_sync_N(<mutex>._native);\n /* body */\n}
sync target expr {\n std::lock_guard<std::mutex> __ev_sync_N(<mutex>._native);\n /* body */\n}
sync target handle {\n std::lock_guard<std::mutex> __ev_sync_N(<mutex>._native);\n /* body */\n}
sync target param {\n std::lock_guard<std::mutex> __ev_sync_N(<mutex>._native);\n /* body */\n}

Part B.xi — Program structure

IrClass — a CLASS declaration — fields, methods, layout, and destructor

Variant / concept C++ lowering Const.
kernel fwd class class String;
namespace block ['namespace IntUtil {']
namespace forward decl inline bool isUpper(char32_t c);
parent base lowered Hasher<K>
singleton instance decl inline _Math Math;

IrNamespace — a NAMESPACE — a stateless host of free functions plus CONSTANT data; lowers to a C++ namespace

Variant / concept C++ lowering Const.
namespace namespace Math { inline float64 sqrt(...); ... } I.J.ii.d

IrInterface — an INTERFACE declaration — pure-virtual method signatures

Variant / concept C++ lowering Const.
interface ret reference (emits — first-gen C++ not captured for this row)

IrStruct — a STRUCT — a public-field data record with generated construction

Variant / concept C++ lowering Const.
class destructor ~File() {
kernel fwd struct struct STATUS;
struct pod alias using DateTimeFields = ::_EV_ENVZN_DateTimeFields;
struct pod global ['struct _EV_ENVZN_DateTimeFields {']
class destructor call (emits — first-gen C++ not captured for this row)

IrGroup — a GROUP — a tagged set of named constants

Variant / concept C++ lowering Const.
decls group forward (emits — first-gen C++ not captured for this row)
group decl (emits — first-gen C++ not captured for this row)

IrEnum — an ENUM declaration and its cases

Variant / concept C++ lowering Const.
enum declaration enum class Color : int32_t { RED, GREEN, BLUE }; I.K.viii

IrMethod — a method definition — signature, body, MODIFY/const, OVERRIDE

Variant / concept C++ lowering Const.
method sig reference (emits — first-gen C++ not captured for this row)

IrParam — a parameter — plain, REFERENCE, MUTABLE REFERENCE, MOVE, or variadic

Variant / concept C++ lowering Const.
variadic opaque ENVZN::EvArray<<elem>> <name> I.I.vi, II.N
variadic std::initializer_list<<elem>> <name> I.I.vi, II.N
value-class by const ref const <Class>& <name> I.I.vi, II.N
by const ref const <type>& <name> I.I.vi, II.N
value-class, MOVE <Class>&& <name> I.I.vi, II.N
value-class <Class>& <name> I.I.vi, II.N
brace, MODIFY <type>& <name> I.I.vi, II.N
brace const <type>& <name> I.I.vi, II.N
heap class, MOVE <owner><<Class>> <name> I.I.vi, II.N
heap class, MODIFY <owner><<Class>>& <name> I.I.vi, II.N
heap class <Class>* <name> I.I.vi, II.N
cxx reserved <type>& <name> I.I.vi, II.N
array, MODIFY <type>& <name> I.J.i, II.N
array const <type>& <name> I.J.i, II.N
primitive scalar <type><ref?> <name> I.I.vi, II.N
call arg parametric adopt clone _ev_adopt_clone<T>(value->clone())
call arg parametric move std::move(key)
interface param template const K& key
arg deref into ref param (emits — first-gen C++ not captured for this row)
call arg parametric constref clone (emits — first-gen C++ not captured for this row)
init param array mutable (emits — first-gen C++ not captured for this row)
init param brace (emits — first-gen C++ not captured for this row)
init param brace mutable (emits — first-gen C++ not captured for this row)

IrField — a data field — owning, REFERENCE, SHARED MUTABLE REFERENCE, or CONSTANT

Variant / concept C++ lowering Const.
class field strong smr _ev_shared<WorkerPoolCore> core{};
cpp name field rename start
field recv pointer h.left->left
field var refvar n.key
struct pod field int32_t day;
auto clone optional field (emits — first-gen C++ not captured for this row)
call arg byref self field (emits — first-gen C++ not captured for this row)
class field foreign (emits — first-gen C++ not captured for this row)
class init field fixed array (emits — first-gen C++ not captured for this row)
field self narrowed handle (emits — first-gen C++ not captured for this row)
field self narrowed optional class (emits — first-gen C++ not captured for this row)
field self narrowed value optional (emits — first-gen C++ not captured for this row)
string arg field clone (emits — first-gen C++ not captured for this row)

Sub-nodes (structural components, lowered as part of their parent — no standalone form): IrMethodSig — a pure-virtual signature, lowered within its IrInterface.

Defined in the IR, lowering not yet spec-traced (node present in compiler/evir/nodes.py; see compiler/evir/emitter.py for current emission): IrUnion.

Part B.xii — Foreign and unsafe

IrForeignExpr — an inline FOREIGN expression block

Variant / concept C++ lowering Const.
inline foreign block (expr) 42 // inline FOREIGN block: cpp_text emitted verbatim into the expression I.N

IrForeignStmt — an inline FOREIGN statement block

Variant / concept C++ lowering Const.
foreign block stmt // <verbatim C++ from the FOREIGN { ... } block, emitted unchanged>\nENVZN::_throw_string_oob("ByteBufferView: range out of bounds");

IrForeignBind — a FOREIGN BIND to a C function — a typed FFI call

Variant / concept C++ lowering Const.
foreign bind (C function) // no decl emitted; use sites lower to a direct ::ev_probe_fn(args) call I.N

IrForeignConstant — a FOREIGN BIND to a C constant

Variant / concept C++ lowering Const.
foreign bind constant PROBE_CONST // bound int32; resolved via a generated link-time macro-shim symbol I.N

IrForeignTypeBind — a FOREIGN_TYPE BIND to a C struct or opaque handle

Variant / concept C++ lowering Const.
foreign type bind (opaque handle) using ProbeHandle = void*; // newtype over opaque; concrete form -> <cpp_type> * I.N

IrUnsafe — an UNSAFE { } block gating raw-handle access

Variant / concept C++ lowering Const.
unsafe block {\n /* UNSAFE body — no runtime guard */\n}

Part B.xiii — Debug instrumentation

IrSnapshot — a SNAPSHOT debug capture of a value

Variant / concept C++ lowering Const.
snapshot array ENVZN::_ev_snapshot(<var>); // -debug only
snapshot block ENVZN::_ev_snapshot(<var>); // -debug only
snapshot class recurse ENVZN::_ev_snapshot(<var>); // -debug only
snapshot collection ENVZN::_ev_snapshot(<var>); // -debug only
snapshot handle ENVZN::_ev_snapshot(<var>); // -debug only
snapshot primitive ENVZN::_ev_snapshot(<var>); // -debug only
snapshot text ENVZN::_ev_snapshot(<var>); // -debug only

IrStacktrace — a STACKTRACE debug statement

Variant / concept C++ lowering Const.
stacktrace stmt ENVZN::_ev_stacktrace(); // -debug only

Defined in the IR, lowering not yet spec-traced (node present in compiler/evir/nodes.py; see compiler/evir/emitter.py for current emission): IrBinding.

Part B.xiv — Types and lifetime

ResolvedType — the resolved type a node carries — primitive, class handle, value-array, or collection

Variant / concept C++ lowering Const.
scalar int8_t I.D.i, II.N
scalar int32_t I.D.i, II.N
scalar int64_t I.D.i, II.N
scalar double I.D.i, II.N
scalar bool I.D.i, II.N
scalar char32_t I.D.i, II.N
scalar uint8_t I.D.i, II.N
numeric group EvNumeric I.J.v, II.N
named group EvGroup_<Name> I.J.v, II.N
fixed dim, int literal <N> I.J.i, II.N
fixed dim, named const <DIM_NAME> I.J.i, II.N
SHARED CLASS owner _ev_shared I.I.ii, II.N
default owner _ev_unique I.I.ii, II.N
UNSAFE.HANDLE/MUTEX/CONDVAR <_UnsafeHandle<T>> I.I.viii, I.D.v, II.N
SBO inline array ENVZN::EvArray<<elem>, <N>> I.J.i, II.N
fixed single-dim array ENVZN::EvArray<<elem>> I.J.i, II.N
multi-dim fixed array std::array<<elem>, <N>> I.J.i, II.N
qualified array ENVZN::EvArray<<ns::Name>> I.J.i, II.N
optional module class <owner><<ns::Name>> I.K.i, I.N, II.N
optional module struct std::optional<<ns::Name>> I.J.iv, II.N
module struct <ns::Name> I.J.iv, I.N, II.N
module class <owner><<ns::Name>> I.K.i, I.N, II.N
set iterator ENVZN::_cxx_setiter<<inner>>
map iterator ENVZN::_cxx_mapiter<<K>, <V>>
reserved type <CXX_RESERVED_TYPES[name]>
void void I.K.vi, II.N
unbounded array ENVZN::EvArray<<elem>> I.J.i, II.N
optional class <owner><<Class>> I.D.iv
optional interface <owner><<Interface>> I.D.iv
optional template param _ev_optional_t<<T>> I.D.iv
optional primitive std::optional<<inner>> I.D.iv
status _EvStatus I.M.i, II.N
value class DynamicString I.D.vi, I.K.i, II.N
heap class <owner><<Class>> I.I.i, I.I.ii, I.K.i, II.N
fallback <name> I.D.ix
class name, parametric <Base><<args>> I.I.i, I.I.ii, I.K.i, II.N
class name <Base> I.I.i, I.I.ii, I.K.i, II.N
array elem, parametric class <Name><<args>> I.J.i, II.N
array elem, class <Name> I.J.i, II.N
reference to class const <Class>* <name> = <src>.get() I.I.iv, I.I.v, II.N
reference to T <const? >_ev_underlying_t<<T>>* I.I.iv, I.I.v, II.N
reference generic <const? ><lowered>* I.I.iv, II.N
ndarray ENVZN::EvNdArray<elem, RANK, MODE, Dims…> (one selector: ev_is_blittable_v<elem> picks _NdArray vs _NdObjectArray; the Dims pack picks fix… I.J

Sub-nodes (structural components, lowered as part of their parent — no standalone form): IrDrop — a scope-exit drop, emitted implicitly by the C++ destructor (RAII); IrCleanupPad — an unwind-path drop set, cleared before emit alongside IrDrop.


Section C — The lowering model and implementation notes

Curated narrative — not generated from the TSV. Section A specifies the EvIR node set and Section B records the per-node C++ mappings. This section explains the lowering model those mappings sit inside: the compilation pipeline, the ownership-handle representation, the statement and abstraction lowering, concurrency, the foreign-function boundary, the generated entry point, diagnostics, and kernel-build facts. It carries the narrative that was Article II of the constitution before the EvIR specification was split into this document.

Part C.i — The compilation pipeline

The canonical compiler is a linear pipeline from Envzn source to a native executable. Source text is first tokenized into a stream of tokens carrying position information. The token stream is then parsed, by recursive descent, into an abstract syntax tree. The tree is then analyzed — the analyzer resolves types, checks the move and lock and reference rules, and verifies interface satisfaction, and it is the analyzer's passes, rather than any separate tool, that serve as the language's lint layer. The analyzed tree is then built into EvIR (build_ir) and the EvIR is emitted as C++20 (compiler/evir/emitter.py). The emitted C++ is finally handed to the backend, which invokes clang++ with -std=c++20 to produce the executable.

Around that per-translation-unit pipeline sits the module driver, which performs the work C.vi describes. It loads manifests, resolves dependencies in topological order, merges a module's source files into one compilation unit, emits the combined C++, and invokes the backend with the dependent libraries linked. All diagnostics are reported before C++ emission is attempted, so that a downstream C++ error never obscures an Envzn one. The canonical compiler is the Python implementation under bin/; a second, trimmer compiler and an in-progress self-hosted compiler exist, and where they diverge from the canonical one the divergence is treated as catching-up work, not as a second opinion.

Part C.ii — Types and memory: the ownership-handle model

The primitive types lower to fixed-width C++ types. The signed and unsigned integers from 8 to 64 bits become the <cstdint> exact-width types. The 128-bit int128 and uint128 lower to the compiler built-ins __int128 and unsigned __int128, which need no header. No libc path renders or parses a 128-bit integer, so the kernel does both through a hand-rolled decimal-and-base conversion. float32 and float64 become float and double, boolean becomes bool, and byte and binary become uint8_t. The char family lowers as three distinct C++ types, deliberately not C++'s 8-bit charchar8 becomes char8_t, char16 becomes char16_t, and char32 (the canonical name char resolves to) becomes char32_t. A character literal lowers to a UTF-32 literal, so 'a' emits as U'a'. These aliases are emitted at global scope rather than inside the kernel namespace, because they are language-level primitives and a developer expects int32 to mean the same thing in every module.

A class type lowers to a heap allocation reached through an owning handle. The default owning handle is _ev_unique<T>, a non-copyable smart handle: its non-copyability at the C++ type level is what makes an accidental second owner a compile error in the emitted code, not merely in the analyzer. The allocation is split in two — a separate T allocation and a small separate control block, _ev_ctrl<T>, of roughly a dozen bytes. The control block carries an atomic alive flag, an atomic weak_count, and an atomic strong_count. The alive flag records whether the T is still valid. The weak_count counts the _ev_weak<T> observers, each incrementing it on construction or copy and decrementing it on destruction. The control block is freed only when that count reaches zero, which guarantees no observer ever reads a deallocated control block. A type that is the referent of an escaping strong reference is shared-eligible, and its strong owners are _ev_shared<T>. That is a copyable handle: it increments strong_count on copy or bind, decrements it on drop, and destroys the T when the strong count reaches zero. A _ev_unique<T> and a _ev_shared<T> are the two owning shapes; a given binding is one or the other, never both, and the analyzer's disposition decision of I.I.v chooses which. Only shared-eligible types pay for the strong handle — every other class stays _ev_unique<T> at zero refcount cost. Primitives, String, STATUS, enum cases, and STRUCT fields are value types and are emitted inline. Stack-frame exit releases owned heap objects in reverse declaration order through the ordinary RAII chain.

A REFERENCE T and a MUTABLE REFERENCE T lower to raw C++ pointers — T const* and T* respectively — and carry no control block and no reference count. This is sound precisely because the reference checker of I.I.v has already proved, at compile time, that the reference cannot outlive its referent and cannot alias a conflicting access. The runtime therefore needs no check, and a reference costs exactly a pointer. The exception is a reference field the checker has classified as strong rather than as a borrow — an escaping SHARED MUTABLE REFERENCE — which lowers to a _ev_shared<T> owner. Reference parameters never escape, so they are always borrows and always raw pointers. The parameter-passing rules of I.I.vi lower as follows:

Envzn parameter C++ lowering
T for a class type (a plain, read-only borrow) T*
String, ByteBuffer (a plain, read-only borrow) const T*
MODIFY T for a class type _ev_unique<T>& (the callee may rebind the handle)
REFERENCE T const T*
MUTABLE REFERENCE T T*
MOVE T for a class type _ev_unique<T> by value (call site emits std::move)
MOVE DynamicString, MOVE DynamicByteBuffer T&& rvalue reference (call site emits std::move)
T[] const ENVZN::EvArray<…>& (resolves _ValueArray<…> or _ObjectArray<…> per element type)
DynamicString, DynamicByteBuffer T& (callee may mutate via methods; the reference cannot outlive the call)
STRUCT S S by value
primitive, STATUS, enum by value

A borrow is a raw pointer, not an owning handle. The earlier ABI passed a class parameter as const _ev_unique<T>& — an owning handle by const reference — which is a category error, because a borrow does not own what it observes, and it made legal programs uncompilable: the only upcast on an owning handle is a move, which a borrow must not perform, so a concrete handle could not be passed to a parameter of a base or interface type, and a borrowed element could not be passed at all. A raw pointer upcasts implicitly, binds a borrowed referent, and keeps EMPTY representable as nullptr, so IS VALID still works and the memory-safety floor of I.A is not traded away.

An ordinary class borrow is T* rather than const T* deliberately. The old const _ev_unique<T>& was const on the handle, not on the pointee — operator-> handed back a non-const T* — so a borrowed parameter has always been able to call the instance's MODIFY methods, and constifying the pointee would smuggle a new restriction into a bug fix. The text types are the exception: String and ByteBuffer are immutable by the type convention of I.D.vi and expose no MODIFY method, so that concern cannot arise and their borrow is const T* — which is also what allows a read-only REFERENCE local, itself a const T*, to bind to one.

Part C.iii — Statements, expressions, and control flow

Most expressions lower directly. The arithmetic and comparison operators become their C++ equivalents, as do the keyword bitwise, shift, and boolean operators. A derived operator — one a type gained by implementing an operator interface of I.K.iv — lowers to a call of the interface method the compiler derived it from. A CREATE lowers to a heap allocation through _ev_unique<T>, followed by the matching INIT call. A := move lowers to a C++ move of the handle; a = value copy to direct initialization, or to the explicit CREATE or clone() the source contained; and a =@ reference to taking the address of the place expression.

A STATUS lowers to the _EvStatus struct, which carries the outcome, a message String, and an int32_t code defaulting to 0. The pipe-XOR shape of I.M lowers to a C++ std::tuple of the success slots followed by the trailing _EvStatusRETURNS (A a, B b | STATUS s) becomes a std::tuple<A, B, _EvStatus>. The consumption form lowers to an if whose condition tests the tuple's _EvStatus slot, with the result tokens resolving to std::get reads of that temporary: $=[i] is std::get<i>(temp), $# is std::get<status_idx>(temp).code, and $! is std::get<status_idx>(temp).message. MATCH lowers according to its subject — an enum or GROUP to a switch or std::variant visitation, a possibly-EMPTY value to a presence test over its two arms, and a condition-form MATCH to an if/else if chain.

FOR IN lowers by the shape of the iterable, in two forms that share one surface. A class collection or a user class implementing Iterator OF T takes the iterator form: a loop FOR T x IN coll { body } becomes, in effect, an owned iterator obtained from coll->iterator(), a WHILE over hasNext(), and a per-iteration next() whose pipe-XOR result binds x as a non-owning reference into the collection:

{
    Iterator OF T _it := coll->iterator()
    WHILE _it->hasNext() {
        IF _it->next() THEN {
            REFERENCE T x =@ $=
            body
        } ELSE {
            PANIC Error("FOR/IN invariant: next() yielded a failure after hasNext() was true")
        }
    }
}

A raw arrayT[], T[N], or T[N+], as distinct from the Array[T] wrapper class — takes the index form instead. The loop is driven by an index over the array buffer, with the loop variable bound to a borrow pointer into that buffer, and the iterable expression evaluated exactly once (it may be side-effecting). The reason is that the shared loop body is lowered for a REFERENCE variable it dereferences, for every element kind including value elements, and a value array's by-value next() cannot hand back a stable pointer to dereference. The two forms are not observably different to a program: both visit every element in order and bind a non-owning reference to it.

The implicit iterator of the first form is owned by the loop and dropped at loop exit, and that lowering serves a kernel collection and a user class that implements Iterator OF T alike. As an optimization with no observable effect, the compiler may inline the iterator's method bodies in place of virtual dispatch when the static type of the implicit iterator resolves to a FINAL CLASS. A program may not depend on whether the inlining fires.

The IDENTITY(subject) reflection intrinsic (I.K.iii(e)) introduces no IR node of its own — it reuses IrCreate. The analyzer computes the Identity field values from the subject's static type and binding. The IR builder then synthesizes an IrCreate of the kernel STRUCT Identity, whose arguments are those values as literal nodes: IrStringLit, IrBoolLit, and an IrArrayLit of IrStringLit for the lenses ancestor list. It then lowers exactly like any struct value-constructor call. No new node, and no emit-phase decision: by construction the value is legal and fixed.

Part C.iv — Abstractions

A class lowers to a C++ class. Its data fields become members and its methods become member functions. The MODIFY distinction of I.K.vi lowers to the C++ const qualifier: a read-only Envzn method emits as a const member function, a MODIFY method as a non-const one. The const-correctness Envzn enforces at its own level is thereby carried into the emitted code. INIT becomes a constructor and CLEANUP, together with the field-destruction chain, becomes the destructor. FINAL emits the C++ final specifier, which both forbids subclassing and lets the C++ compiler devirtualize and inline calls — the mechanism behind the optional iterator inlining of C.iii.

An interface lowers to an abstract C++ class of pure virtual functions, and a class that implements one gains a vtable. A call through an interface-typed reference is an ordinary virtual call — one pointer indirection — and that is the whole runtime cost of the polymorphic collections of I.K.vii. A GROUP lowers to a std::variant over its member types; a group member that recurses through Box lowers that Box to a _ev_unique indirection, which is what breaks the otherwise self-referential variant. An enum lowers by form: a simple enum to a C++ enumeration, a raw-value enum to one carrying its primitive values, and an associated-value enum to a tagged representation that a MATCH destructures.

The library aggregates are implemented internally with C++ templates, which is how Envzn offers parameterized collections without exposing user-defined generics. Array[T] backs onto the T[] storage primitive — its INTERNAL T[] data field lowers to EvArray<T>, which resolves the _ValueArray<T> value-array for a blittable T and the _ObjectArray<_ev_unique<T>> object-array for a class T. An array literal lowers to a C++ brace-init {…} for a value-element array, since _ValueArray has an initializer_list constructor. A non-empty object-element array literal cannot: an array of move-only owning handles has no initializer_list form. It lowers instead through the free factory _ev_object_array_of(e0, e1, …), which move-appends each element onto a fresh _ObjectArray through its existing grow-assign. An empty literal is a plain {} for either backing. Dictionary is a pure INTERFACE Dictionary[K, V, H] with pure-Envzn implementations behind it (ChainedHashDictionary, RedBlackTreeDictionary, ProHashDictionary); the compiler no longer special-cases it, and hashing is pluggable through the H (Hasher) type parameter rather than a C++ functor. Set[V, H] is likewise a pure-Envzn class wrapping a Dictionary, so neither Set nor Dictionary backs onto a C++ unordered container. The iterators the collections hand out are concrete FINAL classes, one per collection, and their FINAL-ness is what permits the loop-body inlining of C.iii.

Part C.v — Concurrency

CONCURRENT { … } lowers to a structured task scope — an _ev_task_scope RAII object over the block body that joins every task it launched before it unwinds. A PARALLEL { … } block lowers to a task launched on a std::thread registered with the innermost enclosing scope, and the task body emits as the callable the thread runs. The capture restrictions of I.L.vii are enforced in the analyzer before emission, so the emitted lambda captures only what the model permits. SYNCHRONIZED(lock) { … } lowers to a std::lock_guard over the lock's native mutex, held for the body and released automatically on every exit path — fall-through, RETURN, BREAK, or a PANIC unwinding through it.

Channel[T] lowers to a typed, bounded message queue with its synchronization state; Broker[T] to the lock-free publish-index-and-per-subscriber-ring structure of I.L.iv; Mutex[T] to a mutex guarding interior storage reachable only inside its SYNCHRONIZED block; Future[T] to an eventually-ready cell sharing the pipe-XOR consumption shape; Atomic[T] to a std::atomic over the primitive width; and WorkerPool[T] to the kernel's pool class built over those primitives. The low-level synchronization primitives the kernel needs — a mutex, a condition variable, an atomic, a raw thread handle — are not expressible as ordinary Envzn classes, because the underlying C++ standard-library types delete their copy and move operations. The kernel reaches them through the FOREIGN_TYPE BIND mechanism of C.vi, as a small family of _cxx-prefixed types: _cxxmutex, _cxxcondvar, _cxxatomic[T], _cxxrawthread. Each binds the corresponding C++ standard type by value, and each emits its parameters by reference rather than by value, precisely because those C++ types cannot be copied.

Part C.vi — Modules, linkage, and the foreign-function boundary

Each module's emitted C++ is wrapped in a namespace. A non-kernel module emits as namespace modulename { using namespace ENVZN; … }, and the using directive is what lets kernel types keep their bare names inside the module's emitted code. The kernel itself emits inside namespace ENVZN, with the one exception of the primitive numeric aliases, which stay at global scope as C.ii records. The module driver compiles a module in five steps. It loads the manifest for identity, target, dependencies, and foreign metadata. It resolves and recursively compiles the dependencies in topological order. It merges the source files into one compilation unit, where a duplicate type name across two files is an error. It emits the combined C++, and invokes clang++ -std=c++20 with the dependent libraries linked. An executable target produces a binary, and the compiler appends a generated int main() under the rules of C.vii. A shared_library target produces a .dylib together with a generated .headers file that lists every public, non-INTERNAL declaration and so forms the authoritative public surface a dependent compiles against.

The foreign-function boundary lowers as follows. A FOREIGN BIND declaration of a C function is type-checked against its Envzn signature alone; the compiler never reads C header content. In the ordinary case it lowers to a direct call of the bare C symbol, so a binding named open lowers FOREIGN::open(...) to ::open(...). The compiler synthesizes the conversion at each boundary type. Three markers change the lowering. The LOAD parameter modifier declares a value-array parameter write-through, so the C function writes through the storage pointer. A binding marked SETS_ERRNO(sentinel) emits a wrapper that turns an errno into a STATUS FAILURE, making it a pipe-XOR producer. A return marked $*, or $(freer()), emits a wrapper that copies the returned C string and frees the raw pointer, so the free is compiler-generated and inseparable from the call. FOREIGN is an Envzn-side greppability marker only — no FOREIGN C++ namespace is emitted. Every type at the boundary is an Envzn type mapped to the C ABI by a fixed table:

Envzn type C ABI type Boundary behavior
int8int64, uint8uint64 int8_tuint64_t direct
float32 / float64 float / double direct
boolean bool direct
byte uint8_t direct; a single C char binds as byte
String (parameter) const char* a scoped, NUL-terminated buffer that lives exactly as long as the call
String (return) const char* copied into a fresh String; a null result becomes EMPTY
ByteBuffer (parameter) element pointer + a separate uint64 length Envzn-owned; the C side borrows it for the call
opaque void* an opaque handle the Envzn side stores and passes back but never dereferences
an Envzn STRUCT the compiler-emitted struct, by value every field must transitively be a boundary type

ByteBuffer is parameter-only: RETURNS ByteBuffer is a compile error, because a single C return value cannot carry both a pointer and a length. A C library struct — struct stat, struct sockaddr — has a layout fixed by system headers, and never crosses the boundary. A C function that needs one is reached through a module-supplied native shim, which speaks only boundary types in its own signature. FOREIGN BIND CONSTANT binds a single integer macro (e.g. O_RDONLY) through a small C shim that re-exports it as a named symbol. The LOAD shape table and the boundary rules are Article I.N(h) of the Constitution; the manifest conventions and the V2 boundary extensions are outside this spec.

Part C.vii — The generated entry point

Every executable module names one entry class, and the compiler generates the main() that runs it. The entry class is named in a sibling file, entrypoint.json, carrying a single class field. Each of the following is a compile error: an executable module that lacks the file, a shared-library module that has it, a malformed file, or a named class that does not exist, does not implement ThreadStarter, or does not declare INIT(String[] argv).

{ "class": "Main" }

The entry class implements ThreadStarter, the single-method interface — METHOD start() RETURNS STATUS — that the program's main thread and every spawned worker thread share. The entry class receives the process arguments through INIT(String[] argv). The body of that INIT is restricted by diagnostic E6037 to plain self-field assignment statements, so it cannot quietly become a second entry point. The language guarantees that start() is the first line of user-controlled logic. The compiler appends an int main() that builds a String[] from the operating system's argv, constructs the entry class with it, and calls start(). It translates the returned STATUS to a POSIX exit code: SUCCESS to 0, PARTIAL_SUCCESS and FAILURE to 1. The whole sequence is wrapped in a C++ try with three narrowing catch arms: Envzn's Error first, then std::exception, then a catch-all. Each writes a diagnostic to standard error and exits 1, so an uncaught exception produces a message rather than a silent std::terminate.

Part C.viii — Error detection and reporting

The compiler detects errors at every stage of the pipeline, and the stage at which an error is found determines both its category and how the compiler recovers from it well enough to keep finding more.

Stage Category Recovery
Tokenization lexical errors — an unterminated quote, an invalid escape skip to the next line
Parsing structural errors — an unexpected token, a malformed header panic-mode resynchronization to the next statement boundary
Analysis type errors — a mismatch, an undefined name, an unimplemented interface report and continue with the other declarations
Analysis move, lock, and reference errors — a use after move, a mutation under an iterator lock report, and suggest a clone() or a lock scope where one is clear
Emission code-generation errors — an unsupported construct report; emit a stub where possible

Every diagnostic carries four things: a source location of file, line, and column; an error level, either error, which blocks compilation, or warning, which does not; a quoted snippet of the offending line with a caret beneath the span; and, where the fix is clear, a suggestion. A diagnostic is identified by a stable E#### code, and the codes named throughout Article I are those identifiers. All errors are reported before C++ emission is attempted, so that a downstream clang++ error cannot mask the Envzn error that caused it.

A location is a range, not a point: start_line/start_col and end_line/end_col, 1-based and counted in Unicode code points. A point is the degenerate range whose end equals its start, so a diagnostic that knows only where a problem begins is expressible without a second shape. The frame is drawn only where the source is readable and the column is known; where either is missing the diagnostic prints its location line alone rather than a partial frame, because a diagnostic must never fail while reporting a failure. The caret is placed by display column — a tab advances to the next multiple of eight, and an East-Asian Wide or emoji glyph occupies two cells — which is not the stored column on any line containing either.

Where a single literal edit resolves the diagnostic, it is offered as a help: line beneath the remedy, and the same edit is machine-applicable. Most diagnostics have none, and that is the expected outcome: the remedy for a type error or a missing contract is a decision, not a substitution.

error [E1174] parse:numeric-literal-malformed: `0x` must be followed by hex digits
  ╭─ examples/hello.ev:6:19
6 │         int32 h = 0x
  │                   ^
  ╰─
  at examples/hello.ev:6:19
  help: replace with `0x1F`

The same diagnostics are available as machine-readable records under --diagnostics=json, shaped as LSP Diagnostic objects — 0-based lines and UTF-16 character offsets, with any fix carried as a TextEdit. Everything Envzn-specific is namespaced under evzn. in the record's data field, which LSP defines as opaque passthrough, so an editor consumes the stream without a translation layer. The document is always emitted, even when empty, so a consumer can distinguish a clean build from a compiler that stopped before it could report.

Part C.ix — Kernel implementation notes

The kernel — the ENVZN module — is compiled as a shared library that every Envzn program links against. It publishes a single canonical header, which the generated C++ of every module includes.

The kernel is authored as Envzn source — roughly one hundred ten .ev files — and the compiler emits from them a per-class header apiece, alongside the hand-written floor and its native glue, all of which the canonical header includes. This is the result of the demagic effort, a staged project to replace hand-written C++ kernel class bodies with emitted ones. A collection or utility that was once a block of C++ in the kernel header is now an ordinary .ev file the compiler lowers like any other. The canonical header retains only the host runtime glue that genuinely cannot be authored in Envzn — the formatting and hashing helpers, the four-form String and Binary primitive machinery, and the low-level _cxx* concurrency types of C.v. The kernel holds to one hard rule: it has no dependency on any external package, and an optional system dependency — OpenSSL, SQLite, a regex library — belongs in the module that consumes it, never in the kernel.


End of specification. Section A specifies 92 EvIR nodes in 14 groups; Section B records 518 TSV-traced lowering rows; Section C is curated narrative. Regenerate Sections A and B with the spec-spec generator.