Using It as a Library
FantASM is a Rust library as well as a command. A program can assemble in-process and get the bytes and the diagnostics back as values, without shelling out and parsing text.
This page is for Rust developers embedding the assembler. Everything else in this documentation is for people writing Z80.
Adding it
⛔ It is not on crates.io. publish = false — FantASM is distributed as signed binaries. Depend on it by path or by git:
[dependencies]
fantasm = { git = "https://codeberg.org/TwistedRaven/fantasm" }There is no semantic-version promise across those. The crate is versioned for its releases, not for its API.
Default features bring in a lot. nex, sna, lsp and update-check are all on by default, and lsp pulls in tower-lsp and an async runtime. If you only want to assemble:
fantasm = { git = "…", default-features = false }Assembling
use fantasm::assembler::{Assembler, AssemblerOptions};
let mut asm = Assembler::new();
asm.enable_console(false);
asm.enable_z80n(true);
let outcome = asm.assemble_from_str(" org $8000\nmain:\n ld a,1\n ret\n", "demo.asm");
let bytes = asm.emitter.bank.as_slice().to_vec();assemble(path) does the same from a file, resolving include and incbin against the include path.
⛔ Call enable_console(false) first. Without it the assembler prints progress and messages to stdout, which is fatal for anything speaking a protocol there — a language server, or a tool whose output is piped.
Diagnostics are on the assembler, not in the Result
This is the part that catches people. The Result carries one error; the collected set lives on the assembler:
let _ = asm.assemble_from_str(source, "demo.asm"); // both consumers ignore this
for e in &asm.errors { /* … */ }
for w in &asm.warnings { /* … */ }asm.errors | Errors, stopping at the first. Two undefined names give one entry. |
asm.warnings | Warnings, and they accumulate. |
⛔ warnings is not only warnings. Progress lines (Info) and !message output (Message) are in the same list, carrying codes 1051 and 1056. Filter on level, never on the code:
use fantasm::assembler::ErrorLevel;
// `display_unused` takes &mut, so ask for the unused-label sweep before borrowing the list.
asm.display_unused();
let real: Vec<_> = asm.warnings.iter()
.filter(|w| matches!(w.level, ErrorLevel::Warning | ErrorLevel::Error))
.collect();W1049 unused label needs asking for. display_unused() is the library equivalent of -W, and it appends to warnings — so call it before you collect, or the borrow checker will say so for you.
Each Diagnostic carries level, error_code, message, hint, location (file, line, column) and related_locations. Nothing needs parsing out of a string — see Diagnostics for what the codes mean.
Debug information
Source-to-address records are on asm.sld_records as values, so you need not read the file back.
⛔ They are only populated if you nominate a file. sld_file() is what turns recording on; without it sld_records is empty, and with it a .sld is written whether you want one or not:
let scratch = std::env::temp_dir().join("mine.sld");
asm.sld_file(scratch.to_string_lossy().as_ref());
// … assemble …
let traces: Vec<_> = asm.sld_records.iter().filter(|r| r.record_type == "T").collect();
let _ = std::fs::remove_file(&scratch);T records map a source line to an address; L records are symbols. See Debugging a Build for the format.
The tokeniser on its own
fantasm::assembler::tokens::{Token, TokenReader} is the lexer the assembler uses, and can be run without assembling anything — which is how an editor gets highlighting that agrees with the assembler rather than approximating it with regular expressions.
What this is used for
0x1DE, the native IDE, embeds it twice: assemble runs a build in-process and turns the diagnostics into its own type, and lexer uses the tokeniser alone for highlighting. Between them that is Assembler, AssemblerOptions, Diagnostic, ErrorLevel and TokenReader — a small surface, and the one most likely to keep working, being the one something exercises.
Reaching further in is possible, since much of the crate is pub, but nothing outside promises to stay put.
What next
- Diagnostics — the codes and levels a
Diagnosticcarries. - Debugging a Build — what the SLD records mean.
- The Language Server — the other way to drive FantASM from a tool, over a protocol rather than in-process.