ALB Ada backend
The ALB Ada backend — ALBA — compiles AdaLogic BASIC into Ada: the language the entire toolchain itself is written in. Every other backend is a translation; this one is a homecoming. It produces real, idiomatic Ada — modular types, digits floats, SPARK annotations, a .gpr project — and it is the largest single emitter in the set at over twelve thousand lines.
Why Ada matters here
ALB's design DNA — sized types, ranges, contracts, the hardened runtime, refusal to corrupt onward — is Ada's design DNA. Every backend has to translate those guarantees: FASM hand-builds trap stubs, C lowers TRY/CATCH to setjmp. The Ada backend mostly just writes them down: range checks, strong typing, and explicit unchecked operations are things Ada already has words for.
The emitted program is a real package
An ALB program doesn't flatten into a main() — it becomes a named Ada package with SPARK mode declared:
pragma SPARK_Mode (On);
with ALBA_API; use ALBA_API;
package My_Program with SPARK_Mode => On is …
package body My_Program is …
pragma SPARK_Mode (On)on the emitted unit — the generated code participates in SPARK's analysis regime by defaultwith ALBA_API— it links the runtime library, not a copy of it:alba_api.adbplus thealba_*_implunits (audio, gc, graphics, io, logic, runtime) living beside the driver- Unsafe blocks stay fenced — when ALB source needs raw memory work, the emitter carves a named
ALBA_Unsafe_Block_Nprocedure and stampspragma SPARK_Mode (Off)inside it — the unsafe region is a labeled island, not a leaked privilege
Types the Ada way
The runtime defines ALB's type system in textbook Ada — not typedef int8_t, but the real things:
type U8 is mod 2 ** 8; for U8'Size use 8;
type S64 is range -(2 ** 63) .. (2 ** 63) - 1; for S64'Size use 64;
type F32 is digits 6; for F32'Size use 32;
And ALB's bitwise operators on signed types — and/or/xor/not — are emitted the honest Ada way: Ada.Unchecked_Conversion to the modular twin, the bitwise op, convert back. Unsafe, named, and confined — which is exactly how Ada thinks unsafe should work.
The | concat operator becomes overload resolution:
function ALB_CAT (Left : ALB_Text; Right : S32) return ALB_Text;
function ALB_CAT (Left : U64; Right : ALB_Text) return ALB_Text;
function ALB_CAT (Left : ALB_Text; Right : Pure_Rational) …
Every operand pairing gets a real overload — Pure_Rational included, as a first-class Ada type with ALB_PURE_ADD/SUB/MUL/DIV/POW and NUM/DEN accessors.
A different breed of emitter
Like the TypeScript backend, ALBA is an AST-walker, not a streaming emitter: Emit_Program receives the tokens, the tree, and the root, then analyzes the whole program — but the analysis here goes deep. Inside one procedure live full semantic tables:
- 16,384 symbols, 8,192 routines, 512 fields, 128 structs, 2,048 constants — with
Has_Range/Range_Low/Range_Highon every symbol, so declared ranges survive into the emitted type system - Static constants evaluated at emit time (
Has_Static_Value) - Temporal symbols, alias resolution, module scoping, struct serialization helpers
pragma Import (C, …)emission for foreign routines — the FFI is Ada's own import pragma
--build then writes a proper GNAT project (for Languages use ("Ada"), for Object_Dir use "obj") and invokes gprbuild — or gnatmake with --gnatmake. This backend doesn't borrow another toolchain's linker; it speaks Ada's own build system.
The runtime nobody else has
The ALBA runtime ships services that exist on no other backend:
- **
ALB_NN_*— a small neural network in the language**:NN_CREATE(layer sizes + activation codes),NN_INFER(forward pass),NN_TRAIN(epochs against expected data), andNN_SEED— deterministic weight initialization, so the same program trains the same net twice ALB_MARKOV_PREDICT— a Markov-chain predictor over a float matrix- **
ALB_NET_*** — real sockets:DEFINE,LISTEN_SOCKET,RECEIVE,SEND,CLOSE ALBA_Save_State/ALBA_Load_State— whole-program state serializationALBA_Sync_Frame_To_VAS— frame output synced into the virtual address space: the framebuffer as memory, the pattern the TypeScript backend'salbVasmirrorsALB_SIN/ALB_COSin integer degrees,ALB_ROLrotate-left,ALB_COLLIDE_RECT— the helpers a BASIC-flavored language is expected to haveALB_Peek_Address/ALB_Poke_Address/ALBA_Deref_Address— and they're emitted as named functions, so every bare-metal access is findable in the generated source
The oracles
When parsing fails, alba doesn't say "syntax error" — it reports an oracle code (ALBA: oracle code <n>) from the lexer/parser diagnostics. The compiler tells you which oracle was offended.
Under the hood
Emit_Native_Ada (~12,300 lines, pragma SPARK_Mode (On) — even the emitter's spec is annotated) is driven by alba.adb: flags (-o, --outdir, --build, --gprbuild/--gnatmake), the .gpr writer, the runtime-directory staging, and the build invocation. It is the only backend whose output a SPARK prover could, in principle, read.
See also
- AdaLogic BASIC — the language
- ALB FASM backend · ALB C backend · ALB FASM16 backend · ALB TypeScript backend · ALB NASM backend
- Ada Lovelace — the namesake at the top of the tree
- History of Programming — where Ada (the language) sits in the arc