l0_backend.py

l0_backend.py

Module: l0_backend

Source: compiler/stage1_py/l0_backend.py Language: Python

Symbols

Namespace l0_backend

Class l0_backend::Backend

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.).

Member Data l0_backend.Backend.analysis

1
AnalysisResult analysis

Member Data l0_backend.Backend.emitter

1
CEmitter emitter

Member Data l0_backend.Backend.current_module

1
Optional current_module

Member Data l0_backend.Backend._current_func_result

1
Optional _current_func_result

Member Data l0_backend.Backend._current_scope

1
Optional _current_scope

Member Data l0_backend.Backend._loop_cleanup_scope_stack

1
List _loop_cleanup_scope_stack

Member Data l0_backend.Backend._switch_depth

1
int _switch_depth

Member Data l0_backend.Backend._loop_label_stack

1
List _loop_label_stack

Member Data l0_backend.Backend._label_counter

1
int _label_counter

Member Data l0_backend.Backend._next_stmt_unreachable

1
bool _next_stmt_unreachable

Member Data l0_backend.Backend.analysis

1
l0_backend.Backend::analysis

Member Data l0_backend.Backend.current_module

1
l0_backend.Backend::current_module

Member Data l0_backend.Backend._current_scope

1
l0_backend.Backend::_current_scope

Member Data l0_backend.Backend._emit_let_initializer

1
l0_backend.Backend::_emit_let_initializer

Member Data l0_backend.Backend._next_stmt_unreachable

1
l0_backend.Backend::_next_stmt_unreachable

Member Data l0_backend.Backend._current_func_result

1
l0_backend.Backend::_current_func_result

Function l0_backend.Backend.__post_init__

1
l0_backend.Backend.__post_init__(self)

Initialize emitter with analysis data.

Function l0_backend.Backend.generate

1
str l0_backend.Backend.generate(self)

Main entry point: generate complete C source for the compilation unit.

Returns: C source code as a string.

Function l0_backend.Backend.ice

1
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.

    Function l0_backend.Backend.find_variant_decl

1
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.

This is needed to get field names when binding pattern variables, since pattern variables are positional, but we need to access fields by name.

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.

Function l0_backend.Backend._fresh_label

1
str l0_backend.Backend._fresh_label(self, str prefix)

Generate a unique C label name.

Parameters:

  • prefix: Prefix for the label name.

Returns: A unique label string.

Function l0_backend.Backend._push_scope

1
ScopeContext l0_backend.Backend._push_scope(self)

Enter a new scope.

Returns: The newly created ScopeContext.

Function l0_backend.Backend._pop_scope

1
None l0_backend.Backend._pop_scope(self)

Exit current scope.

Function l0_backend.Backend._types_equal

1
bool l0_backend.Backend._types_equal(self, Type a, Type b)

Check if two types are structurally equal.

Parameters:

  • a: First type.
  • b: Second type.

Returns: True if types are equal, False otherwise.

Function l0_backend.Backend._is_int_assignable

1
bool l0_backend.Backend._is_int_assignable(self, Type typ)

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.

Function l0_backend.Backend._is_binary_op_enabled

1
bool l0_backend.Backend._is_binary_op_enabled(self, Type typ)

Check if a type supports binary operations.

Currently only int, byte, and bool support binary operations.

Parameters:

  • typ: The type to check.

Returns: True if binary operations are supported for the type.

Function l0_backend.Backend._is_place_expr

1
bool l0_backend.Backend._is_place_expr(self, Expr expr)

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).

Function l0_backend.Backend._is_unwrap_cast_from_place

1
bool l0_backend.Backend._is_unwrap_cast_from_place(self, Expr expr)

Check if a cast expression still borrows from an existing owner.

Outer parentheses are ownership-transparent. Owner-producing ARC value-optional wraps are excluded.

Parameters:

  • expr: The expression to check.

Returns: True for non-owner-producing casts whose source is a place.

