Lumen on Android
LumenRuntimeAndroid (com.spikest3r.lumenruntime) is a self-contained Lumen toolchain for Android. It bundles an in-app editor, the compiler, the VM, a disassembler, and a QR scanner for importing programs compiled elsewhere, all behind a Kotlin UI with a JNI bridge into the same C++ core described in Compiler Pipeline and The Virtual Machine.
This places Android in a different category from the Pico and AVR ports. Those are VM-only, compile-on-desktop targets with no on-device compilation path. Android has no such constraint: a .lmn program can be written, compiled, disassembled, and run entirely on the device, mirroring the desktop lumen CLI’s workflow. The QR pipeline is an additional means of getting a program onto the device, not the only one.
What’s on-device
- Editor. Write and edit
.lmnsource directly in the app. - Compiler. The same compiler pipeline as desktop, turning
.lmnsource into bytecode (.bin) locally — see Compiler Pipeline. - VM. The same
execute()core used on desktop, Pico, and AVR, reached through a JNI bridge. - Disassembler. A live disassembly view alongside the running program, matching the desktop
--disassembleoutput described in Disassembler. - QR scanner. An import path for bytecode compiled elsewhere — covered below.
Because compilation happens on-device, the Android workflow parallels the desktop workflow described in CLI Reference: write source, compile, run, and optionally disassemble, through a touch UI rather than command-line flags.
The QR import pipeline
The QR path is intended for programs not written on the device itself. Android has no convenient equivalent to dropping a .bin file onto a filesystem, so LumenRuntimeAndroid can instead reconstruct a compiled program by scanning a sequence of QR codes.
The pipeline has two sides:
- Encoding (WASM). A compiled
.binfile is split into indexed chunks, each small enough to fit into a single QR code. Every chunk carries its index, the total chunk count, and a CRC32 checksum of its payload. - Decoding (Android). The app scans chunks with the device camera in any order; chunks need not be scanned sequentially. Each incoming chunk is validated against its CRC32 before being accepted, and ingestion is idempotent, so re-scanning an already-captured chunk is a no-op rather than a source of corruption. Once every chunk index from
0tototal-1has been seen and validated, the runtime reassembles the original.binbytes and hands them to the same on-device VM used for locally-compiled programs.
This design allows a grid of QR codes for a program to be scanned in whatever order is convenient, rather than requiring a strict sequence.
Running a program
Once bytecode is ready — whether compiled on-device or reconstructed via QR — the JNI bridge hands it to the native execute() loop. Two Android-specific pieces sit around that core:
- Blocking input. Lumen’s
inputInt/inputStr(see Input & Output) expect to block on stdin on desktop. Android has no stdin, so the runtime surfaces anAlertDialoginstead, with the native thread blocked on astd::mutex/std::condition_variablepair until the user submits a value through the dialog. - Console output.
print/printlncalls are relayed from native code to the Kotlin UI thread via a fire-and-forget JNI callback, rendered in a monospace console below the source editor. Output is capped at 1000 lines; once the limit is reached, execution halts rather than continuing to produce output the console can’t display.
Cancellation
Long-running or accidentally-infinite programs — an unbounded label/jump loop, for instance (see Labels & Jumps) — are cancellable from the UI. The VM checks a std::atomic<bool> cancellation flag cooperatively between instructions, so stopping a program from the Android UI does not require killing the native thread outright; execution unwinds cleanly the next time execute() checks the flag.
Two ways to get a program running
Written on-device:
- Open the editor in LumenRuntimeAndroid and write the
.lmnsource directly. - Compile it in-app.
- Run it, with the disassembler view available alongside.
Imported from elsewhere:
- Write and compile a
.lmnprogram on the WASM Playground. - Export the compiled
.binas a QR sequence rather than, or alongside, a regular file download. - Open LumenRuntimeAndroid and scan the codes — order does not matter, and the app reports how many chunks remain outstanding.
- Once reconstruction finishes, run the program directly on-device.
Each example in this book’s Examples chapter includes a QR placeholder alongside its source, generated with this same chunking scheme, so it can be scanned directly into the Android runtime once real codes are filled in — or retyped in the on-device editor.