diff --git a/compiler/examples/cube3d.p8 b/compiler/examples/cube3d.p8 index fe69ca701..7bc493d8e 100644 --- a/compiler/examples/cube3d.p8 +++ b/compiler/examples/cube3d.p8 @@ -53,38 +53,22 @@ ; rotate around origin (0,0,0) ; set up the 3d rotation matrix values - float cosa - float sina - float cosb - float sinb - float cosc - float sinc - float Axx - float Axy - float Axz - float Ayx - float Ayy - float Ayz - float Azx - float Azy - float Azz + float cosa = cos(t) + float sina = sin(t) + float cosb = cos(t*0.33) + float sinb = sin(t*0.33) + float cosc = cos(t*0.78) + float sinc = sin(t*0.78) - cosa = cos(t) - sina = sin(t) - cosb = cos(t*0.33) - sinb = sin(t*0.33) - cosc = cos(t*0.78) - sinc = sin(t*0.78) - - Axx = cosa*cosb - Axy = cosa*sinb*sinc - sina*cosc - Axz = cosa*sinb*cosc + sina*sinc - Ayx = sina*cosb - Ayy = sina*sinb*sinc + cosa*cosc - Ayz = sina*sinb*cosc - cosa*sinc - Azx = -sinb - Azy = cosb*sinc - Azz = cosb*cosc + float Axx = cosa*cosb + float Axy = cosa*sinb*sinc - sina*cosc + float Axz = cosa*sinb*cosc + sina*sinc + float Ayx = sina*cosb + float Ayy = sina*sinb*sinc + cosa*cosc + float Ayz = sina*sinb*cosc - cosa*sinc + float Azx = -sinb + float Azy = cosb*sinc + float Azz = cosb*cosc for i in 0 to len(xcoor)-1 { rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i] diff --git a/compiler/examples/numbergame.p8 b/compiler/examples/numbergame.p8 index b5f5e5ece..3b3a57988 100644 --- a/compiler/examples/numbergame.p8 +++ b/compiler/examples/numbergame.p8 @@ -5,7 +5,6 @@ str name = " " str guess = "000000" byte guessednumber - byte secretnumber byte attempts_left _vm_write_str("Let's play a number guessing game!\n") @@ -15,7 +14,7 @@ _vm_write_str(name) _vm_write_str(".\nI am thinking of a number from 1 to 100! You'll have to guess it!\n") - secretnumber = rnd() % 100 + byte secretnumber = rnd() % 100 for attempts_left in 10 to 1 step -1 { _vm_write_str("\nYou have ") diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index d53c66846..c1dd636f0 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -4,73 +4,24 @@ ~ main { + X=0 -sub sub1() -> byte { - return 11 -} + word mainvar = 44*Y + return -sub sub2() -> byte { - return 22 -} - - A=55 - -sub sub3() -> byte { - return 33 -} - - X=34 - -sub sub4() -> byte { - return 44 -} - - A=sub1() - A=sub2() - A=sub3() - A=sub4() sub start() { - byte bvar = 128 - word wvar = 128 - float fvar = 128 + A=99 - bvar = 1 - bvar = 2.0 - bvar = 2.w - bvar = 255.w - wvar = 1 - wvar = 2.w - wvar = 2.0 - wvar = bvar - fvar = 1 - fvar = 2.w - fvar = 22.33 - fvar = bvar - fvar = wvar + byte bvar = 4*X + word wvar = 44*XY + float fvar = 128.34+XY + A=100 return } - A=sub1() - A=sub2() - A=sub3() - A=sub4() - sub4() - - -} - - -~ test { - - sub test() -> byte { - return 44 - } - sub test2() -> byte { - return 43 - } } diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index fc3382006..fb2b3c6f7 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -55,7 +55,7 @@ fun main(args: Array) { val heap = HeapValues() moduleAst.checkIdentifiers() moduleAst.constantFold(namespace, heap) - StatementReorderer().process(moduleAst) // reorder statements to please the compiler later + StatementReorderer(namespace, heap).process(moduleAst) // reorder statements to please the compiler later moduleAst.checkValid(namespace, compilerOptions, heap) // check if tree is valid // optimize the parse tree diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 5ef475060..84bceff8b 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -585,7 +585,7 @@ enum class VarDeclType { } class VarDecl(val type: VarDeclType, - declaredDatatype: DataType, + private val declaredDatatype: DataType, val arrayspec: ArraySpec?, val name: String, var value: IExpression?, @@ -623,40 +623,20 @@ class VarDecl(val type: VarDeclType, override fun process(processor: IAstProcessor) = processor.process(this) val scopedname: String by lazy { makeScopedName(name).joinToString(".") } - val memorySize: Int - get() = when(datatype) { - DataType.BYTE -> 1 - DataType.WORD -> 2 - DataType.FLOAT -> Mflpt5.MemorySize - DataType.STR, - DataType.STR_P, - DataType.STR_S, - DataType.STR_PS -> { - val lv = value as? LiteralValue ?: throw ExpressionError("need constant initializer value expression", position) - lv.strvalue!!.length + 1 - } - DataType.ARRAY -> { - val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position) - aX.asIntegerValue!! - } - DataType.ARRAY_W -> { - val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position) - 2*aX.asIntegerValue!! - } - DataType.ARRAY_F -> { - val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position) - Mflpt5.MemorySize*aX.asIntegerValue!! - } - DataType.MATRIX -> { - val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position) - val aY = arrayspec.y as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position) - aX.asIntegerValue!! * aY.asIntegerValue!! - } - } override fun toString(): String { return "VarDecl(name=$name, vartype=$type, datatype=$datatype, value=$value, pos=$position)" } + + fun asDefaultValueDecl(): VarDecl { + val constValue = when(declaredDatatype) { + DataType.BYTE -> LiteralValue(DataType.BYTE, 0, position=position) + DataType.WORD -> LiteralValue(DataType.WORD, wordvalue=0, position=position) + DataType.FLOAT -> LiteralValue(DataType.FLOAT, floatvalue=0.0, position=position) + else -> throw FatalAstException("can only set a default value for a numeric type") + } + return VarDecl(type, declaredDatatype, arrayspec, name, constValue, position) + } } diff --git a/compiler/src/prog8/ast/StmtReorderer.kt b/compiler/src/prog8/ast/StmtReorderer.kt index 26df2b237..1ca9bd39a 100644 --- a/compiler/src/prog8/ast/StmtReorderer.kt +++ b/compiler/src/prog8/ast/StmtReorderer.kt @@ -1,6 +1,8 @@ package prog8.ast -class StatementReorderer: IAstProcessor { +import prog8.compiler.HeapValues + +class StatementReorderer(private val namespace: INameScope, private val heap: HeapValues): IAstProcessor { // Reorders the statements in a way the compiler needs. // - 'main' block must be the very first statement. // - in every scope: @@ -12,8 +14,10 @@ class StatementReorderer: IAstProcessor { // - all other subroutines will be moved to the end of their block. private val directivesToMove = setOf("%output", "%launcher", "%zeropage", "%address", "%option") + private val vardeclsToAdd = mutableMapOf>() override fun process(module: Module) { + super.process(module) val mainBlock = module.statements.single { it is Block && it.name=="main" } module.statements.remove(mainBlock) module.statements.add(0, mainBlock) @@ -23,7 +27,13 @@ class StatementReorderer: IAstProcessor { val directives = module.statements.filter {it is Directive && it.directive in directivesToMove} module.statements.removeAll(directives) module.statements.addAll(0, directives) - super.process(module) + + // add any new vardecls + for(decl in vardeclsToAdd) + for(d in decl.value) { + d.linkParents(decl.key as Node) + decl.key.statements.add(0, d) + } } override fun process(block: Block): IStatement { @@ -48,7 +58,7 @@ class StatementReorderer: IAstProcessor { // make sure there is a 'return' in front of the first subroutine // (if it isn't the first statement in the block itself, and isn't the program's entrypoint) - if(block.statements.size > numSubroutinesAtEnd) { + if(numSubroutinesAtEnd>0 && block.statements.size > (numSubroutinesAtEnd+1)) { val firstSub = block.statements[block.statements.size - numSubroutinesAtEnd] as Subroutine if(firstSub.name != "start" && block.name != "main") { val stmtBeforeFirstSub = block.statements[block.statements.size - numSubroutinesAtEnd - 1] @@ -73,12 +83,34 @@ class StatementReorderer: IAstProcessor { } override fun process(subroutine: Subroutine): IStatement { + super.process(subroutine) val varDecls = subroutine.statements.filter { it is VarDecl } subroutine.statements.removeAll(varDecls) subroutine.statements.addAll(0, varDecls) val directives = subroutine.statements.filter {it is Directive && it.directive in directivesToMove} subroutine.statements.removeAll(directives) subroutine.statements.addAll(0, directives) - return super.process(subroutine) + return subroutine + } + + override fun process(decl: VarDecl): IStatement { + super.process(decl) + if(decl.type==VarDeclType.VAR || decl.type==VarDeclType.CONST) { + if(decl.value!=null && decl.value?.constValue(namespace, heap)==null) { + // the value assigned to the variable isn't a constant. + // replace the var decl with an assignment and add a new vardecl with the default constant value. + val scope = decl.definingScope() + if(scope !in vardeclsToAdd) + vardeclsToAdd[scope] = mutableListOf() + vardeclsToAdd[scope]!!.add(decl.asDefaultValueDecl()) + return Assignment( + AssignTarget(null, IdentifierReference(decl.scopedname.split("."), decl.position), null, decl.position), + null, + decl.value!!, + decl.position + ) + } + } + return decl } } diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index f31f7beb1..d6b294979 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -674,7 +674,7 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.PUSH_VAR_W -> { val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - checkDt(value, DataType.WORD) + checkDt(value, setOf(DataType.WORD, DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.MATRIX)) evalstack.push(value) } Opcode.PUSH_VAR_F -> { @@ -691,7 +691,7 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.POP_VAR_W -> { val value = evalstack.pop() - checkDt(value, DataType.WORD) + checkDt(value, setOf(DataType.WORD, DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.MATRIX)) val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") checkDt(variable, DataType.WORD) variables[ins.callLabel!!] = value diff --git a/compiler/test/StackVMOpcodeTests.kt b/compiler/test/StackVMOpcodeTests.kt index 9c7dda53e..58a16d1a3 100644 --- a/compiler/test/StackVMOpcodeTests.kt +++ b/compiler/test/StackVMOpcodeTests.kt @@ -247,383 +247,166 @@ class TestStackVmOpcodes { @Test fun testAdd() { - val values = listOf( - Value(DataType.FLOAT, 42.25), - Value(DataType.WORD, 4000), - Value(DataType.BYTE, 40)) - val expected = listOf( - Value(DataType.WORD, 4000+40), - Value(DataType.FLOAT, 42.25+(4000+40))) - val operator = Opcode.ADD - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.WORD, 4000), Opcode.ADD, Value(DataType.BYTE, 40), Value(DataType.WORD, 4000+40)) + testBinaryOperator(Value(DataType.WORD, 4000+40), Opcode.ADD, Value(DataType.WORD, 123), Value(DataType.WORD, 4000+40+123)) + assertFailsWith { + testBinaryOperator(Value(DataType.WORD, 4000 + 40), Opcode.ADD, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 + (4000 + 40))) + } } @Test fun testSub() { - val values = listOf( - Value(DataType.FLOAT, 42.25), - Value(DataType.WORD, 4000), - Value(DataType.BYTE, 40)) - val expected = listOf( - Value(DataType.WORD, 4000-40), - Value(DataType.FLOAT, 42.25-(4000-40))) - val operator = Opcode.SUB - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.WORD, 4000), Opcode.SUB, Value(DataType.BYTE, 40), Value(DataType.WORD, 4000-40)) + testBinaryOperator(Value(DataType.WORD, 4000), Opcode.SUB, Value(DataType.WORD, 123), Value(DataType.WORD, 4000-123)) + assertFailsWith { + testBinaryOperator(Value(DataType.WORD, 4000 - 40), Opcode.SUB, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 - (4000 - 40))) + } } @Test fun testMul() { - val values = listOf( - Value(DataType.FLOAT, 42.2533), - Value(DataType.WORD, 401), - Value(DataType.BYTE, 4)) - val expected = listOf( - Value(DataType.WORD, 401*4), - Value(DataType.FLOAT, 42.2533*(401*4))) - val operator = Opcode.MUL - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.WORD, 401), Opcode.MUL, Value(DataType.BYTE, 4), Value(DataType.WORD, 401*4)) + testBinaryOperator(Value(DataType.WORD, 401), Opcode.MUL, Value(DataType.WORD, 4), Value(DataType.WORD, 401*4)) + assertFailsWith { + testBinaryOperator(Value(DataType.WORD, 401 * 4), Opcode.MUL, Value(DataType.FLOAT, 42.2533), Value(DataType.FLOAT, 42.2533 * (401 * 4))) + } } @Test fun testDiv() { - val values = listOf( - Value(DataType.FLOAT, 42.25), - Value(DataType.WORD, 3999), - Value(DataType.BYTE, 40) - ) - val expected = listOf( - Value(DataType.WORD, 99), - Value(DataType.FLOAT, 42.25/99)) - val operator = Opcode.DIV - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV, Value(DataType.BYTE, 40), Value(DataType.WORD, 99)) + testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV, Value(DataType.WORD, 40), Value(DataType.WORD, 99)) + testBinaryOperator(Value(DataType.FLOAT, 42.25), Opcode.DIV, Value(DataType.WORD, 99), Value(DataType.FLOAT, 42.25/99)) + assertFailsWith { + testBinaryOperator(Value(DataType.WORD, 3333), Opcode.DIV, Value(DataType.FLOAT, 2.22), Value(DataType.FLOAT, 3333 / 2.22)) + } } @Test fun testFloorDiv() { - val values = listOf( - Value(DataType.FLOAT, 4000.25), - Value(DataType.WORD, 3999), - Value(DataType.BYTE, 40) - ) - val expected = listOf( - Value(DataType.WORD, 99), - Value(DataType.FLOAT, 40.0)) - val operator = Opcode.FLOORDIV - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV, Value(DataType.BYTE, 99), Value(DataType.WORD, 40)) + testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV, Value(DataType.WORD, 99), Value(DataType.WORD, 40)) + testBinaryOperator(Value(DataType.FLOAT, 4000.25), Opcode.FLOORDIV, Value(DataType.BYTE, 40), Value(DataType.FLOAT, 100.0)) } @Test fun testPow() { - val values = listOf( - Value(DataType.FLOAT, 1.1), - Value(DataType.WORD, 3), - Value(DataType.BYTE, 4) - ) - val expected = listOf( - Value(DataType.WORD, 81), - Value(DataType.FLOAT, 2253.2402360440274)) - val operator = Opcode.POW - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.WORD, 3), Opcode.POW, Value(DataType.BYTE, 4), Value(DataType.WORD, 81)) + testBinaryOperator(Value(DataType.WORD, 3), Opcode.POW, Value(DataType.WORD, 4), Value(DataType.WORD, 81)) + testBinaryOperator(Value(DataType.FLOAT, 1.1), Opcode.POW, Value(DataType.BYTE, 81), Value(DataType.FLOAT, 2253.2402360440274)) } @Test fun testRemainder() { - val values = listOf( - Value(DataType.FLOAT, 2022.5), - Value(DataType.WORD, 500), - Value(DataType.BYTE, 29) - ) - val expected = listOf( - Value(DataType.BYTE, 7), - Value(DataType.FLOAT, 6.5)) - val operator = Opcode.REMAINDER - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.WORD, 500), Opcode.REMAINDER, Value(DataType.BYTE, 29), Value(DataType.BYTE, 7)) + testBinaryOperator(Value(DataType.WORD, 500), Opcode.REMAINDER, Value(DataType.WORD, 29), Value(DataType.BYTE, 7)) + testBinaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.REMAINDER, Value(DataType.BYTE, 7), Value(DataType.FLOAT, 6.5)) } @Test fun testBitand() { - val values = listOf( - Value(DataType.WORD, 0b0011001011110001), - Value(DataType.BYTE, 0b10011111), - Value(DataType.BYTE, 0b11111101)) - val expected = listOf( - Value(DataType.BYTE, 0b10011101), - Value(DataType.WORD, 0b0000000010010001)) - val operator = Opcode.BITAND - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.BYTE, 0b10011111), Opcode.BITAND, Value(DataType.BYTE, 0b11111101), Value(DataType.BYTE, 0b10011101)) + testBinaryOperator(Value(DataType.WORD, 0b0011001011110001), Opcode.BITAND, Value(DataType.BYTE, 0b10011101), Value(DataType.WORD, 0b0000000010010001)) } @Test fun testBitor() { - val values = listOf( - Value(DataType.WORD, 0b0011001011100000), - Value(DataType.BYTE, 0b00011101), - Value(DataType.BYTE, 0b10010001)) - val expected = listOf( - Value(DataType.BYTE, 0b10011101), - Value(DataType.WORD, 0b0011001011111101)) - val operator = Opcode.BITOR - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.BYTE, 0b00011101), Opcode.BITOR, Value(DataType.BYTE, 0b10010001), Value(DataType.BYTE, 0b10011101)) + testBinaryOperator(Value(DataType.WORD, 0b0011001011100000), Opcode.BITOR, Value(DataType.BYTE, 0b10011101), Value(DataType.WORD, 0b0011001011111101)) } @Test fun testBitxor() { - val values = listOf( - Value(DataType.WORD, 0b0011001011100000), - Value(DataType.BYTE, 0b00011101), - Value(DataType.BYTE, 0b10010001)) - val expected = listOf( - Value(DataType.BYTE, 0b10001100), - Value(DataType.WORD, 0b0011001001101100)) - val operator = Opcode.BITXOR - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.BYTE, 0b00011101), Opcode.BITXOR, Value(DataType.BYTE, 0b10010001), Value(DataType.BYTE, 0b10001100)) + testBinaryOperator(Value(DataType.WORD, 0b0011001011100000), Opcode.BITXOR, Value(DataType.BYTE, 0b10001100), Value(DataType.WORD, 0b0011001001101100)) } @Test fun testAnd() { - val values = listOf( - Value(DataType.ARRAY, 111), - Value(DataType.BYTE, 0), - Value(DataType.WORD, 0), - Value(DataType.STR, 222), - Value(DataType.STR, 333), - Value(DataType.ARRAY, 444), - Value(DataType.FLOAT, 300.33), - Value(DataType.WORD, 5000), - Value(DataType.BYTE, 200), - Value(DataType.BYTE, 1)) - val expected = listOf( - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 0)) - val operator = Opcode.AND - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.BYTE, 200), Opcode.AND, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.BYTE, 200), Opcode.AND, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.BYTE, 0), Opcode.AND, Value(DataType.BYTE, 101), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.AND, Value(DataType.WORD, 13455), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.AND, Value(DataType.WORD, 0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 0), Opcode.AND, Value(DataType.WORD, 101), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.AND, Value(DataType.FLOAT, 13455.55), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.AND, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 0.0), Opcode.AND, Value(DataType.FLOAT, 101.11), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.STR, 222), Opcode.AND, Value(DataType.STR, 333), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.ARRAY, 444), Opcode.AND, Value(DataType.ARRAY, 444), Value(DataType.BYTE, 1)) } @Test fun testOr() { - val values = listOf( - Value(DataType.BYTE, 0), - Value(DataType.WORD, 0), - Value(DataType.STR, 222), - Value(DataType.STR, 333), - Value(DataType.ARRAY, 444), - Value(DataType.FLOAT, 0), - Value(DataType.WORD, 1), - Value(DataType.WORD, 0), - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 0)) - val expected = listOf( - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1)) - val operator = Opcode.OR - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.BYTE, 200), Opcode.OR, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.BYTE, 200), Opcode.OR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.BYTE, 0), Opcode.OR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.OR, Value(DataType.WORD, 13455), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.OR, Value(DataType.WORD, 0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 0), Opcode.OR, Value(DataType.WORD, 0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.OR, Value(DataType.FLOAT, 13455.55), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.OR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.FLOAT, 0.0), Opcode.OR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.STR, 222), Opcode.OR, Value(DataType.STR, 333), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.ARRAY, 444), Opcode.OR, Value(DataType.ARRAY, 444), Value(DataType.BYTE, 1)) } @Test fun testXor() { - val values = listOf( - Value(DataType.ARRAY, 111), - Value(DataType.BYTE, 1), - Value(DataType.WORD, 0), - Value(DataType.STR, 222), - Value(DataType.STR, 333), - Value(DataType.ARRAY, 444), - Value(DataType.FLOAT, 300.33), - Value(DataType.WORD, 5000), - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 20)) - val expected = listOf( - 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, 0), - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 0)) - val operator = Opcode.XOR - - testBinaryOperator(values, operator, expected) + testBinaryOperator(Value(DataType.BYTE, 200), Opcode.XOR, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.BYTE, 200), Opcode.XOR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.BYTE, 0), Opcode.XOR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.XOR, Value(DataType.WORD, 13455), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.XOR, Value(DataType.WORD, 0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 0), Opcode.XOR, Value(DataType.WORD, 0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.XOR, Value(DataType.FLOAT, 13455.55), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.XOR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.FLOAT, 0.0), Opcode.XOR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.STR, 222), Opcode.XOR, Value(DataType.STR, 333), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.ARRAY, 444), Opcode.XOR, Value(DataType.ARRAY, 444), Value(DataType.BYTE, 0)) } @Test fun testNot() { - val values = listOf( - Value(DataType.STR, 111), - Value(DataType.STR, 222), - 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, 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) - ) - val operator = Opcode.NOT - - testUnaryOperator(values, operator, expected, listOf(DataType.BYTE, DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE)) + testUnaryOperator(Value(DataType.BYTE, 0), Opcode.NOT, Value(DataType.BYTE, 1)) + testUnaryOperator(Value(DataType.BYTE, 20), Opcode.NOT, Value(DataType.BYTE, 0)) + testUnaryOperator(Value(DataType.WORD, 0), Opcode.NOT, Value(DataType.BYTE, 1)) + testUnaryOperator(Value(DataType.WORD, 5000), Opcode.NOT, Value(DataType.BYTE, 0)) + testUnaryOperator(Value(DataType.FLOAT, 0.0), Opcode.NOT, Value(DataType.BYTE, 1)) + testUnaryOperator(Value(DataType.FLOAT, 5000.0), Opcode.NOT, Value(DataType.BYTE, 0)) } @Test fun testInc() { - val values = listOf( - Value(DataType.BYTE, 255), - Value(DataType.BYTE, 99) - ) - val expected = listOf( - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 100) - ) - testUnaryOperator(values, Opcode.INC, expected) - - val valuesw = listOf( - Value(DataType.WORD, 65535), - Value(DataType.WORD, 999) - ) - val expectedw = listOf( - Value(DataType.WORD, 0), - Value(DataType.WORD, 1000) - ) - testUnaryOperator(valuesw, Opcode.INC_W, expectedw) - - val valuesf = listOf( - Value(DataType.FLOAT, -1.0), - Value(DataType.FLOAT, 2022.5) - ) - val expectedf = listOf( - Value(DataType.FLOAT, 0.0), - Value(DataType.FLOAT, 2023.5) - ) - testUnaryOperator(valuesf, Opcode.INC_F, expectedf) + testUnaryOperator(Value(DataType.BYTE, 255), Opcode.INC, Value(DataType.BYTE, 0)) + testUnaryOperator(Value(DataType.BYTE, 99), Opcode.INC, Value(DataType.BYTE, 100)) + testUnaryOperator(Value(DataType.WORD, 65535), Opcode.INC_W, Value(DataType.WORD, 0)) + testUnaryOperator(Value(DataType.WORD, 999), Opcode.INC_W, Value(DataType.WORD, 1000)) + testUnaryOperator(Value(DataType.FLOAT, -1.0), Opcode.INC_F, Value(DataType.FLOAT, 0.0)) + testUnaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.INC_F, Value(DataType.FLOAT, 2023.5)) } @Test fun testDec() { - val values = listOf( - Value(DataType.BYTE, 100), - Value(DataType.BYTE, 0) - ) - val expected = listOf( - Value(DataType.BYTE, 99), - Value(DataType.BYTE, 255) - ) - testUnaryOperator(values, Opcode.DEC, expected) - - val valuesw = listOf( - Value(DataType.WORD, 1000), - Value(DataType.WORD, 0) - ) - val expectedw = listOf( - Value(DataType.WORD, 999), - Value(DataType.WORD, 65535) - ) - testUnaryOperator(valuesw, Opcode.DEC_W, expectedw) - - val valuesf = listOf( - Value(DataType.FLOAT, 0.5), - Value(DataType.FLOAT, 123.456) - ) - val expectedf = listOf( - Value(DataType.FLOAT, -0.5), - Value(DataType.FLOAT, 122.456) - ) - testUnaryOperator(valuesf, Opcode.DEC_F, expectedf) + testUnaryOperator(Value(DataType.BYTE, 100), Opcode.DEC, Value(DataType.BYTE, 99)) + testUnaryOperator(Value(DataType.BYTE, 0), Opcode.DEC, Value(DataType.BYTE, 255)) + testUnaryOperator(Value(DataType.WORD, 1000), Opcode.DEC_W, Value(DataType.WORD, 999)) + testUnaryOperator(Value(DataType.WORD, 0), Opcode.DEC_W, Value(DataType.WORD, 65535)) + testUnaryOperator(Value(DataType.FLOAT, 0.5), Opcode.DEC_F, Value(DataType.FLOAT, -0.5)) + testUnaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.DEC_F, Value(DataType.FLOAT, 2021.5)) } @Test fun testNeg() { - val ins = mutableListOf( - Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 123.456)), - Instruction(Opcode.NEG), - Instruction(Opcode.NEG) - ) - vm.load(makeProg(ins), null) - assertThat(vm.evalstack, empty()) - vm.step(2) - assertEquals(1, vm.evalstack.size) - assertEquals(Value(DataType.FLOAT, -123.456), vm.evalstack.peek()) - vm.step(1) - assertEquals(1, vm.evalstack.size) - assertEquals(Value(DataType.FLOAT, 123.456), vm.evalstack.peek()) - - val ins2 = mutableListOf( - Instruction(Opcode.PUSH_W, Value(DataType.WORD, 1234)), - Instruction(Opcode.NEG) - ) - vm.load(makeProg(ins2), null) - vm.step(2) - assertEquals(Value(DataType.WORD, 64302), vm.evalstack.pop()) - - val ins3 = mutableListOf( - Instruction(Opcode.PUSH, Value(DataType.BYTE, 12)), - Instruction(Opcode.NEG) - ) - vm.load(makeProg(ins3), null) - vm.step(2) - assertEquals(Value(DataType.BYTE, 244), vm.evalstack.pop()) + testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG, Value(DataType.BYTE, 244)) + testUnaryOperator(Value(DataType.WORD, 1234), Opcode.NEG, Value(DataType.WORD, 64302)) + testUnaryOperator(Value(DataType.FLOAT, 123.456), Opcode.NEG, Value(DataType.FLOAT, -123.456)) } @Test fun testInv() { - val ins = mutableListOf( - Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)), - Instruction(Opcode.PUSH_W, Value(DataType.WORD, 4044)), - Instruction(Opcode.INV), - Instruction(Opcode.INV), - Instruction(Opcode.INV) - ) - vm.load(makeProg(ins), null) - assertThat(vm.evalstack, empty()) - vm.step(3) - assertEquals(2, vm.evalstack.size) - assertEquals(Value(DataType.WORD, 0xf033), vm.evalstack.pop()) - vm.step(1) - assertEquals(1, vm.evalstack.size) - assertEquals(Value(DataType.BYTE, 0x84), vm.evalstack.pop()) - - val ins2 = mutableListOf( - Instruction(Opcode.PUSH_W, Value(DataType.FLOAT, 1234.33)), // todo should crash - Instruction(Opcode.INV) - ) - vm.load(makeProg(ins2), null) - assertFailsWith { - vm.step(2) - } + testUnaryOperator(Value(DataType.BYTE, 123), Opcode.INV, Value(DataType.BYTE, 0x84)) + testUnaryOperator(Value(DataType.WORD, 4044), Opcode.INV, Value(DataType.WORD, 0xf033)) } @Test @@ -1480,17 +1263,6 @@ class TestStackVmOpcodes { assertEquals(Value(DataType.WORD, 0b1001001100001101), vm.evalstack.peek()) } - - private fun discardOpcode(dt: DataType): Opcode { - return when(dt) { - DataType.BYTE -> Opcode.DISCARD - DataType.WORD -> Opcode.DISCARD_W - DataType.FLOAT -> Opcode.DISCARD_F - DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, - DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.DISCARD_W - } - } - private fun pushOpcode(dt: DataType): Opcode { return when (dt) { DataType.BYTE -> Opcode.PUSH @@ -1519,50 +1291,27 @@ class TestStackVmOpcodes { } } - private fun testBinaryOperator(valuesToPush: List, operator: Opcode, expected: List) { - assertEquals(valuesToPush.size, expected.size+1) - val ins = mutableListOf() - for (value in valuesToPush) { - ins.add(Instruction(pushOpcode(value.type), value)) - } - for (i in 1 until valuesToPush.size) - ins.add(Instruction(operator)) - vm.load(makeProg(ins), null) - vm.step(valuesToPush.size) - assertEquals(valuesToPush.size, vm.evalstack.size) - for (expectedVal in expected) { - vm.step(1) - assertEquals(expectedVal, vm.evalstack.peek()) - } - assertFailsWith { - vm.step(1) - } + private fun testBinaryOperator(left: Value, operator: Opcode, right: Value, result: Value) { + val program=makeProg(mutableListOf( + Instruction(pushOpcode(left.type), left), + Instruction(pushOpcode(right.type), right), + Instruction(operator) + )) + vm.load(program, null) + vm.step(3) + assertEquals(1, vm.evalstack.size) + assertEquals(result, vm.evalstack.pop()) } - private fun testUnaryOperator(valuesToPush: List, operator: Opcode, expected: List, expectedTypes: List?=null) { - assertEquals(valuesToPush.size, expected.size) - val typesExpected = expectedTypes?.reversed() ?: expected.reversed().map{it.type} - - val ins = mutableListOf() - for (value in valuesToPush) { - ins.add(Instruction(pushOpcode(value.type), value)) - } - for (type in typesExpected) { - ins.add(Instruction(operator)) - ins.add(Instruction(discardOpcode(type))) - } - vm.load(makeProg(ins), null) - vm.step(valuesToPush.size) - assertEquals(valuesToPush.size, vm.evalstack.size) - - for (expectedVal in expected.reversed()) { - vm.step(1) - assertEquals(expectedVal, vm.evalstack.peek()) - vm.step(1) - } - assertTrue(vm.evalstack.empty()) - assertFailsWith { - vm.step(1) - } + private fun testUnaryOperator(value: Value, operator: Opcode, result: Value) { + val program=makeProg(mutableListOf( + Instruction(pushOpcode(value.type), value), + Instruction(operator) + )) + vm.load(program, null) + vm.step(2) + assertEquals(1, vm.evalstack.size) + assertEquals(result, vm.evalstack.pop()) } + } diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index cd98c60a7..726b66dd3 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -199,7 +199,7 @@ Variable declarations Variables should be declared with their exact type and size so the compiler can allocate storage for them. You must give them an initial value as well. That value can be a simple literal value, -or a (constant) expression. The syntax is:: +or an expression. The syntax is:: [ = ]