Function l0_backend.Backend._needs_arc_temp

1
bool l0_backend.Backend._needs_arc_temp(self, Expr expr)

Check if a non-place rvalue with ARC data needs temp materialization.

String literals are static constants and don’t need cleanup.

Parameters:

  • expr: The expression to check.

Returns: True if temp materialization is needed.

Function l0_backend.Backend._should_materialize_arc_temp

1
bool l0_backend.Backend._should_materialize_arc_temp(self, Expr expr, Type expr_type)

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.

Function l0_backend.Backend._materialize_arc_temp

1
str l0_backend.Backend._materialize_arc_temp(self, str c_expr, Type expr_type)

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.

Function l0_backend.Backend._has_side_effects

1
bool l0_backend.Backend._has_side_effects(self, Expr expr)

Check if the expression has side effects or contains function calls.

Such expressions should be evaluated once and cached in a temporary to avoid multiple evaluation when used in contexts like assignment with ARC operations.

Parameters:

  • expr: The expression to check.

Returns: True if the expression has potential side effects.

Function l0_backend.Backend._pointer_type_or_none

1
Optional[PointerType] l0_backend.Backend._pointer_type_or_none(self, Optional[Type] ty)

Return the represented pointer type for pointer-shaped values.

Function l0_backend.Backend._sizeof_expr_for_type

1
str l0_backend.Backend._sizeof_expr_for_type(self, Type ty)

Return a C sizeof expression for the runtime access extent.

Function l0_backend.Backend._alignof_expr_for_type

1
str l0_backend.Backend._alignof_expr_for_type(self, Type ty)

Return a C alignment expression for the runtime access target.

Function l0_backend.Backend._emit_checked_pointer_expr

1
str l0_backend.Backend._emit_checked_pointer_expr(self, str c_ptr_expr, Type ptr_ty, Optional[Node] node=None, str access_mode="_RT_ACCESS_READ")

Emit a pointer expression checked for one pointee-sized access.

Function l0_backend.Backend._emit_pointer_index_lvalue

1
str l0_backend.Backend._emit_pointer_index_lvalue(self, str c_base, str c_index, Type base_ty, Optional[Node] node=None, str access_mode="_RT_ACCESS_WRITE")

Emit a checked pointer-index lvalue expression.

Function l0_backend.Backend._lookup_local_var_type

1
Optional[Type] l0_backend.Backend._lookup_local_var_type(self, str var_name)

Look up a local variable’s type in the current scope chain.

Searches declared_vars (includes both locals and parameters).

Parameters:

  • var_name: The name of the variable to look up.

Returns: The variable’s Type, or None if not found.

Function l0_backend.Backend._lookup_owned_local_name

1
Optional[str] l0_backend.Backend._lookup_owned_local_name(self, VarRef expr)

Return the mangled local name when a VarRef resolves to an owned local binding.

Parameters are local VarRefs but are not owned by the callee, so they do not appear in owned_vars and return None.

Parameters:

  • expr: The variable reference expression.

Returns: The mangled local name if it’s an owned binding, otherwise None.

Function l0_backend.Backend._extract_value_type_dependencies

1
Set[Tuple[str, str]] l0_backend.Backend._extract_value_type_dependencies(self, Type typ)

Extract type dependencies for VALUE fields only.

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)

Parameters:

  • typ: The type to extract dependencies from.

Returns: Set of (module, name) tuples for types that must be defined first.

Function l0_backend.Backend._build_type_dependency_graph

1
Dict[Tuple[str, str], Set[Tuple[str, str]]] l0_backend.Backend._build_type_dependency_graph(self)

Build dependency graph for type definitions.

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).

Returns: Dict mapping (module, type_name) -> Set of (module, type_name) dependencies.

Function l0_backend.Backend._find_cycle_details

1
str l0_backend.Backend._find_cycle_details(self, Dict[Tuple[str, str], Set[Tuple[str, str]]] graph, List[Tuple[str, str]] unresolved)

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.

