148 lines
3.7 KiB
TypeScript
148 lines
3.7 KiB
TypeScript
import {
|
|
type ILuaFunction,
|
|
LuaBuiltinFunction,
|
|
luaCall,
|
|
LuaEnv,
|
|
LuaMultiRes,
|
|
LuaRuntimeError,
|
|
type LuaTable,
|
|
luaToString,
|
|
luaTypeOf,
|
|
type LuaValue,
|
|
} from "$common/space_lua/runtime.ts";
|
|
import { stringApi } from "$common/space_lua/stdlib/string.ts";
|
|
import { tableApi } from "$common/space_lua/stdlib/table.ts";
|
|
import { osApi } from "$common/space_lua/stdlib/os.ts";
|
|
import { jsApi } from "$common/space_lua/stdlib/js.ts";
|
|
|
|
const printFunction = new LuaBuiltinFunction((_sf, ...args) => {
|
|
console.log("[Lua]", ...args.map(luaToString));
|
|
});
|
|
|
|
const assertFunction = new LuaBuiltinFunction(
|
|
async (sf, value: any, message?: string) => {
|
|
if (!await value) {
|
|
throw new LuaRuntimeError(`Assertion failed: ${message}`, sf);
|
|
}
|
|
},
|
|
);
|
|
|
|
const ipairsFunction = new LuaBuiltinFunction((_sf, ar: LuaTable) => {
|
|
let i = 1;
|
|
return () => {
|
|
if (i > ar.length) {
|
|
return;
|
|
}
|
|
const result = new LuaMultiRes([i, ar.get(i)]);
|
|
i++;
|
|
return result;
|
|
};
|
|
});
|
|
|
|
const pairsFunction = new LuaBuiltinFunction((_sf, t: LuaTable) => {
|
|
const keys = t.keys();
|
|
let i = 0;
|
|
return () => {
|
|
if (i >= keys.length) {
|
|
return;
|
|
}
|
|
const key = keys[i];
|
|
i++;
|
|
return new LuaMultiRes([key, t.get(key)]);
|
|
};
|
|
});
|
|
|
|
const unpackFunction = new LuaBuiltinFunction((_sf, t: LuaTable) => {
|
|
const values: LuaValue[] = [];
|
|
for (let i = 1; i <= t.length; i++) {
|
|
values.push(t.get(i));
|
|
}
|
|
return new LuaMultiRes(values);
|
|
});
|
|
|
|
const typeFunction = new LuaBuiltinFunction((_sf, value: LuaValue): string => {
|
|
return luaTypeOf(value);
|
|
});
|
|
|
|
const tostringFunction = new LuaBuiltinFunction((_sf, value: any) => {
|
|
return luaToString(value);
|
|
});
|
|
|
|
const tonumberFunction = new LuaBuiltinFunction((_sf, value: LuaValue) => {
|
|
return Number(value);
|
|
});
|
|
|
|
const errorFunction = new LuaBuiltinFunction((_sf, message: string) => {
|
|
throw new Error(message);
|
|
});
|
|
|
|
const pcallFunction = new LuaBuiltinFunction(
|
|
async (sf, fn: ILuaFunction, ...args) => {
|
|
try {
|
|
return new LuaMultiRes([true, await luaCall(fn, args, sf.astCtx!, sf)]);
|
|
} catch (e: any) {
|
|
return new LuaMultiRes([false, e.message]);
|
|
}
|
|
},
|
|
);
|
|
|
|
const xpcallFunction = new LuaBuiltinFunction(
|
|
async (sf, fn: ILuaFunction, errorHandler: ILuaFunction, ...args) => {
|
|
try {
|
|
return new LuaMultiRes([true, await fn.call(sf, ...args)]);
|
|
} catch (e: any) {
|
|
return new LuaMultiRes([
|
|
false,
|
|
await luaCall(errorHandler, [e.message], sf.astCtx!, sf),
|
|
]);
|
|
}
|
|
},
|
|
);
|
|
|
|
const setmetatableFunction = new LuaBuiltinFunction(
|
|
(_sf, table: LuaTable, metatable: LuaTable) => {
|
|
table.metatable = metatable;
|
|
return table;
|
|
},
|
|
);
|
|
|
|
const rawsetFunction = new LuaBuiltinFunction(
|
|
(_sf, table: LuaTable, key: LuaValue, value: LuaValue) => {
|
|
table.rawSet(key, value);
|
|
return table;
|
|
},
|
|
);
|
|
|
|
const getmetatableFunction = new LuaBuiltinFunction((_sf, table: LuaTable) => {
|
|
return table.metatable;
|
|
});
|
|
|
|
export function luaBuildStandardEnv() {
|
|
const env = new LuaEnv();
|
|
// Top-level builtins
|
|
env.set("print", printFunction);
|
|
env.set("assert", assertFunction);
|
|
env.set("type", typeFunction);
|
|
env.set("tostring", tostringFunction);
|
|
env.set("tonumber", tonumberFunction);
|
|
env.set("unpack", unpackFunction);
|
|
// Iterators
|
|
env.set("pairs", pairsFunction);
|
|
env.set("ipairs", ipairsFunction);
|
|
// meta table stuff
|
|
env.set("setmetatable", setmetatableFunction);
|
|
env.set("getmetatable", getmetatableFunction);
|
|
env.set("rawset", rawsetFunction);
|
|
// Error handling
|
|
env.set("error", errorFunction);
|
|
env.set("pcall", pcallFunction);
|
|
env.set("xpcall", xpcallFunction);
|
|
|
|
// APIs
|
|
env.set("string", stringApi);
|
|
env.set("table", tableApi);
|
|
env.set("os", osApi);
|
|
env.set("js", jsApi);
|
|
return env;
|
|
}
|