ALB TypeScript backend
The ALB TypeScript backend — ALBW — compiles AdaLogic BASIC into a self-contained TypeScript program that runs in any browser or under Node.js. It is the backend that makes an ALB game a web page: canvas graphics, a real console, chiptune audio, files, and the full logic engine — all inside a single emitted .ts file.
The pipeline
Unlike the streaming emitters behind FASM and C, ALBW's emitter takes the whole AST in one call — Compile_To_File (Root : AST_Node) — and walks it directly: it owns a symbol table, scopes names (Safe_JS_Name, Scoped_Name), evaluates constants at emit time, and emits TypeScript source. Different architecture, same language.
| Flag | What it does |
|---|---|
-o <file> | Output .ts path (default: derived from input name) |
--outdir <dir> | Output directory |
--tsc | Also run tsc — .ts → .js |
--target <ver> | TypeScript target: es5, es2020 (default), esnext |
--build, -b | Full build: transpile + tsc + index.html shell |
--library, -l | Shared module build — no HTML shell (for EXPORT_ES/EXPORT_WASM) |
--metrics, -m · --walker, -w · --quiet, -q | Metrics · AST dump · silence |
A --build folder is a complete, openable website: the emitted .ts, a generated tsconfig.json (strict: false, noCheck: true — the generated code is already correct; the checker just gets in the way), and an index.html that loads the script — as a plain script or an ES module, depending on the program.
A computer inside a file
The generated file is not a thin translation — it emits an entire runtime machine, expressed as typed arrays so the JIT keeps it fast:
const albKeys = new Uint8Array(512); // keyboard state
const albMouseButtons = new Uint8Array(8);
const albVas = new Int32Array(65536); // virtual address space
const albGcAlive = new Uint8Array(1024); // object grid, alive flags
const albGcRefs = new Uint16Array(1024); // refcounts
const albGcChildA … albGcChildD // four child links per node
It is the same architecture as the C and FASM16 Dumptruck — same node grid, same refcount contract — ported to the substrate JavaScript gives you: Uint8Array and Int32Array instead of structs.
- Sized integers, emulated —
albU8/albU16/albU32mask;albI8/albI16/albI32sign-extend. ALB's sized type system behaves correctly on a language with onlynumber - PURE, packed into one f64 —
albPurePackencodes an exact rational (numerator+denominator, gcd-reduced, graceful shrink on overflow) into a single JavaScript number - Division semantics —
albDiv/albModtruncate like integer division should; divide-by-zero yields 0 rather than crashing a browser tab - Integer powers —
albPowIntdoes exponentiation by squaring, the way you teach it - A working logic engine —
albFact*fact store plusalbRel*relation tables andalbRule*rule records with bodies (head predicate, body length, body terms, arg modes) — Prolog, in the browser
The console overlay
PRINT in a browser has nowhere to go — so ALBW builds one. The emitted runtime injects a console: a <div> containing a <pre>, monospace on #050511, that pins itself to the bottom 40% of the viewport when a canvas is active (fullscreen otherwise):
function albWriteText(text) { … albTextRows[row] =
padded.slice(0, col) + ch + padded.slice(col + 1) … }
Underneath the div is a character-grid text model — albTextRows, an x/y cursor, padEnd for sparse writes — so LOCATE-style text behaves like a real terminal, not like console.log. MODE NO CONSOLE or the --no-console path disables it for programs that want only graphics.
The frame loop — events are real
ALB's event-driven model maps directly onto the browser's:
function ALB_RunFrame(now) {
if (!albRunning) { ALB_ProgramShutdown(); return; }
requestAnimationFrame(ALB_RunFrame);
if (now < albDelayUntil) return;
if (now - albLastFrame < albFrameInterval) return;
try { ALB_PREPARE_FRAME(); ALB_ON_TICK(); ALB_ON_PAINT(); }
catch (err) { ALB_FATAL(err); }
}
requestAnimationFrame drives the loop; ON TICK and ON PAINT become literal emitted functions; DELAY is a deadline check; frame-rate throttling is a comparison. A BASIC event loop and a browser event loop turn out to be the same idea wearing different clothes.
Graphics and sound
- Canvas —
HTMLCanvasElement+CanvasRenderingContext2D, base framebuffer 320×200 (yes, the classic resolution), scaled to the window with correct mouse-coordinate transform, and a color LUT (palette entries evaluated at compile time) - Colors —
albColorToCssunpacks a packed RGBAu32intorgba(r,g,b,a)— the same 0xAABBGGRR value every backend understands - PC speaker chiptune —
albPcSpeakerTonedrives a WebAudio square-wave oscillator with an attack-hold-release gain envelope: real retro beeps, polyphonic viaalbActiveMusicVoices(live[OscillatorNode, GainNode]pairs, reaped onended) - Music —
ALB_PLAY_MUSIC_FROMfetches an ALB score file and plays it — the notation survives the journey to the web
Files in a browser (and Node)
Browsers can't open files — so the backend emits a virtual file table: 64 handles (albFileLive, albFileName, albFileBuffer, albFileCursor) over a albSaveStore object, with real ALB_Open/Read/Write/Seek/Close semantics. Writes persist into the store on close.
Then the clever bit — the same emitted file detects Node.js:
const nodeProcess = globalThis.process;
if (nodeProcess?.versions?.node)
buf = eval('require')('fs').readFileSync(path, 'latin1');
In a browser, files are virtual. Under node game.js, they're real — one source, two worlds, literally.
The serious machinery
It even learns
The language-level learning statements work here too: ALB_NN_CREATE, ALB_NN_SEED, ALB_NN_INFER, ALB_NN_TRAIN, ALB_NN_ACT, and ALB_MARKOV_PREDICT are emitted as TypeScript functions for NEURAL TOPOLOGY, TRAIN NETWORK, INFER NETWORK, MARKOV MODEL, and PREDICT MARKOV. Deterministic weight seeding means a program's net starts identically in a typed-array browser runtime as it does in the x86-64 asm or C builds — train a model on the desktop, deploy it to a page. (One learning feature stays native: EMOTION is FASM-only.)
Modes and library exports
MODE DOCUMENTin the source flips the generatedindex.htmlfrom the dark game shell to a light document shell — the same language emits games or pagesEXPORT_ES/EXPORT_WASMwith--libraryemit a module-aware build (no HTML shell,module: es2020tsconfig) — ALB programs compiled into importable web libraries; the foreign-export table is sized to matchalbt'sMax_Foreign_Exportsso even the full-enginelibgamedeckfaçade fits one weave
Under the hood
Emit_Native_TypeScript is ~7,000 lines of SPARK-annotated Ada — second in size only to the Ada emitter — driven by albw.adb, which handles flags, the tsconfig writer, the HTML shell writer, and the tsc/package dance. Where the native backends stream tokens into buffers, this one is an AST interpreter that prints TypeScript: it sees the whole program before it writes a line.
See also
- AdaLogic BASIC — the language
- ALB C backend · ALB FASM backend · ALB FASM16 backend — the native siblings
- History of Programming — JavaScript's chapter in the arc
- Z3 · Manchester Baby — the web page as a machine, then and now