* Space Lua: Add AST block type label/goto and duplicated label bools * Space Lua: Add label/goto resolution and evaluation Add per block map of labels metadata, per function block metadata cache and `processBlock` to track AST blocks (`If`, `While`, `Repeat`, `For` and `ForIn`, and `Do`) while recording labels and their positions. Align with Lua scoping rules (_e.g._, a `goto` can not jump into the scope of a local). Also allow the super-special "safe" end of block cases (except inside `Repeat`). Duplicated labels are detected (error `label 'foo' is already defined` etc.). The AST context for error reporting is preserved. The `WeakMap` caches map any block to its function's metadata. Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Space Lua: The `goto` parse flags and eval path At parser mark each block with `hasLabel`/`hasGoto` and record the first duplicated label. Flags then propagate through blocks and control flow. If no `goto`, run the block in a simple loop and raise duplicate label error if any is present. If `goto` exists, jump via a label map. Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Space Lua: Add labels and `goto` statement test suite Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Space Lua: Minor `goto`/labels improvement and test hotfix - The `getBlockGotoMeta` now called only when a block has either `hasGoto` or `hasLabel`. - Add `BlocksFlags` type to get rid of some `(... as any)`s by view. - Add `blockMetaOrThrow` helper. - Fix test to reflect standard Lua semantics. Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Space Lua: Goto: Add missing Lua semantics checks Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Space Lua: Goto: Add Lua semantics checks also covered in Lua tests Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Space Lua: Goto: Fix semantic divergence revealed by fixing unfinished test Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Fix typo Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Space Lua: Optimize block env creation and cache goto metadata Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Avoid using the venomous snake case Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Add comment for WeakMap use Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Space Lua: Block Label Fast-path Optimization Add block flag `hasLabelHere` during parsing and use it in eval to skip expensive metadata generation for blocks and entire functions without label or goto. Refactor eval logic: - early fast path when a function is known to have no label/goto, - later fast path for blocks in functions with goto. Fetch metadata only when needed. Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Space Lua: Remove `BlockFlags` indirection from eval - Add `hasLabelHere` flag to `LuaBlock`. - Remove `BlockFlags` indirection from eval. - Set `hasLabelHere` directly. - Add some "guards". - Improve consistency of child filtering. Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> * Remove redundant return statement Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz> --------- Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
96 lines
2.6 KiB
TypeScript
96 lines
2.6 KiB
TypeScript
import { parse } from "./parse.ts";
|
|
import { luaBuildStandardEnv } from "./stdlib.ts";
|
|
import { LuaEnv, LuaRuntimeError, LuaStackFrame } from "./runtime.ts";
|
|
import { evalStatement } from "./eval.ts";
|
|
import { assert } from "@std/assert/assert";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
Deno.test("[Lua] Core language", async () => {
|
|
await runLuaTest("./language_core_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Core language (labels and goto)", async () => {
|
|
await runLuaTest("./goto_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Core language (length)", async () => {
|
|
await runLuaTest("./len_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Core language (truthiness)", async () => {
|
|
await runLuaTest("./truthiness_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Core language (arithmetic)", async () => {
|
|
await runLuaTest("./arithmetic_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Load tests", async () => {
|
|
await runLuaTest("./stdlib/load_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Table tests", async () => {
|
|
await runLuaTest("./stdlib/table_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] String to number tests", async () => {
|
|
await runLuaTest("./tonumber_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] String tests", async () => {
|
|
await runLuaTest("./stdlib/string_test.lua");
|
|
// await runLuaTest("./stdlib/string_test2.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Space Lua tests", async () => {
|
|
await runLuaTest("./stdlib/space_lua_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] OS tests", async () => {
|
|
await runLuaTest("./stdlib/os_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Math tests", async () => {
|
|
await runLuaTest("./stdlib/math_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] JS tests", async () => {
|
|
await runLuaTest("./stdlib/js_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Global functions tests", async () => {
|
|
await runLuaTest("./stdlib/global_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Encoding functions tests", async () => {
|
|
await runLuaTest("./stdlib/encoding_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Crypto functions tests", async () => {
|
|
await runLuaTest("./stdlib/crypto_test.lua");
|
|
});
|
|
|
|
Deno.test("[Lua] Lume functions tests", async () => {
|
|
await runLuaTest("./lume_test.lua");
|
|
});
|
|
|
|
async function runLuaTest(luaPath: string) {
|
|
const luaFile = await Deno.readTextFile(
|
|
fileURLToPath(new URL(luaPath, import.meta.url)),
|
|
);
|
|
const chunk = parse(luaFile, {});
|
|
const env = new LuaEnv(luaBuildStandardEnv());
|
|
const sf = LuaStackFrame.createWithGlobalEnv(env, chunk.ctx);
|
|
|
|
try {
|
|
await evalStatement(chunk, env, sf);
|
|
} catch (e: any) {
|
|
if (e instanceof LuaRuntimeError) {
|
|
console.error(`Error evaluating script:`, e.toPrettyString(luaFile));
|
|
} else {
|
|
console.error(`Error evaluating script:`, e);
|
|
}
|
|
assert(false);
|
|
}
|
|
}
|