import type { System } from "../lib/plugos/system.ts"; import type { ScriptObject } from "../plugs/index/script.ts"; import { LuaEnv, LuaRuntimeError, LuaStackFrame, } 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 { type PageRef, parsePageRef, } from "@silverbulletmd/silverbullet/lib/page_ref"; import type { ASTCtx } from "$common/space_lua/ast.ts"; import { buildLuaEnv } from "$common/space_lua_api.ts"; 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, ) { const allScripts: ScriptObject[] = await system.invokeFunction( "index.queryObjects", ["space-lua", { orderBy: [{ expr: ["attr", "priority"], desc: true, }], }], ); try { this.env = buildLuaEnv(system); const tl = new LuaEnv(); tl.setLocal("_GLOBAL", this.env); for (const script of allScripts) { try { console.log("Now evaluating", script.ref); const ast = parseLua(script.script, { ref: script.ref }); // We create a local scope for each script const scriptEnv = new LuaEnv(this.env); const sf = new LuaStackFrame(tl, ast.ctx); await evalStatement(ast, scriptEnv, sf); } catch (e: any) { if (e instanceof LuaRuntimeError) { const origin = resolveASTReference(e.sf.astCtx!); if (origin) { console.error( `Error evaluating script: ${e.message} at [[${origin.page}@${origin.pos}]]`, ); continue; } } console.error( `Error evaluating script: ${e.message} for script: ${script.script}`, ); } } console.log("[Lua] Loaded", allScripts.length, "scripts"); } catch (e: any) { console.error("Error reloading Lua scripts:", e.message); } } } 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!, }; }