2024-10-05 21:37:36 +08:00
|
|
|
import type { System } from "../lib/plugos/system.ts";
|
|
|
|
import type { ScriptObject } from "../plugs/index/script.ts";
|
|
|
|
import {
|
|
|
|
LuaEnv,
|
|
|
|
LuaFunction,
|
2024-10-09 01:53:09 +08:00
|
|
|
LuaRuntimeError,
|
2024-10-20 21:06:23 +08:00
|
|
|
LuaStackFrame,
|
2024-10-05 21:37:36 +08:00
|
|
|
} from "$common/space_lua/runtime.ts";
|
|
|
|
import { parse as parseLua } from "$common/space_lua/parse.ts";
|
|
|
|
import { evalStatement } from "$common/space_lua/eval.ts";
|
|
|
|
import { jsToLuaValue } from "$common/space_lua/runtime.ts";
|
2024-10-09 01:53:09 +08:00
|
|
|
import {
|
|
|
|
type PageRef,
|
|
|
|
parsePageRef,
|
|
|
|
} from "@silverbulletmd/silverbullet/lib/page_ref";
|
2024-10-05 21:37:36 +08:00
|
|
|
import type { ScriptEnvironment } from "$common/space_script.ts";
|
|
|
|
import { luaValueToJS } from "$common/space_lua/runtime.ts";
|
2024-10-09 01:53:09 +08:00
|
|
|
import type { ASTCtx } from "$common/space_lua/ast.ts";
|
2024-10-11 21:34:27 +08:00
|
|
|
import type { ObjectQuery } from "@silverbulletmd/silverbullet/types";
|
|
|
|
import { buildLuaEnv } from "$common/space_lua_api.ts";
|
2024-10-05 21:37:36 +08:00
|
|
|
|
|
|
|
export class SpaceLuaEnvironment {
|
|
|
|
env: LuaEnv = new LuaEnv();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads all Lua scripts from the database and evaluates them in a new environment
|
|
|
|
* @param system
|
|
|
|
*/
|
|
|
|
async reload(system: System<any>, scriptEnv: ScriptEnvironment) {
|
|
|
|
const allScripts: ScriptObject[] = await system.invokeFunction(
|
|
|
|
"index.queryObjects",
|
2024-10-11 21:34:27 +08:00
|
|
|
["space-lua", {
|
|
|
|
// This is a bit silly, but at least makes the order deterministic
|
|
|
|
orderBy: [{ expr: ["attr", "ref"] }],
|
|
|
|
} as ObjectQuery],
|
2024-10-05 21:37:36 +08:00
|
|
|
);
|
2024-10-11 21:34:27 +08:00
|
|
|
this.env = buildLuaEnv(system, scriptEnv);
|
2024-10-05 21:37:36 +08:00
|
|
|
for (const script of allScripts) {
|
|
|
|
try {
|
|
|
|
const ast = parseLua(script.script, { ref: script.ref });
|
|
|
|
// We create a local scope for each script
|
2024-10-11 21:34:27 +08:00
|
|
|
const scriptEnv = new LuaEnv(this.env);
|
2024-10-20 21:06:23 +08:00
|
|
|
const sf = new LuaStackFrame(new LuaEnv(), ast.ctx);
|
|
|
|
await evalStatement(ast, scriptEnv, sf);
|
2024-10-05 21:37:36 +08:00
|
|
|
} catch (e: any) {
|
2024-10-09 01:53:09 +08:00
|
|
|
if (e instanceof LuaRuntimeError) {
|
2024-10-20 21:06:23 +08:00
|
|
|
const origin = resolveASTReference(e.sf.astCtx!);
|
2024-10-09 01:53:09 +08:00
|
|
|
if (origin) {
|
|
|
|
console.error(
|
|
|
|
`Error evaluating script: ${e.message} at [[${origin.page}@${origin.pos}]]`,
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2024-10-05 21:37:36 +08:00
|
|
|
console.error(
|
|
|
|
`Error evaluating script: ${e.message} for script: ${script.script}`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2024-10-11 21:34:27 +08:00
|
|
|
|
2024-10-05 21:37:36 +08:00
|
|
|
// Find all functions and register them
|
2024-10-11 21:34:27 +08:00
|
|
|
for (const globalName of this.env.keys()) {
|
|
|
|
const value = this.env.get(globalName);
|
2024-10-05 21:37:36 +08:00
|
|
|
if (value instanceof LuaFunction) {
|
2025-01-09 00:09:09 +08:00
|
|
|
console.log(
|
|
|
|
`[Lua] Registering global function '${globalName}' (source: ${value.body.ctx.ref})`,
|
|
|
|
);
|
2024-10-05 21:37:36 +08:00
|
|
|
scriptEnv.registerFunction({ name: globalName }, (...args: any[]) => {
|
2024-10-20 21:06:23 +08:00
|
|
|
const sf = new LuaStackFrame(new LuaEnv(), value.body.ctx);
|
|
|
|
return luaValueToJS(value.call(sf, ...args.map(jsToLuaValue)));
|
2024-10-05 21:37:36 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2025-01-09 00:09:09 +08:00
|
|
|
console.log("[Lua] Loaded", allScripts.length, "scripts");
|
2024-10-05 21:37:36 +08:00
|
|
|
}
|
|
|
|
}
|
2024-10-09 01:53:09 +08:00
|
|
|
|
|
|
|
export function resolveASTReference(ctx?: ASTCtx): PageRef | null {
|
|
|
|
if (!ctx?.ref) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const pageRef = parsePageRef(ctx.ref);
|
|
|
|
return {
|
|
|
|
page: pageRef.page,
|
|
|
|
pos: (pageRef.pos as number) + "```space-lua\n".length + ctx.from!,
|
|
|
|
};
|
|
|
|
}
|