Function l0_backend.Backend._topological_sort

1
List[Tuple[str, str]] l0_backend.Backend._topological_sort(self, Dict[Tuple[str, str], Set[Tuple[str, str]]] graph)

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).

Function l0_backend.Backend._find_struct_decl

1
Optional[StructDecl] l0_backend.Backend._find_struct_decl(self, str module_name, str struct_name)

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.

Function l0_backend.Backend._find_enum_decl

1
Optional[EnumDecl] l0_backend.Backend._find_enum_decl(self, str module_name, str enum_name)

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.

Function l0_backend.Backend._expect_expr_type

1
Type l0_backend.Backend._expect_expr_type(self, Expr expr)

Look up an expression’s type and fail if missing.

Parameters:

  • expr: The expression to look up.

Returns: The resolved Type of the expression.

Function l0_backend.Backend._emit_line_directive

1
None l0_backend.Backend._emit_line_directive(self, Node node)

Emit #line directive if node has span info and context allows it.

Parameters:

  • node: The AST node containing span information.

    Function l0_backend.Backend._emit_let_declarations

1
None l0_backend.Backend._emit_let_declarations(self)

Emit static global variables for top-level let declarations.

Function l0_backend.Backend._emit_let_declaration

1
None l0_backend.Backend._emit_let_declaration(self, str module_name, LetDecl decl)

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.

    Function l0_backend.Backend._emit_let_initializer

1
str l0_backend.Backend._emit_let_initializer(self, Expr expr, Type expected_type)

Generate C initializer expression for a top-level let.

Supports compile-time constant literals and struct/enum construction.

Parameters:

  • expr: The initializer expression.
  • expected_type: The expected type of the constant.

Returns: A C initializer expression string.

Function l0_backend.Backend._emit_bare_variant_static_initializer

1
str l0_backend.Backend._emit_bare_variant_static_initializer(self, VarRef expr, Type expected_type)

Emit a bare zero-argument enum variant for static initialization.

Function l0_backend.Backend._emit_const_constructor

1
str l0_backend.Backend._emit_const_constructor(self, CallExpr expr, Type expected_type)

Emit a constant struct or enum constructor for static initialization.

Similar to _try_emit_constructor but only handles constant expressions.

Parameters:

  • expr: The constructor call expression.
  • expected_type: The expected struct or enum type.

Returns: A C initializer string.

Function l0_backend.Backend._emit_const_struct_constructor

1
str l0_backend.Backend._emit_const_struct_constructor(self, CallExpr expr, StructType struct_type)

Emit constant struct constructor for static initialization.

Parameters:

  • expr: The constructor call expression.
  • struct_type: The struct type.

Returns: A C struct initializer string.

Function l0_backend.Backend._emit_const_variant_constructor

1
str l0_backend.Backend._emit_const_variant_constructor(self, CallExpr expr, EnumType enum_type)

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.

Function l0_backend.Backend._emit_function_declarations

1
None l0_backend.Backend._emit_function_declarations(self)

Emit forward declarations for all functions.

Function l0_backend.Backend._emit_function_declaration

1
None l0_backend.Backend._emit_function_declaration(self, str module_name, FuncDecl decl)

Emit a single function declaration.

Parameters:

  • module_name: Name of the module.
  • decl: The FuncDecl AST node.

    Function l0_backend.Backend._emit_function_definitions

1
None l0_backend.Backend._emit_function_definitions(self)

Emit function definitions (bodies).

Function l0_backend.Backend._emit_function_definition

1
None l0_backend.Backend._emit_function_definition(self, str module_name, FuncDecl decl)

Emit a complete function definition with body.

Parameters:

  • module_name: Name of the module.
  • decl: The FuncDecl AST node.

    Function l0_backend.Backend._emit_main_wrapper_if_needed

1
None l0_backend.Backend._emit_main_wrapper_if_needed(self)

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.

