Skip to content

Commit 3a46b19

Browse files
authored
fix(compiler): pop stale bool from stack in emitLoopBackwards (#954)
emitLoopBackwards uses OpMoreOrEqual + OpJumpIfFalse to check the loop condition, but never pops the comparison result from the stack. This leaves a stale bool that corrupts the value stack for the parent context. When findLast or findLastIndex is used inside a map literal like {"r": findLast([1, 2, 3], # > 3)}, the OpMap opcode tries to pop a string key but finds the leftover bool instead, causing: interface conversion: interface {} is bool, not string The forward-iterating emitLoop avoids this by using OpJumpIfEnd, which checks scope.Index directly without touching the stack. Fix: add OpPop after OpJumpIfFalse (continue path) and after patchJump (exit path), matching the convention used by emitCond and every other OpJumpIfFalse callsite in the compiler. Fixes #950 Co-authored-by: lawrence3699 <lawrence3699@users.noreply.github.com>
1 parent b90e77c commit 3a46b19

2 files changed

Lines changed: 18 additions & 0 deletions

File tree

compiler/compiler.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,12 +1213,14 @@ func (c *compiler) emitLoopBackwards(body func()) {
12131213
c.emit(OpInt, 0)
12141214
c.emit(OpMoreOrEqual)
12151215
end := c.emit(OpJumpIfFalse, placeholder)
1216+
c.emit(OpPop)
12161217

12171218
body()
12181219

12191220
c.emit(OpDecrementIndex)
12201221
c.emit(OpJumpBackward, c.calcBackwardJump(begin))
12211222
c.patchJump(end)
1223+
c.emit(OpPop)
12221224
}
12231225

12241226
func (c *compiler) PredicateNode(node *ast.PredicateNode) {

expr_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,22 @@ func TestExpr(t *testing.T) {
12751275
`findLastIndex(1..9, # % 2 == 0)`,
12761276
7,
12771277
},
1278+
{
1279+
`{"r": findLast([1, 2, 3, 4, 5], # > 3)}`,
1280+
map[string]any{"r": 5},
1281+
},
1282+
{
1283+
`{"r": findLastIndex([1, 2, 3, 4, 5], # > 3)}`,
1284+
map[string]any{"r": 4},
1285+
},
1286+
{
1287+
`{"r": findLast([1, 2, 3], # > 10)}`,
1288+
map[string]any{"r": nil},
1289+
},
1290+
{
1291+
`{"a": findLast([1, 2, 3], # > 1), "b": findLastIndex([4, 5, 6], # > 4)}`,
1292+
map[string]any{"a": 3, "b": 2},
1293+
},
12781294
{
12791295
`filter(1..9, # % 2 == 0)[-1]`,
12801296
8,

0 commit comments

Comments
 (0)