139 lines
3.9 KiB
TypeScript
139 lines
3.9 KiB
TypeScript
import { parseExpressionString } from "$common/space_lua/parse.ts";
|
|
import type { LuaExpression } from "$common/space_lua/ast.ts";
|
|
import { evalExpression } from "$common/space_lua/eval.ts";
|
|
import {
|
|
LuaBuiltinFunction,
|
|
LuaEnv,
|
|
LuaRuntimeError,
|
|
type LuaStackFrame,
|
|
LuaTable,
|
|
luaToString,
|
|
luaValueToJS,
|
|
} from "$common/space_lua/runtime.ts";
|
|
|
|
/**
|
|
* These are Space Lua specific functions that are available to all scripts, but are not part of the standard Lua language.
|
|
*/
|
|
|
|
/**
|
|
* Helper function to create an augmented environment
|
|
*/
|
|
function createAugmentedEnv(
|
|
sf: LuaStackFrame,
|
|
envAugmentation?: LuaTable,
|
|
): LuaEnv {
|
|
const globalEnv = sf.threadLocal.get("_GLOBAL");
|
|
if (!globalEnv) {
|
|
throw new Error("_GLOBAL not defined");
|
|
}
|
|
const env = new LuaEnv(globalEnv);
|
|
if (envAugmentation) {
|
|
env.setLocal("_", envAugmentation);
|
|
for (const key of envAugmentation.keys()) {
|
|
env.setLocal(key, envAugmentation.rawGet(key));
|
|
}
|
|
}
|
|
return env;
|
|
}
|
|
|
|
/**
|
|
* Interpolates a string with lua expressions and returns the result.
|
|
*
|
|
* @param sf - The current space_lua state.
|
|
* @param template - The template string to interpolate.
|
|
* @param envAugmentation - An optional environment to augment the global environment with.
|
|
* @returns The interpolated string.
|
|
*/
|
|
export async function interpolateLuaString(
|
|
sf: LuaStackFrame,
|
|
template: string,
|
|
envAugmentation?: LuaTable,
|
|
): Promise<string> {
|
|
let result = "";
|
|
let currentIndex = 0;
|
|
|
|
while (true) {
|
|
const startIndex = template.indexOf("${", currentIndex);
|
|
if (startIndex === -1) {
|
|
result += template.slice(currentIndex);
|
|
break;
|
|
}
|
|
|
|
result += template.slice(currentIndex, startIndex);
|
|
|
|
// Find matching closing brace by counting nesting
|
|
let nestLevel = 1;
|
|
let endIndex = startIndex + 2;
|
|
while (nestLevel > 0 && endIndex < template.length) {
|
|
if (template[endIndex] === "{") {
|
|
nestLevel++;
|
|
} else if (template[endIndex] === "}") {
|
|
nestLevel--;
|
|
}
|
|
if (nestLevel > 0) {
|
|
endIndex++;
|
|
}
|
|
}
|
|
|
|
if (nestLevel > 0) {
|
|
throw new LuaRuntimeError("Unclosed interpolation expression", sf);
|
|
}
|
|
|
|
const expr = template.slice(startIndex + 2, endIndex);
|
|
try {
|
|
const parsedExpr = parseExpressionString(expr);
|
|
const env = createAugmentedEnv(sf, envAugmentation);
|
|
const luaResult = luaValueToJS(
|
|
await evalExpression(parsedExpr, env, sf),
|
|
);
|
|
result += luaToString(luaResult);
|
|
} catch (e: any) {
|
|
throw new LuaRuntimeError(
|
|
`Error evaluating "${expr}": ${e.message}`,
|
|
sf,
|
|
);
|
|
}
|
|
|
|
currentIndex = endIndex + 1;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
export const spaceLuaApi = new LuaTable({
|
|
/**
|
|
* Parses a lua expression and returns the parsed expression.
|
|
*
|
|
* @param sf - The current space_lua state.
|
|
* @param luaExpression - The lua expression to parse.
|
|
* @returns The parsed expression.
|
|
*/
|
|
parse_expression: new LuaBuiltinFunction(
|
|
(_sf, luaExpression: string) => {
|
|
return parseExpressionString(luaExpression);
|
|
},
|
|
),
|
|
/**
|
|
* Evaluates a parsed lua expression and returns the result.
|
|
*
|
|
* @param sf - The current space_lua state.
|
|
* @param parsedExpr - The parsed lua expression to evaluate.
|
|
* @param envAugmentation - An optional environment to augment the global environment with.
|
|
* @returns The result of the evaluated expression.
|
|
*/
|
|
eval_expression: new LuaBuiltinFunction(
|
|
async (sf, parsedExpr: LuaExpression, envAugmentation?: LuaTable) => {
|
|
const env = createAugmentedEnv(sf, envAugmentation);
|
|
return luaValueToJS(await evalExpression(parsedExpr, env, sf));
|
|
},
|
|
),
|
|
/**
|
|
* Interpolates a string with lua expressions and returns the result.
|
|
*/
|
|
interpolate: new LuaBuiltinFunction(
|
|
(sf, template: string, envAugmentation?: LuaTable) => {
|
|
return interpolateLuaString(sf, template, envAugmentation);
|
|
},
|
|
),
|
|
});
|