import { LuaBuiltinFunction, type LuaEnv, LuaMultiRes, type LuaStackFrame, type LuaValue, } from "../runtime.ts"; import { parseBlock } from "../parse.ts"; import { evalStatement } from "../eval.ts"; // Returns a function (callable chunk) or (nil, "error message") pair. export function luaLoad(code: LuaValue, sf: LuaStackFrame): LuaValue { const s = typeof code === "string" ? code : String(code); try { const block = parseBlock(s, sf.astCtx || {}); const globalEnvMaybe = sf.threadLocal.get("_GLOBAL"); // Be vocal when no _GLOBAL is set if (!globalEnvMaybe) { console.warn("load() called without _GLOBAL in thread-local environment"); return new LuaMultiRes([null, "Global environment not set"]); } const globalEnv: LuaEnv = globalEnvMaybe as LuaEnv; const runner = new LuaBuiltinFunction({ callback: async (innerSf: LuaStackFrame) => { const res = await evalStatement(block, globalEnv, innerSf, true); if (res === undefined) { return null; } else { if ( res && typeof res === "object" && (res as any).ctrl === "return" ) { return new LuaMultiRes((res as any).values); } if (res && typeof res === "object" && (res as any).ctrl === "break") { throw new Error("break outside loop"); } if (res && typeof res === "object" && (res as any).ctrl === "goto") { throw new Error("unexpected goto signal"); } return null; } }, description: "Executes the Lua chunk compiled by `load`.", signatures: ["function(...)"], returns: [{ description: "Values returned by the compiled chunk." }], }); return runner; } catch (e: any) { const msg = e && typeof e.message === "string" ? e.message : String(e); return new LuaMultiRes([null, msg]); } }