Skip to content

Zymbol-Lang v0.0.8

Latest

Choose a tag to compare

@zymbol-lang zymbol-lang released this 02 Aug 11:23
· 5 commits to main since this release

Memory-model debt release. Every divergence found by the design-vs-implementation audit in MEMORY_MODEL.md is resolved, and three validation projects written in Zymbol (zy-GO, zy-Serpiente, zyKlingonGalaxy) contributed the rest: HLZ-001 … HLZ-011 are findings from writing real applications, not from unit tests. Full detail in CHANGELOG.md.

✨ Added

  • Automatic destruction at last use (auto-free) — both engines, always on. A variable's memory is released right after the statement containing its last use instead of at scope end. Invisible by design: it never changes a correct program's behavior, it only lowers peak memory (measured: a script holding two sequential 30 MB strings peaks at ~64 MB instead of ~94 MB in the tree-walker). Backed by a new purely lexical, conservative last-use analysis (zymbol_semantic::last_use); constants, hot names (/°x), _-prefixed names and module-level bindings are never auto-freed.
  • Zymbol Packages (.zyp) — one file for a multi-file program. zymbol package DIR --script main.zy -o out.zyp computes the transitive closure of module imports and </ file.zy /> targets and zips it; zymbol run out.zyp [--script name] [--vm|--tw] extracts to an ephemeral temp dir and runs from there, never chdir-ing — so the code is disposable but the data a script writes still lands in your real working directory. A .zyp is an archive of source, unrelated to zymbol build. Deterministic writer (fixed timestamps and entry order): the same tree always produces a byte-identical archive.
  • std/term — terminal display metrics. width / pad_left / pad_right / center / truncate, measured in terminal columns rather than grapheme count, so "手番"$# is 2 but term::width("手番") is 4. truncate never splits a wide glyph. Replaces the hand-maintained East Asian width table zy-GO carried inside the game.
  • Match or-patterns — p1 || p2 alternatives in a ?? arm. Alternatives mix any pattern kind, not just literals: 1..10 || 20..30, < 0 || > 100, ["run", _] || ["build", _]. Tested left to right, first match wins.
  • ##! on a Char yields its Unicode code point##!'A' is 65. The only direct Char→Int route, which makes characters classifiable by range.

🛠 Changed

  • One shared module-path resolution rule — ModulePath::resolve_from. The tree-walker, the semantic analyzer and the VM compiler each carried their own copy of "which file is this import?", and they diverged: compile_import ignored is_absolute and home_relative, so <# /abs/path => x resolved to a different file under --vm than under the tree-walker — silently. All three now call one rule.
  • zymbol check now checks the whole program, not just the named file. It followed no imports, so a clean check meant nothing for any project organised in modules. It now walks imports transitively (stdlib excluded, cycles cut) and reports each module's errors at its own line. The LSP gets the same coverage, plus a module-has-errors diagnostic on the import line.

🐛 Fixed

  • Memory model (MM-1 … MM-11). Module-state mutations made by intra-module calls were lost; \ x inside a function poisoned the caller's same-named variable; root-scope constants vanished at call depth ≥ 2; modules loaded at run time skipped semantic analysis; /°x inside a function called from a @ loop panicked the tree-walker. VM parity bugs found while verifying the fixes: each import alias got its own module-state copy (MM-10), and a leftover loop-iterator value diverged from the tree-walker (MM-11).
  • Numeral mode (#d0d9#), audited end to end. It reached >> but not interpolation, juxtaposition, $++ or >>~, and not collections or the round trip. It is now one rule across every string-building path, with ordering comparisons unified so no digit script is second-class.
  • Findings from the validation projects. HLZ-SRP-001 (a module function that wrote state and returned a value lost the write), HLZ-KL-001 (string interpolation rejected identifiers the lexer accepts), HLZ-008 (the VM silently dropped output parameters of module functions), HLZ-010 (the VM turned an interpolated constant into literal text), HLZ-009 (the VM could not slice a String inside a module function), plus HLZ-001 … HLZ-007 and HLZ-011.
  • Static-tooling audit — what check and the LSP could not see: recursive check, stdlib visibility, re-export ordering, pattern-literal escapes.
  • Three bugs found by the new package gate itself: >>? aborted in one engine and returned a size in the other when there was no terminal; the Linux packages declared a glibc floor they did not honour; a stdlib module the build does not include reported two different names.

📦 Packaging — releases now gate on a .deb that actually installs

Linux packages go through build → verify → publish: nothing reaches this page until the .deb has been installed and exercised in a pristine debian:12 container (packaging/verify/verify-deb.sh, 41 checks — dependency resolution, dpkg --audit, dynamic linkage, the declared glibc floor, CLI smoke tests, the full E2E parity suite, reinstall and removal). Reproduce it locally with bash packaging/verify/run-local.sh.

Availability of std/db: Windows binaries and source builds only (default db cargo feature). The prebuilt Linux/macOS binaries exclude it — the ODBC driver manager needs dlopen, impossible in a fully static binary.

✅ Validation

  • cargo test: 936 / 936 pass
  • vm_compare.sh (tree-walker vs VM parity): 536 / 536 PASS, 0 SKIP — the whole tracked corpus, verified against the installed .deb as well as the development build
  • Golden suite: 523 / 525 — the two failures are stale hand-written .expected fixtures, not interpreter regressions (IMPL_V008.md § E.1)
  • Formatter property harness: 600 PASS / 0 FAIL, no regressions against the baseline
  • Debian package gate: 41 / 41 checks in a pristine debian:12 container

Known debt: the browser interpreter is behind the Rust engines on seven cases — six v0.0.8 fixes with no counterpart there yet, plus one float-literal precision bug that predates this release (IMPL_V008.md § E.3).

Full Changelog: v0.0.7...v0.0.8