Input/Output Format: JSON AST and Scope Tree

The main public API is roughly compile(BabelAst, Scope) -> Option<BabelAst> returning None if no changes, or Some with the updated ast.

Arenas

Use arenas and Copy-able "id" values that index into the arenas in order to migrate "shared" mutable references.

Instructions Table

Store instructions indirectly. This allows passes that need to cache or remember an instruction's location (to work around borrowing issues) to have a single id to use to reference that instruction. Do not use (BlockId, usize) or similar.

AliasingEffect

Environment

Pass a single mutable environment reference separately from the HIR.

Error Handling

In general there are two categories of errors:

Specific Error Patterns and Approaches

Pass and Pipeline Structure

Structure the pipeline and passes along these lines to align with the above error handling guidelines:

// pipeline.rs
fn compile(
    ast: Ast, 
    scope: Scope,
    env: &mut Environment,
) -> Result<CompileResult, CompilerDiagnostic>> {
    // "?" to handle cases that would have thrown or produced an invariant
    let mut hir = lower(ast, scope, env)?;
    some_compiler_pass(&mut hir, env)?;
    ...
    let ast = codegen(...)?;

    if (env.has_errors()) {
        // result with errors
        Ok(CompileResult::Failure(env.take_errors()))
    } else {
        // result with 
        Ok(CompileResult::Success(ast))
    }
}

// <compilerpasss>.rs
fn passname(
    func: &mut HirFunction,
    env: &mut Environment
) -> Result<_, CompilerDiagnostic>;