From 105908204be798c5c93c5346243a0d7f046fc62b Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Sat, 22 Feb 2025 21:28:00 +0100 Subject: [PATCH] Fixes #1253 More accurate type classification and eager evaluation of left "and" operand. --- common/space_lua/eval.ts | 15 +++++++++++++++ common/space_lua/language_core_test.lua | 8 ++++++++ common/space_lua/runtime.ts | 7 ++++++- common/space_lua/stdlib.ts | 8 +++++--- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/common/space_lua/eval.ts b/common/space_lua/eval.ts index 7b3d7514..0c9cfbc7 100644 --- a/common/space_lua/eval.ts +++ b/common/space_lua/eval.ts @@ -154,6 +154,21 @@ export function evalExpression( } else { return evalExpression(e.right, env, sf); } + } else if (e.operator === "and") { + // Special case: eagerly evaluate left before even attempting right + const left = evalExpression(e.left, env, sf); + if (left instanceof Promise) { + return left.then((left) => { + if (!luaTruthy(left)) { + return left; + } + return evalExpression(e.right, env, sf); + }); + } else if (!luaTruthy(left)) { + return left; + } else { + return evalExpression(e.right, env, sf); + } } const values = evalPromiseValues([ evalExpression(e.left, env, sf), diff --git a/common/space_lua/language_core_test.lua b/common/space_lua/language_core_test.lua index b5da8684..eba1c8c3 100644 --- a/common/space_lua/language_core_test.lua +++ b/common/space_lua/language_core_test.lua @@ -433,3 +433,11 @@ end assertEqual(sum(1, 2, 3), 6) assertEqual(sum(1, 2, 3, 4, 5), 15) + +local data = { { name = "John", favorite = { color = "blue" } }, { name = "Jane" } } +assertEqual(type(data[1].favorite), "table") +assertEqual(data[1].favorite.color, "blue") + +local r = query [[from p = data where type(p.favorite) == "table" and p.favorite.color == "blue"]] +assertEqual(#r, 1) +assertEqual(r[1].name, "John") diff --git a/common/space_lua/runtime.ts b/common/space_lua/runtime.ts index e9342697..e12a1343 100644 --- a/common/space_lua/runtime.ts +++ b/common/space_lua/runtime.ts @@ -657,9 +657,12 @@ export function luaKeys(val: any): any[] { } } -export function luaTypeOf(val: any): LuaType { +export function luaTypeOf(val: any): LuaType | Promise { if (val === null || val === undefined) { return "nil"; + } + if (val instanceof Promise) { + return val.then((v) => luaTypeOf(v)); } else if (typeof val === "boolean") { return "boolean"; } else if (typeof val === "number") { @@ -672,6 +675,8 @@ export function luaTypeOf(val: any): LuaType { return "table"; } else if (typeof val === "function" || val.call) { return "function"; + } else if (typeof val === "object" && val.constructor === Object) { + return "table"; } else { return "userdata"; } diff --git a/common/space_lua/stdlib.ts b/common/space_lua/stdlib.ts index b9b6ad9a..30ef7a46 100644 --- a/common/space_lua/stdlib.ts +++ b/common/space_lua/stdlib.ts @@ -80,9 +80,11 @@ const unpackFunction = new LuaBuiltinFunction(async (sf, t: LuaTable) => { return new LuaMultiRes(values); }); -const typeFunction = new LuaBuiltinFunction((_sf, value: LuaValue): string => { - return luaTypeOf(value); -}); +const typeFunction = new LuaBuiltinFunction( + (_sf, value: LuaValue): string | Promise => { + return luaTypeOf(value); + }, +); const tostringFunction = new LuaBuiltinFunction((_sf, value: any) => { return luaToString(value);