diff options
| author | T <t@tjp.lol> | 2026-05-26 20:14:37 -0600 |
|---|---|---|
| committer | T <t@tjp.lol> | 2026-05-27 06:26:36 -0600 |
| commit | 1f0915edbe0213e8bc134922f10933468d35a172 (patch) | |
| tree | 11834769555c7037f3393ef8d98bf5841846144a /src/lua_bridge.zig | |
| parent | b788eb05c6d194b91fdc141b6655e61ccaa76ddb (diff) | |
finish lua runtime makeover
- new multi-tool registration via ToolSource
- thread per source-or-standalone-tool
- switched to zig 0.16 Io threading interface
- cli: include `luv` package and run concurrent lua tools via libuv
- one single long-lived lua_State for the whole cli program
Diffstat (limited to 'src/lua_bridge.zig')
| -rw-r--r-- | src/lua_bridge.zig | 53 |
1 files changed, 34 insertions, 19 deletions
diff --git a/src/lua_bridge.zig b/src/lua_bridge.zig index 3d4a24f..eca5661 100644 --- a/src/lua_bridge.zig +++ b/src/lua_bridge.zig @@ -1,7 +1,7 @@ //! Lua C-API bridge for the panto CLI. //! -//! Exposes a `panto` global table inside any `lua_State` we construct, with -//! a single function: +//! Exposes a `panto` global table inside any `lua_State` we construct, +//! with a single function: //! //! panto.register_tool { //! name = "...", @@ -10,26 +10,29 @@ //! handler = function(input) ... end, //! } //! -//! The single-table-argument form is idiomatic Lua "named arguments". It's -//! also forward-compatible: future optional fields (examples, version, etc.) -//! can be added without breaking existing extensions. +//! The single-table-argument form is idiomatic Lua "named arguments". +//! It's also forward-compatible: future optional fields (examples, +//! version, etc.) can be added without breaking existing extensions. //! -//! Each call records a registration in a Lua-side table at a fixed registry -//! slot. The Zig side then reads that table to decide what to do with it: +//! Each call records a registration in a Lua-side table at a fixed +//! registry slot (`registrations_key`). The Zig side reads that table +//! to decide what to do with the entries: //! -//! - **Discovery** (`harvestRegistrations`): runs an extension script once at -//! startup to learn the *names*, *descriptions*, and *schemas* of every -//! tool it declares. The handler functions are discarded — that throwaway -//! state will be closed immediately. +//! - The long-lived `LuaRuntime` (`src/lua_runtime.zig`) loads each +//! extension into a single `lua_State`, then walks the registrations +//! table once per loaded script (between loads it calls +//! `resetRegistrations`). For each entry it copies name / +//! description / schema, `luaL_ref`s the handler function into the +//! Lua registry, and records the ref under the tool name. //! -//! - **Invocation** (`fetchHandler` + `runHandler`): per tool call, we open -//! a fresh `lua_State`, re-run the script, then look up the handler by -//! name in the same registry table. +//! - On dispatch, the runtime spawns a coroutine, pushes the handler +//! onto it via `lua_rawgeti(LUA_REGISTRYINDEX, ref)`, pushes the +//! parsed JSON input, and `lua_resume`s. Top-level extension code +//! never runs again — only handler bodies. //! -//! No `lua_State` pooling, no shared mutable state across calls. Every -//! `LuaTool.invoke` builds and tears down its own state. This is slow per- -//! call (~ms of Lua startup) but mechanically the simplest model: there is -//! nothing that can leak between invocations. +//! This bridge module itself is stateless beyond the public +//! `registrations_key` address; it cooperates with whatever runtime +//! owns the `lua_State`. const std = @import("std"); const Allocator = std.mem.Allocator; @@ -69,7 +72,10 @@ pub const BridgeError = error{ /// The key under which we stash the registrations table in /// `LUA_REGISTRYINDEX`. Any unique pointer works — we use the address of a /// module-level `u8` so multiple states all use the same key value. -var registrations_key: u8 = 0; +/// +/// Public so the long-lived runtime can poke at it directly when it +/// needs to harvest entries. +pub var registrations_key: u8 = 0; /// A single declared tool, as harvested from a script's top-level call to /// `panto.register_tool`. All slices reference Lua-owned strings on the @@ -103,6 +109,15 @@ pub fn install(L: *c.lua_State) void { c.lua_setglobal(L, "panto"); } +/// Replace the registrations table with a fresh empty one. Used by the +/// long-lived runtime between loading distinct extension scripts so it +/// can harvest only the registrations made by the script just loaded +/// (not accumulated from prior loads). +pub fn resetRegistrations(L: *c.lua_State) void { + c.lua_createtable(L, 0, 0); + c.lua_rawsetp(L, LUA_REGISTRYINDEX, ®istrations_key); +} + /// Load and execute a Lua source file in the given state. The file's /// top-level code typically calls `panto.register_tool(...)` one or more /// times, populating the registrations table. |
