Lyric v2.12.0

Changelog

This file starts at v1.0.0. Before it there was no compatibility promise to describe — neither for the language nor for the .lyrbc format — and a changelog written under those conditions records churn rather than change. The pre-1.0 releases carry their notes in their annotated tags.

Versions follow vMAJOR.MINOR.PATCH, as described in README. Each entry lists what changed for someone using the toolchain: the language, the standard library, the bytecode format, the command line and the embedding API. Compiler internals are in git log.


v2.12.0 — 2026-08-22

Bytecode format 3.6. The interpreter runs the same programs in a third of the instructions, and the release is about why that is the number that mattered.

The measurement it started from

An instruction on this VM costs ~6 ns — and costs it regardless of what it does. A br, an add f64 and an and i64 lie within twenty percent of each other. That is the normal price of a switch-dispatch stack machine, not a slow interpreter: the dispatch is the whole bill. So nothing that makes an instruction cheaper moves a program's time, and the only lever is executing fewer.

The loop test of every while in the language was four instructions, of which three existed to move a value onto the operand stack and off it again.

Added

Measured

Same harness, same machine, same session; the baseline is a build with selection switched off and the old nextInt. Two iteration counts differenced, so nothing that happens once is in the figure, and the instruction counts are read from an ExecutionBudget rather than counted by hand.

case instr ns/iter instr ns/iter
2.11 2.11 2.12 2.12
a counting loop 9 44.3 3 18.2 2.4×
an integer accumulator 13 59.2 4 27.6 2.1×
a float accumulator 13 68.7 4 24.8 2.8×
a masked accumulator 15 88.7 9 61.2 1.4×
a native call 14 82.4 8 56.9 1.4×
Random.nextFloat() 70 395.4 42 199.2 2.0×
an array read 19 91.6 13 65.8 1.4×

The time fell WITH the count rather than beside it, which is the claim the release rests on. What rose is the average price per instruction (≈4.9 → ≈6.3 ns), and that is the healthy direction: the instructions the fusion removed were the cheapest ones, the moves.

The rows that gain least say where the remaining work is: a nested expression keeps its intermediate on the stack, and neither fused form can reach a value that is not in a slot.

Format

3.6 against 3.5: four new opcodes. A producer may emit the unfused sequences instead, and one that never emits a fused form writes a module any 3.5 runtime accepts; a module that uses one needs a 3.6 runtime, named at load time.

The §Versioning rule was corrected in the same round. It read "a minor version may only add skippable sections", which 3.4 was not — the note beside that version said as much, so the document had contradicted itself since the day it shipped. It now states the compatibility the format has actually delivered: per MODULE, not per version.

v2.11.0 — 2026-08-22

Bytecode format 3.5. One new section, and the whole release is about a name that used to get lost.

Added

Format

v2.10.1 — 2026-08-22

One fix, reported the day 2.10.0 landed: the new enum argument was unusable in the shape an SDK actually writes.

Fixed

v2.10.0 — 2026-08-22

An attribute argument may name an enum variant. The bytecode format goes 3.3 → 3.4, and this is the first change to it that an older reader cannot ignore — see below.

Added

Changed

v2.9.0 — 2026-08-22

An editor can attach to a program a host is already running. The bytecode format stays 3.3 and the language gains nothing.

Added

v2.8.0 — 2026-08-22

Module constants initialize in dependency order, so a file compiles the same way whoever compiles it. The bytecode format stays 3.3; more programs compile than before and none fewer.

Fixed

v2.7.1 — 2026-08-22

One fix, to a request the debug adapter left unanswered.

Fixed

v2.7.0 — 2026-08-21

One overload, and with it the debugger reaches the shape an embedded script actually has. The bytecode format stays 3.3 and the language gains nothing.

Added

v2.6.0 — 2026-08-21

A compilation error tells an embedding host WHERE it happened, and a panic hands over its backtrace. Both were already known inside the toolchain and stopped at the boundary. The bytecode format stays 3.3 and the language gains nothing.

Added

Changed

v2.5.1 — 2026-08-21

One fix, to a promise the formatter's own chapter makes.

Fixed

v2.5.0 — 2026-08-21

One requirement from the embedder, and the documentation gap beside it. The bytecode format stays 3.3; nothing on the wire changes, which is the whole finding.

Fixed

Documentation

v2.4.0 — 2026-08-21

