From 2727a4dcb3bf3449bea322d11c0869e62ec059e2 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 23 Dec 2024 17:27:57 +0100 Subject: [PATCH] tweak DataType class and memsizer related to subtypes/elementtypes --- codeCore/src/prog8/code/core/Enumerations.kt | 107 +++++++----------- codeCore/src/prog8/code/core/IMemSizer.kt | 11 +- codeCore/src/prog8/code/target/AtariTarget.kt | 17 +-- .../src/prog8/code/target/Neo6502Target.kt | 17 +-- codeCore/src/prog8/code/target/VMTarget.kt | 19 ++-- .../prog8/code/target/cbm/CbmMemorySizer.kt | 19 ++-- codeGenCpu6502/test/Dummies.kt | 6 +- .../prog8/codegen/intermediate/IRCodeGen.kt | 5 +- codeGenIntermediate/test/Dummies.kt | 6 +- .../optimizer/ConstantIdentifierReplacer.kt | 2 +- .../compiler/astprocessing/AstPreprocessor.kt | 2 +- .../astprocessing/IntermediateAstMaker.kt | 4 +- compiler/test/TestMemory.kt | 33 +++--- compiler/test/ast/TestVariousCompilerAst.kt | 42 +++---- compiler/test/helpers/Dummies.kt | 8 +- compilerAst/src/prog8/ast/AstToplevel.kt | 2 - .../prog8/ast/expressions/InferredTypes.kt | 4 +- .../src/prog8/ast/statements/AstStatements.kt | 4 +- docs/source/todo.rst | 3 + examples/test.p8 | 45 +++++--- gradle.properties | 2 +- intermediate/src/prog8/intermediate/Utils.kt | 4 +- 22 files changed, 175 insertions(+), 187 deletions(-) diff --git a/codeCore/src/prog8/code/core/Enumerations.kt b/codeCore/src/prog8/code/core/Enumerations.kt index 27a7a8bd1..987efe4be 100644 --- a/codeCore/src/prog8/code/core/Enumerations.kt +++ b/codeCore/src/prog8/code/core/Enumerations.kt @@ -55,43 +55,18 @@ val BaseDataType.isPassByRef get() = this.isIterable val BaseDataType.isPassByValue get() = !this.isIterable -sealed class SubType(val dt: BaseDataType) { - companion object { - private val types by lazy { - // lazy because of static initialization order - mapOf( - BaseDataType.UBYTE to SubUnsignedByte, - BaseDataType.BYTE to SubSignedByte, - BaseDataType.UWORD to SubUnsignedWord, - BaseDataType.WORD to SubSignedWord, - BaseDataType.FLOAT to SubFloat, - BaseDataType.BOOL to SubBool - )} - - fun forDt(dt: BaseDataType) = types.getValue(dt) - } -} - -data object SubUnsignedByte: SubType(BaseDataType.UBYTE) -data object SubSignedByte: SubType(BaseDataType.BYTE) -data object SubUnsignedWord: SubType(BaseDataType.UWORD) -data object SubSignedWord: SubType(BaseDataType.WORD) -data object SubBool: SubType(BaseDataType.BOOL) -data object SubFloat: SubType(BaseDataType.FLOAT) - - -class DataType private constructor(val base: BaseDataType, val sub: SubType?) { +class DataType private constructor(val base: BaseDataType, val sub: BaseDataType?) { init { if(base.isArray) { require(sub != null) if(base.isSplitWordArray) - require(sub.dt == BaseDataType.UWORD || sub.dt == BaseDataType.WORD) + require(sub == BaseDataType.UWORD || sub == BaseDataType.WORD) } else if(base==BaseDataType.STR) - require(sub?.dt==BaseDataType.UBYTE) { "STR subtype should be ubyte" } + require(sub==BaseDataType.UBYTE) { "string subtype should be ubyte" } else - require(sub == null) + require(sub == null) { "only string and array base types can have a subtype"} } override fun equals(other: Any?): Boolean { @@ -111,7 +86,7 @@ class DataType private constructor(val base: BaseDataType, val sub: SubType?) { BaseDataType.LONG to DataType(BaseDataType.LONG, null), BaseDataType.FLOAT to DataType(BaseDataType.FLOAT, null), BaseDataType.BOOL to DataType(BaseDataType.BOOL, null), - BaseDataType.STR to DataType(BaseDataType.STR, SubUnsignedByte), + BaseDataType.STR to DataType(BaseDataType.STR, BaseDataType.UBYTE), BaseDataType.UNDEFINED to DataType(BaseDataType.UNDEFINED, null) ) @@ -119,10 +94,14 @@ class DataType private constructor(val base: BaseDataType, val sub: SubType?) { fun arrayFor(elementDt: BaseDataType, splitwordarray: Boolean=true): DataType { val actualElementDt = if(elementDt==BaseDataType.STR) BaseDataType.UWORD else elementDt // array of strings is actually just an array of UWORD pointers - return if(splitwordarray && elementDt.isWord) - DataType(BaseDataType.ARRAY_SPLITW, SubType.forDt(actualElementDt)) - else - DataType(BaseDataType.ARRAY, SubType.forDt(actualElementDt)) + return if(splitwordarray && actualElementDt.isWord) + DataType(BaseDataType.ARRAY_SPLITW, actualElementDt) + else { + if(actualElementDt.isNumericOrBool && actualElementDt != BaseDataType.LONG) + DataType(BaseDataType.ARRAY, actualElementDt) + else + throw NoSuchElementException("invalid element dt "+elementDt) + } } } @@ -133,26 +112,26 @@ class DataType private constructor(val base: BaseDataType, val sub: SubType?) { fun elementType(): DataType = if(base.isArray || base==BaseDataType.STR) - forDt(sub!!.dt) + forDt(sub!!) else throw IllegalArgumentException("not an array") override fun toString(): String = when(base) { BaseDataType.ARRAY -> { when(sub) { - SubBool -> "bool[]" - SubFloat -> "float[]" - SubSignedByte -> "byte[]" - SubSignedWord -> "word[]" - SubUnsignedByte -> "ubyte[]" - SubUnsignedWord -> "uword[]" - null -> throw IllegalArgumentException("invalid sub type") + BaseDataType.BOOL -> "bool[]" + BaseDataType.FLOAT -> "float[]" + BaseDataType.BYTE -> "byte[]" + BaseDataType.WORD -> "word[]" + BaseDataType.UBYTE -> "ubyte[]" + BaseDataType.UWORD -> "uword[]" + else -> throw IllegalArgumentException("invalid sub type") } } BaseDataType.ARRAY_SPLITW -> { when(sub) { - SubSignedWord -> "word[] (split)" - SubUnsignedWord -> "uword[] (split)" + BaseDataType.WORD -> "word[] (split)" + BaseDataType.UWORD -> "uword[] (split)" else -> throw IllegalArgumentException("invalid sub type") } } @@ -170,19 +149,19 @@ class DataType private constructor(val base: BaseDataType, val sub: SubType?) { BaseDataType.STR -> "str" BaseDataType.ARRAY -> { when(sub) { - SubUnsignedByte -> "ubyte[" - SubUnsignedWord -> "@nosplit uword[" - SubBool -> "bool[" - SubSignedByte -> "byte[" - SubSignedWord -> "@nosplit word[" - SubFloat -> "float[" - null -> throw IllegalArgumentException("invalid sub type") + BaseDataType.UBYTE -> "ubyte[" + BaseDataType.UWORD -> "@nosplit uword[" + BaseDataType.BOOL -> "bool[" + BaseDataType.BYTE -> "byte[" + BaseDataType.WORD -> "@nosplit word[" + BaseDataType.FLOAT -> "float[" + else -> throw IllegalArgumentException("invalid sub type") } } BaseDataType.ARRAY_SPLITW -> { when(sub) { - SubUnsignedWord -> "uword[" - SubSignedWord -> "word[" + BaseDataType.UWORD -> "uword[" + BaseDataType.WORD -> "word[" else -> throw IllegalArgumentException("invalid sub type") } } @@ -228,22 +207,22 @@ class DataType private constructor(val base: BaseDataType, val sub: SubType?) { val isSigned = base.isSigned val isUnsigned = !base.isSigned val isArray = base.isArray - val isBoolArray = base.isArray && sub?.dt == BaseDataType.BOOL - val isByteArray = base.isArray && (sub?.dt == BaseDataType.UBYTE || sub?.dt == BaseDataType.BYTE) - val isUnsignedByteArray = base.isArray && sub?.dt == BaseDataType.UBYTE - val isSignedByteArray = base.isArray && sub?.dt == BaseDataType.BYTE - val isWordArray = base.isArray && (sub?.dt == BaseDataType.UWORD || sub?.dt == BaseDataType.WORD) - val isUnsignedWordArray = base.isArray && sub?.dt == BaseDataType.UWORD - val isSignedWordArray = base.isArray && sub?.dt == BaseDataType.WORD - val isFloatArray = base.isArray && sub?.dt == BaseDataType.FLOAT + val isBoolArray = base.isArray && sub == BaseDataType.BOOL + val isByteArray = base.isArray && (sub == BaseDataType.UBYTE || sub == BaseDataType.BYTE) + val isUnsignedByteArray = base.isArray && sub == BaseDataType.UBYTE + val isSignedByteArray = base.isArray && sub == BaseDataType.BYTE + val isWordArray = base.isArray && (sub == BaseDataType.UWORD || sub == BaseDataType.WORD) + val isUnsignedWordArray = base.isArray && sub == BaseDataType.UWORD + val isSignedWordArray = base.isArray && sub == BaseDataType.WORD + val isFloatArray = base.isArray && sub == BaseDataType.FLOAT val isString = base == BaseDataType.STR val isBool = base == BaseDataType.BOOL val isFloat = base == BaseDataType.FLOAT val isLong = base == BaseDataType.LONG - val isStringly = base == BaseDataType.STR || base == BaseDataType.UWORD || (base == BaseDataType.ARRAY && (sub?.dt == BaseDataType.UBYTE || sub?.dt == BaseDataType.BYTE)) + val isStringly = base == BaseDataType.STR || base == BaseDataType.UWORD || (base == BaseDataType.ARRAY && (sub == BaseDataType.UBYTE || sub == BaseDataType.BYTE)) val isSplitWordArray = base.isSplitWordArray - val isSplitUnsignedWordArray = base.isSplitWordArray && sub?.dt == BaseDataType.UWORD - val isSplitSignedWordArray = base.isSplitWordArray && sub?.dt == BaseDataType.WORD + val isSplitUnsignedWordArray = base.isSplitWordArray && sub == BaseDataType.UWORD + val isSplitSignedWordArray = base.isSplitWordArray && sub == BaseDataType.WORD val isIterable = base.isIterable val isPassByRef = base.isPassByRef val isPassByValue = base.isPassByValue diff --git a/codeCore/src/prog8/code/core/IMemSizer.kt b/codeCore/src/prog8/code/core/IMemSizer.kt index 214aed0d1..c611229c9 100644 --- a/codeCore/src/prog8/code/core/IMemSizer.kt +++ b/codeCore/src/prog8/code/core/IMemSizer.kt @@ -2,5 +2,14 @@ package prog8.code.core interface IMemSizer { fun memorySize(dt: DataType, numElements: Int?): Int - fun memorySize(dt: SubType): Int + + fun memorySize(dt: BaseDataType): Int { + if(dt.isPassByRef) + return memorySize(DataType.forDt(BaseDataType.UWORD), null) // a pointer size + try { + return memorySize(DataType.forDt(dt), null) + } catch (x: NoSuchElementException) { + throw IllegalArgumentException(x.message) + } + } } diff --git a/codeCore/src/prog8/code/target/AtariTarget.kt b/codeCore/src/prog8/code/target/AtariTarget.kt index e65038449..b56e8457c 100644 --- a/codeCore/src/prog8/code/target/AtariTarget.kt +++ b/codeCore/src/prog8/code/target/AtariTarget.kt @@ -15,23 +15,26 @@ class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { override fun memorySize(dt: DataType, numElements: Int?): Int { if(dt.isArray) { - require(numElements!=null) - return when(dt.sub?.dt) { + if(numElements==null) return 2 // treat it as a pointer size + return when(dt.sub) { BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements - BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2 + BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE + BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size") else -> throw IllegalArgumentException("invalid sub type") } } + else if (dt.isString) { + if(numElements!=null) return numElements // treat it as the size of the given string with the length + else return 2 // treat it as the size to store a string pointer + } return when { dt.isByteOrBool -> 1 * (numElements ?: 1) dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) + dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory") + dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") else -> 2 * (numElements ?: 1) } } - - override fun memorySize(dt: SubType): Int { - return memorySize(DataType.forDt(dt.dt), null) - } } diff --git a/codeCore/src/prog8/code/target/Neo6502Target.kt b/codeCore/src/prog8/code/target/Neo6502Target.kt index 07225daae..5b5ae9539 100644 --- a/codeCore/src/prog8/code/target/Neo6502Target.kt +++ b/codeCore/src/prog8/code/target/Neo6502Target.kt @@ -15,23 +15,26 @@ class Neo6502Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { override fun memorySize(dt: DataType, numElements: Int?): Int { if(dt.isArray) { - require(numElements!=null) - return when(dt.sub?.dt) { + if(numElements==null) return 2 // treat it as a pointer size + return when(dt.sub) { BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements - BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2 + BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE + BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size") else -> throw IllegalArgumentException("invalid sub type") } } + else if (dt.isString) { + if(numElements!=null) return numElements // treat it as the size of the given string with the length + else return 2 // treat it as the size to store a string pointer + } return when { dt.isByteOrBool -> 1 * (numElements ?: 1) dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) + dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory") + dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") else -> 2 * (numElements ?: 1) } } - - override fun memorySize(dt: SubType): Int { - return memorySize(DataType.forDt(dt.dt), null) - } } diff --git a/codeCore/src/prog8/code/target/VMTarget.kt b/codeCore/src/prog8/code/target/VMTarget.kt index f9736fdc5..102b237d9 100644 --- a/codeCore/src/prog8/code/target/VMTarget.kt +++ b/codeCore/src/prog8/code/target/VMTarget.kt @@ -14,23 +14,26 @@ class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { override fun memorySize(dt: DataType, numElements: Int?): Int { if(dt.isArray) { - require(numElements!=null) - return when(dt.sub?.dt) { + if(numElements==null) return 2 // treat it as a pointer size + return when(dt.sub) { BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements - BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2 + BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE + BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size") else -> throw IllegalArgumentException("invalid sub type") } } + else if (dt.isString) { + if(numElements!=null) return numElements // treat it as the size of the given string with the length + else return 2 // treat it as the size to store a string pointer + } + return when { dt.isByteOrBool -> 1 * (numElements ?: 1) dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) + dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory") + dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") else -> 2 * (numElements ?: 1) } } - - override fun memorySize(dt: SubType): Int { - return memorySize(DataType.forDt(dt.dt), null) - } - } \ No newline at end of file diff --git a/codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt b/codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt index 789067f79..4e474df3c 100644 --- a/codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt +++ b/codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt @@ -3,28 +3,31 @@ package prog8.code.target.cbm import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.IMemSizer -import prog8.code.core.SubType internal object CbmMemorySizer: IMemSizer { override fun memorySize(dt: DataType, numElements: Int?): Int { if(dt.isArray) { - require(numElements!=null) - return when(dt.sub?.dt) { + if(numElements==null) return 2 // treat it as a pointer size + return when(dt.sub) { BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements - BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2 + BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 BaseDataType.FLOAT-> numElements * Mflpt5.FLOAT_MEM_SIZE + BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size") else -> throw IllegalArgumentException("invalid sub type") } } + else if (dt.isString) { + if(numElements!=null) return numElements // treat it as the size of the given string with the length + else return 2 // treat it as the size to store a string pointer + } + return when { dt.isByteOrBool -> 1 * (numElements ?: 1) dt.isFloat -> Mflpt5.FLOAT_MEM_SIZE * (numElements ?: 1) + dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory") + dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") else -> 2 * (numElements ?: 1) } } - - override fun memorySize(dt: SubType): Int { - return memorySize(DataType.forDt(dt.dt), null) - } } \ No newline at end of file diff --git a/codeGenCpu6502/test/Dummies.kt b/codeGenCpu6502/test/Dummies.kt index 6d9b9d174..45a179bf1 100644 --- a/codeGenCpu6502/test/Dummies.kt +++ b/codeGenCpu6502/test/Dummies.kt @@ -7,7 +7,7 @@ internal object DummyMemsizer : IMemSizer { override fun memorySize(dt: DataType, numElements: Int?): Int { if(dt.isArray) { require(numElements != null) - return when(dt.sub?.dt) { + return when(dt.sub) { BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements BaseDataType.UWORD, BaseDataType.WORD -> numElements*2 BaseDataType.FLOAT -> numElements*5 @@ -21,8 +21,8 @@ internal object DummyMemsizer : IMemSizer { } } - override fun memorySize(dt: SubType): Int { - return memorySize(DataType.forDt(dt.dt), null) + override fun memorySize(dt: BaseDataType): Int { + return memorySize(DataType.forDt(dt), null) } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 3c8903e8b..92123260a 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -477,9 +477,8 @@ class IRCodeGen( } else -> { // iterate over regular array - val element = iterable.type.sub!! - val elementDt = element.dt - val elementSize = program.memsizer.memorySize(element) + val elementDt = iterable.type.sub!! + val elementSize = program.memsizer.memorySize(elementDt) val lengthBytes = iterableLength!! * elementSize addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) result += IRCodeChunk(loopLabel, null).also { diff --git a/codeGenIntermediate/test/Dummies.kt b/codeGenIntermediate/test/Dummies.kt index 2e4cccf51..73d7dcdaf 100644 --- a/codeGenIntermediate/test/Dummies.kt +++ b/codeGenIntermediate/test/Dummies.kt @@ -5,7 +5,7 @@ internal object DummyMemsizer : IMemSizer { override fun memorySize(dt: DataType, numElements: Int?): Int { if(dt.isArray || dt.isSplitWordArray) { require(numElements!=null) - return when(dt.sub?.dt) { + return when(dt.sub) { BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements BaseDataType.UWORD, BaseDataType.WORD -> numElements*2 BaseDataType.FLOAT -> numElements*5 @@ -19,8 +19,8 @@ internal object DummyMemsizer : IMemSizer { } } - override fun memorySize(dt: SubType): Int { - return memorySize(DataType.forDt(dt.dt), null) + override fun memorySize(dt: BaseDataType): Int { + return memorySize(DataType.forDt(dt), null) } } diff --git a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt index 8310e404d..8bdd43272 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -438,7 +438,7 @@ internal class ConstantIdentifierReplacer( } else { require(rangeType.sub!=null) ArrayLiteral(InferredTypes.InferredType.known(decl.datatype), - constRange.map { NumericLiteral(rangeType.sub!!.dt, it.toDouble(), decl.value!!.position) }.toTypedArray(), + constRange.map { NumericLiteral(rangeType.sub!!, it.toDouble(), decl.value!!.position) }.toTypedArray(), position = decl.value!!.position) } } diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index 7dc6c5628..02775fcfd 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -198,7 +198,7 @@ class AstPreprocessor(val program: Program, options.dontSplitWordArrays && decl.datatype.isSplitWordArray private fun makeUnSplitArray(decl: VarDecl): Iterable { - val splitDt = DataType.arrayFor(decl.datatype.sub!!.dt, false) + val splitDt = DataType.arrayFor(decl.datatype.sub!!, false) val newDecl = VarDecl( decl.type, decl.origin, splitDt, decl.zeropage, decl.splitwordarray, decl.arraysize, decl.name, emptyList(), decl.value?.copy(), decl.sharedWithAsm, decl.alignment, false, decl.position diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index 531f1bd3e..4890e10d8 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -743,8 +743,8 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr if(type.isSplitWordArray) { // ranges are never a split word array! when(type.sub) { - is SubSignedWord -> type = DataType.arrayFor(BaseDataType.WORD, false) - is SubUnsignedWord -> type = DataType.arrayFor(BaseDataType.UWORD, false) + BaseDataType.WORD -> type = DataType.arrayFor(BaseDataType.WORD, false) + BaseDataType.UWORD -> type = DataType.arrayFor(BaseDataType.UWORD, false) else -> { } } } diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index f3816a12f..0d1ec9b32 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -253,32 +253,27 @@ class TestMemory: FunSpec({ } context("memsizer") { - withData(VMTarget(), AtariTarget(), C64Target(), PETTarget(), AtariTarget(), C128Target()) { target -> - shouldThrow { - target.memorySize(SubType.forDt(BaseDataType.UNDEFINED)) + withData(VMTarget(), AtariTarget(), C64Target(), PETTarget(), AtariTarget(), C128Target(), Neo6502Target()) { target -> + shouldThrow { + target.memorySize(BaseDataType.UNDEFINED) } - shouldThrow { - target.memorySize(SubType.forDt(BaseDataType.LONG)) + shouldThrow { + target.memorySize(BaseDataType.LONG) } - shouldThrow { - target.memorySize(SubType.forDt(BaseDataType.STR)) - } - shouldThrow { - target.memorySize(SubType.forDt(BaseDataType.ARRAY)) - } - shouldThrow { - target.memorySize(SubType.forDt(BaseDataType.ARRAY_SPLITW)) - } - target.memorySize(SubType.forDt(BaseDataType.BOOL)) shouldBe 1 - target.memorySize(SubType.forDt(BaseDataType.BYTE)) shouldBe 1 - target.memorySize(SubType.forDt(BaseDataType.WORD)) shouldBe 2 - target.memorySize(SubType.forDt(BaseDataType.FLOAT)) shouldBe target.machine.FLOAT_MEM_SIZE + target.memorySize(BaseDataType.BOOL) shouldBe 1 + target.memorySize(BaseDataType.BYTE) shouldBe 1 + target.memorySize(BaseDataType.WORD) shouldBe 2 + target.memorySize(BaseDataType.FLOAT) shouldBe target.machine.FLOAT_MEM_SIZE - target.memorySize(DataType.forDt(BaseDataType.UNDEFINED), null) shouldBe 2 target.memorySize(DataType.forDt(BaseDataType.BOOL), null) shouldBe 1 target.memorySize(DataType.forDt(BaseDataType.WORD), null) shouldBe 2 target.memorySize(DataType.forDt(BaseDataType.FLOAT), null) shouldBe target.machine.FLOAT_MEM_SIZE + target.memorySize(DataType.forDt(BaseDataType.STR), null) shouldBe 2 + target.memorySize(DataType.forDt(BaseDataType.STR), 50) shouldBe 50 + target.memorySize(BaseDataType.STR) shouldBe 2 + target.memorySize(BaseDataType.ARRAY) shouldBe 2 + target.memorySize(BaseDataType.ARRAY_SPLITW) shouldBe 2 target.memorySize(DataType.arrayFor(BaseDataType.BOOL), 10) shouldBe 10 target.memorySize(DataType.arrayFor(BaseDataType.BYTE), 10) shouldBe 10 diff --git a/compiler/test/ast/TestVariousCompilerAst.kt b/compiler/test/ast/TestVariousCompilerAst.kt index 70d44db21..0b27dbe0d 100644 --- a/compiler/test/ast/TestVariousCompilerAst.kt +++ b/compiler/test/ast/TestVariousCompilerAst.kt @@ -15,7 +15,6 @@ import prog8.code.ast.* import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.Position -import prog8.code.core.SubType import prog8.code.target.C64Target import prog8.code.target.Cx16Target import prog8.code.target.VMTarget @@ -846,29 +845,7 @@ main { errors.errors[2] shouldEndWith "cannot assign to 'void', perhaps a void function call was intended" } - test("datatype subtype consistencies") { - shouldThrow { - SubType.forDt(BaseDataType.STR) - } - shouldThrow { - SubType.forDt(BaseDataType.UNDEFINED) - } - shouldThrow { - SubType.forDt(BaseDataType.ARRAY_SPLITW) - } - shouldThrow { - SubType.forDt(BaseDataType.ARRAY) - } - SubType.forDt(BaseDataType.FLOAT).dt shouldBe BaseDataType.FLOAT - } - test("datatype consistencies") { - shouldThrow { - DataType.forDt(BaseDataType.ARRAY) - } - shouldThrow { - DataType.forDt(BaseDataType.ARRAY_SPLITW) - } DataType.forDt(BaseDataType.UNDEFINED).isUndefined shouldBe true DataType.forDt(BaseDataType.LONG).isLong shouldBe true DataType.forDt(BaseDataType.WORD).isWord shouldBe true @@ -876,6 +853,19 @@ main { DataType.forDt(BaseDataType.BYTE).isByte shouldBe true DataType.forDt(BaseDataType.UBYTE).isByte shouldBe true + DataType.arrayFor(BaseDataType.UBYTE, true).isUnsignedByteArray shouldBe true + DataType.arrayFor(BaseDataType.FLOAT).isFloatArray shouldBe true + DataType.arrayFor(BaseDataType.UWORD).isUnsignedWordArray shouldBe true + DataType.arrayFor(BaseDataType.UWORD).isArray shouldBe true + DataType.arrayFor(BaseDataType.UWORD).isSplitWordArray shouldBe true + DataType.arrayFor(BaseDataType.UWORD, false).isSplitWordArray shouldBe false + + shouldThrow { + DataType.forDt(BaseDataType.ARRAY) + } + shouldThrow { + DataType.forDt(BaseDataType.ARRAY_SPLITW) + } shouldThrow { DataType.arrayFor(BaseDataType.ARRAY) } @@ -885,12 +875,6 @@ main { shouldThrow { DataType.arrayFor(BaseDataType.UNDEFINED) } - DataType.arrayFor(BaseDataType.UBYTE, true).isUnsignedByteArray shouldBe true - DataType.arrayFor(BaseDataType.FLOAT).isFloatArray shouldBe true - DataType.arrayFor(BaseDataType.UWORD).isUnsignedWordArray shouldBe true - DataType.arrayFor(BaseDataType.UWORD).isArray shouldBe true - DataType.arrayFor(BaseDataType.UWORD).isSplitWordArray shouldBe true - DataType.arrayFor(BaseDataType.UWORD, false).isSplitWordArray shouldBe false } test("array of strings becomes array of uword pointers") { diff --git a/compiler/test/helpers/Dummies.kt b/compiler/test/helpers/Dummies.kt index 0ece1def8..8fe541968 100644 --- a/compiler/test/helpers/Dummies.kt +++ b/compiler/test/helpers/Dummies.kt @@ -24,7 +24,7 @@ internal object DummyMemsizer : IMemSizer { override fun memorySize(dt: DataType, numElements: Int?): Int { if(dt.isArray || dt.isSplitWordArray) { require(numElements!=null) - return when(dt.sub?.dt) { + return when(dt.sub) { BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements BaseDataType.UWORD, BaseDataType.WORD -> numElements*2 BaseDataType.FLOAT -> numElements*5 @@ -38,8 +38,8 @@ internal object DummyMemsizer : IMemSizer { } } - override fun memorySize(dt: SubType): Int { - return memorySize(DataType.forDt(dt.dt), null) + override fun memorySize(dt: BaseDataType): Int { + return memorySize(DataType.forDt(dt), null) } } @@ -82,7 +82,7 @@ internal object DummyCompilationTarget : ICompilationTarget { throw NotImplementedError("dummy") } - override fun memorySize(dt: SubType): Int { + override fun memorySize(dt: BaseDataType): Int { throw NotImplementedError("dummy") } } diff --git a/compilerAst/src/prog8/ast/AstToplevel.kt b/compilerAst/src/prog8/ast/AstToplevel.kt index c32c2c907..a6909278f 100644 --- a/compilerAst/src/prog8/ast/AstToplevel.kt +++ b/compilerAst/src/prog8/ast/AstToplevel.kt @@ -385,6 +385,4 @@ fun defaultZero(dt: BaseDataType, position: Position) = when(dt) { else -> throw FatalAstException("can only determine default zero value for a numeric type") } -fun defaultZero(dt: SubType, position: Position) = defaultZero(dt.dt, position) - fun defaultZero(idt: InferredTypes.InferredType, position: Position) = defaultZero(idt.getOrUndef().base, position) \ No newline at end of file diff --git a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt index 016a5d790..d802763e0 100644 --- a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt +++ b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt @@ -83,7 +83,7 @@ object InferredTypes { type.isString -> InferredType.known(BaseDataType.STR) type.isLong -> InferredType.known(BaseDataType.LONG) type.isSplitWordArray -> { - when(type.sub?.dt) { + when(type.sub) { BaseDataType.UWORD -> InferredType.known(DataType.arrayFor(BaseDataType.UWORD, true)) BaseDataType.WORD -> InferredType.known(DataType.arrayFor(BaseDataType.WORD, true)) BaseDataType.STR -> InferredType.known(DataType.arrayFor(BaseDataType.STR, true)) @@ -91,7 +91,7 @@ object InferredTypes { } } type.isArray -> { - InferredType.known(DataType.arrayFor(type.sub!!.dt, false)) + InferredType.known(DataType.arrayFor(type.sub!!, false)) } else -> throw IllegalArgumentException("invalid type") } diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index fb4f6046a..bd6982291 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -285,8 +285,8 @@ class VarDecl(val type: VarDeclType, if(arrayDt.isSplitWordArray) { // autovars for array literals are NOT stored as a split word array! when(arrayDt.sub) { - is SubSignedWord -> arrayDt = DataType.arrayFor(BaseDataType.WORD, false) - is SubUnsignedWord -> arrayDt = DataType.arrayFor(BaseDataType.UWORD, false) + BaseDataType.WORD -> arrayDt = DataType.arrayFor(BaseDataType.WORD, false) + BaseDataType.UWORD -> arrayDt = DataType.arrayFor(BaseDataType.UWORD, false) else -> { } } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 09a5b7ba0..ec41cbcdc 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,6 +1,7 @@ TODO ==== +- add paypal donation button as well? - announce prog8 on the 6502.org site? ... @@ -9,6 +10,7 @@ TODO Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ +- Kotlin: can we use inline value classes in certain spots? - Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions - Compiling Libraries: improve ability to create library files in prog8; for instance there's still stuff injected into the start of the start() routine AND there is separate setup logic going on before calling it. @@ -20,6 +22,7 @@ Future Things and Ideas - [problematic due to using 64tass:] better support for building library programs, where unused .proc are NOT deleted from the assembly. Perhaps replace all uses of .proc/.pend/.endproc by .block/.bend will fix that with a compiler flag? But all library code written in asm uses .proc already..... (textual search/replace when writing the actual asm?) + Maybe propose a patch to 64tass itself that will treat .proc as .block ? Once new codegen is written that is based on the IR, this point is mostly moot anyway as that will have its own dead code removal on the IR level. - Allow normal subroutines to return multiple values as well (just as asmsubs already can) diff --git a/examples/test.p8 b/examples/test.p8 index c2f909057..ce2f21bff 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,31 +1,40 @@ -%import textio +%import sprites +%import palette %import math - %zeropage basicsafe %option no_sysinit main { sub start() { - str input = iso:"the quick brown fox jumps over the lazy dog" + word[128] xpos + word[128] ypos + for cx16.r2L in 0 to 127 { + sprites.init(cx16.r2L, 0, 0, sprites.SIZE_8, sprites.SIZE_8, sprites.COLORS_16, 0) + xpos[cx16.r2L] = math.rndw() & 511 as word + 64 + ypos[cx16.r2L] = math.rnd() + } - txt.print_uwhex(math.crc16(input, len(input)), true) - txt.nl() + repeat { + sys.waitvsync() + palette.set_color(6, $f00) - math.crc32(input, len(input)) + sprites.pos_batch(0, 128, &xpos, &ypos) - txt.print_uwhex(cx16.r15, true) - txt.print_uwhex(cx16.r14, false) - txt.nl() - - math.crc32_start() - for cx16.r0L in input - math.crc32_update(cx16.r0L) - uword hiw,low - hiw,low = math.crc32_end_result() - txt.print_uwhex(hiw, true) - txt.print_uwhex(low, false) - txt.nl() + palette.set_color(6, $0f0) + for cx16.r2L in 0 to 127 { + if cx16.r2L & 1 == 0 { + xpos[cx16.r2L] ++ + if xpos[cx16.r2L] > 640 + xpos[cx16.r2L] = 0 + } else { + ypos[cx16.r2L] ++ + if ypos[cx16.r2L] > 480 + ypos[cx16.r2L] = 0 + } + } + palette.set_color(6, $00f) + } } } diff --git a/gradle.properties b/gradle.properties index d1a0bc9ec..6168ceaad 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ org.gradle.console=rich org.gradle.parallel=true org.gradle.daemon=true kotlin.code.style=official -version=11.0 +version=11.1-SNAPSHOT diff --git a/intermediate/src/prog8/intermediate/Utils.kt b/intermediate/src/prog8/intermediate/Utils.kt index bf2841cdf..6dcedea69 100644 --- a/intermediate/src/prog8/intermediate/Utils.kt +++ b/intermediate/src/prog8/intermediate/Utils.kt @@ -18,7 +18,7 @@ fun DataType.irTypeString(length: Int?): String { BaseDataType.FLOAT -> "float" BaseDataType.STR -> "ubyte[$lengthStr]" // here string doesn't exist as a seperate datatype anymore BaseDataType.ARRAY -> { - when(this.sub?.dt) { + when(this.sub) { BaseDataType.UBYTE -> "ubyte[$lengthStr]" BaseDataType.UWORD -> "uword[$lengthStr]" BaseDataType.BYTE -> "byte[$lengthStr]" @@ -29,7 +29,7 @@ fun DataType.irTypeString(length: Int?): String { } } BaseDataType.ARRAY_SPLITW -> { - when(this.sub?.dt) { + when(this.sub) { BaseDataType.UWORD -> "uword[$lengthStr]" // should be 2 separate byte arrays by now really? BaseDataType.WORD -> "word[$lengthStr]" // should be 2 separate byte arrays by now really? else -> throw IllegalArgumentException("invalid sub type")