ALB Lua backend
The ALB Lua backend — ALBL — compiles AdaLogic BASIC into one self-contained .lua file: program, runtime, and all. No compiler is needed where it lands — drop it next to alb_sdl3.dll and SDL3.dll, run lua program.lua (or luajit), and a BASIC program with a Prolog engine and a framebuffer comes alive inside the most embeddable scripting runtime ever made.
Why Lua, and why it works
Lua's proposition is unique among the backends: the emitted file is portable source that runs anywhere a Lua interpreter lives — game engines with Lua scripting, mods, tools, embedded hosts. The emitted header says it plainly: "self-contained Lua 5.1+/LuaJIT runtime" — the file doesn't even insist on LuaJIT; plain Lua 5.1 and up will do.
The catch — that Lua is a small language — is exactly where the emitter earns its keep. Everything ALB needs that Lua doesn't have gets built out of Lua tables.
A computer inside a script
The runtime reconstructs ALB's machinery the way the TypeScript backend does it in typed arrays — here, in plain tables:
albVas— the virtual address space: framebuffer and memory-mapped state as a Lua tablealbGcAlive/albGcRefs/albGcChildA–D— the Dumptruck claim-grid, running inside Lua's own garbage collector (two collectors, one process)albTextRows+ a cursor — the console-overlay model:PRINTwrites to a character grid,LOCATEpositions the cursor — a terminal inside the window, killed only byMODE NO CONSOLEin sourcealbSaveStore+ALB_serialize_state/ALB_deserialize_state— whole-programSAVE STATE/LOAD STATE, Lua-side- PURE arithmetic, for real —
albPureGcdreduces rationals properly;PURE_ADD/SUB/MUL/DIV/POWkeep numerator and denominator separate so ⅓ stays exactly ⅓ - 64-bit-safe math shims —
albDiv,albMod,albPowInt,ALB_shl/shr— because Lua numbers are doubles and precision past 2^53 is a cliff, the emitter implements sized-integer ops as algorithms instead of trusting the operators - The capability firewall —
ALB_FIREWALL_ENTER/LEAVE/READ/WRITE/TOUCHwith per-frame allow tables — in a scripting language, where sandboxing is the whole point ALB_KNOWS_GET/HAS/SET— the Knows store- INI files, PPM export,
ALB_FILE_XOR, bitmap/system fonts — the file-and-format suite didn't get left behind either
The Logic pillar, with rules
This backend doesn't ship a toy Prolog — it ships the rule engine:
local albRelPred = {}; local albRelArity = {}
local albRelArg1 = {}; local albRelArg4 = {}
local albRuleHeadPred = {}; local albRuleBodyLen = {}
local albRuleBodyPred = {}; local albRuleBodyArgMode = {}
Facts live in one table family (albRel*), rules in another — albRuleHeadPred (the rule's head predicate), albRuleBodyLen and albRuleBodyPred/ArgMode (the body, with per-argument modes). ALB_INIT_LOGIC wires it up; AST_Logic_Var handles real unification variables; watch nodes re-evaluate when the KB changes. The Logic in AdaLogic BASIC, running in a language that fits in a few hundred kilobytes.
The alb_sdl3 bridge
Graphics and input don't use LuaJIT's FFI at all — both script backends share one design: alb_sdl3.dll, a Lua C-module loaded by name:
local ok, mod = pcall(require, "alb_sdl3")
if not ok then ALB_FATAL("ALBL requires alb_sdl3.dll next to the .lua (and Lua 5.4).") end
albSDL = mod
albSDL.init()
One bridge, one call surface — create_window, prepare_frame, color, clear, plot, draw_rect, fill_rect, draw_line, ticks — behind which SDL3.dll does the actual work. Lazy-loaded via albEnsureSDL() so programs that never draw never pay for it, and pcall wraps the load so the failure message is friendly.
The game loop
ON TICK / ON PAINT / ON KEY blocks become literal Lua functions wired into a while ALB_Running loop that pumps the bridge's event queue — the same frame model as every other backend, expressed in local functions and tables.
Flags and output
-o, --outdir, --metrics, --walker, --quiet; --build stages SDL3.dll + a run.bat beside the .lua in lua_<name>/; --run finds luajit.exe (deps tree or PATH) and runs it in place.
Under the hood
Emit_Native_Lua (~8,500 lines, SPARK-annotated) is the AST-walker architecture: Compile_To_File(Root, Output_Filename) receives the whole tree and walks it top-down — the same shape as the TypeScript and Ada emitters, and literally mirrored by the MoonScript sibling, which shares the runtime design, the bridge, and most of its source structure.
See also
- AdaLogic BASIC — the language
- ALB MoonScript backend — the sibling: same runtime, sweeter syntax, through
moonc - ALB TypeScript backend — the other "computer in a file"
- ALB FASM backend · ALB C backend · ALB .NET backend · ALB Ada backend · ALB NASM backend · ALB FASM16 backend