Bytecode compile is/not is and contains
This commit is contained in:
parent
250220a42f
commit
490faea2ba
@ -209,15 +209,8 @@ class BytecodeCompiler(
|
||||
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)
|
||||
builder.emit(Opcode.CONTAINS_OBJ, rightObj.slot, leftObj.slot, boolSlot)
|
||||
updateSlotType(boolSlot, SlotType.BOOL)
|
||||
if (op == BinOp.NOTIN) {
|
||||
val outSlot = allocSlot()
|
||||
@ -227,6 +220,22 @@ class BytecodeCompiler(
|
||||
}
|
||||
return CompiledValue(boolSlot, SlotType.BOOL)
|
||||
}
|
||||
if (op == BinOp.IS || op == BinOp.NOTIS) {
|
||||
val objValue = compileRefWithFallback(binaryLeft(ref), null, refPos(ref)) ?: return null
|
||||
val typeValue = compileRefWithFallback(binaryRight(ref), null, refPos(ref)) ?: return null
|
||||
val objSlot = ensureObjSlot(objValue)
|
||||
val typeSlot = ensureObjSlot(typeValue)
|
||||
val checkSlot = allocSlot()
|
||||
builder.emit(Opcode.CHECK_IS, objSlot.slot, typeSlot.slot, checkSlot)
|
||||
updateSlotType(checkSlot, SlotType.BOOL)
|
||||
if (op == BinOp.NOTIS) {
|
||||
val outSlot = allocSlot()
|
||||
builder.emit(Opcode.NOT_BOOL, checkSlot, outSlot)
|
||||
updateSlotType(outSlot, SlotType.BOOL)
|
||||
return CompiledValue(outSlot, SlotType.BOOL)
|
||||
}
|
||||
return CompiledValue(checkSlot, SlotType.BOOL)
|
||||
}
|
||||
val leftRef = binaryLeft(ref)
|
||||
val rightRef = binaryRight(ref)
|
||||
var a = compileRef(leftRef) ?: return null
|
||||
|
||||
@ -157,7 +157,7 @@ class CmdBuilder {
|
||||
Opcode.CMP_GTE_INT_REAL, Opcode.CMP_GTE_REAL_INT, Opcode.CMP_NEQ_INT_REAL, Opcode.CMP_NEQ_REAL_INT,
|
||||
Opcode.CMP_EQ_OBJ, Opcode.CMP_NEQ_OBJ, Opcode.CMP_REF_EQ_OBJ, Opcode.CMP_REF_NEQ_OBJ,
|
||||
Opcode.CMP_LT_OBJ, Opcode.CMP_LTE_OBJ, Opcode.CMP_GT_OBJ, Opcode.CMP_GTE_OBJ,
|
||||
Opcode.ADD_OBJ, Opcode.SUB_OBJ, Opcode.MUL_OBJ, Opcode.DIV_OBJ, Opcode.MOD_OBJ,
|
||||
Opcode.ADD_OBJ, Opcode.SUB_OBJ, Opcode.MUL_OBJ, Opcode.DIV_OBJ, Opcode.MOD_OBJ, Opcode.CONTAINS_OBJ,
|
||||
Opcode.AND_BOOL, Opcode.OR_BOOL ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.INC_INT, Opcode.DEC_INT, Opcode.RET ->
|
||||
@ -348,6 +348,7 @@ class CmdBuilder {
|
||||
Opcode.MUL_OBJ -> CmdMulObj(operands[0], operands[1], operands[2])
|
||||
Opcode.DIV_OBJ -> CmdDivObj(operands[0], operands[1], operands[2])
|
||||
Opcode.MOD_OBJ -> CmdModObj(operands[0], operands[1], operands[2])
|
||||
Opcode.CONTAINS_OBJ -> CmdContainsObj(operands[0], operands[1], operands[2])
|
||||
Opcode.JMP -> CmdJmp(operands[0])
|
||||
Opcode.JMP_IF_TRUE -> CmdJmpIfTrue(operands[0], operands[1])
|
||||
Opcode.JMP_IF_FALSE -> CmdJmpIfFalse(operands[0], operands[1])
|
||||
|
||||
@ -160,6 +160,7 @@ object CmdDisassembler {
|
||||
is CmdMulObj -> Opcode.MUL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst)
|
||||
is CmdDivObj -> Opcode.DIV_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst)
|
||||
is CmdModObj -> Opcode.MOD_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst)
|
||||
is CmdContainsObj -> Opcode.CONTAINS_OBJ to intArrayOf(cmd.target, cmd.value, cmd.dst)
|
||||
is CmdJmp -> Opcode.JMP to intArrayOf(cmd.target)
|
||||
is CmdJmpIfTrue -> Opcode.JMP_IF_TRUE to intArrayOf(cmd.cond, cmd.target)
|
||||
is CmdJmpIfFalse -> Opcode.JMP_IF_FALSE to intArrayOf(cmd.cond, cmd.target)
|
||||
@ -235,7 +236,7 @@ object CmdDisassembler {
|
||||
Opcode.CMP_GTE_INT_REAL, Opcode.CMP_GTE_REAL_INT, Opcode.CMP_NEQ_INT_REAL, Opcode.CMP_NEQ_REAL_INT,
|
||||
Opcode.CMP_EQ_OBJ, Opcode.CMP_NEQ_OBJ, Opcode.CMP_REF_EQ_OBJ, Opcode.CMP_REF_NEQ_OBJ,
|
||||
Opcode.CMP_LT_OBJ, Opcode.CMP_LTE_OBJ, Opcode.CMP_GT_OBJ, Opcode.CMP_GTE_OBJ,
|
||||
Opcode.ADD_OBJ, Opcode.SUB_OBJ, Opcode.MUL_OBJ, Opcode.DIV_OBJ, Opcode.MOD_OBJ,
|
||||
Opcode.ADD_OBJ, Opcode.SUB_OBJ, Opcode.MUL_OBJ, Opcode.DIV_OBJ, Opcode.MOD_OBJ, Opcode.CONTAINS_OBJ,
|
||||
Opcode.AND_BOOL, Opcode.OR_BOOL ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.INC_INT, Opcode.DEC_INT, Opcode.RET ->
|
||||
|
||||
@ -913,6 +913,13 @@ class CmdModObj(internal val a: Int, internal val b: Int, internal val dst: Int)
|
||||
}
|
||||
}
|
||||
|
||||
class CmdContainsObj(internal val target: Int, internal val value: Int, internal val dst: Int) : Cmd() {
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
frame.setBool(dst, frame.slotToObj(target).contains(frame.scope, frame.slotToObj(value)))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
class CmdJmp(internal val target: Int) : Cmd() {
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
frame.ip = target
|
||||
|
||||
@ -105,6 +105,7 @@ enum class Opcode(val code: Int) {
|
||||
MUL_OBJ(0x79),
|
||||
DIV_OBJ(0x7A),
|
||||
MOD_OBJ(0x7B),
|
||||
CONTAINS_OBJ(0x7C),
|
||||
|
||||
JMP(0x80),
|
||||
JMP_IF_TRUE(0x81),
|
||||
|
||||
@ -5215,6 +5215,20 @@ class ScriptTest {
|
||||
assertEquals(ObjFalse, scope.eval("inList(5, [1,2,3])"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsOperatorBytecode() = runTest {
|
||||
val scope = Script.newScope()
|
||||
scope.eval(
|
||||
"""
|
||||
fun isInt(x) { x is Int }
|
||||
""".trimIndent()
|
||||
)
|
||||
val disasm = scope.disassembleSymbol("isInt")
|
||||
assertFalse(disasm.contains("not a compiled body"))
|
||||
assertEquals(ObjTrue, scope.eval("isInt(42)"))
|
||||
assertEquals(ObjFalse, scope.eval("isInt(\"42\")"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFilterBug() = runTest {
|
||||
eval(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user