Skip to content
ALB Wiki

Diff — MALBR

Comparing rev 4 → rev 5

{{infobox
| title = MALBR
| image = [[File:malbr-logo.png|center|300px|The MALBR logo — rusted gears and metal lettering]]
| name = MALBR — Micro ALB Rust
| type = compiler — ALB to Rust source
| written_in = [[Ada Programming Language|Ada]] (malbr.adb + emit_native_micro_rust.adb)
| emits = `#![no_std]` / `#![no_main]` Rust + a `support.rs` runtime
| companion = [[MALB]] — the same compiler written in ALB itself
| memory_model = deterministic statics — fixed arena, no heap, no crates
| status = draft spec freeze candidate — bootstrap compiler for MALB
| download = [MALBR-RELEASE.zip](/dist/MALBR-RELEASE.zip) — 306 MB, early access
| repository = [https://github.com/rockyoliver454/AdaLogic-BASIC-ALB-Programming-Language github.com/rockyoliver454/AdaLogic-BASIC]
}}
**MALBR** — *Micro ALB Rust* — is the second compiler in the AdaLogic BASIC
toolchain, and the path by which ALB reaches machines its reference
compiler cannot. Where [[ALB FASM backend|albt]] is a complete,
batteries-included compiler that assembles FASM directly and serves the
retro backends, MALBR is deliberately small: it translates ALB source into
clean, deterministic `#![no_std]` Rust and hands the result to rustc, which
brings cross-compilation to dozens of targets, a mature optimizer, bare-metal
support, and an enormous linker ecosystem. MALBR does not try to be smarter
than rustc — it emits predictable code and lets the backend machinery do
what it was built to do.
Its sibling is **MALB**: the same ALB→Rust compiler written in ALB itself,
roughly 3,900 lines of it, compiled first by MALBR and then by itself —
proven self-hosting through a byte-identical bootstrap fixpoint. Together
they move ALB toward a two-flagship toolchain: `albt` as the reference
compiler, and the MALBR/MALB pair as the road to embedded targets, foreign
operating systems, and a compiler maintained in the language it compiles.
-
## Why a second compiler
+
# Why a second compiler
`albt` knows the whole language — the full builtin set, the special blocks,
the sixteen targets from native x86-64 down to 6502 assembly. What it cannot
easily do is reach the places ALB increasingly wants to go: small boards,
embedded targets, toolchains the project does not own. A FASM-centric
pipeline cannot piggyback on someone else's backend ecosystem.
MALBR was created to fix exactly that gap. Rust already solves
cross-compilation, optimization, and `no_std` bare-metal deployment — so
MALBR emits Rust source rather than machine code, keeping itself small and
auditable while inheriting everything rustc knows about target triples,
linking, and code generation. The trade is explicit: one more language in
the pipeline, in exchange for the widest backend reach a modern toolchain
offers.
-
## What the output looks like
+
# What the output looks like
Every MALBR program compiles to a crate with a fixed shape:
```frame The generated crate skeleton
#![no_std]               // every generated crate — embedded first
#![no_main]
#![allow(unused_unsafe)]          // static-mut access nests unsafe blocks
#![allow(unconditional_panic)]    // bounds panics route to fault 101
#![allow(unused_parens)]
```
The program body lands in `fn _alb_main_body()`, behind a
`#[no_mangle] pub extern "C" fn main()` that calls it and exits through
`support::_alb_exit(0)`. File-scope `LET` declarations become `static mut`
with `unsafe` access; routine-local `LET`s stay ordinary `let mut`s.
String handling runs through a **static arena** — 64 KiB by default,
resizable with `--arena <bytes>` — with `CLAIM`, `SWEEP`, and `DROP` as
checkpoint/rewind/release controls. There is no heap and no crates.io
dependency: the binary can be audited byte-for-byte and flashed directly.
-
### Fault codes — one trap door
+
## Fault codes — one trap door
Every runtime trap in generated code funnels into a single function,
`support::_alb_fault(code)` — the override point embedded ports replace:
| Code | Trap |
|------|------|
| 21 | `REQUIRE` contract violated |
| 22 | `ENSURE` contract violated |
| 23 | range-type bound violated |
| 24 | checked `+` `−` `*` overflow |
| 25 | checked `/` `MOD` — division by zero or `MIN/-1` |
| 26 | unset routine-typed field invoked |
| 27 | `ASSERT` failed |
| 74 | `--strict-io` I/O failure |
| 101 | panic — bounds, arena exhaustion, unreachable |
A bare-metal port can hang, log over UART, or blink an LED on any of these —
the generated code never decides the policy.
-
## The support ABI — porting is six functions
+
# The support ABI — porting is six functions
MALBR's runtime boundary is `support.rs`, a three-file facade:
| File | Role |
|------|------|
| `support.rs` | facade — `ALB_ABI_VERSION = 1` plus two `include!`s; never edited |
| `alb_core.rs` | **tier 1 — the port**: `_alb_putchar`, `_alb_print_*`, `_alb_exit`, `_alb_fault` |
| `alb_host.rs` | tier 2 — files (memfs by default, hostfs via `--hostfs`), stdin, args, env, exec, clock, dir |
To take ALB to a new board you replace tier 1 — roughly six functions —
and optionally tier 2 for environment services. Generated code only ever
talks to `support::_alb_*`, so a port never touches emitted source. This is
the same strategy small language ports have used since the early byte-code
machines: separate *what the program means* from *what the machine can do*.
-
## Semantics are the spec
+
# Semantics are the spec
MALBR's contract is behavioral, not structural. The test suite diffs real
program *output* — a semantic drift is a test failure, not a shrug. The
details it guarantees are the ones a user would notice:
- `|` stays string concatenation (and `&` its alias); bitwise work uses
  `AND`/`OR`/`XOR` keywords, `^` is exponentiation
- `NOT` keeps classic-BASIC precedence — looser than comparisons, tighter
  than `AND`; `NOT x = 5` means `NOT (x = 5)`
- `AND`/`OR` never short-circuit; `ANDALSO`/`ORELSE` do
- `PRINT` truncates floats to six decimals — display only, not the value
- `READ(h, 0)` reads the rest of the file; both `ELSEIF` and `ELSIF` parse
- reserved words error with line/column instead of cascading parse failures
```fact Pipe is still concat
In MALBR-generated Rust, `a | b` compiles to string concatenation — the
compiler emits a PIPE-AS-CONCAT warning only when a `|` expression feeds a
numeric assignment with two integer operands, the one pattern that could
mean bitwise OR in other languages.
```
-
## Float math without a standard library
+
# Float math without a standard library
`#![no_std]` means no libm, so MALBR carries its own: Cody–Waite argument
reduction plus minimax polynomials give `sin`, `cos`, `atan`, `exp`, and
`ln` to about 1 ulp, with `tan`, `asin`, `acos`, `atan2`, and `pow` in the
2–3 ulp range. `floor`, `ceil`, `trunc`, `round`, and `sqrt` are integer
casts with Newton fixups — the core intrinsics would pull in `std`. For an
embedded BASIC, that is an unusually serious numerics story: see
[[Scientific notation]] and [[History of Mathematics]] for why floating
point conventions mattered enough to standardize.
-
## MALB — ALB written in ALB
+
# MALB — ALB written in ALB
[[File:malbr-logo.png|right|140px|The MALBR mark — rusted gear, rusted letters]]
Once MALBR could compile real programs, one question became inevitable: can
ALB compile its own compiler? **MALB** (`MALBR_BS/malb.alb`, about 3,900
lines) is the answer — a complete ALB→Rust compiler written in the language
it compiles. The self-hosting claim is proven the hard way, not asserted:
```flow The three-stage bootstrap — a byte-identical fixpoint
  malbr.exe  builds  malb.exe                       (stage 1 — Ada backend)
  malb.exe   compiles malb.alb -> malb2.rs          (stage 2)
  malb2.exe  compiles malb.alb -> malb3.rs          (stage 3)
  malb2.rs == malb3.rs    — identical, byte for byte
```
When a compiler's own 3,900-line source is the test program and the
stage-2 and stage-3 outputs agree exactly, "almost right" has nowhere to
hide. This is the same fixpoint argument classic self-hosting
compilers — from Pascal's P-system to GCC's three-stage build — have used
to demonstrate correctness; see [[Compilers]] for the tradition.
-
## Coverage and status
+
# Coverage and status
MALB currently passes **209 of 209 output-verified fixtures** — emit →
rustc → run → diff — including MD5, FFT, Jaro–Winkler, N-queens, maze
generation, FFI calls into kernel32, and the semantics regression tests
(short-circuit behavior, `NOT` precedence, checked overflow, contracts).
The language coverage is full: modules and `INCLUDE`, contracts
(`REQUIRE`/`ENSURE`/`OLD`), structs, enums, bitfields, range types, routine
references and `REF`, floats, multi-dimensional arrays, `SELECT`,
`ENABLE RUST`, and the complete builtin set.
```alb
malb input.alb [output.rs]
```
```alb Download
**[MALBR-RELEASE.zip](/dist/MALBR-RELEASE.zip)** — 306 MB early-access
release (SHA-256 `e8069fa2becaef28664bfb30290a8587d8d86cc56955ee7d3d3d3ad7c71c299b`).
```
The CLI is deliberately boring. MALB is in early access; the roadmap's
priorities are performance of the self-built binary, `--map`-style audit
output, and then the point of the exercise — `malbr.adb` freezing forever
as the bootstrap compiler, with ALB's compiler maintained in ALB from that
day forward.
-
## Where it sits in the toolchain
+
# Where it sits in the toolchain
| Compiler | Written in | Emits | Role |
|----------|-----------|-------|------|
| `albt` | Ada | FASM, C, and 14 more targets | reference compiler — batteries included |
| `malbr` | Ada | `#![no_std]` Rust | embedded/foreign targets — rustc does the rest |
| `malb` | **ALB** | Rust | self-hosted twin of malbr — early access |
```tip Port instead of patch
Shipping ALB to a microcontroller? Write six `_alb_*` functions in
`alb_core.rs` — putchar, print, exit, fault — and every MALBR program
follows. Never edit generated code.
```
-
## See also
+
# See also
- [[AdaLogic BASIC]] — the language these compilers serve
- [[ALB Ada backend]] — sibling backend in the same Ada toolchain
- [[ALB FASM backend]] — the workhorse native x86-64 target
- [[Rust]] — the language MALBR emits
- [[Ada Programming Language]] — the language both `albt` and `malbr` are written in
- [[Compilers]] — self-hosting and bootstrap traditions
- [[Forth]] — another language that took tiny, auditable toolchains to telescopes and space probes
-
## References
+
# References
1. "Update: MALBR and MALB — a second compiler, and ALB written in ALB," ALB repository, `docs/updates/2026-10-malbr-malb-announcement.md` (October 2026).
2. *MALBR Dialect Specification — Micro ALB*, ALB repository, `docs/MALBR_SPEC.md` — the normative dialect contract.
3. *MALBR Internals — what the generated Rust actually looks like*, `docs/MALBR_INTERNALS.md`.
4. *MALBR Porting Guide — taking ALB to a new target*, `docs/MALBR_PORTING.md`.
5. *MALBR ABI*, `docs/MALBR_ABI.md` — the `support.rs` two-tier contract.
6. *MALBR Roadmap — Micro ALB compiler → production*, `docs/MALBR_ROADMAP.md`.
7. ALB source — [github.com/rockyoliver454/AdaLogic-BASIC-ALB-Programming-Language](https://github.com/rockyoliver454/AdaLogic-BASIC-ALB-Programming-Language) — Apache 2.0, including `src/malbr.adb`, `src/EMITTER/emit_native_micro_rust.adb`, and `MALBR_BS/malb.alb`.
8. ALB Handbook — [alb-lang.org/handbook](/handbook) — the language reference shared by every backend.
-
## Quiz — MALBR and MALB
+
# Quiz — MALBR and MALB
- [ ] What does "MALBR" stand for, and what language does it emit?
- [ ] Why does ALB need a second compiler when `albt` already targets sixteen backends?
- [ ] What two attributes appear at the top of every MALBR-generated crate?
- [ ] How large is MALBR's default string arena, and which flag resizes it?
- [ ] Name the function every runtime trap routes through, and give three fault codes.
- [ ] How many functions does a minimal MALBR board port require, and in which file do they live?
- [ ] In ALB, what does `|` mean — and how does MALBR treat it in generated Rust?
- [ ] Which ALB keywords provide short-circuit logic, since `AND`/`OR` do not?
- [ ] Approximately how accurate are MALBR's `sin`/`cos`/`exp`/`ln` implementations?
- [ ] What is MALB, and roughly how many lines of ALB is it?
- [ ] Describe the three stages of the MALB bootstrap and what equality proves.
- [ ] How many output-verified fixtures does MALB currently pass?
```hide Answers
MALBR = Micro ALB Rust; it emits Rust source. albt cannot piggyback on
rustc's cross-compilation, optimizer, and no_std ecosystem — MALBR fills
that gap. Every crate starts `#![no_std]`/`#![no_main`. The arena is
64 KiB by default, resized with `--arena`. All traps route through
`support::_alb_fault(code)` — e.g. 21 REQUIRE, 24 overflow, 101 panic. A
minimal port is about six functions in `alb_core.rs`. `|` is string
concatenation, and MALBR preserves that in Rust. `ANDALSO` and `ORELSE`
short-circuit. The libm-grade functions are ~1 ulp (2–3 for the rest).
MALB is the ALB→Rust compiler written in ALB, about 3,900 lines.
Bootstrap: malbr builds malb.exe; malb.exe compiles malb.alb into
malb2.rs/malb2.exe; malb2.exe compiles malb.alb into malb3.rs; and
malb2.rs == malb3.rs byte-for-byte — the fixpoint that proves the
compiler implements the language correctly. The suite: 209/209.
```
{{date|2026-10-14}}
[[Category:AdaLogic BASIC]]
[[Category:Backends]]
[[Category:Programming]]