Backend class
Defined in module l0_backend (l0_backend.py).
Language-agnostic code generation backend.
Orchestrates code generation by:
- Managing compilation unit structure and emission order.
- Resolving types and symbols.
- Tracking variable scopes and lifetimes.
- Scheduling cleanup operations.
- Delegating all target-specific code emission to the emitter.
The backend decides WHAT to emit and WHEN, but not HOW (that's the emitter's job). This allows the same backend logic to work with different emitters (C, LLVM IR, WASM, etc.).
Public static attributes
- static AnalysisResult analysis
- static CEmitter emitter
- static Optional current_module
Constructors, destructors, conversion operators
- __post_init__(self)
- Initialize emitter with analysis data.
- _iter_body_stmts(self, Optional stmt[Stmt]) protected
- Yield every statement reachable from stmt, recursing into block-bearing nodes.
- _resolve_type_ref(self, TypeRef tref, str module_name) protected
- Resolve an AST TypeRef into an l0_
types.Type. - _int_type_size(self, Type src_ty) protected
- Get the byte size of an integer builtin type.
Public functions
- auto generate(self) -> str
- Main entry point: generate complete C source for the compilation unit.
- auto ice(self, str message, *Optional node[Node] = None) -> NoReturn
- Raise an internal compiler error.
- auto find_variant_decl(self, str module_name, str enum_name, str variant_name) -> Optional[EnumVariant]
- Find the EnumVariant AST node for a given variant in an enum.
Public attributes
Protected functions
- auto _fresh_label(self, str prefix) -> str
- Generate a unique C label name.
- auto _push_scope(self) -> ScopeContext
- Enter a new scope.
- auto _pop_scope(self) -> None
- Exit current scope.
- auto _types_equal(self, Type a, Type b) -> bool
- Check if two types are structurally equal.
- auto _is_int_assignable(self, Type typ) -> bool
- Check if a type is assignable to an integer.
- auto _is_binary_op_enabled(self, Type typ) -> bool
- Check if a type supports binary operations.
- auto _is_place_expr(self, Expr expr) -> bool
- Check if an expression refers to an existing binding.
- auto _is_unwrap_cast_from_place(self, Expr expr) -> bool
- Check if a cast expression still borrows from an existing owner.
- auto _needs_arc_temp(self, Expr expr) -> bool
- Check if a non-place rvalue with ARC data needs temp materialization.
- auto _should_materialize_arc_temp(self, Expr expr, Type expr_type) -> bool
- Check if an ARC expression should be hoisted to a cleanup temp.
- auto _materialize_arc_temp(self, str c_expr, Type expr_type) -> str
- Materialize an ARC rvalue into a scope-owned temporary for automatic cleanup.
- auto _has_side_effects(self, Expr expr) -> bool
- Check if the expression has side effects or contains function calls.
- auto _pointer_type_or_none(self, Optional ty[Type]) -> Optional[PointerType]
- Return the represented pointer type for pointer-shaped values.
- auto _sizeof_expr_for_type(self, Type ty) -> str
- Return a C
sizeofexpression for the runtime access extent. - auto _alignof_expr_for_type(self, Type ty) -> str
- Return a C alignment expression for the runtime access target.
- auto _emit_checked_pointer_expr(self, str c_ptr_expr, Type ptr_ty, Optional node[Node] = None, str access_mode = "_RT_ACCESS_READ") -> str
- Emit a pointer expression checked for one pointee-sized access.
- auto _emit_pointer_index_lvalue(self, str c_base, str c_index, Type base_ty, Optional node[Node] = None, str access_mode = "_RT_ACCESS_WRITE") -> str
- Emit a checked pointer-index lvalue expression.
- auto _lookup_local_var_type(self, str var_name) -> Optional[Type]
- Look up a local variable's type in the current scope chain.
- auto _lookup_owned_local_name(self, VarRef expr) -> Optional[str]
- Return the mangled local name when a VarRef resolves to an owned local binding.
- auto _extract_value_type_dependencies(self, Type typ) -> Set[Tuple[str, str]]
- Extract type dependencies for VALUE fields only.
- auto _build_type_dependency_graph(self) -> Dict[Tuple[str, str], Set[Tuple[str, str]]]
- Build dependency graph for type definitions.
- auto _find_cycle_details(self, Dict[Tuple[str, str], Set]] graph[Tuple[str, str], List] unresolved[Tuple[str, str]) -> str
- Find and format cycle details for error message.
- auto _topological_sort(self, Dict[Tuple[str, str], Set]] graph[Tuple[str, str]) -> List[Tuple[str, str]]
- Perform topological sort on type dependency graph using Kahn's algorithm.
- auto _find_struct_decl(self, str module_name, str struct_name) -> Optional[StructDecl]
- Find the StructDecl AST node for a given struct.
- auto _find_enum_decl(self, str module_name, str enum_name) -> Optional[EnumDecl]
- Find the EnumDecl AST node for a given enum.
- auto _expect_expr_type(self, Expr expr) -> Type
- Look up an expression's type and fail if missing.
- auto _emit_line_directive(self, Node node) -> None
- Emit #line directive if node has span info and context allows it.
- auto _emit_let_declarations(self) -> None
- Emit static global variables for top-level let declarations.
- auto _emit_let_declaration(self, str module_name, LetDecl decl) -> None
- Emit a single top-level let declaration as a static variable.
- auto _emit_let_initializer(self, Expr expr, Type expected_type) -> str
- Generate C initializer expression for a top-level let.
- auto _emit_bare_variant_static_initializer(self, VarRef expr, Type expected_type) -> str
- Emit a bare zero-argument enum variant for static initialization.
- auto _emit_const_constructor(self, CallExpr expr, Type expected_type) -> str
- Emit a constant struct or enum constructor for static initialization.
- auto _emit_const_struct_constructor(self, CallExpr expr, StructType struct_type) -> str
- Emit constant struct constructor for static initialization.
- auto _emit_const_variant_constructor(self, CallExpr expr, EnumType enum_type) -> str
- Emit constant enum variant constructor for static initialization.
- auto _emit_function_declarations(self) -> None
- Emit forward declarations for all functions.
- auto _emit_function_declaration(self, str module_name, FuncDecl decl) -> None
- Emit a single function declaration.
- auto _emit_function_definitions(self) -> None
- Emit function definitions (bodies).
- auto _emit_function_definition(self, str module_name, FuncDecl decl) -> None
- Emit a complete function definition with body.
- auto _emit_main_wrapper_if_needed(self) -> None
- If the entry module has a main function, emit a C main() wrapper.
- auto _scope_chain_has_cleanup(self) -> bool
- Check if any scope in the chain has cleanup requirements.
- auto _emit_cleanup_for_return(self, Optional returned_var[str] = None) -> None
- Emit cleanup logic for a return statement.
- auto _emit_cleanup_for_loop_exit(self, *bool is_break) -> None
- Emit cleanup for break/continue.
- auto _emit_cleanup_at_scope_exit(self, ScopeContext scope) -> None
- Emit cleanup at scope exit.
- auto _emit_with_cleanup_from_scope(self, ScopeContext scope, str module_name) -> None
- Emit with-statement cleanup for a scope.
- auto _emit_value_cleanup(self, str c_expr, Type ty) -> None
- Emit cleanup code for a by-value variable before reassignment.
- auto _emit_struct_cleanup(self, str c_ptr_expr, StructType struct_type) -> None
- Emit cleanup code for all owned fields in a struct.
- auto _emit_enum_cleanup(self, str c_ptr_expr, EnumType enum_type) -> None
- Emit cleanup code for owned fields in an enum's active variant.
- auto _emit_block_sequence(self, Block block, str module_name) -> None
- Emit statements in a block.
- auto _emit_stmt(self, Stmt stmt, str module_name) -> None
- Emit a single statement.
- auto _emit_block(self, Block stmt, str module_name) -> Any
- Emit a block statement with its own scope.
- auto _emit_return(self, ReturnStmt stmt, Optional[Callable[[], None]] before_cleanup = None) -> Any
- Emit a return statement with cleanup.
- auto _register_inline_with_cleanup(self, ScopeContext scope, "WithItem" item) -> None
- Register one inline with-item cleanup in LIFO order.
- auto _emit_inline_with_header_item(self, "WithItem" item, str module_name, ScopeContext scope) -> None
- Emit one inline with header item and register its cleanup at the committed point.
- auto _emit_condition_branch(self, Expr expr, str true_label, str false_label) -> None
- Emit control flow for one condition expression with short-circuit semantics.
- auto _emit_condition_expr(self, Expr expr) -> str
- Emit a top-level condition expression for direct statement headers.
- auto _emit_condition_value(self, Expr expr) -> str
- Evaluate a statement condition into a stable boolean temporary.
- auto _emit_while(self, WhileStmt stmt, str module_name) -> Any
- Emit a while loop.
- auto _emit_for(self, ForStmt stmt, str module_name) -> Any
- Emit a for loop.
- auto _emit_if_else(self, IfStmt stmt, str module_name) -> Any
- Emit an if-else statement.
- auto _gen_if_else_branch(self, Stmt stmt, str module_name) -> bool
- Emit a branch of an if/else.
- auto _collect_reassigned_arc_params(self, FuncDecl decl, FuncType func_type) -> set
- Collect the names of ARC-typed parameters reassigned syntactically in the body.
- auto _emit_reassignment(self, AssignStmt stmt) -> None
- Emit an assignment statement.
- auto _emit_lvalue_with_caching(self, Expr target) -> str
- Emit an lvalue expression, caching sub-expressions with side effects.
- auto _emit_let(self, LetStmt stmt, str module_name) -> Any
- Emit a local 'let' declaration.
- auto _resolve_let_type(self, LetStmt stmt, str module_name) -> Type
- Resolve concrete type for a let declaration.
- auto _emit_with_cleanup_header_let_predecl(self, LetStmt stmt, str module_name) -> Optional[Type]
- Predeclare a nullable
with-headerlet for cleanup-block form. - auto _emit_with_cleanup_header_let_assign(self, LetStmt stmt, Type var_ty) -> None
- Emit initializer assignment for a predeclared cleanup-block let.
- auto _emit_retain_for_copied_value(self, str c_expr, Type ty) -> None
- Emit retain operations for a copied owned value.
- auto _emit_copy_expr_with_retains(self, str c_expr, Type ty) -> str
- Materialize copied values in a temp and emit retain logic when needed.
- auto _emit_match(self, MatchStmt stmt, str module_name) -> None
- Emit a match statement as a switch on the tag field.
- auto _emit_case(self, CaseStmt stmt, str module_name) -> None
- Emit a case statement as a scalar switch or string if/else chain.
- auto _emit_case_literal(self, Expr expr) -> str
- Emit a constant literal for a case statement.
- auto _emit_pattern_bindings(self, VariantPattern pattern, EnumType enum_type, ScopeContext arm_scope) -> None
- Emit pattern variable bindings and add them to arm scope.
- auto _emit_with(self, WithStmt stmt, str module_name) -> None
- Emit a with statement.
- auto _emit_drop(self, DropStmt stmt, str module_name) -> None
- Emit drop statement with automatic cleanup of owned fields.
- auto _try_emit_intrinsic(self, CallExpr expr) -> Optional[str]
- Expand compiler intrinsics inline.
- auto _emit_sizeof_intrinsic(self, CallExpr expr) -> str
- Emit sizeof intrinsic.
- auto _emit_ord_intrinsic(self, CallExpr expr) -> str
- Emit ord(enum_value) intrinsic.
- auto _try_emit_constructor(self, CallExpr expr) -> Optional[str]
- Check if expr is a constructor call and emit appropriate initialization.
- auto _emit_struct_constructor(self, CallExpr expr, StructType struct_type) -> str
- Emit struct constructor as C designated initializer.
- auto _emit_variant_constructor(self, CallExpr expr, EnumType enum_type) -> str
- Emit enum variant constructor as C tagged union initializer.
- auto _emit_new_expr(self, NewExpr expr) -> str
- Emit a heap allocation
newexpression. - auto _convert_expr_with_expected_type(self, str c_expr, Optional natural_ty[Type], Type expected) -> str
- Convert a pre-emitted expression into the expected type when required.
- auto _emit_expr_with_expected_type(self, Expr e, Type expected) -> str
- Emit expression with implicit type conversion to expected type.
- auto _emit_owned_expr_with_expected_type(self, Expr e, Type expected) -> str
- Emit expression for contexts that create a new owner.
- auto _emit_expr(self, Expr expr, *bool is_statement = False) -> str
- Emit an expression and return the C code.
- auto _emit_unwrap(self, str c_dst, str c_inner, NullableType src_ty) -> str
- Emit code to unwrap a nullable value.
- auto _emit_binary_op(self, Expr expr_node, str expr_op, Expr expr_left, Expr expr_right, *bool for_condition = False) -> str
- Emit code for a binary operation.
- auto _lookup_symbol(self, str name, str current_module_name, Optional] module_path[List[str] = None) -> Optional[ Symbol]
- Look up a symbol in the current module's environment.
- auto _is_extern_function(self, Symbol sym) -> bool
- Check if a symbol is an 'extern' function.
Protected static attributes
- static Optional _current_func_result
- static Optional _current_scope
- static List _loop_cleanup_scope_stack
- static int _switch_depth
- static List _loop_label_stack
- static int _label_counter
- static bool _next_stmt_unreachable
Protected attributes
Function documentation
l0_backend:: Backend:: _iter_body_stmts(self,
Optional stmt[Stmt]) protected
Yield every statement reachable from stmt, recursing into block-bearing nodes.
| Parameters | |
|---|---|
| stmt | The root statement (or None). |
| Returns | An iterator over every Stmt in the sub-tree, including stmt itself. |
l0_backend:: Backend:: _resolve_type_ref(self,
TypeRef tref,
str module_name) protected
Resolve an AST TypeRef into an l0_
| Parameters | |
|---|---|
| tref | The TypeRef AST node. |
| module_name | Name of current module. |
| Returns | The resolved Type. |
This is needed so "let x: int? = null;" uses the declared type (int?) instead of the initializer type (null).
l0_backend:: Backend:: _int_type_size(self,
Type src_ty) protected
Get the byte size of an integer builtin type.
| Parameters | |
|---|---|
| src_ty | The type to check. |
| Returns | Byte size (1 for byte, 4 for int). |
| Exceptions | |
| InternalCompilerError | If type is not an integer builtin. |
str l0_backend:: Backend:: generate(self)
Main entry point: generate complete C source for the compilation unit.
| Returns | C source code as a string. |
|---|---|
| Exceptions | |
| ValueError | If there is no compilation unit or if there are semantic errors. |
NoReturn l0_backend:: Backend:: ice(self,
str message,
*Optional node[Node] = None)
Raise an internal compiler error.
| Parameters | |
|---|---|
| message | The error message. |
| node | Optional AST node associated with the error. |
| Exceptions | |
| InternalCompilerError | Always raised with the provided message and location. |
Optional[EnumVariant] l0_backend:: Backend:: find_variant_decl(self,
str module_name,
str enum_name,
str variant_name)
Find the EnumVariant AST node for a given variant in an enum.
| Parameters | |
|---|---|
| module_name | Name of module containing the enum. |
| enum_name | Name of the enum. |
| variant_name | Name of the variant. |
| Returns | The EnumVariant AST node if found, otherwise None. |
This is needed to get field names when binding pattern variables, since pattern variables are positional, but we need to access fields by name.
str l0_backend:: Backend:: _fresh_label(self,
str prefix) protected
Generate a unique C label name.
| Parameters | |
|---|---|
| prefix | Prefix for the label name. |
| Returns | A unique label string. |
ScopeContext l0_backend:: Backend:: _push_scope(self) protected
Enter a new scope.
| Returns | The newly created ScopeContext. |
|---|
None l0_backend:: Backend:: _pop_scope(self) protected
Exit current scope.
| Exceptions | |
|---|---|
| InternalCompilerError | If there is no current scope to pop. |
bool l0_backend:: Backend:: _types_equal(self,
Type a,
Type b) protected
Check if two types are structurally equal.
| Parameters | |
|---|---|
| a | First type. |
| b | Second type. |
| Returns | True if types are equal, False otherwise. |
bool l0_backend:: Backend:: _is_int_assignable(self,
Type typ) protected
Check if a type is assignable to an integer.
| Parameters | |
|---|---|
| typ | The type to check. |
| Returns | True if it's an 'int' or 'byte' builtin type. |
bool l0_backend:: Backend:: _is_binary_op_enabled(self,
Type typ) protected
Check if a type supports binary operations.
| Parameters | |
|---|---|
| typ | The type to check. |
| Returns | True if binary operations are supported for the type. |
Currently only int, byte, and bool support binary operations.
bool l0_backend:: Backend:: _is_place_expr(self,
Expr expr) protected
Check if an expression refers to an existing binding.
| Parameters | |
|---|---|
| expr | The expression to check. |
| Returns | True if expr refers to an existing binding (retain on copy). False if expr produces a fresh value (ownership transfer, no retain). |
bool l0_backend:: Backend:: _is_unwrap_cast_from_place(self,
Expr expr) protected
Check if a cast expression still borrows from an existing owner.
| Parameters | |
|---|---|
| expr | The expression to check. |
| Returns | True for non-owner-producing casts whose source is a place. |
Outer parentheses are ownership-transparent. Owner-producing ARC value-optional wraps are excluded.
bool l0_backend:: Backend:: _needs_arc_temp(self,
Expr expr) protected
Check if a non-place rvalue with ARC data needs temp materialization.
| Parameters | |
|---|---|
| expr | The expression to check. |
| Returns | True if temp materialization is needed. |
String literals are static constants and don't need cleanup.
bool l0_backend:: Backend:: _should_materialize_arc_temp(self,
Expr expr,
Type expr_type) protected
Check if an ARC expression should be hoisted to a cleanup temp.
| Parameters | |
|---|---|
| expr | The expression to check. |
| expr_type | The type of the expression. |
| Returns | True if the expression should be materialized into a temporary. |
str l0_backend:: Backend:: _materialize_arc_temp(self,
str c_expr,
Type expr_type) protected
Materialize an ARC rvalue into a scope-owned temporary for automatic cleanup.
| Parameters | |
|---|---|
| c_expr | The C expression string. |
| expr_type | The type of the expression. |
| Returns | The name of the generated temporary variable. |
bool l0_backend:: Backend:: _has_side_effects(self,
Expr expr) protected
Check if the expression has side effects or contains function calls.
| Parameters | |
|---|---|
| expr | The expression to check. |
| Returns | True if the expression has potential side effects. |
Such expressions should be evaluated once and cached in a temporary to avoid multiple evaluation when used in contexts like assignment with ARC operations.
Optional[Type] l0_backend:: Backend:: _lookup_local_var_type(self,
str var_name) protected
Look up a local variable's type in the current scope chain.
| Parameters | |
|---|---|
| var_name | The name of the variable to look up. |
| Returns | The variable's Type, or None if not found. |
Searches declared_vars (includes both locals and parameters).
Optional[str] l0_backend:: Backend:: _lookup_owned_local_name(self,
VarRef expr) protected
Return the mangled local name when a VarRef resolves to an owned local binding.
| Parameters | |
|---|---|
| expr | The variable reference expression. |
| Returns | The mangled local name if it's an owned binding, otherwise None. |
Parameters are local VarRefs but are not owned by the callee, so they do not appear in owned_vars and return None.
Set[Tuple[str, str]] l0_backend:: Backend:: _extract_value_type_dependencies(self,
Type typ) protected
Extract type dependencies for VALUE fields only.
| Parameters | |
|---|---|
| typ | The type to extract dependencies from. |
| Returns | Set of (module, name) tuples for types that must be defined first. |
Value-type fields create dependencies (types must be fully defined). Pointer-type fields do NOT create dependencies (forward declarations suffice).
Examples:
- StructType("main", "Point") -> {("main", "Point")}
- EnumType("main", "Status") -> {("main", "Status")}
- PointerType(StructType("main", "Node")) -> {} (no dependency, forward decl works)
- NullableType(PointerType(...)) -> {} (pointer-optional, no dependency)
- NullableType(BuiltinType("int")) -> {} (value-optional of builtin, no dependency)
- NullableType(StructType("main", "Point")) -> {("main", "Point")} (value-optional of struct)
- BuiltinType("int") -> {} (no dependency)
Dict[Tuple[str, str], Set[Tuple[str, str]]] l0_backend:: Backend:: _build_type_dependency_graph(self) protected
Build dependency graph for type definitions.
| Returns | Dict mapping (module, type_name) -> Set of (module, type_name) dependencies. |
|---|
A type X depends on type Y if X has a VALUE field of type Y. Pointer fields do NOT create dependencies (forward declarations handle them).
str l0_backend:: Backend:: _find_cycle_details(self,
Dict[Tuple[str, str],
Set]] graph[Tuple[str, str],
List] unresolved[Tuple[str, str]) protected
Find and format cycle details for error message.
| Parameters | |
|---|---|
| graph | The type dependency graph. |
| unresolved | List of unresolved nodes. |
| Returns | A string describing the detected cycle details. |
List[Tuple[str, str]] l0_backend:: Backend:: _topological_sort(self,
Dict[Tuple[str, str],
Set]] graph[Tuple[str, str]) protected
Perform topological sort on type dependency graph using Kahn's algorithm.
| Parameters | |
|---|---|
| graph | The type dependency graph. |
| Returns | List of (module, type_name) in dependency order (dependencies first). |
| Exceptions | |
| InternalCompilerError | On cycles (value-type cycles are impossible in valid L0). |
Optional[StructDecl] l0_backend:: Backend:: _find_struct_decl(self,
str module_name,
str struct_name) protected
Find the StructDecl AST node for a given struct.
| Parameters | |
|---|---|
| module_name | Name of the module. |
| struct_name | Name of the struct. |
| Returns | The StructDecl if found, otherwise None. |
Optional[EnumDecl] l0_backend:: Backend:: _find_enum_decl(self,
str module_name,
str enum_name) protected
Find the EnumDecl AST node for a given enum.
| Parameters | |
|---|---|
| module_name | Name of the module. |
| enum_name | Name of the enum. |
| Returns | The EnumDecl if found, otherwise None. |
Type l0_backend:: Backend:: _expect_expr_type(self,
Expr expr) protected
Look up an expression's type and fail if missing.
| Parameters | |
|---|---|
| expr | The expression to look up. |
| Returns | The resolved Type of the expression. |
| Exceptions | |
| InternalCompilerError | If the type is missing from the analysis. |
None l0_backend:: Backend:: _emit_line_directive(self,
Node node) protected
Emit #line directive if node has span info and context allows it.
| Parameters | |
|---|---|
| node | The AST node containing span information. |
None l0_backend:: Backend:: _emit_let_declaration(self,
str module_name,
LetDecl decl) protected
Emit a single top-level let declaration as a static variable.
| Parameters | |
|---|---|
| module_name | Name of the module containing the declaration. |
| decl | The LetDecl AST node. |
str l0_backend:: Backend:: _emit_let_initializer(self,
Expr expr,
Type expected_type) protected
Generate C initializer expression for a top-level let.
| Parameters | |
|---|---|
| expr | The initializer expression. |
| expected_type | The expected type of the constant. |
| Returns | A C initializer expression string. |
| Exceptions | |
| InternalCompilerError | If the initializer is not constant or supported. |
Supports compile-time constant literals and struct/enum construction.
str l0_backend:: Backend:: _emit_const_constructor(self,
CallExpr expr,
Type expected_type) protected
Emit a constant struct or enum constructor for static initialization.
| Parameters | |
|---|---|
| expr | The constructor call expression. |
| expected_type | The expected struct or enum type. |
| Returns | A C initializer string. |
| Exceptions | |
| InternalCompilerError | If symbol or constructor type is invalid. |
Similar to _try_emit_constructor but only handles constant expressions.
str l0_backend:: Backend:: _emit_const_struct_constructor(self,
CallExpr expr,
StructType struct_type) protected
Emit constant struct constructor for static initialization.
| Parameters | |
|---|---|
| expr | The constructor call expression. |
| struct_type | The struct type. |
| Returns | A C struct initializer string. |
| Exceptions | |
| InternalCompilerError | If struct info is missing or argument count mismatches. |
str l0_backend:: Backend:: _emit_const_variant_constructor(self,
CallExpr expr,
EnumType enum_type) protected
Emit constant enum variant constructor for static initialization.
| Parameters | |
|---|---|
| expr | The variant call expression. |
| enum_type | The enum type. |
| Returns | A C enum variant initializer string. |
| Exceptions | |
| InternalCompilerError | If variant info or declaration is missing. |
None l0_backend:: Backend:: _emit_function_declaration(self,
str module_name,
FuncDecl decl) protected
Emit a single function declaration.
| Parameters | |
|---|---|
| module_name | Name of the module. |
| decl | The FuncDecl AST node. |
| Exceptions | |
| InternalCompilerError | If FuncType is missing. |
None l0_backend:: Backend:: _emit_function_definition(self,
str module_name,
FuncDecl decl) protected
Emit a complete function definition with body.
| Parameters | |
|---|---|
| module_name | Name of the module. |
| decl | The FuncDecl AST node. |
| Exceptions | |
| InternalCompilerError | If scope is not reset or FuncType is missing. |
None l0_backend:: Backend:: _emit_main_wrapper_if_needed(self) protected
If the entry module has a main function, emit a C main() wrapper.
This allows us to consistently mangle all L0 functions (including main) while still providing the expected C entry point.
bool l0_backend:: Backend:: _scope_chain_has_cleanup(self) protected
Check if any scope in the chain has cleanup requirements.
| Returns | True if any scope has a with-cleanup or owned ARC variables. |
|---|
None l0_backend:: Backend:: _emit_cleanup_for_return(self,
Optional returned_var[str] = None) protected
Emit cleanup logic for a return statement.
| Parameters | |
|---|---|
| returned_var | Mangled name of variable being returned (to skip cleanup). |
Walks up scope chain, executes any with-statement cleanup data, then cleans ALL owned variables (except return value). The with-cleanup runs first because user cleanup code may reference variables whose owned resources (e.g. string refcounts) are released by the automatic owned-var cleanup.
None l0_backend:: Backend:: _emit_cleanup_for_loop_exit(self,
*bool is_break) protected
Emit cleanup for break/continue.
| Parameters | |
|---|---|
| is_break | True if cleaning for 'break', False for 'continue'. |
| Exceptions | |
| InternalCompilerError | If called outside of a loop. |
Walks from current scope up to and including the innermost loop cleanup target, executing any with-statement cleanup data along the way. The with-cleanup runs before owned-var cleanup (see _emit_cleanup_for_return for rationale).
None l0_backend:: Backend:: _emit_cleanup_at_scope_exit(self,
ScopeContext scope) protected
Emit cleanup at scope exit.
| Parameters | |
|---|---|
| scope | The scope being exited. |
Only cleans variables declared in THIS scope that have owned fields.
None l0_backend:: Backend:: _emit_with_cleanup_from_scope(self,
ScopeContext scope,
str module_name) protected
Emit with-statement cleanup for a scope.
| Parameters | |
|---|---|
| scope | The scope containing cleanup logic. |
| module_name | Name of current module. |
None l0_backend:: Backend:: _emit_value_cleanup(self,
str c_expr,
Type ty) protected
Emit cleanup code for a by-value variable before reassignment.
| Parameters | |
|---|---|
| c_expr | C expression for the value (e.g., "x__v", "obj.field") |
| ty | The type of the value being cleaned up |
Similar to _emit_field_cleanup, but expects c_expr to be a direct value reference (not a pointer), so uses '.' instead of '->'.
None l0_backend:: Backend:: _emit_struct_cleanup(self,
str c_ptr_expr,
StructType struct_type) protected
Emit cleanup code for all owned fields in a struct.
| Parameters | |
|---|---|
| c_ptr_expr | C expression evaluating to a pointer to the struct. |
| struct_type | The struct type. |
Recursively handles nested structs (by-value fields).
None l0_backend:: Backend:: _emit_enum_cleanup(self,
str c_ptr_expr,
EnumType enum_type) protected
Emit cleanup code for owned fields in an enum's active variant.
| Parameters | |
|---|---|
| c_ptr_expr | C expression evaluating to a pointer to the enum. |
| enum_type | The enum type. |
Uses switch on tag to only clean up the fields that are actually present.
None l0_backend:: Backend:: _emit_block_sequence(self,
Block block,
str module_name) protected
Emit statements in a block.
| Parameters | |
|---|---|
| block | The Block AST node. |
| module_name | Name of current module. |
None l0_backend:: Backend:: _emit_stmt(self,
Stmt stmt,
str module_name) protected
Emit a single statement.
| Parameters | |
|---|---|
| stmt | The Stmt AST node. |
| module_name | Name of current module. |
| Exceptions | |
| InternalCompilerError | If statement type is unsupported. |
Any l0_backend:: Backend:: _emit_block(self,
Block stmt,
str module_name) protected
Emit a block statement with its own scope.
| Parameters | |
|---|---|
| stmt | The Block AST node. |
| module_name | Name of current module. |
Any l0_backend:: Backend:: _emit_return(self,
ReturnStmt stmt,
Optional[Callable[[],
None]] before_cleanup = None) protected
Emit a return statement with cleanup.
| Parameters | |
|---|---|
| stmt | The ReturnStmt AST node. |
| before_cleanup | Optional hook to run after the return value is evaluated and before scope cleanup is emitted. |
None l0_backend:: Backend:: _emit_condition_branch(self,
Expr expr,
str true_label,
str false_label) protected
Emit control flow for one condition expression with short-circuit semantics.
| Parameters | |
|---|---|
| expr | Condition expression to lower. |
| true_label | Jump target when the condition is true. |
| false_label | Jump target when the condition is false. |
This path is used only for statement conditions so ARC temps emitted by expression lowering stay inside the correct structural block instead of being hoisted into an enclosing "if (...)" or "while (...)" header.
str l0_backend:: Backend:: _emit_condition_value(self,
Expr expr) protected
Evaluate a statement condition into a stable boolean temporary.
| Parameters | |
|---|---|
| expr | Condition expression to lower. |
| Returns | Name of the generated boolean temp. |
The returned temp is safe to reference from an if/ because any ARC temps created while evaluating the condition are scoped to the emitted condition block and cleaned before control continues.while header
Any l0_backend:: Backend:: _emit_while(self,
WhileStmt stmt,
str module_name) protected
Emit a while loop.
| Parameters | |
|---|---|
| stmt | The WhileStmt AST node. |
| module_name | Name of current module. |
Any l0_backend:: Backend:: _emit_if_else(self,
IfStmt stmt,
str module_name) protected
Emit an if-else statement.
| Parameters | |
|---|---|
| stmt | The IfStmt AST node. |
| module_name | Name of current module. |
bool l0_backend:: Backend:: _gen_if_else_branch(self,
Stmt stmt,
str module_name) protected
Emit a branch of an if/else.
| Parameters | |
|---|---|
| stmt | The statement in the branch. |
| module_name | Name of current module. |
| Returns | True if branch is unreachable at end. |
set l0_backend:: Backend:: _collect_reassigned_arc_params(self,
FuncDecl decl,
FuncType func_type) protected
Collect the names of ARC-typed parameters reassigned syntactically in the body.
| Parameters | |
|---|---|
| decl | The FuncDecl AST node. |
| func_type | The resolved FuncType for the declaration. |
| Returns | Set of parameter names (source names, not mangled) to retain at entry. |
Any function whose body contains an AssignStmt whose target is a bare VarRef naming an ARC-typed parameter needs a defensive retain on that parameter at entry.
None l0_backend:: Backend:: _emit_reassignment(self,
AssignStmt stmt) protected
Emit an assignment statement.
| Parameters | |
|---|---|
| stmt | The AssignStmt AST node. |
| Exceptions | |
| InternalCompilerError | If types are missing or emission fails. |
str l0_backend:: Backend:: _emit_lvalue_with_caching(self,
Expr target) protected
Emit an lvalue expression, caching sub-expressions with side effects.
| Parameters | |
|---|---|
| target | The lvalue expression. |
| Returns | A C lvalue expression string. |
| Exceptions | |
| InternalCompilerError | If types are missing for complex lvalues. |
For targets like *(func_call()), the pointer expression func_call() must be evaluated exactly once, not multiple times during release/assign/retain.
Type l0_backend:: Backend:: _resolve_let_type(self,
LetStmt stmt,
str module_name) protected
Resolve concrete type for a let declaration.
| Parameters | |
|---|---|
| stmt | The LetStmt AST node. |
| module_name | Name of current module. |
| Returns | The resolved Type. |
| Exceptions | |
| InternalCompilerError | If type cannot be inferred. |
Optional[Type] l0_backend:: Backend:: _emit_with_cleanup_header_let_predecl(self,
LetStmt stmt,
str module_name) protected
Predeclare a nullable with-header let for cleanup-block form.
| Parameters | |
|---|---|
| stmt | The LetStmt AST node. |
| module_name | Name of current module. |
| Returns | The Type if it was a nullable let, otherwise None. |
Nullable lets are predeclared as null so cleanup code can reference them on header ? failure paths.
Non-nullable lets use the normal declaration+initializer path and return None here.
None l0_backend:: Backend:: _emit_with_cleanup_header_let_assign(self,
LetStmt stmt,
Type var_ty) protected
Emit initializer assignment for a predeclared cleanup-block let.
| Parameters | |
|---|---|
| stmt | The LetStmt AST node. |
| var_ty | The resolved type of the let. |
None l0_backend:: Backend:: _emit_retain_for_copied_value(self,
str c_expr,
Type ty) protected
Emit retain operations for a copied owned value.
| Parameters | |
|---|---|
| c_expr | C expression evaluating to the value. |
| ty | The type of the value. |
| Exceptions | |
| InternalCompilerError | If variant decl is missing for enum types. |
Used when copying from place expressions so source and destination own independent references.
str l0_backend:: Backend:: _emit_copy_expr_with_retains(self,
str c_expr,
Type ty) protected
Materialize copied values in a temp and emit retain logic when needed.
| Parameters | |
|---|---|
| c_expr | C expression evaluating to the value. |
| ty | The type of the value. |
| Returns | The name of the temporary containing the copied and retained value. |
None l0_backend:: Backend:: _emit_match(self,
MatchStmt stmt,
str module_name) protected
Emit a match statement as a switch on the tag field.
| Parameters | |
|---|---|
| stmt | The MatchStmt AST node. |
| module_name | Name of current module. |
| Exceptions | |
| InternalCompilerError | If types or patterns are unsupported. |
None l0_backend:: Backend:: _emit_case(self,
CaseStmt stmt,
str module_name) protected
Emit a case statement as a scalar switch or string if/else chain.
| Parameters | |
|---|---|
| stmt | The CaseStmt AST node. |
| module_name | Name of current module. |
| Exceptions | |
| InternalCompilerError | If types or literals are unsupported. |
str l0_backend:: Backend:: _emit_case_literal(self,
Expr expr) protected
Emit a constant literal for a case statement.
| Parameters | |
|---|---|
| expr | The literal expression. |
| Returns | A C constant string. |
| Exceptions | |
| InternalCompilerError | If literal type is unsupported. |
None l0_backend:: Backend:: _emit_pattern_bindings(self,
VariantPattern pattern,
EnumType enum_type,
ScopeContext arm_scope) protected
Emit pattern variable bindings and add them to arm scope.
| Parameters | |
|---|---|
| pattern | The variant pattern. |
| enum_type | The enum type. |
| arm_scope | The scope for the match arm. |
| Exceptions | |
| InternalCompilerError | If variant decl is missing. |
None l0_backend:: Backend:: _emit_with(self,
WithStmt stmt,
str module_name) protected
Emit a with statement.
| Parameters | |
|---|---|
| stmt | The WithStmt AST node. |
| module_name | Name of current module. |
Inline => form (LIFO cleanup): Emit init statements, then body, then cleanup statements in reverse order.
Cleanup block form: Emit init statements, then body, then cleanup block statements.
Cleanup is emitted at block end and before every early exit (return, break, continue). The scope stores cleanup data so _emit_cleanup_for_return and _emit_cleanup_for_loop_exit can emit it before leaving.
The body and cleanup block are each emitted as real nested C blocks so that any declarations inside them do not collide with the header scope (e.g., legal L0 shadowing like "let x" in both the header and body).
None l0_backend:: Backend:: _emit_drop(self,
DropStmt stmt,
str module_name) protected
Emit drop statement with automatic cleanup of owned fields.
| Parameters | |
|---|---|
| stmt | The DropStmt AST node. |
| module_name | Name of current module. |
| Exceptions | |
| InternalCompilerError | If variable is undefined or not a pointer. |
For structs: releases all string fields. For enums: switches on tag, releases strings in active variant. Then calls the drop-finish helper to release the memory.
Optional[str] l0_backend:: Backend:: _try_emit_intrinsic(self,
CallExpr expr) protected
Expand compiler intrinsics inline.
| Parameters | |
|---|---|
| expr | The call expression to check. |
| Returns | C code string if it is an intrinsic, otherwise None. |
str l0_backend:: Backend:: _emit_sizeof_intrinsic(self,
CallExpr expr) protected
Emit sizeof intrinsic.
| Parameters | |
|---|---|
| expr | The sizeof call expression. |
| Returns | A C sizeof expression string. |
| Exceptions | |
| InternalCompilerError | If target type cannot be resolved. |
str l0_backend:: Backend:: _emit_ord_intrinsic(self,
CallExpr expr) protected
Emit ord(enum_value) intrinsic.
| Parameters | |
|---|---|
| expr | The ord call expression. |
| Returns | A C expression string for the ordinal value. |
| Exceptions | |
| InternalCompilerError | If argument count is incorrect. |
Returns 0-based ordinal of enum variant.
Optional[str] l0_backend:: Backend:: _try_emit_constructor(self,
CallExpr expr) protected
Check if expr is a constructor call and emit appropriate initialization.
| Parameters | |
|---|---|
| expr | The call expression to check. |
| Returns | C code string if this is a constructor, otherwise None. |
Struct: Point(1, 2) -> { .x = 1, .y = 2 } Enum: Int(42) -> { .tag = Expr_Int, .data = { .Int = { .value = 42 } } }
str l0_backend:: Backend:: _emit_struct_constructor(self,
CallExpr expr,
StructType struct_type) protected
Emit struct constructor as C designated initializer.
| Parameters | |
|---|---|
| expr | The constructor call expression. |
| struct_type | The struct type. |
| Returns | A C struct initializer expression string. |
| Exceptions | |
| InternalCompilerError | If struct info is missing or argument count mismatches. |
Point(1, 2) -> (struct l0_modulename_Point){ .x = 1, .y = 2 }
str l0_backend:: Backend:: _emit_variant_constructor(self,
CallExpr expr,
EnumType enum_type) protected
Emit enum variant constructor as C tagged union initializer.
| Parameters | |
|---|---|
| expr | The variant call expression. |
| enum_type | The enum type. |
| Returns | A C variant initializer expression string. |
| Exceptions | |
| InternalCompilerError | If variant info or declaration is missing. |
Example: Int(42) -> (struct l0_modulename_Int){ .tag = l0_modulename_Int_Int, .data.Int.value = 42 }
str l0_backend:: Backend:: _emit_new_expr(self,
NewExpr expr) protected
Emit a heap allocation new expression.
| Parameters | |
|---|---|
| expr | The NewExpr AST node. |
| Returns | A C expression string for the newly allocated pointer. |
| Exceptions | |
| InternalCompilerError | If type or symbol resolution fails, or if args mismatch. |
str l0_backend:: Backend:: _convert_expr_with_expected_type(self,
str c_expr,
Optional natural_ty[Type],
Type expected) protected
Convert a pre-emitted expression into the expected type when required.
| Parameters | |
|---|---|
| c_expr | The C expression string. |
| natural_ty | The natural type of the expression. |
| expected | The expected type. |
| Returns | A C expression string, potentially wrapped or widened. |
str l0_backend:: Backend:: _emit_expr_with_expected_type(self,
Expr e,
Type expected) protected
Emit expression with implicit type conversion to expected type.
| Parameters | |
|---|---|
| e | The expression to emit. |
| expected | The expected type. |
| Returns | A C expression string. |
| Exceptions | |
| InternalCompilerError | If null literal is assigned to invalid type. |
str l0_backend:: Backend:: _emit_owned_expr_with_expected_type(self,
Expr e,
Type expected) protected
Emit expression for contexts that create a new owner.
| Parameters | |
|---|---|
| e | The expression to emit. |
| expected | The expected type. |
| Returns | A C expression string. |
This applies retain-on-copy when a place expression is copied into an owned destination, while delegating regular type conversion to _emit_expr_with_expected_type.
str l0_backend:: Backend:: _emit_expr(self,
Expr expr,
*bool is_statement = False) protected
Emit an expression and return the C code.
| Parameters | |
|---|---|
| expr | The expression to emit. |
| is_statement | True if the expression is used as a statement. |
| Returns | A C expression string, or empty string if used as a statement and no-op. |
| Exceptions | |
| InternalCompilerError | If expression type is unsupported or resolution fails. |
str l0_backend:: Backend:: _emit_unwrap(self,
str c_dst,
str c_inner,
NullableType src_ty) protected
Emit code to unwrap a nullable value.
| Parameters | |
|---|---|
| c_dst | C type of destination. |
| c_inner | C expression of nullable value. |
| src_ty | The NullableType. |
| Returns | C code for unwrapped value. |
str l0_backend:: Backend:: _emit_binary_op(self,
Expr expr_node,
str expr_op,
Expr expr_left,
Expr expr_right,
*bool for_condition = False) protected
Emit code for a binary operation.
| Parameters | |
|---|---|
| expr_node | The BinaryOp AST node. |
| expr_op | The operator string. |
| expr_left | The left operand. |
| expr_right | The right operand. |
| for_condition | Whether to preserve condition-context code generation. |
| Returns | C code string for the operation. |
| Exceptions | |
| InternalCompilerError | If types are missing, mismatch, or operation is unsupported. |
Optional[ Symbol] l0_backend:: Backend:: _lookup_symbol(self,
str name,
str current_module_name,
Optional] module_path[List[str] = None) protected
Look up a symbol in the current module's environment.
| Parameters | |
|---|---|
| name | The name of the symbol. |
| current_module_name | Name of current module. |
| module_path | Optional module path for qualified names. |
| Returns | The resolved Symbol, or None if not found. |
This is used to determine which module a function is defined in so we can generate the correct mangled name.
bool l0_backend:: Backend:: _is_extern_function(self,
Symbol sym) protected
Check if a symbol is an 'extern' function.
| Parameters | |
|---|---|
| sym | The symbol to check. |
| Returns | True if it is an extern function. |