51 lines
1.6 KiB
TypeScript
51 lines
1.6 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(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]);
|
|
}
|
|
}
|