Bytecode compile in/not in via contains

This commit is contained in:
Sergey Chernov 2026-01-28 16:49:06 +03:00
parent 63bcb91504
commit 250220a42f
2 changed files with 37 additions and 0 deletions

View File

@ -204,6 +204,29 @@ class BytecodeCompiler(
if (op == BinOp.AND || op == BinOp.OR) {
return compileLogical(op, binaryLeft(ref), binaryRight(ref), refPos(ref))
}
if (op == BinOp.IN || op == BinOp.NOTIN) {
val leftValue = compileRefWithFallback(binaryLeft(ref), null, refPos(ref)) ?: return null
val rightValue = compileRefWithFallback(binaryRight(ref), null, refPos(ref)) ?: return null
val leftObj = ensureObjSlot(leftValue)
val rightObj = ensureObjSlot(rightValue)
val methodId = builder.addConst(BytecodeConst.StringVal("contains"))
if (methodId > 0xFFFF) return null
val argSlot = allocSlot()
builder.emit(Opcode.BOX_OBJ, leftObj.slot, argSlot)
updateSlotType(argSlot, SlotType.OBJ)
val callSlot = allocSlot()
builder.emit(Opcode.CALL_VIRTUAL, rightObj.slot, methodId, argSlot, 1, callSlot)
val boolSlot = allocSlot()
builder.emit(Opcode.OBJ_TO_BOOL, callSlot, boolSlot)
updateSlotType(boolSlot, SlotType.BOOL)
if (op == BinOp.NOTIN) {
val outSlot = allocSlot()
builder.emit(Opcode.NOT_BOOL, boolSlot, outSlot)
updateSlotType(outSlot, SlotType.BOOL)
return CompiledValue(outSlot, SlotType.BOOL)
}
return CompiledValue(boolSlot, SlotType.BOOL)
}
val leftRef = binaryLeft(ref)
val rightRef = binaryRight(ref)
var a = compileRef(leftRef) ?: return null

View File

@ -5201,6 +5201,20 @@ class ScriptTest {
assertEquals(ObjInt(2), scope.eval("firstEvenOrMinus()"))
}
@Test
fun testInOperatorBytecode() = runTest {
val scope = Script.newScope()
scope.eval(
"""
fun inList(x, xs) { x in xs }
""".trimIndent()
)
val disasm = scope.disassembleSymbol("inList")
assertFalse(disasm.contains("not a compiled body"))
assertEquals(ObjTrue, scope.eval("inList(2, [1,2,3])"))
assertEquals(ObjFalse, scope.eval("inList(5, [1,2,3])"))
}
@Test
fun testFilterBug() = runTest {
eval(