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 rightValue = compileRefWithFallback(binaryRight(ref), null, refPos(ref)) ?: return null
|
||||||
val leftObj = ensureObjSlot(leftValue)
|
val leftObj = ensureObjSlot(leftValue)
|
||||||
val rightObj = ensureObjSlot(rightValue)
|
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()
|
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)
|
updateSlotType(boolSlot, SlotType.BOOL)
|
||||||
if (op == BinOp.NOTIN) {
|
if (op == BinOp.NOTIN) {
|
||||||
val outSlot = allocSlot()
|
val outSlot = allocSlot()
|
||||||
@ -227,6 +220,22 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
return CompiledValue(boolSlot, SlotType.BOOL)
|
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 leftRef = binaryLeft(ref)
|
||||||
val rightRef = binaryRight(ref)
|
val rightRef = binaryRight(ref)
|
||||||
var a = compileRef(leftRef) ?: return null
|
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_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_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.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 ->
|
Opcode.AND_BOOL, Opcode.OR_BOOL ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||||
Opcode.INC_INT, Opcode.DEC_INT, Opcode.RET ->
|
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.MUL_OBJ -> CmdMulObj(operands[0], operands[1], operands[2])
|
||||||
Opcode.DIV_OBJ -> CmdDivObj(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.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 -> CmdJmp(operands[0])
|
||||||
Opcode.JMP_IF_TRUE -> CmdJmpIfTrue(operands[0], operands[1])
|
Opcode.JMP_IF_TRUE -> CmdJmpIfTrue(operands[0], operands[1])
|
||||||
Opcode.JMP_IF_FALSE -> CmdJmpIfFalse(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 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 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 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 CmdJmp -> Opcode.JMP to intArrayOf(cmd.target)
|
||||||
is CmdJmpIfTrue -> Opcode.JMP_IF_TRUE to intArrayOf(cmd.cond, 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)
|
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_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_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.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 ->
|
Opcode.AND_BOOL, Opcode.OR_BOOL ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||||
Opcode.INC_INT, Opcode.DEC_INT, Opcode.RET ->
|
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() {
|
class CmdJmp(internal val target: Int) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
frame.ip = target
|
frame.ip = target
|
||||||
|
|||||||
@ -105,6 +105,7 @@ enum class Opcode(val code: Int) {
|
|||||||
MUL_OBJ(0x79),
|
MUL_OBJ(0x79),
|
||||||
DIV_OBJ(0x7A),
|
DIV_OBJ(0x7A),
|
||||||
MOD_OBJ(0x7B),
|
MOD_OBJ(0x7B),
|
||||||
|
CONTAINS_OBJ(0x7C),
|
||||||
|
|
||||||
JMP(0x80),
|
JMP(0x80),
|
||||||
JMP_IF_TRUE(0x81),
|
JMP_IF_TRUE(0x81),
|
||||||
|
|||||||
@ -5215,6 +5215,20 @@ class ScriptTest {
|
|||||||
assertEquals(ObjFalse, scope.eval("inList(5, [1,2,3])"))
|
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
|
@Test
|
||||||
fun testFilterBug() = runTest {
|
fun testFilterBug() = runTest {
|
||||||
eval(
|
eval(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user