M31: two additive answers to what an embedder found in production. A host can bound how long foreign code runs, and an attribute argument may name its value instead of repeating it. The bytecode format stays 3.3, and a module compiled by 2.3 loads unchanged. Two conformance cases activate with this release (//! since: 2.4.0); the suite stands at 90.

Added

v2.3.1 — 2026-08-21

The post-2.3.0 audit's patch wave: four measured bugs, none of them reachable from a program that was doing anything unusual. The bytecode format stays 3.3, and the language gains nothing — three of the four were valid programs the toolchain mishandled. Three conformance cases activate with this release (//! since: 2.3.1); the suite stands at 88.

Fixed

v2.3.0 — 2026-08-20

M30: the toolchain learns to debug. Breakpoints, stepping, the call stack and the variables panel, in any editor that speaks the Debug Adapter Protocol — the VS Code extension wires it to F5. The bytecode format goes 3.2 → 3.3; the change is one strippable section, so a 3.2 runtime loads a 3.3 module unchanged, and every 2.x module keeps loading here.

Added

Fixed

v2.2.1 — 2026-08-20

One fix, found by the embedder the same day: the specification's §3.5 promises that an opaque alias resolves to its underlying in a native signature — without restricting where the alias was declared. The toolchain under-delivered.

Fixed

v2.2.0 — 2026-08-20

The A8 wave: both coroutine edges Erato's register filed after building its cutscene driver, plus one the fix uncovered. The bytecode format stays 3.2; a module that never calls next() loads on every 2.x runtime. Four conformance cases activate with this release (//! since: 2.2.0); the suite stands at 85.

Added

Fixed

v2.1.1 — 2026-08-20

One fix, found the day of 2.1.0 by the first embedder to re-pin: a compiler crash on a form the language always meant to allow.

Fixed

v2.1.0 — 2026-08-20

The ergonomics wave: two additive changes the audit measured the edges of. Four conformance cases activate with this release (//! since: 2.1.0); one 2.0 case pinning the old non-context rule retires with its sentence.

Added

v2.0.1 — 2026-08-20

The first harvest of the deep audit: seven bugs measured against the now-normative specification, fixed as one wave. Seven new conformance cases activate with this release (//! since: 2.0.1); the suite stands at 78.

Fixed

Improved

v2.0.0 — 2026-08-20

The specification is normative from this release on: lyriclang/lyric-spec defines the language, the toolchain implements it, and a divergence is a toolchain bug. The major cuts the SOURCE surface — everything the 1.x deprecation clocks announced — while the bytecode format stays 3.2 and bytecode compiled against 1.x keeps loading.

Removed — the 2.0 cut

Everything @Deprecated announced through 1.x is gone from the source surface. The registry still binds the old NATIVE names, so bytecode compiled against 1.x keeps loading; what the cut takes is the ability to write the old forms in new code.

Changed

v1.16.0 — 2026-08-19

The language has a specification: lyriclang/lyric-spec holds twelve chapters and a conformance suite, non-normative until 2.0 — and from this release on the semantics are FROZEN. Two toolchain fixes came out of writing it. The bytecode format stays 3.2.

Fixed

v1.15.0 — 2026-08-19

The freeze prep: the design leftovers settled before the spec freezes semantics. opaque type arrives, the string API becomes methods, iterator chaining gets its documented No — and a latent function-id collision in the lowering falls. The bytecode format stays 3.2.

Fixed

Added

v1.14.0 — 2026-08-19

The std polish, born from a line-by-line audit. The string module stops being quadratic, the print family collapses to one generic concept, the collections learn the operations daily use kept reaching for, arrays cross the native boundary as parameters for the first time — and two new modules arrive: std.random and std.time. The bytecode format stays 3.2.

Added

Fixed

v1.13.0 — 2026-08-19

The language gaps close. Interface inheritance arrives — one parent, implied through the whole chain — compound assignment reaches through the operator interfaces, block lambdas infer their return type, and std.core becomes the import-free root of the library. One question got its documented No: heterogeneous operator arithmetic. The bytecode format stays 3.2.

Added

Changed

Fixed

v1.12.0 — 2026-08-19

The standard library grows up. Every public item is documented, constructors live on the types, the first real deprecations start their clock, and the library tests itself — in Lyric. Two compiler fixes came out of the work. The bytecode format stays 3.2.

Added

Changed

v1.11.0 — 2026-08-19

Attributes stop being decoration. One is now read by the compiler — @Deprecated — and one by a new tool: lyric test runs every function marked @Test. The bytecode format stays 3.2, and no existing program changes meaning.

Added

Not in this release

v1.10.0 — 2026-08-19

The compiler learns to speak below "error". Four severities, warnings that matter, notes that point at places, and a CI gate. The language, the bytecode format (3.2) and the embedding API are unchanged; every program that compiled still compiles — some now hear about themselves.

Added

Changed

v1.9.1 — 2026-08-19

The formatter reaches the editor. textDocument/formatting is served by the language server — format on save works wherever the editor offers it, in VS Code and the JetBrains IDEs alike, with no client update needed.

The answer is one whole-document edit off the buffer as it stands, an empty list when the file already has the shape, and NO edits for a buffer that does not parse: the formatter never writes a guess over broken text, behind the editor's gesture either. The editor's tab settings are deliberately ignored — one shape is the tool's contract, in every surface it has.

The toolchain is otherwise unchanged.

v1.9.0 — 2026-08-19

Two tools. lyric pack turns a program into one standalone executable, and lyric fmt gives every Lyric file the one shape there is. The language, the standard library, the bytecode format and the embedding API are untouched; the format stays 3.2, and a .lyrbc built by 1.8.0 packs and runs unchanged.

Added

Changed

Not in this release

v1.8.1 — 2026-08-18

A one-line fix for the JetBrains plugin (now 1.2.1): the TextMate bundle provider was registered under an extension-point namespace that does not exist, so .lyr files rendered uncolored while everything the language server answers worked. The point is declared by the TextMate plugin but qualified under com.intellij; the registration moved there, and highlighting appears. The toolchain itself is unchanged.

v1.8.0 — 2026-08-18

The editors catch up with the compiler. No language change and no format change: the language server compiles the PROJECT instead of the open buffer, answers everything an editor asks, and two installable clients ship beside the toolchain — the VS Code extension as a .vsix, and a new JetBrains plugin.

Changed

Added

The interpreter stops allocating — and so does the native boundary. No language change and no format change: the same programs compile to faster, smaller modules, run with far fewer heap allocations, and a host SDK can now put Vec2 in a native signature. The numbers below come from tools/Bench (new in this release), Release, per operation, against v1.6.0.

Changed

Added

Not in this release

v1.6.0 — 2026-08-18

Attributes. A program can say things about itself that a tool outside it can read — which functions a host should call, what a script-declared type looks like, what a module is. The bytecode format goes 3.1 → 3.2; both new sections are skippable, so a 1.5.0 runtime loads a 1.6.0 module and runs it unchanged.

Added

Fixed

Changed

Not in this release

v1.5.0 — 2026-08-18

Operators on your types. Everything resolves through the one mechanism this language has for polymorphism — the interface a type declares — so there is no operator declaration syntax, no new opcode, and the .lyrbc format stays 3.1.

Added

Fixed

Not in this release

v1.4.0 — 2026-08-17

Completion, and a standard library that says what it does. The language, the command line, the embedding API and the .lyrbc format are untouched; the format stays 3.1.

Added

Fixed

Not in this release

v1.3.1 — 2026-08-17

Fixed

v1.3.0 — 2026-08-17

Everything in this release is the language server. The language, the standard library, the command line and the .lyrbc format are untouched; the format stays 3.1.

Added

Changed

Fixed

Not in this release

v1.2.0 — 2026-08-17

Changed

Added

v1.1.0 — 2026-08-15

Bytecode format 3.1. A minor of the format may only add skippable sections, so a 1.0 runtime reads a module built by this release and a 1.1 runtime reads one built by 1.0 — with one caveat below.

Added

Fixed

Not in this release

Both need a place where a project says what it consists of, and putting that on the command line would make a third place where the layout is written down.

v1.0.1 — 2026-08-14

Fixed

v1.0.0 — 2026-08-14

The first release with a compatibility promise. Everything below describes the state it ships, not a change against v0.9.0: there is no earlier entry to compare against.

From here on the .lyrbc format and the language carry the promise the versioning describes: a minor may add, a major may break.

Language

The whole grammar in docs/Grammar.md compiles and runs: functions, structs and classes, enums with match, interfaces with default methods and :: conformance, generics with constraints, optionals, exceptions with throws and defer, closures, coroutines, modules, and extend blocks on own and primitive types.

Fixed against v0.9.0, each of them a case that used to be refused or to fail late:

Toolchain

Documentation

Not in this release