Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .agents/plans/A33-perf-baseline-luerl-gap.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ issue: null
pr: null
branch: perf/baseline-luerl-gap
base: main
status: ready
status: merged
direction: A
unlocks:
- per-workload perf fix plans
Expand Down Expand Up @@ -145,4 +145,6 @@ this plan can use it. If not, run the scripts directly.

## Discoveries

(populated during measurement)
The baseline was captured and committed as
[`benchmarks/BASELINE.md`](../../benchmarks/BASELINE.md) (2026-06-15),
which supersedes the planned `bench_results/baseline-<date>.md` path.
77 changes: 77 additions & 0 deletions .agents/plans/A49-release-docs-sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
id: A49
title: "Docs sync for 1.0.0: roadmap, changelog, guides, README true-up"
issue: null
pr: 381
branch: docs/release-docs-sync
base: main
status: review
direction: A
---

## Goal

Bring every user-facing doc and status artifact in line with reality
(20/29 official suite files passing, `rc.3` → `1.0.0` pending) so the
`1.0.0` cut is documentation-clean.

## Out of scope

- Any source behavior change, except the test-warning fix (item 8) and
the doctest wiring (item 9).
- API changes — a sibling PR handles those. Unreleased CHANGELOG entries
are kept in clearly-labeled subsections to minimize the merge conflict.
- The `1.0.0` version bump and release CHANGELOG section (release-cut PR).
- Blog post, website.

## Success criteria

- [ ] `ROADMAP.md` Status reflects 20/29, dated 2026-07-05; suite gate marked MET.
- [ ] `CHANGELOG.md` Unreleased documents #376 and #379; suite-exclusion
doc entry lists the 9 exclusions by category; heading/link-ref
mismatch fixed; "Upgrading from 0.x" migration section added.
- [ ] `guides/sandboxing.md` CPU section leads with `:max_instructions`.
- [ ] `README.md`: `utf8` in coverage list; host-filesystem claim qualified;
`import Lua` shown in the Tour.
- [ ] `lib/lua.ex` `load_file!` links the Lua 5.3 manual.
- [ ] `lib/lua/runtime_exception.ex` moduledoc uses `<eval>` for default source.
- [ ] `guides/mix_tasks.md` sample output + skips-file reference updated.
- [ ] `test/lua_test.exs` encode-nil test no longer emits a type warning.
- [ ] `doctest Lua.Parser.Error` wired into a test file and passing.
- [ ] `.agents/plans/B17-*.md` and `A33-*.md` statuses reconciled with reality.
- [ ] `mix format`, `mix compile --warnings-as-errors`, `mix test`,
`mix docs --warnings-as-errors` all clean.

## Implementation notes

Verify each item still needs fixing before touching it — PR #378 shifted
line numbers and fixed some issues already.

## Verification

```
mix format
mix compile --warnings-as-errors
mix test
mix docs --warnings-as-errors
```

## Risks

- Concurrent API-PR CHANGELOG conflict — kept small via labeled subsections.

## What changed

PR #381. Files touched: `ROADMAP.md`, `CHANGELOG.md`, `README.md`,
`guides/sandboxing.md`, `guides/mix_tasks.md`, `lib/lua.ex`,
`lib/lua/runtime_exception.ex`, `tasks/lua.suite.ex`,
`test/lua_test.exs`, `test/lua/parser/error_unit_test.exs`, and the
`B17` / `A33` plan files.

Discoveries:
- The `mix lua.suite` task moduledoc (`tasks/lua.suite.ex`) carried the
same stale `@ready_tests` reference and sample output as the guide, so
it was fixed alongside item 7 — same doc-only class, no behavior change.
- The canonical suite count (20/29, skip ranges applied) differs from the
raw `mix lua.suite` count (9/17/3, no skips); the guide now distinguishes
them explicitly.
6 changes: 4 additions & 2 deletions .agents/plans/B17-vm-max-steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ issue: 306
pr: 320
branch: feat/vm-max-steps
base: main
status: review
status: merged
direction: B
unlocks:
- deterministic CPU bound for library consumers calling Lua.eval!/2 without a host Task + timeout wrapper
Expand Down Expand Up @@ -193,7 +193,9 @@ mix test --only lua53

