EMPL IR
NodeKind — exhaustive enumeration
NodeKind — exhaustive enumeration
NodeKind is the closed enumeration (enum class) that discriminates every concrete IR node. It is declared in core/ir/EMPLNode.h:19-70 and currently contains 41 values grouped into seven semantic families.
// MPL_Compiler/core/ir/EMPLNode.h:19
enum class NodeKind {
Program,
Module,
Import,
Export,
FunctionDecl,
VariableDecl,
DestructuringPattern,
ClassDecl,
InterfaceDecl,
EnumDecl,
TypeAliasDecl,
Block,
If,
For,
ForEach,
While,
DoWhile,
Switch,
Throw,
Return,
Break,
Continue,
TryCatch,
Assignment,
BinaryOp,
UnaryOp,
FunctionCall,
MethodCall,
MemberAccess,
IndexAccess,
Literal,
Identifier,
ArrayLiteral,
ObjectLiteral,
RecordLiteral,
TupleLiteral,
Lambda,
Await,
Yield,
Cast,
Ternary,
StandardLibraryCall,
// Legacy aliases (deprecated — prefer StandardLibraryCall over PrintCall)
PrintCall,
FuncDecl,
Unsupported,
};
Complete table
| Index | NodeKind | Class | Family | Source:line | Description |
|---|---|---|---|---|---|
| 0 | Program |
ProgramNode |
Module | EMPLNode.h:103 |
Root: graph of ModuleEntry with dependency edges and topological ordering. |
| 1 | Module |
ModuleNode |
Module | EMPLNode.h:88 |
A single compilation unit (one source file, one library, …). |
| 2 | Import |
ImportNode |
Module | EMPLNode.h:634 |
Cross-module import (ESM, CJS, Python import, etc.). |
| 3 | Export |
ExportNode |
Module | EMPLNode.h:656 |
Cross-module export. |
| 4 | FunctionDecl |
FunctionDeclNode |
Declaration | EMPLNode.h:162 |
Function or method declaration. |
| 5 | VariableDecl |
VariableDeclNode |
Declaration | EMPLNode.h:446 |
let, const, var, etc. |
| 6 | DestructuringPattern |
DestructuringPatternNode |
Declaration | EMPLNode.h:427 |
Object or array destructuring pattern. |
| 7 | ClassDecl |
ClassDeclNode |
Declaration | EMPLNode.h:183 |
Class (or struct, depending on isStruct). |
| 8 | InterfaceDecl |
InterfaceDeclNode |
Declaration | EMPLNode.h:199 |
Interface (TS / Java / C# interface). |
| 9 | EnumDecl |
EnumDeclNode |
Declaration | EMPLNode.h:212 |
Enumeration. |
| 10 | TypeAliasDecl |
TypeAliasDeclNode |
Declaration | EMPLNode.h:228 |
Type alias (TS type). |
| 11 | Block |
BlockNode |
Block | EMPLNode.h:153 |
A { … } sequence of statements. |
| 12 | If |
IfNode |
Control flow | EMPLNode.h:239 |
if (cond) { … } else { … }. |
| 13 | For |
ForNode |
Control flow | EMPLNode.h:250 |
C-style for (init; cond; incr). |
| 14 | ForEach |
ForEachNode |
Control flow | EMPLNode.h:262 |
for (target : iterable). |
| 15 | While |
WhileNode |
Control flow | EMPLNode.h:273 |
while (cond). |
| 16 | DoWhile |
DoWhileNode |
Control flow | EMPLNode.h:283 |
do { … } while (cond). |
| 17 | Switch |
SwitchNode |
Control flow | EMPLNode.h:293 |
switch (expr) { case … }. |
| 18 | Throw |
ThrowNode |
Jump | EMPLNode.h:329 |
throw expr. |
| 19 | Return |
ReturnNode |
Jump | EMPLNode.h:320 |
return [expr]. |
| 20 | Break |
BreakNode |
Jump | EMPLNode.h:338 |
break. |
| 21 | Continue |
ContinueNode |
Jump | EMPLNode.h:345 |
continue. |
| 22 | TryCatch |
TryCatchNode |
Control flow | EMPLNode.h:309 |
try { … } catch (…) { … } finally { … }. |
| 23 | Assignment |
AssignmentNode |
Expression | EMPLNode.h:460 |
lhs = rhs (or +=, -=, …). |
| 24 | BinaryOp |
BinaryOpNode |
Expression | EMPLNode.h:471 |
a + b, a && b, a == b, … |
| 25 | UnaryOp |
UnaryOpNode |
Expression | EMPLNode.h:482 |
!x, -x, ++x, typeof x, … |
| 26 | FunctionCall |
FunctionCallNode |
Expression | EMPLNode.h:493 |
f(arg1, arg2, …). |
| 27 | MethodCall |
MethodCallNode |
Expression | EMPLNode.h:352 |
obj.method(arg1, …). |
| 28 | MemberAccess |
MemberAccessNode |
Expression | EMPLNode.h:363 |
obj.field. |
| 29 | IndexAccess |
IndexAccessNode |
Expression | EMPLNode.h:373 |
arr[i], map[key]. |
| 30 | Literal |
LiteralNode |
Literal | EMPLNode.h:393 |
Numeric, string, boolean, or null literal. |
| 31 | Identifier |
IdentifierNode |
Literal | EMPLNode.h:383 |
A bare name reference (no obj. prefix). |
| 32 | ArrayLiteral |
ArrayLiteralNode |
Literal | EMPLNode.h:529 |
[1, 2, 3]. |
| 33 | ObjectLiteral |
ObjectLiteralNode |
Literal | EMPLNode.h:538 |
{ a: 1, b: 2 }. |
| 34 | RecordLiteral |
RecordLiteralNode |
Literal | EMPLNode.h:547 |
Struct-shaped literal (named keys, fixed shape). |
| 35 | TupleLiteral |
TupleLiteralNode |
Literal | EMPLNode.h:556 |
[1, "x"] where types are heterogeneous and fixed. |
| 36 | Lambda |
LambdaNode |
Expression | EMPLNode.h:565 |
Anonymous function ((x) => x, function(x){}, lambda x: x). |
| 37 | Await |
AwaitNode |
Expression | EMPLNode.h:581 |
await expr. |
| 38 | Yield |
YieldNode |
Expression | EMPLNode.h:590 |
yield expr / yield* expr. |
| 39 | Cast |
CastNode |
Expression | EMPLNode.h:600 |
Explicit type cast. |
| 40 | Ternary |
TernaryNode |
Expression | EMPLNode.h:610 |
cond ? a : b. |
| 41 | StandardLibraryCall |
StandardLibraryCallNode |
Literal | EMPLNode.h:517 |
Language-neutral stdlib call (Console.WriteLine, Math.Sqrt, …). |
| 42 | PrintCall |
PrintCallNode |
Legacy | EMPLNode.h:503 |
Deprecated; prefer StandardLibraryCall. |
| 43 | FuncDecl |
(alias) | Legacy | EMPLNode.h:181 |
Deprecated alias for FunctionDecl. |
| 44 | Unsupported |
UnsupportedNode |
Legacy | EMPLNode.h:621 |
Frontend hit a construct it cannot represent. |
Note. The
enum classis non-sparse —EMPLValidator::validatewalks the value space and reports unknown kinds as errors. The legacy entries (PrintCall,FuncDecl,Unsupported) are retained for source compatibility but new code MUST emit the canonical equivalents.
Family overview
Module / program (4 values)
These nodes form the top-level structure emitted by every frontend.
| Kind | Purpose |
|---|---|
Program |
Top-level; only one ever exists per compilation. Holds ModuleEntry[] (id, ModuleNode, dependencies, isEntry). Exposes findModule(id) and topologicalOrder(). |
Module |
One compilation unit. Holds name, sourceLanguage, imports, declarations, statements. |
Import |
Cross-module dependency. ImportBinding { importedName, localName, isDefault, isNamespace } plus module specifier. |
Export |
Either named bindings, a default value, or a re-export. |
Declarations (7 values)
All produce a top-level binding in the containing module's scope.
| Kind | Carrier |
|---|---|
FunctionDecl |
FunctionDeclNode with body BlockNode and optional flags (isAsync, isGenerator, isConstructor, isStatic). |
VariableDecl |
VariableDeclNode; carries name, pattern, type, initializer, plus isConst/isMutable. |
DestructuringPattern |
DestructuringPatternNode; PatternKind::Object or PatternKind::Array. |
ClassDecl |
ClassDeclNode; holds name, optional baseClass, constructor, methods[], members[], staticBlocks[], decorators[]. |
InterfaceDecl |
InterfaceDeclNode; name + extends + members. |
EnumDecl |
EnumDeclNode; name + Member[] (each with name + optional initializer). |
TypeAliasDecl |
TypeAliasDeclNode; name + free-form typeExpr text. |
Blocks & control flow (11 values)
| Kind | Carrier |
|---|---|
Block |
BlockNode { statements[] }. |
If |
IfNode { condition, thenBranch, elseBranch }. |
For |
ForNode { init, condition, increment, body } — any of init/cond/incr may be null. |
ForEach |
ForEachNode { target, iterable, body }. |
While |
WhileNode { condition, body }. |
DoWhile |
DoWhileNode { body, condition } — body first. |
Switch |
SwitchNode { expr, cases[], defaultCase }; each case has label, body, fallthrough. |
TryCatch |
TryCatchNode { tryBlock, catchBlocks[], finallyBlock }. |
Return / Throw / Break / Continue |
Single-purpose jumps. |
Expressions (15 values)
| Kind | Carrier |
|---|---|
Assignment |
AssignmentNode { target, value, op }. |
BinaryOp |
BinaryOpNode { op, left, right }. |
UnaryOp |
UnaryOpNode { op, operand, isPrefix }. |
FunctionCall / MethodCall |
FunctionCallNode { name, args[] } / MethodCallNode { object, methodName, args[] }. |
MemberAccess / IndexAccess |
Member / index read or write (target context determined by parent). |
Cast |
CastNode { targetType, expression }. |
Ternary |
TernaryNode { condition, whenTrue, whenFalse }. |
Lambda |
LambdaNode { parameters, body, expressionBody, isAsync, capturesLexicalThis, isConstructible, hasOwnArguments }. |
Await |
AwaitNode { expression }. |
Yield |
YieldNode { expression, delegate }. |
Literals (7 values)
| Kind | Carrier |
|---|---|
Literal |
LiteralNode { value: variant<int64, double, string, bool, nullptr>, type }. |
Identifier |
IdentifierNode { name }. |
ArrayLiteral / ObjectLiteral / RecordLiteral / TupleLiteral |
List- or property-shaped literal nodes. |
StandardLibraryCall |
StandardLibraryCallNode { moduleName, functionName, arguments[], argumentNames[] }. |
Legacy (3 values)
PrintCall, FuncDecl, Unsupported — see comments at EMPLNode.h:66-69. New code MUST NOT emit them.
See also
index.md— IR overview and design philosophytypes.md—TypeKindenum andUIRTypestructnodes/— per-node documentation
Numeric stability
The NodeKind enum is the IR's stable contract. Backends switch on the integer value of the kind to decide lowering. The numeric values are part of the IR ABI and MUST NOT be reordered or renumbered — only appended to. The current highest value is Unsupported at 44.
When reading EMPLNode.h (EMPLNode.h:19), the enum is laid out in source order. The integer values are:
| Index range | Values |
|---|---|
| 0–3 | Module / program family |
| 4–10 | Declaration family |
| 11 | Block |
| 12–17, 22 | Control-flow family (excluding jumps) |
| 18–21 | Jump family |
| 23–41 | Expression / literal family |
| 42–44 | Legacy family |
Frontends that need to round-trip IR through a binary format should serialize the integer value directly (with appropriate endian conversion). Frontends that need to persist IR to JSON / text should use the symbolic name (e.g. "FunctionDecl") for forward compatibility.
Reserved values
There are no reserved NodeKind values. New kinds are simply appended. The validator emits a warning (not an error) for unknown kinds from older IRs, which lets new compilers load older IR files.
Convention summary
When adding a new node:
- Append the new enum value to
EMPLNode.h(do not insert in the middle). - Declare the new class deriving from
EMPLNodewith the correctEMPLNode(NodeKind::New)constructor call. - Add an
accept(EMPLVisitor& v) override { v.visit(*this); }method. - Add a corresponding
visit(NewNode& node)method to theEMPLVisitorbase class. Existing visitors will fail to compile until they implement the new visit method — this is intentional, forcing all visitors to handle the new kind. - Add a case to
EMPLPrinter::printNodefor human-readable dump. - Add structural rules to
EMPLValidatorif the kind has invariants. - Update this document.
- Update
../standard-library/index.mdif the new kind affects stdlib emission.