From 1163543a98528eeb535587b3721c83cb5a4cb980 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 7 Jul 2022 22:09:04 +0200 Subject: [PATCH] fix bool param lookup problem --- .../codegen/cpu6502/FunctionCallAsmGen.kt | 2 +- .../astprocessing/VerifyFunctionArgTypes.kt | 11 ++--- compiler/test/TestTypecasts.kt | 43 ++++++++++++++++++- compilerAst/src/prog8/ast/AstToplevel.kt | 6 ++- .../src/prog8/ast/statements/AstStatements.kt | 4 +- docs/source/todo.rst | 3 -- examples/test.p8 | 21 ++++----- 7 files changed, 63 insertions(+), 27 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index a37589667..68082a768 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -159,7 +159,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg } argOrder.forEach { val param = callee.parameters[it] - val targetVar = callee.searchAsmParameter(param.name)!! + val targetVar = callee.searchParameter(param.name)!! asmgen.popCpuStack(param.type, targetVar, (call as Node).definingSubroutine) } } diff --git a/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt b/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt index 66af7d0f7..9144355ac 100644 --- a/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt +++ b/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt @@ -55,9 +55,10 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe return Pair("invalid number of arguments", call.position) val mismatch = argtypes.zip(consideredParamTypes).indexOfFirst { !argTypeCompatible(it.first, it.second) } if(mismatch>=0) { - val actual = argtypes[mismatch].toString() - val expected = consideredParamTypes[mismatch].toString() - return Pair("argument ${mismatch + 1} type mismatch, was: $actual expected: $expected", call.args[mismatch].position) + val actual = argtypes[mismatch] + val expected = consideredParamTypes[mismatch] + if(expected==DataType.BOOL && actual==DataType.UBYTE && call.args[mismatch].constValue(program)?.number !in setOf(0.0, 1.0)) + return Pair("argument ${mismatch + 1} type mismatch, was: $actual expected: $expected", call.args[mismatch].position) } if(target.isAsmSubroutine) { if(target.asmReturnvaluesRegisters.size>1) { @@ -85,9 +86,9 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe argtypes.zip(consideredParamTypes).forEachIndexed { index, pair -> val anyCompatible = pair.second.any { argTypeCompatible(pair.first, it) } if (!anyCompatible) { - val actual = pair.first.toString() + val actual = pair.first return if(pair.second.size==1) { - val expected = pair.second[0].toString() + val expected = pair.second[0] Pair("argument ${index + 1} type mismatch, was: $actual expected: $expected", call.args[index].position) } else { val expected = pair.second.toList().toString() diff --git a/compiler/test/TestTypecasts.kt b/compiler/test/TestTypecasts.kt index d9e1388d8..58b0c8ab4 100644 --- a/compiler/test/TestTypecasts.kt +++ b/compiler/test/TestTypecasts.kt @@ -7,15 +7,54 @@ import io.kotest.matchers.shouldNotBe import io.kotest.matchers.string.shouldContain import io.kotest.matchers.types.instanceOf import prog8.ast.IFunctionCall -import prog8.ast.expressions.AddressOf -import prog8.ast.expressions.IdentifierReference +import prog8.ast.expressions.* +import prog8.ast.statements.Assignment +import prog8.ast.statements.IfElse +import prog8.code.core.DataType +import prog8.code.core.Position import prog8.code.target.C64Target +import prog8.compiler.printProgram import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.compileText class TestTypecasts: FunSpec({ + test("correct handling of bool parameters") { + val text=""" + main { + + sub thing(bool b1, bool b2) -> bool { + return (b1 and b2) or b1 + } + + sub start() { + bool boolvalue1 = true + bool boolvalue2 = false + uword xx + + boolvalue1 = thing(true, false) + boolvalue2 = thing(xx, xx) + + if boolvalue1 and boolvalue2 + boolvalue1=false + } + }""" + val result = compileText(C64Target(), false, text, writeAssembly = false)!! + val stmts = result.program.entrypoint.statements + stmts.size shouldBe 9 + val fcall1 = ((stmts[6] as Assignment).value as IFunctionCall) + fcall1.args[0] shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY) + fcall1.args[1] shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY) + val fcall2 = ((stmts[7] as Assignment).value as IFunctionCall) + (fcall2.args[0] as TypecastExpression).type shouldBe DataType.BOOL + (fcall2.args[1] as TypecastExpression).type shouldBe DataType.BOOL + val ifCond = (stmts[8] as IfElse).condition as BinaryExpression + ifCond.operator shouldBe "&" + (ifCond.left as IdentifierReference).nameInSource shouldBe listOf("boolvalue1") + (ifCond.right as IdentifierReference).nameInSource shouldBe listOf("boolvalue2") + } + test("correct evaluation of words in boolean expressions") { val text=""" main { diff --git a/compilerAst/src/prog8/ast/AstToplevel.kt b/compilerAst/src/prog8/ast/AstToplevel.kt index 12bd5277d..720a597b0 100644 --- a/compilerAst/src/prog8/ast/AstToplevel.kt +++ b/compilerAst/src/prog8/ast/AstToplevel.kt @@ -77,7 +77,7 @@ interface IStatementContainer { fun searchSymbol(name: String): Statement? { if(this is Subroutine && isAsmSubroutine) - return searchAsmParameter(name) + return searchParameter(name) // this is called quite a lot and could perhaps be optimized a bit more, // but adding a memoization cache didn't make much of a practical runtime difference... @@ -138,6 +138,10 @@ interface IStatementContainer { } } } + + if(this is Subroutine && !isAsmSubroutine) + return searchParameter(name) + return null } diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 9e0c359b9..01aa5ffc6 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -770,9 +770,7 @@ class Subroutine(override val name: String, // code to provide the ability to reference asmsub parameters via qualified name: private val asmParamsDecls = mutableMapOf() - fun searchAsmParameter(name: String): VarDecl? { - require(isAsmSubroutine) - + fun searchParameter(name: String): VarDecl? { val existingDecl = asmParamsDecls[name] if(existingDecl!=null) return existingDecl diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4fbb399ea..0cddfd5ff 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -5,9 +5,6 @@ For next release ^^^^^^^^^^^^^^^^ - add ARRAY_OF_BOOL array type -- test various scenarios of using bool type vs byte actually produces tighter code - make unit test of them? - ... diff --git a/examples/test.p8 b/examples/test.p8 index 4884f0c7c..5f3de569e 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,22 +3,19 @@ main { - bool boolvalue1 = true - bool boolvalue2 = false - ubyte @shared ubvalue1 = true - ubyte @shared ubvalue2 = false - sub thing(bool b1, bool b2) -> bool { - return b1 and b2 + return (b1 and b2) or b1 } sub start() { + bool boolvalue1 = true + bool boolvalue2 = false + uword xx - ubvalue1 = boolvalue1 & 1 - ubvalue2 = 1 & boolvalue1 - ubvalue1 = boolvalue1 & 0 - ubvalue2 = boolvalue1 & 8 - boolvalue1 = boolvalue2 & 1 ==0 - ; boolvar & 1 -> boolvar, (boolvar & 1 == 0) -> not boolvar + boolvalue1 = thing(true, false) + boolvalue2 = thing(xx, xx) + + if boolvalue1 and boolvalue2 + boolvalue1=false } }