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

51 lines
1.6 KiB
TypeScript

import {
LuaBuiltinFunction,
type LuaEnv,
LuaMultiRes,
type LuaStackFrame,
type LuaValue,
} from "../runtime.ts";
import { parse } 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 = parse(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(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;
}
});
return runner;
} catch (e: any) {
const msg = e && typeof e.message === "string" ? e.message : String(e);
return new LuaMultiRes([null, msg]);
}
}