Function l0_backend.Backend._scope_chain_has_cleanup

1
bool l0_backend.Backend._scope_chain_has_cleanup(self)

Check if any scope in the chain has cleanup requirements.

Returns: True if any scope has a with-cleanup or owned ARC variables.

Function l0_backend.Backend._emit_cleanup_for_return

1
None l0_backend.Backend._emit_cleanup_for_return(self, Optional[str] returned_var=None)

Emit cleanup logic for a return statement.

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.

Parameters:

  • returned_var: Mangled name of variable being returned (to skip cleanup).

    Function l0_backend.Backend._emit_cleanup_for_loop_exit

1
None l0_backend.Backend._emit_cleanup_for_loop_exit(self, *bool is_break)

Emit cleanup for break/continue.

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).

Parameters:

  • is_break: True if cleaning for ‘break’, False for ‘continue’.

    Function l0_backend.Backend._emit_cleanup_at_scope_exit

1
None l0_backend.Backend._emit_cleanup_at_scope_exit(self, ScopeContext scope)

Emit cleanup at scope exit.

Only cleans variables declared in THIS scope that have owned fields.

Parameters:

  • scope: The scope being exited.

    Function l0_backend.Backend._emit_with_cleanup_from_scope

1
None l0_backend.Backend._emit_with_cleanup_from_scope(self, ScopeContext scope, str module_name)

Emit with-statement cleanup for a scope.

Parameters:

  • scope: The scope containing cleanup logic.
  • module_name: Name of current module.

    Function l0_backend.Backend._emit_value_cleanup

1
None l0_backend.Backend._emit_value_cleanup(self, str c_expr, Type ty)

Emit cleanup code for a by-value variable before reassignment.

Similar to _emit_field_cleanup, but expects c_expr to be a direct value reference (not a pointer), so uses ‘.’ instead of ‘->’.

Parameters:

  • c_expr: C expression for the value (e.g., “x__v”, “obj.field”)
  • ty: The type of the value being cleaned up

    Function l0_backend.Backend._emit_struct_cleanup

1
None l0_backend.Backend._emit_struct_cleanup(self, str c_ptr_expr, StructType struct_type)

Emit cleanup code for all owned fields in a struct.

Recursively handles nested structs (by-value fields).

Parameters:

  • c_ptr_expr: C expression evaluating to a pointer to the struct.
  • struct_type: The struct type.

    Function l0_backend.Backend._emit_enum_cleanup

1
None l0_backend.Backend._emit_enum_cleanup(self, str c_ptr_expr, EnumType enum_type)

Emit cleanup code for owned fields in an enum’s active variant.

Uses switch on tag to only clean up the fields that are actually present.

Parameters:

  • c_ptr_expr: C expression evaluating to a pointer to the enum.
  • enum_type: The enum type.

    Function l0_backend.Backend._emit_block_sequence

1
None l0_backend.Backend._emit_block_sequence(self, Block block, str module_name)

Emit statements in a block.

Parameters:

  • block: The Block AST node.
  • module_name: Name of current module.

    Function l0_backend.Backend._emit_stmt

1
None l0_backend.Backend._emit_stmt(self, Stmt stmt, str module_name)

Emit a single statement.

Parameters:

  • stmt: The Stmt AST node.
  • module_name: Name of current module.

    Function l0_backend.Backend._emit_block

1
Any l0_backend.Backend._emit_block(self, Block stmt, str module_name)

Emit a block statement with its own scope.

Parameters:

  • stmt: The Block AST node.
  • module_name: Name of current module.

    Function l0_backend.Backend._emit_return

1
Any l0_backend.Backend._emit_return(self, ReturnStmt stmt, Optional[Callable[[], None]] before_cleanup=None)

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.

    Function l0_backend.Backend._register_inline_with_cleanup

1
None l0_backend.Backend._register_inline_with_cleanup(self, ScopeContext scope, "WithItem" item)

