Lyric
A statically typed application language with a bytecode VM — standalone, and embeddable in a host with a capability-based sandbox.
What changed in 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
A native signature may name a value struct of ANOTHER SDK module. An SDK of several files declares its
Vec2once; before this only the declaring module could name it, so a second module (engine.camera.toWorld(x, y): world.Vec2) wasLYR-IR0001— "non-primitive type in a declared signature" — whether the type was imported selectively or written module-qualified. Both forms work now, as parameter and as return.It is the same shape as the imported-alias fix of 2.2.1, one function away in the same file: the lookup was module-local and never asked the resolver. The 2.2.1 note called the restriction "documented and deliberate" — that was too generous. Its reason (an alias has nothing to flatten) explains why the alias fix did not carry structs along; it does not explain why a foreign struct may not be flattened, and there is no such reason. What crosses the wire is a LAYOUT, a layout belongs to the program rather than to the file that wrote it down, and the host is held to it by the same load-time check as before.
Unchanged: a struct in a native signature flattens to scalars and strings, so a field that is an array or an object is still refused — crossing a module line changes nothing about what the host would have to know.
Documentation
- The
…Intfamily ofstd.mathis named in the guide.clamptakes floats andclampInttakes ints, asmin/minIntandabs/absIntdo, because the language has no overloading and the library distinguishes by the type in the name. Reaching forclampwith threeints and gettingcannot assign 'int' to 'float'is the convention working as designed — but chapter 13 never said so where someone would look for it.