From d990b05998b63a13ac097a73bbfccf5c22b2cffa Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 25 Sep 2018 01:02:01 +0200 Subject: [PATCH] compilation of prefix operators, added NOT opcode --- compiler/src/prog8/ast/AST.kt | 2 +- compiler/src/prog8/compiler/Compiler.kt | 15 ++++++++++++++ compiler/src/prog8/stackvm/StackVm.kt | 6 ++++++ compiler/test/StackVMOpcodeTests.kt | 26 +++++++++++++++++++++++++ compiler/test/ValueOperationsTests.kt | 23 ++++++++++++++++++++++ 5 files changed, 71 insertions(+), 1 deletion(-) diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index daf00e8f8..ca337e5b4 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -725,7 +725,7 @@ class BinaryExpression(var left: IExpression, val operator: String, var right: I val leftDt = left.resultingDatatype(namespace) val rightDt = right.resultingDatatype(namespace) return when(operator) { - "+", "-", "*", "**" -> if(leftDt==null || rightDt==null) null else arithmeticOpDt(leftDt, rightDt) + "+", "-", "*", "**", "%" -> if(leftDt==null || rightDt==null) null else arithmeticOpDt(leftDt, rightDt) "/" -> if(leftDt==null || rightDt==null) null else DataType.FLOAT "//" -> if(leftDt==null || rightDt==null) null else integerDivisionOpDt(leftDt, rightDt) "&" -> leftDt diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 457835fd6..7a9f6a774 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -294,6 +294,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva is RegisterExpr -> { stackvmProg.instr(Opcode.PUSH_VAR, Value(DataType.STR, null, expr.register.toString())) } + is PrefixExpression -> { + translate(expr.expression) + translatePrefixOperator(expr.operator) + } is BinaryExpression -> { translate(expr.left) translate(expr.right) @@ -399,6 +403,17 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva stackvmProg.instr(opcode) } + private fun translatePrefixOperator(operator: String) { + val opcode = when(operator) { + "+" -> Opcode.NOP + "-" -> Opcode.NEG + "~" -> Opcode.INV + "not" -> Opcode.NOT + else -> throw FatalAstException("const evaluation for invalid prefix operator $operator") + } + stackvmProg.instr(opcode) + } + private fun translate(stmt: FunctionCallStatement) { stackvmProg.line(stmt.position) val targetStmt = stmt.target.targetStatement(namespace)!! diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index ca7453c71..d4c54883d 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -75,6 +75,7 @@ enum class Opcode { AND, OR, XOR, + NOT, // increment, decrement INC, @@ -546,6 +547,7 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?= fun and(other: Value) = Value(DataType.BYTE, if(this.asBooleanValue && other.asBooleanValue) 1 else 0) fun or(other: Value) = Value(DataType.BYTE, if(this.asBooleanValue || other.asBooleanValue) 1 else 0) fun xor(other: Value) = Value(DataType.BYTE, if(this.asBooleanValue xor other.asBooleanValue) 1 else 0) + fun not() = Value(DataType.BYTE, if(this.asBooleanValue) 0 else 1) fun inv(): Value { return when(type) { @@ -1485,6 +1487,10 @@ class StackVm(val traceOutputFile: String?) { val (top, second) = evalstack.pop2() evalstack.push(second.xor(top)) } + Opcode.NOT -> { + val value = evalstack.pop() + evalstack.push(value.not()) + } Opcode.LESS -> { val (top, second) = evalstack.pop2() evalstack.push(Value(DataType.BYTE, if(second < top) 1 else 0)) diff --git a/compiler/test/StackVMOpcodeTests.kt b/compiler/test/StackVMOpcodeTests.kt index 90c226847..55a9f4bf0 100644 --- a/compiler/test/StackVMOpcodeTests.kt +++ b/compiler/test/StackVMOpcodeTests.kt @@ -522,6 +522,32 @@ class TestStackVmOpcodes { testBinaryOperator(values, operator, expected) } + @Test + fun testNot() { + val values = listOf( + Value(DataType.STR, null, ""), + Value(DataType.STR, null, "hello"), + Value(DataType.FLOAT, 0.0), + Value(DataType.FLOAT, 300.33), + Value(DataType.WORD, 0), + Value(DataType.WORD, 5000), + Value(DataType.BYTE, 0), + Value(DataType.BYTE, 20)) + val expected = listOf( + Value(DataType.BYTE, 0), + Value(DataType.BYTE, 1), + Value(DataType.BYTE, 0), + Value(DataType.BYTE, 1), + Value(DataType.BYTE, 0), + Value(DataType.BYTE, 1), + Value(DataType.BYTE, 0), + Value(DataType.BYTE, 1) + ) + val operator = Opcode.NOT + + testUnaryOperator(values, operator, expected) + } + @Test fun testInc() { val values = listOf( diff --git a/compiler/test/ValueOperationsTests.kt b/compiler/test/ValueOperationsTests.kt index 0dc99236d..d0859ed58 100644 --- a/compiler/test/ValueOperationsTests.kt +++ b/compiler/test/ValueOperationsTests.kt @@ -197,6 +197,29 @@ class TestStackVmValue { assertEquals(DataType.WORD, r.type) assertEquals(33, r.integerValue()) } + + @Test + fun testNoAutoFloatConversion() { + assertFailsWith { + Value(DataType.BYTE, 233).add(Value(DataType.FLOAT, 1.234)) + } + assertFailsWith { + Value(DataType.WORD, 233).add(Value(DataType.FLOAT, 1.234)) + } + assertFailsWith { + Value(DataType.BYTE, 233).mul(Value(DataType.FLOAT, 1.234)) + } + assertFailsWith { + Value(DataType.WORD, 233).mul(Value(DataType.FLOAT, 1.234)) + } + assertFailsWith { + Value(DataType.BYTE, 233).div(Value(DataType.FLOAT, 1.234)) + } + assertFailsWith { + Value(DataType.WORD, 233).div(Value(DataType.FLOAT, 1.234)) + } + val result = Value(DataType.FLOAT, 233.333).add(Value(DataType.FLOAT, 1.234)) + } }