Register one inline with-item cleanup in LIFO order.

Function l0_backend.Backend._emit_inline_with_header_item

1
None l0_backend.Backend._emit_inline_with_header_item(self, "WithItem" item, str module_name, ScopeContext scope)

Emit one inline with header item and register its cleanup at the committed point.

Function l0_backend.Backend._emit_condition_branch

1
None l0_backend.Backend._emit_condition_branch(self, Expr expr, str true_label, str false_label)

Emit control flow for one condition expression with short-circuit semantics.

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.

Parameters:

  • expr: Condition expression to lower.
  • true_label: Jump target when the condition is true.
  • false_label: Jump target when the condition is false.

    Function l0_backend.Backend._emit_condition_expr

1
str l0_backend.Backend._emit_condition_expr(self, Expr expr)

Emit a top-level condition expression for direct statement headers.

Function l0_backend.Backend._emit_condition_value

1
str l0_backend.Backend._emit_condition_value(self, Expr expr)

Evaluate a statement condition into a stable boolean temporary.

The returned temp is safe to reference from an if/while header because any ARC temps created while evaluating the condition are scoped to the emitted condition block and cleaned before control continues.

Parameters:

  • expr: Condition expression to lower.

Returns: Name of the generated boolean temp.

Function l0_backend.Backend._emit_while

1
Any l0_backend.Backend._emit_while(self, WhileStmt stmt, str module_name)

Emit a while loop.

Parameters:

  • stmt: The WhileStmt AST node.
  • module_name: Name of current module.

    Function l0_backend.Backend._emit_for

1
Any l0_backend.Backend._emit_for(self, ForStmt stmt, str module_name)

Emit a for loop.

Parameters:

  • stmt: The ForStmt AST node.
  • module_name: Name of current module.

    Function l0_backend.Backend._emit_if_else

1
Any l0_backend.Backend._emit_if_else(self, IfStmt stmt, str module_name)

Emit an if-else statement.

Parameters:

  • stmt: The IfStmt AST node.
  • module_name: Name of current module.

    Function l0_backend.Backend._gen_if_else_branch

1
bool l0_backend.Backend._gen_if_else_branch(self, Stmt stmt, str module_name)

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.

Function l0_backend.Backend._iter_body_stmts

1
l0_backend.Backend._iter_body_stmts(self, Optional[Stmt] stmt)

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.

Function l0_backend.Backend._collect_reassigned_arc_params

1
set l0_backend.Backend._collect_reassigned_arc_params(self, FuncDecl decl, FuncType func_type)

Collect the names of ARC-typed parameters reassigned syntactically in the body.

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.

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.

Function l0_backend.Backend._emit_reassignment

1
None l0_backend.Backend._emit_reassignment(self, AssignStmt stmt)

Emit an assignment statement.

Parameters:

  • stmt: The AssignStmt AST node.

    Function l0_backend.Backend._emit_lvalue_with_caching

1
str l0_backend.Backend._emit_lvalue_with_caching(self, Expr target)

Emit an lvalue expression, caching sub-expressions with side effects.

For targets like * (func_call()), the pointer expression func_call() must be evaluated exactly once, not multiple times during release/assign/retain.

Parameters:

  • target: The lvalue expression.

Returns: A C lvalue expression string.

Function l0_backend.Backend._emit_let

1
Any l0_backend.Backend._emit_let(self, LetStmt stmt, str module_name)

Emit a local ‘let’ declaration.

Parameters:

  • stmt: The LetStmt AST node.
  • module_name: Name of current module.

    Function l0_backend.Backend._resolve_let_type

1
Type l0_backend.Backend._resolve_let_type(self, LetStmt stmt, str module_name)

Resolve concrete type for a let declaration.

Parameters:

  • stmt: The LetStmt AST node.
  • module_name: Name of current module.

Returns: The resolved Type.

