# FantASM 2.0.0

The editor now answers with what the build answers. Libraries get a real interface, tests get
spans and checksums, and 59 new diagnostic codes say what is wrong rather than sharing one
number between five faults.

## Breaking

- **The machine is a `device`, not a `target`.** `-d`/`--device`, `!device`, `[assembler] device` and `{_device}` replace the `target` spellings. Each old one still works, says so once (`W1103`), and goes in 2.1. `[[target]]` is unchanged.
- **The unused-label sweep is `--find-unused`, not `--enable-warnings`.** `-u`, `--no-find-unused` and `find_unused` replace the `warnings` spellings, which never turned any other warning on or off.
- **`INCLUDE` no longer searches the working directory first.** A basename finds the file beside the including source, so a build is the same wherever `fantasm` is run from. Name the directory, or add it with `-I`.
- **A `bin` whose code is not contiguous is refused (`E1085`).** It used to write a file where a label pointed at the wrong byte. Assemble each region separately and combine them.
- **A label must start at column 0 (`E1093`).** An indented name that is no instruction, directive or macro is refused. Locals, constants and names inside a macro body are unaffected.
- **A macro's name at column 0 defines a label rather than expanding (`W1094`).** Indent the call.
- **`rep` is a directive, so it may not name a macro (`E1060`).** Rename the macro; labels and `STRUCT` members still take the word.
- **`assert` and `debug` are directives, so neither may name a macro (`E1060`).** Same fix, same exemptions.
- **An index displacement outside -128 to 127 is refused (`E1123`).** `ld a,(ix+200)` used to assemble as `ld a,(ix-56)` in silence.
- **A `!test` command outside a `!test` block is refused (`E1122`).** They were accepted anywhere and discarded, so an assertion past its `!endtest` passed without running.
- **An undefined name in an `ENUM` member's value is refused (`E1003`).** The member used to take the next counter value silently.
- **Two targets may not share an artifact path.** A project-wide `[artifacts]` with one `labels` key left a file holding only the last target's symbols. Move the key into each `[target.artifacts]`.
- **`!nex screen` is refused for anything but `0` (`E1117`).** No screen was ever written, so the flag sent a loader into the program.
- **A `.nex` is tagged `V1.2` unless it needs `V1.3`.** It was always `V1.3`, which a core older than 3.x refuses to load.
- **`init --force` has no short form.** `-f` is `--format` everywhere else. `init -f` still works and says so.
- **`-vvv` is refused.** There are two levels of `-v` and it silently meant `-vv`.

**13 more breaking changes to the Rust API** are listed under *Internal* in `HISTORY.md`. The crate is not on crates.io and makes no semantic-version promise; only a program embedding it is affected.

## Added

- **A language server worth using** — rename across the project, call hierarchy, quick fixes from a diagnostic's hint, a nested outline, folding, inlay hints, clickable `INCLUDE`s. It reads your `fantasm.toml`, and a file a `[[target]]` includes is analysed as part of that target.
- **Libraries** — `!library` makes a file a namespace with its own include guard, `INTERFACE` says what is public, and `--gc-libraries` discards what nothing calls without touching a placement `MODULE`.
- **`REP <count>, <instruction>`**, and a `REP`/`ENDR` block, for unrolling without `ldir`'s loop overhead.
- **Tests that check memory** — `assert_mem` and `init_mem` take a run, a fill, a file to compare against or a physical address; `assert_checksum` folds a run into a CRC-32C; `init_cycle_limit` and `assert_cycles` budget the time.
- **Debugger annotations** — `!assert` and `!debug` record a claim into the `--sld` file, emitting nothing.
- **A `[lint]` table** in `fantasm.toml` sets what each warning is filed as, by code [`w1049 = "deny"`].
- **Nested structs**, `--reloc` for relocatable images, `--report-discards`, `--color`, and Rhai scripts as `include "x.rhai"` with `rhai.file.fn()` calls.
- **These notes ship with the build** — `RELEASE-NOTES.md`, beside the licence in every package.

46 additions in all.

## Fixed

**113 fixes**, and the worst of each group:

- **2 crashes** — `ds -1` and `db (1<<63)/-1` aborted the assembler outright.
- **24 wrong output, silently** — a bank's code written twice into a `.nex`, `add hl,ix` assembling as `add hl,hl`, `db 1<2<3` giving 8, seven block-graphics characters emitting the wrong code.
- **24 sources that should have assembled, or should not have** — an `IF` inside a branch that was not being assembled having its condition evaluated anyway, a `!test` body inside a `MODULE` unable to use that scope's own names, a macro parameter inside brackets never substituted.
- **37 in output and tooling** — colour written into a redirected log, only the first error of a build reported however many it found, no two `--sld` files matching between builds.
- **19 diagnostics** that named the wrong thing, or put the caret at the end of the statement rather than on the name.
- **5 in the language server**, and **2 in the documentation**.

**26 of those 113 are the editor's**, spread across the groups rather than gathered in one: it disagreed with the build on any file holding a `MODULE`, opening a second file of one program filled the screen with faults in correct source, and an accented character in a comment took the server down.

## Internal

59 new diagnostic codes, 84 to 140, and three withdrawn — `E1034`, `I1051` and `E1062` documented rules the assembler did not have. Test coverage expanded from 742 to 1,432 tests, and every combination of the `nex`, `sna`, `lsp` and `update-check` features builds and passes.

---

Every change is in [HISTORY.md](HISTORY.md) under `[2.0.0]`.