## What changed

PR #320.
PR #320 (merged). The option shipped **renamed** from the plan's working
name `:max_steps` to `:max_instructions` — the name used in `Lua.new/1`,
the docs, and the CHANGELOG. Everything else below matches what landed.

Files touched:

Expand Down
88 changes: 79 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,59 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
> Upgrading from a Luerl-based `0.x` release? See
> [Upgrading from 0.x](#upgrading-from-0x-luerl-based-versions) below.

## Upgrading from 0.x (Luerl-based versions)

`1.0.0` replaces the Luerl backend with an Elixir-native Lua 5.3 VM, and
Luerl is no longer a runtime dependency. Most code built on the high-level
`Lua` API (`Lua.new/1`, `Lua.eval!/2`, `Lua.set!/3`, `deflua`,
`Lua.load_api/2`) keeps working unchanged. The breaking changes are all at
the value-encoding and error boundaries:

- **Encoded table / userdata / function tags changed.** Values that carried
Luerl's internal tags now use the new VM's representation: tables are
`{:tref, integer()}` (was `:luerl.tref()`), userdata is
`{:udref, integer()}` (was `:luerl.usdref()`), and Elixir-defined Lua
callables are `{:native_func, fun}` (was `:luerl.erl_func()`); compiled Lua
functions are `{:lua_closure, _, _}`. If you pattern-matched the old
tuples, update the patterns — better still, treat encoded refs as opaque
and round-trip them through `Lua.decode!/2`.
- **MFA callback encoding was removed.** `Lua.encode!/2` no longer accepts the
`{module(), atom(), list()}` MFA tuple form. Replace it with a function
literal or a `deflua` callback.
- **Parser error messages have a new format.** The Luerl-style
`"Line 1: syntax error before: ';'"` is gone; the native parser produces
messages like `"Expected expression"`, with rich structured data available
via `Lua.Parser.parse_structured/1`. Assertions that string-matched the old
wording need updating.
- **64-bit integers wrap on overflow.** Arithmetic and bitwise ops follow Lua
5.3 §3.4.1 (wrap-around at 2^63) instead of widening to bignums as Luerl
did. Code depending on arbitrary-precision integer results will now see
wrapped values.
- **Chunks are self-contained.** `Lua.Chunk` now holds a compiled prototype
and is reusable across `Lua.eval!/2` calls; there is no separate load step.
- **Exceptions are public.** `Lua.RuntimeException` and `Lua.CompilerException`
are documented, so user code can rescue and pattern-match them.

Everything else — the default sandbox, `_G`/`_ENV` semantics, metatables, and
the standard-library surface — is compatible. The full breaking-change list
is in the [`1.0.0-rc.0`](#100-rc0---2026-05-26) entry below.

## [Unreleased]

### Changed
- Elixir callbacks now receive the public `Lua.t` (`%Lua{}`) as their state
argument **regardless of how they enter the VM**. Previously a two-arity
callback (`fn args, state -> {results, state} end`) got a `%Lua{}` when set
at a path or loaded via `deflua`/`Lua.load_api/2`, but the raw internal
`Lua.VM.State` when it reached the VM as an encoded value — nested inside a
value passed to `Lua.set!/3`, or produced by `Lua.encode!/2`. Those paths
now wrap the state consistently and validate the callback's return value, so
the same closure behaves identically everywhere. Code relying on the rc.3
raw-state behaviour (or a `%Lua{state: raw}` workaround) should drop the
workaround (#379).

### Fixed
- `Lua.encode!/2` now maps Elixir `nil` to Lua `nil` instead of the string
Expand All @@ -14,6 +66,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
then ...` checks and breaking `return nil, "reason"` error patterns. The
round trip `decode!(encode!(nil))` is now lossless, matching the existing
behaviour for `nil` inside tables and function result lists (#374).
- `string.rep` now sizes its allocation to the actual result length instead of
the raw repeat count, so a large count paired with an empty or short string
(e.g. `string.rep("", 1e9)`) no longer over-allocates or trips the
string-size guard spuriously. The guard still refuses genuinely oversized
results (#376).

### Documentation
- The Lua 5.3 official test suite now passes **20/29** files. The 9 excluded
files are deliberate, documented exclusions rather than open bugs:
- **Filesystem / subprocess non-goals** — `main`, `files`, `attrib`,
`verybig` (shell-out, file I/O, and filesystem `require`, which a
sandboxed embedded VM does not support).
- **Capability non-goals** — `coroutine`, `db` (the full
continuation/coroutine model and the full `debug` library).
- **Perf-bound, revisit in 1.0.x** — `big`, `closure` (run past the suite
timeout on the BEAM tuple-copy ceiling; the VM results are correct).
- **PUC error-wording divergence** — `errors` (our structured error
messages diverge from PUC-Lua's exact strings).

## [1.0.0-rc.3] - 2026-06-15

Expand Down Expand Up @@ -217,7 +287,7 @@ The public API is unchanged from rc.1.
faster. This remains a deliberate safety/speed tradeoff for the RC and
will be addressed before `1.0.0` final.

## [v1.0.0-rc.1] - 2026-06-02
## [1.0.0-rc.1] - 2026-06-02

The second release candidate for `1.0.0`. It builds on rc.0 with a new
`os` and `utf8` standard library, richer `debug` and error introspection,
Expand Down Expand Up @@ -303,7 +373,7 @@ the same machine (Luerl and PUC-Lua used as drift controls, ±3%):
are unaffected or faster. This is a deliberate safety/speed tradeoff for
the RC and will be addressed before `1.0.0` final.

## [v1.0.0-rc.0] - 2026-05-26
## [1.0.0-rc.0] - 2026-05-26

This is the first release candidate for `1.0.0`. The library has been
rewritten on a new Elixir-native Lua 5.3 virtual machine, and the public
Expand Down Expand Up @@ -414,15 +484,15 @@ API is intended to be stable. Please report any regressions before final.
- Line number attribution for the first line of a chunk (#240).
- `string.pack` no longer emits compile warnings (#224).

## [v0.4.0] - 2025-12-06
## [0.4.0] - 2025-12-06

### Changed
- Upgrade to Luerl 1.5.1

### Fixed
- Warnings on Elixir 1.19

## [v0.3.0] - 2025-06-09
## [0.3.0] - 2025-06-09

### Added
- Guards for encoded Lua values in `deflua` functions
Expand All @@ -435,26 +505,26 @@ API is intended to be stable. Please report any regressions before final.
### Fixed
- `deflua` function can now specify guards when using or not using state

## [v0.2.1] - 2025-05-14
## [0.2.1] - 2025-05-14

### Added
- `Lua.encode_list!/2` and `Lua.decode_list!/2` for encoding and decoding function arguments and return values

### Fixed
- Ensure that list return values are properly encoded

## [v0.2.0] - 2025-05-14
## [0.2.0] - 2025-05-14

### Changed
- Any data returned from a `deflua` function, or a function set by `Lua.set!/3` is now validated. If the data is not an identity value, or an encoded value, it will raise an exception. In the past, `Lua` and Luerl would happily accept bad values, causing downstream problems in the program. This led to unexpected behavior, where depending on if the data passed was decoded or not, the program would succeed or fail.


## [v0.1.1] - 2025-05-13
## [0.1.1] - 2025-05-13

### Added
- `Lua.put_private/3`, `Lua.get_private/2`, `Lua.get_private!/2`, and `Lua.delete_private/2` for working with private state

## [v0.1.0] - 2025-05-12
## [0.1.0] - 2025-05-12

### Fixed

Expand Down
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ read them back:
Runtime errors raise `Lua.RuntimeException`, which carries the failing
`:source` and `:line` so you can report exactly where a script broke:

The `~LUA` sigil used below (and elsewhere in this tour) needs `import Lua`:

```elixir
import Lua

try do
Lua.eval!(~LUA"""
local x = 1
Expand Down Expand Up @@ -175,15 +179,19 @@ Lua object patterns work as written:
`Lua` targets Lua 5.3. The lexer, parser, register-based VM, value
encoding/decoding, varargs, multiple returns, `_G`/`_ENV`, metatables, the
string-pattern engine (`find`/`match`/`gmatch`/`gsub`), and the `string`,
`table`, `math`, `os`, and `debug` standard libraries are implemented.
`table`, `math`, `os`, `utf8`, and `debug` standard libraries are implemented.

As a sandboxed *embedded* VM, some standalone-interpreter behavior is a
deliberate non-goal rather than a missing feature:

- **Standalone interpreter / `os.execute`** — there is no shell-out to the host.
- **Host filesystem access** — `Lua` does not read your host filesystem. The
`io.*` library and `require`/`dofile` are sandboxed by default and raise
rather than touching disk; there is no host-OS file or module resolution.
- **Host filesystem access is deny-by-default** — `Lua` does not read your
host filesystem unless you opt in. The `io.*` library and `require`/`dofile`
are sandboxed by default and raise rather than touching disk, so out of the
box there is no host-OS file or module resolution. When you *want* it, you
enable it explicitly: `Lua.set_lua_paths/2` configures where `require`
resolves modules on disk, and `Lua.load_file!/2` loads a Lua file from the
host.
- **Coroutines**, **garbage collection / weak tables**, and the **full
`debug` library**.

Expand Down
32 changes: 18 additions & 14 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@

This is the strategic overview. For per-PR detail, see [`.agents/plans/`](.agents/plans).

## Status: 2026-06-15

- **Version**: `1.0.0-rc.3` shipped (rc.0–rc.3 all released).
- **Lua 5.3 official suite**: 17/29 files passing. 8 fully clean
(`api`, `bitwise`, `code`, `nextvar`, `simple_test`, `tpack`, `utf8`,
`vararg`) plus 9 passing with documented skip-ranges (`all`, `calls`,
`constructs`, `events`, `gc`, `goto`, `literals`, `locals`, `pm`). 4
deliberate non-goals (`main`, `files`, `attrib`, `verybig`). 8 still
whole-file-skipped pending triage (`big`, `closure`, `coroutine`,
`db`, `errors`, `math`, `sort`, `strings`).
## Status: 2026-07-05

- **Version**: `1.0.0-rc.3` shipped (rc.0–rc.3 all released); `1.0.0`
final is pending the release cut.
- **Lua 5.3 official suite**: 20/29 files passing. 9 fully clean
(`api`, `bitwise`, `code`, `locals`, `nextvar`, `simple_test`, `tpack`,
`utf8`, `vararg`) plus 11 passing with documented skip-ranges (`all`,
`calls`, `constructs`, `events`, `gc`, `goto`, `literals`, `math`,
`pm`, `sort`, `strings`). The remaining 9 are the documented
exclusions: 5 whole-file skips (`big`, `closure` — perf-bound, revisit
in 1.0.x; `coroutine`, `db` — capability non-goals; `errors` — PUC
error-wording divergence) plus 4 deliberate non-goals (`main`, `files`,
`attrib`, `verybig` — filesystem/subprocess). `strings`, `sort`, and
`math` were promoted in #368.
- **Current focus**: closing the `1.0.0` release gates in
[`A13`](.agents/plans/A13-release-rc1.md) — the suite gate (aim 20/29
with 9 documented exclusions; 17 pass today, three triage targets
remain: `strings`/`sort`/`math`) and a one-time perf-gate check
(fib already at 1.03–1.11× Luerl after #324/#360).
[`A13`](.agents/plans/A13-release-rc1.md) — the suite gate is **MET**
(20/29 passing with 9 documented exclusions), and the one-time
perf-gate check is satisfied (fib already at 1.03–1.11× Luerl after
#324/#360). Remaining work is the release-cut and docs true-up.

## Release sequencing (decided 2026-06-15)

Expand Down
Loading
Loading