Function l0_backend.Backend._emit_with_cleanup_header_let_predecl

1
Optional[Type] l0_backend.Backend._emit_with_cleanup_header_let_predecl(self, LetStmt stmt, str module_name)

Predeclare a nullable with-header let for cleanup-block form.

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.

Parameters:

  • stmt: The LetStmt AST node.
  • module_name: Name of current module.

Returns: The Type if it was a nullable let, otherwise None.

Function l0_backend.Backend._emit_with_cleanup_header_let_assign

1
None l0_backend.Backend._emit_with_cleanup_header_let_assign(self, LetStmt stmt, Type var_ty)

Emit initializer assignment for a predeclared cleanup-block let.

Parameters:

  • stmt: The LetStmt AST node.
  • var_ty: The resolved type of the let.

    Function l0_backend.Backend._emit_retain_for_copied_value

1
None l0_backend.Backend._emit_retain_for_copied_value(self, str c_expr, Type ty)

Emit retain operations for a copied owned value.

Used when copying from place expressions so source and destination own independent references.

Parameters:

  • c_expr: C expression evaluating to the value.
  • ty: The type of the value.

    Function l0_backend.Backend._emit_copy_expr_with_retains

1
str l0_backend.Backend._emit_copy_expr_with_retains(self, str c_expr, Type ty)

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.

Function l0_backend.Backend._emit_match

1
None l0_backend.Backend._emit_match(self, MatchStmt stmt, str module_name)

Emit a match statement as a switch on the tag field.

Parameters:

  • stmt: The MatchStmt AST node.
  • module_name: Name of current module.

    Function l0_backend.Backend._emit_case

1
None l0_backend.Backend._emit_case(self, CaseStmt stmt, str module_name)

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.

    Function l0_backend.Backend._emit_case_literal

1
str l0_backend.Backend._emit_case_literal(self, Expr expr)

Emit a constant literal for a case statement.

Parameters:

  • expr: The literal expression.

Returns: A C constant string.

Function l0_backend.Backend._emit_pattern_bindings

1
None l0_backend.Backend._emit_pattern_bindings(self, VariantPattern pattern, EnumType enum_type, ScopeContext arm_scope)

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.

    Function l0_backend.Backend._emit_with

1
None l0_backend.Backend._emit_with(self, WithStmt stmt, str module_name)

Emit a with statement.

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).

Parameters:

  • stmt: The WithStmt AST node.
  • module_name: Name of current module.

    Function l0_backend.Backend._emit_drop

1
None l0_backend.Backend._emit_drop(self, DropStmt stmt, str module_name)

Emit drop statement with automatic cleanup of owned fields.

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.

Parameters:

  • stmt: The DropStmt AST node.
  • module_name: Name of current module.

    Function l0_backend.Backend._try_emit_intrinsic

1
Optional[str] l0_backend.Backend._try_emit_intrinsic(self, CallExpr expr)

Expand compiler intrinsics inline.

Parameters:

  • expr: The call expression to check.

Returns: C code string if it is an intrinsic, otherwise None.

Function l0_backend.Backend._emit_sizeof_intrinsic

1
str l0_backend.Backend._emit_sizeof_intrinsic(self, CallExpr expr)

Emit sizeof intrinsic.

Parameters:

  • expr: The sizeof call expression.

Returns: A C sizeof expression string.

Function l0_backend.Backend._emit_ord_intrinsic

1
str l0_backend.Backend._emit_ord_intrinsic(self, CallExpr expr)

Emit ord(enum_value) intrinsic.

Returns 0-based ordinal of enum variant.

Parameters:

  • expr: The ord call expression.

Returns: A C expression string for the ordinal value.

Function l0_backend.Backend._try_emit_constructor

1
Optional[str] l0_backend.Backend._try_emit_constructor(self, CallExpr expr)

Check if expr is a constructor call and emit appropriate initialization.

