From d121e74c6f246005d2b115c10cf98a86d80f73f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=93=9D=E7=AE=94?= <38349409+Sodium-Aluminate@users.noreply.github.com> Date: Mon, 16 Jun 2025 18:17:54 +0800 Subject: [PATCH] Fix: lazy evaluation for logical expressions (#27) (#28) * fix logical expression short-circuit evaluation (#27) * test logical short-circuit cases (#27) --- src/operators.ts | 11 +++++++++-- src/parser.ts | 4 ++-- tests/lua-5.3/logical_operations.lua | 6 ++++++ tests/test.js | 1 + 4 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 tests/lua-5.3/logical_operations.lua diff --git a/src/operators.ts b/src/operators.ts index 6556f00..5a91df4 100644 --- a/src/operators.ts +++ b/src/operators.ts @@ -37,8 +37,15 @@ const binaryBooleanArithmetic = ( const bool = (value: LuaType): boolean => coerceToBoolean(value) // logical -const and = (l: LuaType, r: LuaType): LuaType => coerceToBoolean(l) ? r : l -const or = (l: LuaType, r: LuaType): LuaType => coerceToBoolean(l) ? l : r +const and = (l: () => LuaType, r: () => LuaType): LuaType => { + const lv = l() + return coerceToBoolean(lv) ? r() : lv +} + +const or = (l: () => LuaType, r: () => LuaType): LuaType => { + const lv = l() + return coerceToBoolean(lv) ? lv : r() +} // unary const not = (value: LuaType): boolean => !bool(value) diff --git a/src/parser.ts b/src/parser.ts index c3d5caf..dca6690 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -303,10 +303,10 @@ const generate = (node: luaparse.Node): string | MemExpr => { const operator = node.operator if (operator === 'and') { - return `__lua.and(${left},${right})` + return `__lua.and(() => ${left}, () => ${right})` } if (operator === 'or') { - return `__lua.or(${left},${right})` + return `__lua.or(() => ${left}, () => ${right})` } throw new Error(`Unhandled logical operator: ${node.operator}`) } diff --git a/tests/lua-5.3/logical_operations.lua b/tests/lua-5.3/logical_operations.lua new file mode 100644 index 0000000..c9176c8 --- /dev/null +++ b/tests/lua-5.3/logical_operations.lua @@ -0,0 +1,6 @@ +local x = nil +local x_ = (x and x.k or "fallback") +assert(x_ == "fallback") +local y = "ok" +local y_ = (y or error("should not raise")) +assert(y == y_) \ No newline at end of file diff --git a/tests/test.js b/tests/test.js index 9406ea5..1d18745 100644 --- a/tests/test.js +++ b/tests/test.js @@ -24,6 +24,7 @@ let exitCode = 0 }) luaEnv.parseFile('goto.lua').exec() luaEnv.parseFile('bwcoercion.lua').exec() + luaEnv.parseFile('logical_operations.lua').exec() } {