diff --git a/codeCore/src/prog8/code/ast/AstBase.kt b/codeCore/src/prog8/code/ast/AstBase.kt index 5f373646b..86e6f0682 100644 --- a/codeCore/src/prog8/code/ast/AstBase.kt +++ b/codeCore/src/prog8/code/ast/AstBase.kt @@ -36,6 +36,7 @@ sealed class PtNode(val position: Position) { fun definingBlock() = findParentNode(this) fun definingSub() = findParentNode(this) fun definingAsmSub() = findParentNode(this) + fun definingISub() = findParentNode(this) // TODO null assert here? } diff --git a/codeCore/src/prog8/code/ast/AstExpressions.kt b/codeCore/src/prog8/code/ast/AstExpressions.kt index 417fd0d6c..a0b88b594 100644 --- a/codeCore/src/prog8/code/ast/AstExpressions.kt +++ b/codeCore/src/prog8/code/ast/AstExpressions.kt @@ -45,7 +45,18 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit } infix fun isSameAs(target: PtAssignTarget): Boolean { - TODO() + return when { + target.memory != null && this is PtMemoryByte-> { + target.memory!!.address isSameAs this.address + } + target.identifier != null && this is PtIdentifier -> { + this.name == target.identifier!!.name + } + target.array != null && this is PtArrayIndexer -> { + this.variable.name == target.array!!.variable.name && this.index isSameAs target.array!!.index + } + else -> false + } } } diff --git a/codeCore/src/prog8/code/ast/AstStatements.kt b/codeCore/src/prog8/code/ast/AstStatements.kt index 753e4fc27..329281d6a 100644 --- a/codeCore/src/prog8/code/ast/AstStatements.kt +++ b/codeCore/src/prog8/code/ast/AstStatements.kt @@ -3,14 +3,16 @@ package prog8.code.ast import prog8.code.core.* -interface IPtSubroutine +sealed interface IPtSubroutine { + val name: String +} class PtAsmSub( name: String, val address: UInt?, val clobbers: Set, val parameters: List>, - val returnTypes: List, // TODO join with register as Pairs ? + val returnTypes: List, // TODO join with registers below, as Pairs ? val retvalRegisters: List, val inline: Boolean, position: Position @@ -105,6 +107,8 @@ class PtAssignTarget(position: Position) : PtNode(position) { } override fun printProperties() {} + + infix fun isSameAs(expression: PtExpression): Boolean = expression.isSameAs(this) } diff --git a/codeCore/src/prog8/code/core/ICompilationTarget.kt b/codeCore/src/prog8/code/core/ICompilationTarget.kt index 89f67edeb..865628139 100644 --- a/codeCore/src/prog8/code/core/ICompilationTarget.kt +++ b/codeCore/src/prog8/code/core/ICompilationTarget.kt @@ -7,5 +7,5 @@ interface ICompilationTarget: IStringEncoding, IMemSizer { val defaultEncoding: Encoding override fun encodeString(str: String, encoding: Encoding): List - override fun decodeString(bytes: List, encoding: Encoding): String + override fun decodeString(bytes: Iterable, encoding: Encoding): String } diff --git a/codeCore/src/prog8/code/core/IStringEncoding.kt b/codeCore/src/prog8/code/core/IStringEncoding.kt index 95e9d723f..c10393ef0 100644 --- a/codeCore/src/prog8/code/core/IStringEncoding.kt +++ b/codeCore/src/prog8/code/core/IStringEncoding.kt @@ -10,5 +10,5 @@ enum class Encoding(val prefix: String) { interface IStringEncoding { fun encodeString(str: String, encoding: Encoding): List - fun decodeString(bytes: List, encoding: Encoding): String + fun decodeString(bytes: Iterable, encoding: Encoding): String } diff --git a/codeCore/src/prog8/code/target/Encoder.kt b/codeCore/src/prog8/code/target/Encoder.kt index fb3c967c2..5de4f0920 100644 --- a/codeCore/src/prog8/code/target/Encoder.kt +++ b/codeCore/src/prog8/code/target/Encoder.kt @@ -23,7 +23,7 @@ object Encoder: IStringEncoding { success = { it } ) } - override fun decodeString(bytes: List, encoding: Encoding): String { + override fun decodeString(bytes: Iterable, encoding: Encoding): String { val decoded = when(encoding) { Encoding.PETSCII -> PetsciiEncoding.decodePetscii(bytes, true) Encoding.SCREENCODES -> PetsciiEncoding.decodeScreencode(bytes, true) diff --git a/codeCore/src/prog8/code/target/cbm/AtasciiEncoding.kt b/codeCore/src/prog8/code/target/cbm/AtasciiEncoding.kt index 633978d6d..51f5d3173 100644 --- a/codeCore/src/prog8/code/target/cbm/AtasciiEncoding.kt +++ b/codeCore/src/prog8/code/target/cbm/AtasciiEncoding.kt @@ -208,7 +208,7 @@ object AtasciiEncoding { return Ok(mapped) } - fun decode(bytes: List): Result { + fun decode(bytes: Iterable): Result { return Ok(bytes.map { decodeTable[it.toInt()] }.joinToString("")) } } diff --git a/codeCore/src/prog8/code/target/cbm/IsoEncoding.kt b/codeCore/src/prog8/code/target/cbm/IsoEncoding.kt index 8d427c162..acd12e849 100644 --- a/codeCore/src/prog8/code/target/cbm/IsoEncoding.kt +++ b/codeCore/src/prog8/code/target/cbm/IsoEncoding.kt @@ -27,7 +27,7 @@ object IsoEncoding { } } - fun decode(bytes: List): Result { + fun decode(bytes: Iterable): Result { return try { Ok(String(bytes.map { it.toByte() }.toByteArray(), charset)) } catch (ce: CharConversionException) { diff --git a/codeGenCpu6502/build.gradle b/codeGenCpu6502/build.gradle index 96b17d79c..31390f470 100644 --- a/codeGenCpu6502/build.gradle +++ b/codeGenCpu6502/build.gradle @@ -3,6 +3,7 @@ plugins { id 'java' id 'application' id "org.jetbrains.kotlin.jvm" + id "io.kotest" version "0.3.9" } java { @@ -29,6 +30,7 @@ dependencies { // implementation "org.jetbrains.kotlin:kotlin-reflect" implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16" + testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.3.2' } sourceSets { @@ -40,6 +42,22 @@ sourceSets { srcDirs = ["${project.projectDir}/res"] } } + test { + java { + srcDir "${project.projectDir}/test" + } + } } -// note: there are no unit tests in this module! +test { + // Enable JUnit 5 (Gradle 4.6+). + useJUnitPlatform() + + // Always run tests, even when nothing changed. + dependsOn 'cleanTest' + + // Show test results. + testLogging { + events "skipped", "failed" + } +} diff --git a/codeGenCpu6502/codeGenCpu6502.iml b/codeGenCpu6502/codeGenCpu6502.iml index ea1d940e1..7061784ab 100644 --- a/codeGenCpu6502/codeGenCpu6502.iml +++ b/codeGenCpu6502/codeGenCpu6502.iml @@ -4,6 +4,7 @@ + @@ -11,5 +12,7 @@ + + \ No newline at end of file diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index ba1e0b4a0..efcb9d514 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -13,10 +13,11 @@ internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1" internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2" -class AsmGen(internal val program: PtProgram, - internal val symbolTable: SymbolTable, - internal val options: CompilationOptions, - internal val errors: IErrorReporter +class AsmGen( + val program: PtProgram, + internal val symbolTable: SymbolTable, + internal val options: CompilationOptions, + internal val errors: IErrorReporter ): IAssemblyGenerator { internal val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100) @@ -197,7 +198,7 @@ class AsmGen(internal val program: PtProgram, return name2.replace("prog8_lib.P8ZP_SCRATCH_", "P8ZP_SCRATCH_") // take care of the 'hooks' to the temp vars -> reference zp symbols directly } - internal fun saveRegisterLocal(register: CpuRegister, scope: PtSub) { + internal fun saveRegisterLocal(register: CpuRegister, scope: IPtSubroutine) { if (isTargetCpu(CpuType.CPU65c02)) { // just use the cpu's stack for all registers, shorter code when (register) { @@ -317,6 +318,7 @@ class AsmGen(internal val program: PtProgram, is PtIncludeBinary -> TODO() is PtBreakpoint -> TODO() is PtVariable -> { /* do nothing; variables are handled elsewhere */ } + is PtScopeVarsDecls -> { /* do nothing; variables are handled elsewhere */ } // TODO translate PtScopeVarsDecls ? or ignore? is PtBlock -> throw AssemblyError("block should have been handled elsewhere") is PtNodeGroup -> TODO() is PtNop -> {} @@ -420,7 +422,7 @@ class AsmGen(internal val program: PtProgram, internal fun translateExpression(expression: PtExpression) = expressionsAsmGen.translateExpression(expression) - internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) = + internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? = builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultToStack, resultRegister) internal fun translateFunctionCall(functionCallExpr: PtFunctionCall, isExpression: Boolean) = @@ -689,7 +691,7 @@ $repeatLabel lda $counterVar } private fun createRepeatCounterVar(dt: DataType, preferZeropage: Boolean, stmt: PtRepeatLoop): String { - val scope = stmt.definingSub()!! + val scope = stmt.definingISub()!! val asmInfo = subroutineExtra(scope) var parent = stmt.parent while(parent !is PtProgram) { @@ -969,7 +971,7 @@ $repeatLabel lda $counterVar when(pointervar?.targetStatement(program)) { is PtLabel -> { assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) - out(" lda ${asmSymbolName(pointervar!!)},y") + out(" lda ${asmSymbolName(pointervar)},y") return true } is PtVariable, null -> { @@ -2852,14 +2854,14 @@ $repeatLabel lda $counterVar } } - internal fun popCpuStack(dt: DataType, target: PtVariable, scope: PtSub?) { + /* TODO remove?: + internal fun popCpuStack(dt: DataType, target: PtVariable, scope: IPtSubroutine?) { // note: because A is pushed first so popped last, saving A is often not required here. - val parameter = target.subroutineParameter + val parameter: PtSubroutineParameter = TODO("search subroutine parameter that it may refer to") // target.subroutineParameter if(parameter!=null) { - val sub = parameter.definingSub()!! - require(sub.isAsmSubroutine) { "push/pop arg passing only supported on asmsubs ${sub.position}" } + val sub = parameter.definingAsmSub()!! // TODO or also regular PtSub? val shouldKeepA = sub.asmParameterRegisters.any { it.registerOrPair==RegisterOrPair.AX || it.registerOrPair==RegisterOrPair.AY } - val reg = sub.asmParameterRegisters[sub.parameters.indexOf(parameter)] + val reg: RegisterOrStatusflag = sub.asmParameterRegisters[sub.parameters.indexOf(parameter)] if(reg.statusflag!=null) { if(shouldKeepA) out(" sta P8ZP_SCRATCH_REG") @@ -2950,6 +2952,7 @@ $repeatLabel lda $counterVar else -> throw AssemblyError("can't pop $dt") } } + */ internal fun pushCpuStack(dt: DataType, value: PtExpression) { val signed = value.type.oneOf(DataType.BYTE, DataType.WORD) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctions.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctions.kt new file mode 100644 index 000000000..362898f4c --- /dev/null +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctions.kt @@ -0,0 +1,114 @@ +package prog8.codegen.cpu6502 + +import prog8.code.core.* + +class ReturnConvention(val dt: DataType?, val reg: RegisterOrPair?, val floatFac1: Boolean) +class ParamConvention(val dt: DataType, val reg: RegisterOrPair?, val variable: Boolean) +class CallConvention(val params: List, val returns: ReturnConvention) { + override fun toString(): String { + val paramConvs = params.mapIndexed { index, it -> + when { + it.reg!=null -> "$index:${it.reg}" + it.variable -> "$index:variable" + else -> "$index:???" + } + } + val returnConv = + when { + returns.reg!=null -> returns.reg.toString() + returns.floatFac1 -> "floatFAC1" + else -> "" + } + return "CallConvention[" + paramConvs.joinToString() + " ; returns: $returnConv]" + } +} + +class FParam(val name: String, val possibleDatatypes: Array) + +class FSignature(val name: String, + val pure: Boolean, // does it have side effects? + val parameters: List, + val returnType: DataType?) { + + fun callConvention(actualParamTypes: List): CallConvention { + val returns: ReturnConvention = when (returnType) { + DataType.UBYTE, DataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A, false) + DataType.UWORD, DataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY, false) + DataType.FLOAT -> ReturnConvention(returnType, null, true) + in PassByReferenceDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY, false) + null -> ReturnConvention(null, null, false) + else -> { + // return type depends on arg type + when (val paramType = actualParamTypes.first()) { + DataType.UBYTE, DataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A, false) + DataType.UWORD, DataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY, false) + DataType.FLOAT -> ReturnConvention(paramType, null, true) + in PassByReferenceDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY, false) + else -> ReturnConvention(paramType, null, false) + } + } + } + + return when { + actualParamTypes.isEmpty() -> CallConvention(emptyList(), returns) + actualParamTypes.size==1 -> { + // one parameter goes via register/registerpair + val paramConv = when(val paramType = actualParamTypes[0]) { + DataType.UBYTE, DataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false) + DataType.UWORD, DataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false) + DataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) + in PassByReferenceDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false) + else -> ParamConvention(paramType, null, false) + } + CallConvention(listOf(paramConv), returns) + } + else -> { + // multiple parameters go via variables + val paramConvs = actualParamTypes.map { ParamConvention(it, null, true) } + CallConvention(paramConvs, returns) + } + } + } +} + + +private val functionSignatures: List = listOf( + // this set of function have no return value and operate in-place: + FSignature("rol" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), + FSignature("ror" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), + FSignature("rol2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), + FSignature("ror2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), + FSignature("sort" , false, listOf(FParam("array", ArrayDatatypes)), null), + FSignature("reverse" , false, listOf(FParam("array", ArrayDatatypes)), null), + // cmp returns a status in the carry flag, but not a proper return value + FSignature("cmp" , false, listOf(FParam("value1", IntegerDatatypesNoBool), FParam("value2", NumericDatatypesNoBool)), null), + FSignature("abs" , true, listOf(FParam("value", IntegerDatatypesNoBool)), DataType.UWORD), + FSignature("len" , true, listOf(FParam("values", IterableDatatypes)), DataType.UWORD), + // normal functions follow: + FSignature("sizeof" , true, listOf(FParam("object", DataType.values())), DataType.UBYTE), + FSignature("sgn" , true, listOf(FParam("value", NumericDatatypesNoBool)), DataType.BYTE), + FSignature("sqrt16" , true, listOf(FParam("value", arrayOf(DataType.UWORD))), DataType.UBYTE), + FSignature("any" , true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE), + FSignature("all" , true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE), + FSignature("lsb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE), + FSignature("msb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE), + FSignature("mkword" , true, listOf(FParam("msb", arrayOf(DataType.UBYTE)), FParam("lsb", arrayOf(DataType.UBYTE))), DataType.UWORD), + FSignature("peek" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UBYTE), + FSignature("peekw" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UWORD), + FSignature("poke" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), null), + FSignature("pokemon" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), null), + FSignature("pokew" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UWORD))), null), + FSignature("pop" , false, listOf(FParam("target", ByteDatatypes)), null), + FSignature("popw" , false, listOf(FParam("target", WordDatatypes)), null), + FSignature("push" , false, listOf(FParam("value", ByteDatatypes)), null), + FSignature("pushw" , false, listOf(FParam("value", WordDatatypes)), null), + FSignature("rsave" , false, emptyList(), null), + FSignature("rsavex" , false, emptyList(), null), + FSignature("rrestore" , false, emptyList(), null), + FSignature("rrestorex" , false, emptyList(), null), + FSignature("memory" , true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD), + FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null), + FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null), +) + +val BuiltinFunctions = functionSignatures.associateBy { it.name } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 4542f3546..b08993458 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -9,22 +9,22 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private val asmgen: AsmGen, private val assignAsmGen: AssignmentAsmGen) { - internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { - translateFunctioncall(fcall, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister) + internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? { + return translateFunctioncall(fcall, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister) } internal fun translateFunctioncallStatement(fcall: PtBuiltinFunctionCall) { translateFunctioncall(fcall, discardResult = true, resultToStack = false, resultRegister = null) } - private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? { if (discardResult && fcall.hasNoSideEffects) - return // can just ignore the whole function call altogether + return null // can just ignore the whole function call altogether if(discardResult && resultToStack) throw AssemblyError("cannot both discard the result AND put it onto stack") - val sscope = fcall.definingSub()!! + val sscope = fcall.definingISub()!! when (fcall.name) { "msb" -> funcMsb(fcall, resultToStack, resultRegister) @@ -52,13 +52,15 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, require(fcall.args[0] is PtIdentifier) { "attempt to pop a value into a differently typed variable, or in something else that isn't supported ${fcall.position}" } - asmgen.popCpuStack(DataType.UBYTE, (fcall.args[0] as PtIdentifier).targetVarDecl(program)!!, fcall.definingSub()) + TODO("pop cpu stack byte into ${fcall.args[0]}") + // asmgen.popCpuStack(DataType.UBYTE, (fcall.args[0] as PtIdentifier).targetVarDecl(program)!!, fcall.definingISub()) } "popw" -> { require(fcall.args[0] is PtIdentifier) { "attempt to pop a value into a differently typed variable, or in something else that isn't supported ${fcall.position}" } - asmgen.popCpuStack(DataType.UWORD, (fcall.args[0] as PtIdentifier).targetVarDecl(program)!!, fcall.definingSub()) + TODO("pop cpu stack word into ${fcall.args[0]}") + // asmgen.popCpuStack(DataType.UWORD, (fcall.args[0] as PtIdentifier).targetVarDecl(program)!!, fcall.definingISub()) } "rsave" -> funcRsave() "rsavex" -> funcRsaveX() @@ -69,6 +71,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, "callrom" -> funcCallRom(fcall) else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}") } + TODO("return correct function result type") } private fun funcRsave() { @@ -243,24 +246,24 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.out(" cmp ${arg2.address.asConstInteger()!!.toHex()}") } else { if(arg1.isSimple()) { - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingSub()) + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingISub()) asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A) asmgen.out(" cmp P8ZP_SCRATCH_B1") } else { asmgen.pushCpuStack(DataType.UBYTE, arg1) - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingSub()) + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingISub()) asmgen.out(" pla | cmp P8ZP_SCRATCH_B1") } } } else -> { if(arg1.isSimple()) { - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingSub()) + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingISub()) asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A) asmgen.out(" cmp P8ZP_SCRATCH_B1") } else { asmgen.pushCpuStack(DataType.UBYTE, arg1) - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingSub()) + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingISub()) asmgen.out(" pla | cmp P8ZP_SCRATCH_B1") } } @@ -289,7 +292,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } else -> { if(arg1.isSimple()) { - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, fcall.definingSub()) + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, fcall.definingISub()) asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY) asmgen.out(""" cpy P8ZP_SCRATCH_W1+1 @@ -298,7 +301,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, +""") } else { asmgen.pushCpuStack(DataType.UWORD, arg1) - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, fcall.definingSub()) + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, fcall.definingISub()) asmgen.restoreRegisterStack(CpuRegister.Y, false) asmgen.restoreRegisterStack(CpuRegister.A, false) asmgen.out(""" @@ -332,8 +335,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.translateNormalAssignment(assign) } - private fun funcSqrt16(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: PtSub?) { - translateArguments(fcall.args, func, scope) + private fun funcSqrt16(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { + translateArguments(fcall, scope) if(resultToStack) asmgen.out(" jsr prog8_lib.func_sqrt16_stack") else { @@ -471,9 +474,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } else { val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address) if(ptrAndIndex!=null) { - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X) - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY) asmgen.restoreRegisterLocal(CpuRegister.X) asmgen.out(""" @@ -572,9 +575,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } else { val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address) if(ptrAndIndex!=null) { - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X) - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY) asmgen.restoreRegisterLocal(CpuRegister.X) asmgen.out(""" @@ -628,8 +631,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.assignExpressionToVariable(indexer.index, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE, null) } - private fun funcSgn(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: PtSub?) { - translateArguments(fcall.args, func, scope) + private fun funcSgn(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { + translateArguments(fcall, scope) val dt = fcall.args.single().type if(resultToStack) { when (dt) { @@ -653,7 +656,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } } - private fun funcAnyAll(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: PtSub?) { + private fun funcAnyAll(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { outputAddressAndLenghtOfArray(fcall.args[0]) val dt = fcall.args.single().type if(resultToStack) { @@ -674,8 +677,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } } - private fun funcAbs(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: PtSub?) { - translateArguments(fcall.args, func, scope) + private fun funcAbs(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { + translateArguments(fcall, scope) val dt = fcall.args.single().type if(resultToStack) { when (dt) { @@ -709,7 +712,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, val varname = asmgen.asmVariableName(addrExpr) if(asmgen.isZpVar(addrExpr)) { // pointervar is already in the zero page, no need to copy - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX) if (asmgen.isTargetCpu(CpuType.CPU65c02)) { asmgen.out(""" @@ -734,7 +737,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, val varname = asmgen.asmVariableName(addrExpr.left as PtIdentifier) if(asmgen.isZpVar(addrExpr.left as PtIdentifier)) { // pointervar is already in the zero page, no need to copy - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX) val index = (addrExpr.right as PtNumber).number.toHex() asmgen.out(""" @@ -1017,8 +1020,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, """) } - private fun translateArguments(args: MutableList, signature: FSignature, scope: PtSub?) { - val callConv = signature.callConvention(args.map { it.type}) + private fun translateArguments(call: PtBuiltinFunctionCall, scope: IPtSubroutine?) { + val signature = BuiltinFunctions.getValue(call.name) + val callConv = signature.callConvention(call.args.map { it.type}) fun getSourceForFloat(value: PtExpression): AsmAssignSource { return when (value) { @@ -1044,7 +1048,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } } - args.zip(callConv.params).zip(signature.parameters).forEach { + call.args.zip(callConv.params).zip(signature.parameters).forEach { val paramName = it.second.name val conv = it.first.second val value = it.first.first diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt index 9878a5b45..fc903f326 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt @@ -53,8 +53,7 @@ internal class ExpressionsAsmGen(private val program: PtProgram, } asmgen.restoreXafterCall(call) - sub. - val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters) // TODO does regular sub also have asmReturnvaluesRegisters set? + val returns: List> = sub.returnsWhatWhere() for ((_, reg) in returns) { // result value is in cpu or status registers, put it on the stack instead (as we're evaluating an expression tree) if (reg.registerOrPair != null) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt index 589907ddc..e9fba1dd6 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt @@ -1,8 +1,7 @@ package prog8.codegen.cpu6502 import prog8.code.ast.* -import prog8.code.core.CpuRegister -import prog8.code.core.RegisterOrPair +import prog8.code.core.* import kotlin.math.abs // TODO include this in the node class directly? @@ -89,3 +88,25 @@ internal fun PtAsmSub.shouldKeepA(): KeepAresult { internal fun PtFunctionCall.targetSubroutine(program: PtProgram): IPtSubroutine? { TODO() } + +internal fun IPtSubroutine.returnsWhatWhere(): List> { + when(this) { + is PtAsmSub -> { + return returnTypes.zip(this.retvalRegisters) + } + is PtSub -> { + // for non-asm subroutines, determine the return registers based on the type of the return value + return if(returntype==null) + emptyList() + else { + val register = when (returntype!!) { + in ByteDatatypes -> RegisterOrStatusflag(RegisterOrPair.A, null) + in WordDatatypes -> RegisterOrStatusflag(RegisterOrPair.AY, null) + DataType.FLOAT -> RegisterOrStatusflag(RegisterOrPair.FAC1, null) + else -> RegisterOrStatusflag(RegisterOrPair.AY, null) + } + listOf(Pair(returntype!!, register)) + } + } + } +} diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt index cba2f9e3c..94a85bf87 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt @@ -591,5 +591,5 @@ $loopLabel""") range.from, asmgen.asmVariableName(stmt.variable), stmt.variable.type, - stmt.definingSub()) + stmt.definingISub()) } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index ea3773653..611671157 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -25,9 +25,9 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as if (regSaveOnStack) asmgen.saveRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnEntry) else - asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingISub()!!) } else - asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingISub()!!) } } @@ -130,9 +130,10 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as asmgen.pushCpuStack(callee.parameters[it].first.type, call.args[it]) } argOrder.forEach { - val param = callee.parameters[it].first - val targetVar = callee.searchParameter(param.name)!! - asmgen.popCpuStack(param.type, targetVar, call.definingSub()) + val param = callee.parameters[it] + TODO("pop cpu stack into asmsub param ${param.first.name} ${param.second}") + // val targetVar = callee.searchParameter(param.name)!! + // asmgen.popCpuStack(param.type, targetVar, call.definingISub()) } } @@ -150,7 +151,10 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as if(!isArgumentTypeCompatible(value.type, parameter.value.type)) throw AssemblyError("argument type incompatible") - val paramRegister = if(registerOverride==null) sub.parameters[parameter.index].second else RegisterOrStatusflag(registerOverride, null) + val paramRegister: RegisterOrStatusflag = when(sub) { + is PtAsmSub -> if(registerOverride==null) sub.parameters[parameter.index].second else RegisterOrStatusflag(registerOverride, null) + is PtSub -> RegisterOrStatusflag(registerOverride!!, null) + } val statusflag = paramRegister.statusflag val register = paramRegister.registerOrPair val requiredDt = parameter.value.type diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt index db56a016f..9aceb756b 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt @@ -13,7 +13,7 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as val targetIdent = stmt.target.identifier val targetMemory = stmt.target.memory val targetArrayIdx = stmt.target.array - val scope = stmt.definingSub() + val scope = stmt.definingISub() when { targetIdent!=null -> { val what = asmgen.asmVariableName(targetIdent) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index e3b694292..521ffc36c 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -32,7 +32,7 @@ internal class ProgramAndVarsGen( private val blockVariableInitializers = program.allBlocks().associateWith { it.children.filterIsInstance() } internal fun generate() { - val allInitializers = blockVariableInitializers.asSequence().flatMap { it.value } + val allInitializers = blockVariableInitializers.asSequence().flatMap { it.value } // TODO unused? header() val allBlocks = program.allBlocks() @@ -278,8 +278,9 @@ internal class ProgramAndVarsGen( if(sub.inline) { if(options.optimize) { - if(callGraph.unused(sub)) - return + TODO("check if sub is unused") +// if(callGraph.unused(sub)) +// return // from an inlined subroutine only the local variables are generated, // all other code statements are omitted in the subroutine itself diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt index 3fc9829da..60d7e8826 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt @@ -4,8 +4,8 @@ import prog8.code.ast.* import prog8.code.core.* import prog8.codegen.cpu6502.AsmGen import prog8.codegen.cpu6502.asConstInteger +import prog8.codegen.cpu6502.returnsWhatWhere import prog8.codegen.cpu6502.targetSubroutine -import prog8.codegen.cpu6502.targetVarDecl internal enum class TargetStorageKind { @@ -57,21 +57,21 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, with(assign.target) { when { identifier != null -> { - val parameter = identifier!!.targetVarDecl(program)?.subroutineParameter + val parameter: PtSubroutineParameter = TODO("search subroutine parameter that it may refer to ${assign.target.identifier!!.name}") // identifier!!.targetVarDecl(program)?.subroutineParameter if (parameter!=null) { - val sub = parameter.definingSubroutine!! - if (sub.isAsmSubroutine) { - val reg = sub.asmParameterRegisters[sub.parameters.indexOf(parameter)] + val sub = parameter.definingAsmSub() + if (sub!=null) { + val reg = sub.parameters.single { it.first===parameter }.second if(reg.statusflag!=null) throw AssemblyError("can't assign value to processor statusflag directly") else - return AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, type, assign.definingSub(), register=reg.registerOrPair, origAstTarget = this) + return AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, type, assign.definingISub(), register=reg.registerOrPair, origAstTarget = this) } } - return AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, type, assign.definingSub(), variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this) + return AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, type, assign.definingISub(), variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this) } - array != null -> return AsmAssignTarget(TargetStorageKind.ARRAY, asmgen, type, assign.definingSub(), array = array, origAstTarget = this) - memory != null -> return AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, type, assign.definingSub(), memory = memory, origAstTarget = this) + array != null -> return AsmAssignTarget(TargetStorageKind.ARRAY, asmgen, type, assign.definingISub(), array = array, origAstTarget = this) + memory != null -> return AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, type, assign.definingISub(), memory = memory, origAstTarget = this) else -> throw AssemblyError("weird target") } } @@ -136,8 +136,8 @@ internal class AsmAssignSource(val kind: SourceStorageKind, is PtString -> throw AssemblyError("string literal value should not occur anymore for asm generation") is PtArray -> throw AssemblyError("array literal value should not occur anymore for asm generation") is PtIdentifier -> { - val parameter = value.targetVarDecl(program)?.subroutineParameter - if(parameter!=null && parameter.definingSubroutine!!.isAsmSubroutine) + val parameter: PtSubroutineParameter = TODO("search subroutine parameter that it may refer to ${value.name}") // value.targetVarDecl(program)?.subroutineParameter + if(parameter?.definingAsmSub() != null) throw AssemblyError("can't assign from a asmsub register parameter $value ${value.position}") val varName=asmgen.asmVariableName(value) // special case: "cx16.r[0-15]" are 16-bits virtual registers of the commander X16 system @@ -160,7 +160,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind, } is PtFunctionCall -> { val sub = value.targetSubroutine(program)!! - val returnType = sub.returntypes.zip(sub.asmReturnvaluesRegisters).firstOrNull { rr -> rr.second.registerOrPair != null || rr.second.statusflag!=null }?.first + val returnType = sub.returnsWhatWhere().firstOrNull { rr -> rr.second.registerOrPair != null || rr.second.statusflag!=null }?.first ?: throw AssemblyError("can't translate zero return values in assignment") AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 3e248e14d..66107ab44 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -181,8 +181,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, val sub = value.targetSubroutine(program)!! asmgen.saveXbeforeCall(value) asmgen.translateFunctionCall(value, true) - val returnValue = sub.returntypes.zip(sub.asmReturnvaluesRegisters).singleOrNull { it.second.registerOrPair!=null } ?: - sub.returntypes.zip(sub.asmReturnvaluesRegisters).single { it.second.statusflag!=null } + val returnValue = sub.returnsWhatWhere().singleOrNull() { it.second.registerOrPair!=null } ?: sub.returnsWhatWhere().single() { it.second.statusflag!=null } when (returnValue.first) { DataType.STR -> { asmgen.restoreXafterCall(value) @@ -241,10 +240,10 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } is PtBuiltinFunctionCall -> { - asmgen.translateBuiltinFunctionCallExpression(value, false, assign.target.register) + val returnDt = asmgen.translateBuiltinFunctionCallExpression(value, false, assign.target.register) if(assign.target.register==null) { // still need to assign the result to the target variable/etc. - when(builtinFunctionReturnType(value.name)) { + when(returnDt) { in ByteDatatypes -> assignRegisterByte(assign.target, CpuRegister.A) // function's byte result is in A in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) // function's word result is in AY DataType.STR -> { @@ -386,7 +385,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, else { assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.saveRegisterStack(CpuRegister.A, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSub()) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingISub()) asmgen.restoreRegisterStack(CpuRegister.A, false) when (expr.operator) { "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_B1") @@ -408,7 +407,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) asmgen.saveRegisterStack(CpuRegister.A, false) asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSub()) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingISub()) when (expr.operator) { "&", "and" -> asmgen.out(" pla | and P8ZP_SCRATCH_W1+1 | tay | pla | and P8ZP_SCRATCH_W1") "|", "or" -> asmgen.out(" pla | ora P8ZP_SCRATCH_W1+1 | tay | pla | ora P8ZP_SCRATCH_W1") @@ -441,7 +440,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, expr.left.isSimple() && expr.right.isSimple()) { assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.saveRegisterStack(CpuRegister.A, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSub()) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingISub()) asmgen.restoreRegisterStack(CpuRegister.A, false) if(expr.operator=="==") { asmgen.out(""" @@ -467,7 +466,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) asmgen.saveRegisterStack(CpuRegister.A, false) asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSub()) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingISub()) asmgen.restoreRegisterStack(CpuRegister.Y, false) asmgen.restoreRegisterStack(CpuRegister.A, false) if(expr.operator=="==") { @@ -815,8 +814,8 @@ internal class AssignmentAsmGen(private val program: PtProgram, DataType.STR -> { // use subroutine assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) - asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSub()!!) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSub(), "P8ZP_SCRATCH_W1"), varname) + asmgen.saveRegisterLocal(CpuRegister.A, containment.definingISub()!!) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), "P8ZP_SCRATCH_W1"), varname) asmgen.restoreRegisterLocal(CpuRegister.A) val stringVal = variable.value as PtString asmgen.out(" ldy #${stringVal.value.length}") @@ -829,8 +828,8 @@ internal class AssignmentAsmGen(private val program: PtProgram, DataType.ARRAY_B, DataType.ARRAY_UB -> { val numElements = variable.arraySize!! assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) - asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSub()!!) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSub(), "P8ZP_SCRATCH_W1"), varname) + asmgen.saveRegisterLocal(CpuRegister.A, containment.definingISub()!!) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), "P8ZP_SCRATCH_W1"), varname) asmgen.restoreRegisterLocal(CpuRegister.A) asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_bytearray") @@ -838,8 +837,8 @@ internal class AssignmentAsmGen(private val program: PtProgram, } DataType.ARRAY_W, DataType.ARRAY_UW -> { val numElements = variable.arraySize!! - assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt, containment.definingSub()) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSub(), "P8ZP_SCRATCH_W2"), varname) + assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt, containment.definingISub()) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), "P8ZP_SCRATCH_W2"), varname) asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_wordarray") return @@ -1063,25 +1062,25 @@ internal class AssignmentAsmGen(private val program: PtProgram, when(valueDt) { DataType.UBYTE -> { assignExpressionToRegister(value, RegisterOrPair.Y, false) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.FREADUY") asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.BYTE -> { assignExpressionToRegister(value, RegisterOrPair.A, true) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.FREADSA") asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.UWORD -> { assignExpressionToRegister(value, RegisterOrPair.AY, false) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.GIVUAYFAY") asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.WORD -> { assignExpressionToRegister(value, RegisterOrPair.AY, true) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSub()!!) + asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.GIVAYFAY") asmgen.restoreRegisterLocal(CpuRegister.X) } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index 9c0ade365..b95c3b776 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -232,7 +232,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } else -> { // TODO use some other evaluation here; don't use the estack to transfer the address to read/write from - asmgen.assignExpressionTo(memory.address, AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, memory.definingSub())) + asmgen.assignExpressionTo(memory.address, AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, memory.definingISub())) asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1") when { valueLv != null -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, valueLv.toInt()) @@ -1573,7 +1573,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } - private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: PtExpression, scope: PtSub) { + private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: PtExpression, scope: IPtSubroutine) { asmgen.assignExpressionToRegister(value, RegisterOrPair.FAC1) asmgen.saveRegisterLocal(CpuRegister.X, scope) when (operator) { @@ -1615,7 +1615,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, asmgen.restoreRegisterLocal(CpuRegister.X) } - private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: PtIdentifier, scope: PtSub) { + private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: PtIdentifier, scope: IPtSubroutine) { val valueDt = ident.type if(valueDt != DataType.FLOAT) throw AssemblyError("float variable expected") @@ -1674,7 +1674,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, asmgen.restoreRegisterLocal(CpuRegister.X) } - private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: PtSub) { + private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: IPtSubroutine) { val constValueName = allocator.getFloatAsmConst(value) asmgen.saveRegisterLocal(CpuRegister.X, scope) when (operator) { diff --git a/codeGenCpu6502/test/TestBuiltinFunctions.kt b/codeGenCpu6502/test/TestBuiltinFunctions.kt new file mode 100644 index 000000000..a20f46ba7 --- /dev/null +++ b/codeGenCpu6502/test/TestBuiltinFunctions.kt @@ -0,0 +1,69 @@ +package prog8tests.codegencpu6502 + +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import prog8.code.core.DataType +import prog8.code.core.NumericDatatypesNoBool +import prog8.code.core.RegisterOrPair +import prog8.codegen.cpu6502.BuiltinFunctions + +class TestBuiltinFunctions: FunSpec({ + + test("pure func with fixed type") { + val func = BuiltinFunctions.getValue("sgn") + func.name shouldBe "sgn" + func.parameters.size shouldBe 1 + func.parameters[0].name shouldBe "value" + func.parameters[0].possibleDatatypes shouldBe NumericDatatypesNoBool + func.pure shouldBe true + func.returnType shouldBe DataType.BYTE + + val conv = func.callConvention(listOf(DataType.UBYTE)) + conv.params.size shouldBe 1 + conv.params[0].dt shouldBe DataType.UBYTE + conv.params[0].reg shouldBe RegisterOrPair.A + conv.params[0].variable shouldBe false + conv.returns.dt shouldBe DataType.BYTE + conv.returns.floatFac1 shouldBe false + conv.returns.reg shouldBe RegisterOrPair.A + } + + test("not-pure func with varying result value type") { + val func = BuiltinFunctions.getValue("cmp") + func.name shouldBe "cmp" + func.parameters.size shouldBe 2 + func.pure shouldBe false + func.returnType shouldBe null + + val conv = func.callConvention(listOf(DataType.UWORD, DataType.UWORD)) + conv.params.size shouldBe 2 + conv.returns.dt shouldBe null + conv.returns.floatFac1 shouldBe false + conv.returns.reg shouldBe null + } + + test("func without return type") { + val func = BuiltinFunctions.getValue("poke") + func.name shouldBe "poke" + func.parameters.size shouldBe 2 + func.parameters[0].name shouldBe "address" + func.parameters[0].possibleDatatypes shouldBe arrayOf(DataType.UWORD) + func.parameters[1].name shouldBe "value" + func.parameters[1].possibleDatatypes shouldBe arrayOf(DataType.UBYTE) + func.pure shouldBe false + func.returnType shouldBe null + + val conv = func.callConvention(listOf(DataType.UWORD, DataType.UBYTE)) + conv.params.size shouldBe 2 + conv.params[0].dt shouldBe DataType.UWORD + conv.params[0].reg shouldBe null + conv.params[0].variable shouldBe true + conv.params[1].dt shouldBe DataType.UBYTE + conv.params[1].reg shouldBe null + conv.params[1].variable shouldBe true + conv.returns.dt shouldBe null + conv.returns.floatFac1 shouldBe false + conv.returns.reg shouldBe null + } +}) + diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 0c8688064..fb31ae396 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -1244,7 +1244,7 @@ class IRCodeGen( private fun translate(parameters: List) = parameters.map { - val flattenedName = it.definingSub()!!.scopedName + "." + it.name + val flattenedName = it.definingISub()!!.name + "." + it.name val orig = symbolTable.flat.getValue(flattenedName) as StStaticVariable IRSubroutine.IRParam(flattenedName, orig.dt) } diff --git a/codeGenIntermediate/test/Dummies.kt b/codeGenIntermediate/test/Dummies.kt index 7b51303bd..bfa03f50b 100644 --- a/codeGenIntermediate/test/Dummies.kt +++ b/codeGenIntermediate/test/Dummies.kt @@ -14,7 +14,7 @@ internal object DummyStringEncoder : IStringEncoding { return emptyList() } - override fun decodeString(bytes: List, encoding: Encoding): String { + override fun decodeString(bytes: Iterable, encoding: Encoding): String { return "" } } diff --git a/compiler/test/TestBuiltinFunctions.kt b/compiler/test/TestBuiltinFunctions.kt index f7fc4fa36..59e193afc 100644 --- a/compiler/test/TestBuiltinFunctions.kt +++ b/compiler/test/TestBuiltinFunctions.kt @@ -1,13 +1,8 @@ package prog8tests import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe -import prog8.code.core.DataType -import prog8.code.core.NumericDatatypesNoBool -import prog8.code.core.RegisterOrPair import prog8.code.target.Cx16Target -import prog8.compiler.BuiltinFunctions import prog8tests.helpers.compileText class TestBuiltinFunctions: FunSpec({ @@ -24,62 +19,5 @@ class TestBuiltinFunctions: FunSpec({ }""" compileText(Cx16Target(), false, src, writeAssembly = true) shouldNotBe null } - - test("pure func with fixed type") { - val func = BuiltinFunctions.getValue("sgn") - func.name shouldBe "sgn" - func.parameters.size shouldBe 1 - func.parameters[0].name shouldBe "value" - func.parameters[0].possibleDatatypes shouldBe NumericDatatypesNoBool - func.pure shouldBe true - func.returnType shouldBe DataType.BYTE - - val conv = func.callConvention(listOf(DataType.UBYTE)) - conv.params.size shouldBe 1 - conv.params[0].dt shouldBe DataType.UBYTE - conv.params[0].reg shouldBe RegisterOrPair.A - conv.params[0].variable shouldBe false - conv.returns.dt shouldBe DataType.BYTE - conv.returns.floatFac1 shouldBe false - conv.returns.reg shouldBe RegisterOrPair.A - } - - test("not-pure func with varying result value type") { - val func = BuiltinFunctions.getValue("cmp") - func.name shouldBe "cmp" - func.parameters.size shouldBe 2 - func.pure shouldBe false - func.returnType shouldBe null - - val conv = func.callConvention(listOf(DataType.UWORD, DataType.UWORD)) - conv.params.size shouldBe 2 - conv.returns.dt shouldBe null - conv.returns.floatFac1 shouldBe false - conv.returns.reg shouldBe null - } - - test("func without return type") { - val func = BuiltinFunctions.getValue("poke") - func.name shouldBe "poke" - func.parameters.size shouldBe 2 - func.parameters[0].name shouldBe "address" - func.parameters[0].possibleDatatypes shouldBe arrayOf(DataType.UWORD) - func.parameters[1].name shouldBe "value" - func.parameters[1].possibleDatatypes shouldBe arrayOf(DataType.UBYTE) - func.pure shouldBe false - func.returnType shouldBe null - - val conv = func.callConvention(listOf(DataType.UWORD, DataType.UBYTE)) - conv.params.size shouldBe 2 - conv.params[0].dt shouldBe DataType.UWORD - conv.params[0].reg shouldBe null - conv.params[0].variable shouldBe true - conv.params[1].dt shouldBe DataType.UBYTE - conv.params[1].reg shouldBe null - conv.params[1].variable shouldBe true - conv.returns.dt shouldBe null - conv.returns.floatFac1 shouldBe false - conv.returns.reg shouldBe null - } }) diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index f7f5a006d..4d92e2548 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -28,7 +28,7 @@ class TestMemory: FunSpec({ fun wrapWithProgram(statements: List): Program { val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) - val subroutine = Subroutine("test", mutableListOf(), emptyList(), statements.toMutableList(), false, Position.DUMMY) + val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, statements.toMutableList(), Position.DUMMY) val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) program.addModule(module) return program diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index 42a865a1d..8b9b7dead 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -9,11 +9,15 @@ import prog8.ast.expressions.AddressOf import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteral import prog8.ast.statements.* +import prog8.code.ast.PtAddressOf +import prog8.code.ast.PtAssignment +import prog8.code.ast.PtIdentifier import prog8.code.core.* import prog8.code.target.C64Target import prog8.code.target.VMTarget import prog8.code.target.c64.C64Zeropage import prog8.codegen.cpu6502.AsmGen +import prog8.compiler.astprocessing.IntermediateAstMaker import prog8.compiler.astprocessing.SymbolTableMaker import prog8tests.helpers.* @@ -73,7 +77,8 @@ class TestAsmGenSymbols: StringSpec({ val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target(), 999u) options.compTarget.machine.zeropage = C64Zeropage(options) val st = SymbolTableMaker(program, options).make() - return AsmGen(program, st, options, errors) + val ptProgram = IntermediateAstMaker(program, st, options).transform() + return AsmGen(ptProgram, st, options, errors) } "symbol and variable names from strings" { @@ -92,19 +97,19 @@ class TestAsmGenSymbols: StringSpec({ "symbol and variable names from variable identifiers" { val program = createTestProgram() val asmgen = createTestAsmGen(program) - val sub = program.entrypoint + val sub = asmgen.program.entrypoint()!! - val localvarIdent = sub.statements.asSequence().filterIsInstance().first { it.value is IdentifierReference }.value as IdentifierReference + val localvarIdent = sub.children.asSequence().filterIsInstance().first { it.value is PtIdentifier }.value as PtIdentifier asmgen.asmSymbolName(localvarIdent) shouldBe "localvar" asmgen.asmVariableName(localvarIdent) shouldBe "localvar" - val localvarIdentScoped = (sub.statements.asSequence().filterIsInstance().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("main", "start", "localvar") }.value as AddressOf).identifier + val localvarIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.localvar" }.value as PtAddressOf).identifier asmgen.asmSymbolName(localvarIdentScoped) shouldBe "main.start.localvar" asmgen.asmVariableName(localvarIdentScoped) shouldBe "main.start.localvar" - val scopedVarIdent = (sub.statements.asSequence().filterIsInstance().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("var_outside") }.value as AddressOf).identifier + val scopedVarIdent = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="var_outside" }.value as PtAddressOf).identifier asmgen.asmSymbolName(scopedVarIdent) shouldBe "var_outside" asmgen.asmVariableName(scopedVarIdent) shouldBe "var_outside" - val scopedVarIdentScoped = (sub.statements.asSequence().filterIsInstance().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("main", "var_outside") }.value as AddressOf).identifier + val scopedVarIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier asmgen.asmSymbolName(scopedVarIdentScoped) shouldBe "main.var_outside" asmgen.asmVariableName(scopedVarIdentScoped) shouldBe "main.var_outside" } @@ -112,19 +117,19 @@ class TestAsmGenSymbols: StringSpec({ "symbol and variable names from label identifiers" { val program = createTestProgram() val asmgen = createTestAsmGen(program) - val sub = program.entrypoint + val sub = asmgen.program.entrypoint()!! - val localLabelIdent = (sub.statements.asSequence().filterIsInstance().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("locallabel") }.value as AddressOf).identifier + val localLabelIdent = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="locallabel" }.value as PtAddressOf).identifier asmgen.asmSymbolName(localLabelIdent) shouldBe "locallabel" asmgen.asmVariableName(localLabelIdent) shouldBe "locallabel" - val localLabelIdentScoped = (sub.statements.asSequence().filterIsInstance().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("main","start","locallabel") }.value as AddressOf).identifier + val localLabelIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier asmgen.asmSymbolName(localLabelIdentScoped) shouldBe "main.start.locallabel" asmgen.asmVariableName(localLabelIdentScoped) shouldBe "main.start.locallabel" - val scopedLabelIdent = (sub.statements.asSequence().filterIsInstance().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("label_outside") }.value as AddressOf).identifier + val scopedLabelIdent = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="label_outside" }.value as PtAddressOf).identifier asmgen.asmSymbolName(scopedLabelIdent) shouldBe "label_outside" asmgen.asmVariableName(scopedLabelIdent) shouldBe "label_outside" - val scopedLabelIdentScoped = (sub.statements.asSequence().filterIsInstance().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("main","label_outside") }.value as AddressOf).identifier + val scopedLabelIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier asmgen.asmSymbolName(scopedLabelIdentScoped) shouldBe "main.label_outside" asmgen.asmVariableName(scopedLabelIdentScoped) shouldBe "main.label_outside" } @@ -145,10 +150,8 @@ main { asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_W2") shouldBe "P8ZP_SCRATCH_W2" asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_REG")) shouldBe "P8ZP_SCRATCH_REG" asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_W2")) shouldBe "P8ZP_SCRATCH_W2" - val id1 = IdentifierReference(listOf("prog8_lib","P8ZP_SCRATCH_REG"), Position.DUMMY) - id1.linkParents(program.toplevelModule) - val id2 = IdentifierReference(listOf("prog8_lib","P8ZP_SCRATCH_W2"), Position.DUMMY) - id2.linkParents(program.toplevelModule) + val id1 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_REG", DataType.UBYTE, Position.DUMMY) + val id2 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_W2", DataType.UWORD, Position.DUMMY) asmgen.asmSymbolName(id1) shouldBe "P8ZP_SCRATCH_REG" asmgen.asmSymbolName(id2) shouldBe "P8ZP_SCRATCH_W2" } diff --git a/compiler/test/helpers/Dummies.kt b/compiler/test/helpers/Dummies.kt index ff2939713..16a81bdc4 100644 --- a/compiler/test/helpers/Dummies.kt +++ b/compiler/test/helpers/Dummies.kt @@ -29,7 +29,7 @@ internal object DummyStringEncoder : IStringEncoding { return emptyList() } - override fun decodeString(bytes: List, encoding: Encoding): String { + override fun decodeString(bytes: Iterable, encoding: Encoding): String { return "" } } @@ -37,7 +37,7 @@ internal object DummyStringEncoder : IStringEncoding { internal object AsciiStringEncoder : IStringEncoding { override fun encodeString(str: String, encoding: Encoding): List = str.map { it.code.toUByte() } - override fun decodeString(bytes: List, encoding: Encoding): String { + override fun decodeString(bytes: Iterable, encoding: Encoding): String { return bytes.joinToString() } } @@ -53,7 +53,7 @@ internal object DummyCompilationTarget : ICompilationTarget { throw NotImplementedError("dummy") } - override fun decodeString(bytes: List, encoding: Encoding): String { + override fun decodeString(bytes: Iterable, encoding: Encoding): String { throw NotImplementedError("dummy") } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index e6dcbbba4..90eb01791 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -280,12 +280,19 @@ private fun Prog8ANTLRParser.LabeldefContext.toAst(): Statement = private fun Prog8ANTLRParser.SubroutineContext.toAst() : Subroutine { // non-asm subroutine val returntype = sub_return_part()?.datatype()?.toAst() - return Subroutine(identifier().text, - sub_params()?.toAst()?.toMutableList() ?: mutableListOf(), - if(returntype==null) emptyList() else listOf(returntype), - statement_block()?.toAst() ?: mutableListOf(), - false, - toPosition()) + return Subroutine( + identifier().text, + sub_params()?.toAst()?.toMutableList() ?: mutableListOf(), + if (returntype == null) emptyList() else listOf(returntype), + emptyList(), + emptyList(), + emptySet(), + asmAddress = null, + isAsmSubroutine = false, + inline = false, + statements = statement_block()?.toAst() ?: mutableListOf(), + position = toPosition() + ) } private fun Prog8ANTLRParser.Sub_paramsContext.toAst(): List = diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index a0402e0ff..dfe5f63c8 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -695,22 +695,6 @@ class Subroutine(override val name: String, override var statements: MutableList, override val position: Position) : Statement(), INameScope { - constructor(name: String, parameters: MutableList, returntypes: List, statements: MutableList, inline: Boolean, position: Position) - : this(name, parameters, returntypes, emptyList(), determineReturnRegisters(returntypes), emptySet(), null, false, inline, statements, position) - - companion object { - private fun determineReturnRegisters(returntypes: List): List { - // for non-asm subroutines, determine the return registers based on the type of the return value - return when(returntypes.singleOrNull()) { - in ByteDatatypes -> listOf(RegisterOrStatusflag(RegisterOrPair.A, null)) - in WordDatatypes -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null)) - DataType.FLOAT -> listOf(RegisterOrStatusflag(RegisterOrPair.FAC1, null)) - null -> emptyList() - else -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null)) - } - } - } - override lateinit var parent: Node override fun copy() = throw NotImplementedError("no support for duplicating a Subroutine") diff --git a/compilerAst/src/prog8/compiler/BuiltinFunctions.kt b/compilerAst/src/prog8/compiler/BuiltinFunctions.kt index 353f2fc9f..0d1f6ed26 100644 --- a/compilerAst/src/prog8/compiler/BuiltinFunctions.kt +++ b/compilerAst/src/prog8/compiler/BuiltinFunctions.kt @@ -14,75 +14,13 @@ import kotlin.math.sqrt private typealias ConstExpressionCaller = (args: List, position: Position, program: Program) -> NumericLiteral -class ReturnConvention(val dt: DataType?, val reg: RegisterOrPair?, val floatFac1: Boolean) -class ParamConvention(val dt: DataType, val reg: RegisterOrPair?, val variable: Boolean) -class CallConvention(val params: List, val returns: ReturnConvention) { - override fun toString(): String { - val paramConvs = params.mapIndexed { index, it -> - when { - it.reg!=null -> "$index:${it.reg}" - it.variable -> "$index:variable" - else -> "$index:???" - } - } - val returnConv = - when { - returns.reg!=null -> returns.reg.toString() - returns.floatFac1 -> "floatFAC1" - else -> "" - } - return "CallConvention[" + paramConvs.joinToString() + " ; returns: $returnConv]" - } -} - class FParam(val name: String, val possibleDatatypes: Array) class FSignature(val name: String, val pure: Boolean, // does it have side effects? val parameters: List, val returnType: DataType?, - val constExpressionFunc: ConstExpressionCaller? = null) { - - fun callConvention(actualParamTypes: List): CallConvention { - val returns: ReturnConvention = when (returnType) { - DataType.UBYTE, DataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A, false) - DataType.UWORD, DataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY, false) - DataType.FLOAT -> ReturnConvention(returnType, null, true) - in PassByReferenceDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY, false) - null -> ReturnConvention(null, null, false) - else -> { - // return type depends on arg type - when (val paramType = actualParamTypes.first()) { - DataType.UBYTE, DataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A, false) - DataType.UWORD, DataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY, false) - DataType.FLOAT -> ReturnConvention(paramType, null, true) - in PassByReferenceDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY, false) - else -> ReturnConvention(paramType, null, false) - } - } - } - - return when { - actualParamTypes.isEmpty() -> CallConvention(emptyList(), returns) - actualParamTypes.size==1 -> { - // one parameter goes via register/registerpair - val paramConv = when(val paramType = actualParamTypes[0]) { - DataType.UBYTE, DataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false) - DataType.UWORD, DataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false) - DataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) - in PassByReferenceDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false) - else -> ParamConvention(paramType, null, false) - } - CallConvention(listOf(paramConv), returns) - } - else -> { - // multiple parameters go via variables - val paramConvs = actualParamTypes.map { ParamConvention(it, null, true) } - CallConvention(paramConvs, returns) - } - } - } -} + val constExpressionFunc: ConstExpressionCaller? = null) private val functionSignatures: List = listOf(