Skip to content
ALB Wiki

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.

FlagWhat it does
-o <file>Output .ts path (default: derived from input name)
--outdir <dir>Output directory
--tscAlso run tsc — .ts → .js
--target <ver>TypeScript target: es5, es2020 (default), esnext
--build, -bFull build: transpile + tsc + index.html shell
--library, -lShared module build — no HTML shell (for EXPORT_ES/EXPORT_WASM)
--metrics, -m · --walker, -w · --quiet, -qMetrics · 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/albU32 mask; albI8/albI16/albI32 sign-extend. ALB's sized type system behaves correctly on a language with only number
  • PURE, packed into one f64 — albPurePack encodes an exact rational (numerator+denominator, gcd-reduced, graceful shrink on overflow) into a single JavaScript number
  • Division semantics — albDiv/albMod truncate like integer division should; divide-by-zero yields 0 rather than crashing a browser tab
  • Integer powers — albPowInt does exponentiation by squaring, the way you teach it
  • A working logic engine — albFact* fact store plus albRel* relation tables and albRule* 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 — albColorToCss unpacks a packed RGBA u32 into rgba(r,g,b,a) — the same 0xAABBGGRR value every backend understands
  • PC speaker chiptune — albPcSpeakerTone drives a WebAudio square-wave oscillator with an attack-hold-release gain envelope: real retro beeps, polyphonic via albActiveMusicVoices (live [OscillatorNode, GainNode] pairs, reaped on ended)
  • Music — ALB_PLAY_MUSIC_FROM fetches 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 DOCUMENT in the source flips the generated index.html from the dark game shell to a light document shell — the same language emits games or pages
  • EXPORT_ES / EXPORT_WASM with --library emit a module-aware build (no HTML shell, module: es2020 tsconfig) — ALB programs compiled into importable web libraries; the foreign-export table is sized to match albt's Max_Foreign_Exports so even the full-engine libgamedeck faç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

References

  1. ALB Handbook — alb-lang.org/handbook — the language reference for all backends.
  2. ALB Technology page — alb-lang.org/technology — the sixteen-backend matrix.
  3. ALB source — github.com/rockyoliver454/AdaLogic-BASIC-ALB-Programming-Language — the emitter sources are Apache 2.0.
Categories: AdaLogic BASIC · Backends
This page was last edited 2026-10-20 13:00:48 UTC by ALB Team. What links here