Files
plainleaf/client/space_lua/stdlib/load.ts
T

60 lines
1.9 KiB
TypeScript

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]);
}
}