← Back to Blog

First External Contribution: WASM Backend and Comptime

· John Avera

@arkaitz-dev opened PR #1 and shipped two major features: a WebAssembly codegen backend and compile-time evaluation. This is the first external contribution to the project.

What shipped

The WASM backend is a complete WAT (WebAssembly Text format) transpiler. 2,300 lines of Clojure that takes the same ARIA-IR AST the C backend consumes and produces WAT output. It includes a full printf-style print runtime implemented in WASM itself, so ARIA programs can run on any WASI-compatible runtime with no host dependencies. The pipeline is: ARIA-IR to WAT to WASM via wat2wasm, with optional wasm-opt optimization.

Memory management uses a bump allocator with a stack pointer global. Structs get proper field offset computation with alignment. Extern functions emit as WASM imports. The backend handles every ARIA-IR construct the C backend handles: functions, control flow, type-suffixed arithmetic, loops, mutable and immutable bindings, memory operations.

Cross-backend tests compile the same .aria source through both C and WAT pipelines and compare stdout. The output matches.

Comptime

The compile-time evaluation system uses a two-pass model. A (comptime ...) block in an ARIA module gets extracted, wrapped in a temporary module, compiled via the C backend, and executed. Its stdout is parsed as ARIA s-expressions and spliced back into the original module in place of the comptime block. The expanded module then goes through the normal pipeline: parse, type-check, codegen.

There are three levels. Top-level comptime blocks can emit multiple function definitions. Expression-level comptime produces exactly one form. comptime-val is sugar for computing a single typed constant. Expansion iterates to a fixed point, so comptime can generate more comptime.

Why the generics pattern matters

The comptime system enables a generics mechanism with no new language features. A comptime function takes a type name as a string and prints a type-specialized ARIA function:

(comptime
  (func $gen_max (param $T (ptr i8)) (effects io)
    (print "(func $max_%s (param $a %s) (param $b %s) (result %s) (effects pure)\n" $T $T $T $T)
    (print "  (if (gt.%s $a $b) (then (return $a)) (else (return $b))))\n" $T))

  (func $main (result i32) (effects io)
    (call $gen_max "i32")
    (call $gen_max "f64")
    (return 0)))

The compiler runs this, captures $max_i32 and $max_f64 as fully specialized functions, and compiles them normally. No parametric polymorphism in the IR. No type parameters. No trait resolution. No runtime dispatch. The AI writes a generator once. The compiler produces all the specializations. The type checker verifies each one. The output is the same code you would write by hand for each type.

This is the thesis in action. The IR stays minimal. The pipeline handles the complexity. The AI does not need language features designed for human convenience. It needs a compilation model that turns its output into correct, specialized code. Comptime is that model.

What this means for the project

ARIA now compiles to two backend targets. The same source produces native binaries via gcc and WASM binaries via wat2wasm. The comptime system means the IR can stay simple while supporting patterns that traditionally require generics, templates, or macros in the language specification.

The contributing page has the updated roadmap. The documentation covers the comptime API. The get started guide now includes WASM instructions.