Struct: Point(1, 2) -> { .x = 1, .y = 2 } Enum: Int(42) -> { .tag = Expr_Int, .data = { .Int = { .value = 42 } } }

Parameters:

  • expr: The call expression to check.

Returns: C code string if this is a constructor, otherwise None.

Function l0_backend.Backend._emit_struct_constructor

1
str l0_backend.Backend._emit_struct_constructor(self, CallExpr expr, StructType struct_type)

Emit struct constructor as C designated initializer.

Point(1, 2) -> (struct l0_modulename_Point){ .x = 1, .y = 2 }

Parameters:

  • expr: The constructor call expression.
  • struct_type: The struct type.

Returns: A C struct initializer expression string.

Function l0_backend.Backend._emit_variant_constructor

1
str l0_backend.Backend._emit_variant_constructor(self, CallExpr expr, EnumType enum_type)

Emit enum variant constructor as C tagged union initializer.

Example: Int(42) -> (struct l0_modulename_Int){ .tag = l0_modulename_Int_Int, .data.Int.value = 42 }

Parameters:

  • expr: The variant call expression.
  • enum_type: The enum type.

Returns: A C variant initializer expression string.

Function l0_backend.Backend._emit_new_expr

1
str l0_backend.Backend._emit_new_expr(self, NewExpr expr)

Emit a heap allocation new expression.

Parameters:

  • expr: The NewExpr AST node.

Returns: A C expression string for the newly allocated pointer.

Function l0_backend.Backend._convert_expr_with_expected_type

1
str l0_backend.Backend._convert_expr_with_expected_type(self, str c_expr, Optional[Type] natural_ty, Type expected)

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.

Function l0_backend.Backend._emit_expr_with_expected_type

1
str l0_backend.Backend._emit_expr_with_expected_type(self, Expr e, Type expected)

Emit expression with implicit type conversion to expected type.

Parameters:

  • e: The expression to emit.
  • expected: The expected type.

Returns: A C expression string.

Function l0_backend.Backend._emit_owned_expr_with_expected_type

1
str l0_backend.Backend._emit_owned_expr_with_expected_type(self, Expr e, Type expected)

Emit expression for contexts that create a new owner.

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 .

Parameters:

  • e: The expression to emit.
  • expected: The expected type.

Returns: A C expression string.

Function l0_backend.Backend._emit_expr

1
str l0_backend.Backend._emit_expr(self, Expr expr, *bool is_statement=False)

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.

Function l0_backend.Backend._emit_unwrap

1
str l0_backend.Backend._emit_unwrap(self, str c_dst, str c_inner, NullableType src_ty)

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.

Function l0_backend.Backend._emit_binary_op

1
str l0_backend.Backend._emit_binary_op(self, Expr expr_node, str expr_op, Expr expr_left, Expr expr_right, *bool for_condition=False)

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.

Function l0_backend.Backend._resolve_type_ref

1
l0_backend.Backend._resolve_type_ref(self, TypeRef tref, str module_name)

Resolve an AST TypeRef into an l0_types.Type .

This is needed so “let x: int? = null;” uses the declared type (int?) instead of the initializer type (null).

Parameters:

  • tref: The TypeRef AST node.
  • module_name: Name of current module.

Returns: The resolved Type.

Function l0_backend.Backend._lookup_symbol

1
2
Optional[
        Symbol] l0_backend.Backend._lookup_symbol(self, str name, str current_module_name, Optional[List[str]] module_path=None)

Look up a symbol in the current module’s environment.

This is used to determine which module a function is defined in so we can generate the correct mangled name.

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.

Function l0_backend.Backend._is_extern_function

1
bool l0_backend.Backend._is_extern_function(self, Symbol sym)

Check if a symbol is an ‘extern’ function.

Parameters:

  • sym: The symbol to check.

Returns: True if it is an extern function.

Function l0_backend.Backend._int_type_size

1
l0_backend.Backend._int_type_size(self, Type src_ty)

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).