Choosing Clojure: The S-Expression Alignment Argument
The first prototype of the ARIA toolchain was Python. Python is the default for everything in the AI ecosystem. It was expedient. It worked.
It was also wrong.
Not wrong in the sense that it produced incorrect results. The Python compiler parses ARIA-IR files, type-checks them, and generates C code that compiles to correct binaries. It works. But the implementation fights the representation at every step.
The structural argument
ARIA-IR is s-expressions. Nested parenthesized forms. (module ...) containing (func ...) containing (if ... (then ...) (else ...)). The syntax is the abstract syntax tree. There is no separate parse tree.
In Python, parsing s-expressions requires a hand-written lexer and recursive descent parser. Tokenize the input. Match parentheses. Build an AST from tokens. Hundreds of lines of code to parse a format that a Lisp reader handles natively.
In Clojure, the parser is one function call: read-string. The Clojure reader consumes s-expressions as its native data format. An ARIA-IR file is already a valid Clojure data structure (with minor preprocessing for the $ and % variable prefixes). The parser collapses.
The semantic argument
Clojure's immutable data structures mirror ARIA-IR's SSA semantics. A %-bound value in ARIA-IR cannot be reassigned. A value in Clojure cannot be mutated. The toolchain's data model and the IR's data model are the same.
The compiler pipeline is a sequence of pure transformations: read, validate, type-check, generate. Each stage takes immutable data and returns immutable data. In Python, this requires discipline. In Clojure, it is the default.
The practical argument
Clojure runs on the JVM. A single uberjar runs on any platform with Java installed. No native compilation matrix. No platform-specific builds. One artifact, every target.
The Clojure ecosystem has mature tooling for exactly the kind of work a compiler does: data transformation, tree walking, pattern matching (via core.match), specification (via spec or malli). These are not incidental features. They are the core of what Clojure was designed for.
The result
The Clojure implementation of the ARIA toolchain is smaller, faster to develop, and structurally cleaner than the Python prototype. The reader is a few lines of preprocessing plus read-string. The AST is plain Clojure maps. The type checker threads immutable environments through recursive validation. The C codegen walks the AST with multimethods.
A Lisp compiler for a Lisp IR. The tool and the material are the same substance. This is not clever. It is inevitable.