diff --git a/codeCore/src/prog8/code/SymbolTable.kt b/codeCore/src/prog8/code/SymbolTable.kt index c708c7731..fd860ea5a 100644 --- a/codeCore/src/prog8/code/SymbolTable.kt +++ b/codeCore/src/prog8/code/SymbolTable.kt @@ -208,25 +208,25 @@ class StStaticVariable(name: String, require(initializationArrayValue.isEmpty() ||initializationArrayValue.size==length) } if(initializationNumericValue!=null) { - require(dt in NumericDatatypes || dt==DataType.BOOL) + require(dt.isNumericOrBool) } if(initializationArrayValue!=null) { - require(dt in ArrayDatatypes) - require(length==initializationArrayValue.size) + require(dt.isArray) + require(length == initializationArrayValue.size) } if(initializationStringValue!=null) { - require(dt == DataType.STR) - require(length == initializationStringValue.first.length+1) + require(dt.isString) + require(length == initializationStringValue.first.length + 1) } if(align > 0) { - require(dt == DataType.STR || dt in ArrayDatatypes) + require(dt.isString || dt.isArray) require(zpwish != ZeropageWish.REQUIRE_ZEROPAGE && zpwish != ZeropageWish.PREFER_ZEROPAGE) } } } -class StConstant(name: String, val dt: DataType, val value: Double, astNode: PtNode) : +class StConstant(name: String, val dt: BaseDataType, val value: Double, astNode: PtNode) : StNode(name, StNodeType.CONSTANT, astNode) @@ -238,8 +238,8 @@ class StMemVar(name: String, StNode(name, StNodeType.MEMVAR, astNode) { init{ - require(dt!=DataType.BOOL && dt!=DataType.ARRAY_BOOL) - if(dt in ArrayDatatypes || dt == DataType.STR) + require(!dt.isBool && !dt.isBoolArray) + if(dt.isStringly && !dt.isWord) requireNotNull(length) } } diff --git a/codeCore/src/prog8/code/SymbolTableMaker.kt b/codeCore/src/prog8/code/SymbolTableMaker.kt index c182c9d67..a1dd8574f 100644 --- a/codeCore/src/prog8/code/SymbolTableMaker.kt +++ b/codeCore/src/prog8/code/SymbolTableMaker.kt @@ -10,7 +10,8 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp val st = SymbolTable(program) BuiltinFunctions.forEach { - st.add(StNode(it.key, StNodeType.BUILTINFUNC, PtIdentifier(it.key, it.value.returnType ?: DataType.UNDEFINED, Position.DUMMY))) + val dt = DataType.forDt(it.value.returnType ?: BaseDataType.UNDEFINED) + st.add(StNode(it.key, StNodeType.BUILTINFUNC, PtIdentifier(it.key, dt, Position.DUMMY))) } val scopestack = ArrayDeque() @@ -22,10 +23,10 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp if(options.compTarget.name != VMTarget.NAME) { listOf( - PtMemMapped("P8ZP_SCRATCH_B1", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_B1, null, Position.DUMMY), - PtMemMapped("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY), - PtMemMapped("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY), - PtMemMapped("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_B1, null, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_REG", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_W1", DataType.forDt(BaseDataType.UWORD), options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD), options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY), ).forEach { it.parent = program st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it)) @@ -46,7 +47,8 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp StNode(node.name, StNodeType.BLOCK, node) } is PtConstant -> { - StConstant(node.name, node.type, node.value, node) + require(node.type.isNumericOrBool) + StConstant(node.name, node.type.base, node.value, node) } is PtLabel -> { StNode(node.name, StNodeType.LABEL, node) diff --git a/codeCore/src/prog8/code/ast/AstExpressions.kt b/codeCore/src/prog8/code/ast/AstExpressions.kt index 432d6523f..cc9f79dc9 100644 --- a/codeCore/src/prog8/code/ast/AstExpressions.kt +++ b/codeCore/src/prog8/code/ast/AstExpressions.kt @@ -1,7 +1,7 @@ package prog8.code.ast import prog8.code.core.* -import java.util.Objects +import java.util.* import kotlin.math.abs import kotlin.math.truncate @@ -9,7 +9,7 @@ import kotlin.math.truncate sealed class PtExpression(val type: DataType, position: Position) : PtNode(position) { init { - if(type==DataType.UNDEFINED) { + if(type.isUndefined) { @Suppress("LeakingThis") when(this) { is PtBuiltinFunctionCall -> { /* void function call */ } @@ -66,19 +66,17 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit } } - infix fun isSameAs(target: PtAssignTarget): Boolean { - 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 && this.splitWords==target.array!!.splitWords - } - else -> false + infix fun isSameAs(target: PtAssignTarget): Boolean = 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 && this.splitWords==target.array!!.splitWords + } + else -> false } fun asConstInteger(): Int? = (this as? PtNumber)?.number?.toInt() ?: (this as? PtBool)?.asInt() @@ -139,7 +137,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit */ } -class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) { +class PtAddressOf(position: Position) : PtExpression(DataType.forDt(BaseDataType.UWORD), position) { val identifier: PtIdentifier get() = children[0] as PtIdentifier val arrayIndexExpr: PtExpression? @@ -156,10 +154,10 @@ class PtArrayIndexer(elementType: DataType, position: Position): PtExpression(el val index: PtExpression get() = children[1] as PtExpression val splitWords: Boolean - get() = variable.type in SplitWordArrayTypes + get() = variable.type.isSplitWordArray init { - require(elementType in NumericDatatypesWithBoolean) + require(elementType.isNumericOrBool) } } @@ -185,7 +183,7 @@ class PtBuiltinFunctionCall(val name: String, position: Position) : PtExpression(type, position) { init { if(!void) - require(type!=DataType.UNDEFINED) + require(!type.isUndefined) } val args: List @@ -201,9 +199,9 @@ class PtBinaryExpression(val operator: String, type: DataType, position: Positio init { if(operator in ComparisonOperators + LogicalOperators) - require(type==DataType.BOOL) + require(type.isBool) else - require(type!=DataType.BOOL) { "no bool allowed for this operator $operator"} + require(!type.isBool) { "no bool allowed for this operator $operator"} } } @@ -218,7 +216,7 @@ class PtIfExpression(type: DataType, position: Position): PtExpression(type, pos } -class PtContainmentCheck(position: Position): PtExpression(DataType.BOOL, position) { +class PtContainmentCheck(position: Position): PtExpression(DataType.forDt(BaseDataType.BOOL), position) { val needle: PtExpression get() = children[0] as PtExpression val haystackHeapVar: PtIdentifier? @@ -241,7 +239,7 @@ class PtFunctionCall(val name: String, get() = children.map { it as PtExpression } init { - if(void) require(type==DataType.UNDEFINED) { + if(void) require(type.isUndefined) { "void fcall should have undefined datatype" } // note: non-void calls can have UNDEFINED type: is if they return more than 1 value @@ -258,13 +256,13 @@ class PtIdentifier(val name: String, type: DataType, position: Position) : PtExp } -class PtMemoryByte(position: Position) : PtExpression(DataType.UBYTE, position) { +class PtMemoryByte(position: Position) : PtExpression(DataType.forDt(BaseDataType.UBYTE), position) { val address: PtExpression get() = children.single() as PtExpression } -class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.BOOL, position) { +class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.forDt(BaseDataType.BOOL), position) { override fun hashCode(): Int = Objects.hash(type, value) override fun equals(other: Any?): Boolean { @@ -279,28 +277,28 @@ class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.BOO } -class PtNumber(type: DataType, val number: Double, position: Position) : PtExpression(type, position) { +class PtNumber(type: BaseDataType, val number: Double, position: Position) : PtExpression(DataType.forDt(type), position) { companion object { fun fromBoolean(bool: Boolean, position: Position): PtNumber = - PtNumber(DataType.UBYTE, if(bool) 1.0 else 0.0, position) + PtNumber(BaseDataType.UBYTE, if(bool) 1.0 else 0.0, position) } init { - if(type==DataType.BOOL) + if(type==BaseDataType.BOOL) throw IllegalArgumentException("use PtBool instead") - if(type!=DataType.FLOAT) { + if(type!=BaseDataType.FLOAT) { val trunc = truncate(number) if (trunc != number) throw IllegalArgumentException("refused truncating of float to avoid loss of precision @$position") } when(type) { - DataType.UBYTE -> require(number in 0.0..255.0) - DataType.BYTE -> require(number in -128.0..127.0) - DataType.UWORD -> require(number in 0.0..65535.0) - DataType.WORD -> require(number in -32728.0..32767.0) - DataType.LONG -> require(number in -2147483647.0..2147483647.0) - else -> {} + BaseDataType.UBYTE -> require(number in 0.0..255.0) + BaseDataType.BYTE -> require(number in -128.0..127.0) + BaseDataType.UWORD -> require(number in 0.0..65535.0) + BaseDataType.WORD -> require(number in -32728.0..32767.0) + BaseDataType.LONG -> require(number in -2147483647.0..2147483647.0) + else -> require(type.isNumeric) { "numeric literal type should be numeric: $type" } } } @@ -309,7 +307,7 @@ class PtNumber(type: DataType, val number: Double, position: Position) : PtExpre override fun equals(other: Any?): Boolean { return if(other==null || other !is PtNumber) false - else if(type!=DataType.BOOL && other.type!=DataType.BOOL) + else if(!type.isBool && !other.type.isBool) number==other.number else type==other.type && number==other.number @@ -368,7 +366,7 @@ class PtRange(type: DataType, position: Position) : PtExpression(type, position) } -class PtString(val value: String, val encoding: Encoding, position: Position) : PtExpression(DataType.STR, position) { +class PtString(val value: String, val encoding: Encoding, position: Position) : PtExpression(DataType.forDt(BaseDataType.STR), position) { override fun hashCode(): Int = Objects.hash(value, encoding) override fun equals(other: Any?): Boolean { if(other==null || other !is PtString) @@ -378,7 +376,7 @@ class PtString(val value: String, val encoding: Encoding, position: Position) : } -class PtTypeCast(type: DataType, position: Position) : PtExpression(type, position) { +class PtTypeCast(type: BaseDataType, position: Position) : PtExpression(DataType.forDt(type), position) { val value: PtExpression get() = children.single() as PtExpression } diff --git a/codeCore/src/prog8/code/ast/AstPrinter.kt b/codeCore/src/prog8/code/ast/AstPrinter.kt index ea072b665..2cead573a 100644 --- a/codeCore/src/prog8/code/ast/AstPrinter.kt +++ b/codeCore/src/prog8/code/ast/AstPrinter.kt @@ -1,13 +1,15 @@ package prog8.code.ast -import prog8.code.core.* +import prog8.code.core.DataType +import prog8.code.core.escape +import prog8.code.core.toHex /** * Produces readable text from a [PtNode] (AST node, usually starting with PtProgram as root), * passing it as a String to the specified receiver function. */ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Unit) { - fun type(dt: DataType) = "!${dt.name.lowercase()}!" + fun type(dt: DataType) = "!${dt}!" fun txt(node: PtNode): String { return when(node) { is PtAlign -> "%align ${node.align}" @@ -48,14 +50,14 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni is PtIrRegister -> "IRREG#${node.register} ${type(node.type)}" is PtMemoryByte -> "@()" is PtNumber -> { - val numstr = if(node.type == DataType.FLOAT) node.number.toString() else node.number.toHex() + val numstr = if(node.type.isFloat) node.number.toString() else node.number.toHex() "$numstr ${type(node.type)}" } is PtBool -> node.value.toString() is PtPrefix -> node.operator is PtRange -> "" is PtString -> "\"${node.value.escape()}\"" - is PtTypeCast -> "as ${node.type.name.lowercase()}" + is PtTypeCast -> "as ${node.type}" is PtForLoop -> "for" is PtIfElse -> "ifelse" is PtIncludeBinary -> "%incbin '${node.file}', ${node.offset}, ${node.length}" @@ -103,21 +105,20 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni "\nblock '${node.name}' $addr" } is PtConstant -> { - val value = when(node.type) { - DataType.BOOL -> if(node.value==0.0) "false" else "true" - in IntegerDatatypes -> node.value.toInt().toString() + val value = when { + node.type.isBool -> if(node.value==0.0) "false" else "true" + node.type.isInteger -> node.value.toInt().toString() else -> node.value.toString() } - "const ${node.type.name.lowercase()} ${node.name} = $value" + "const ${node.type} ${node.name} = $value" } is PtLabel -> "${node.name}:" is PtMemMapped -> { - if(node.type in ArrayDatatypes) { + if(node.type.isArray) { val arraysize = if(node.arraySize==null) "" else node.arraySize.toString() - val eltType = ArrayToElementTypes.getValue(node.type) - "&${eltType.name.lowercase()}[$arraysize] ${node.name} = ${node.address.toHex()}" + "&${node.type.elementType()}[$arraysize] ${node.name} = ${node.address.toHex()}" } else { - "&${node.type.name.lowercase()} ${node.name} = ${node.address.toHex()}" + "&${node.type} ${node.name} = ${node.address.toHex()}" } } is PtSub -> { @@ -127,11 +128,11 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni } var str = "sub ${node.name}($params) " if(node.returntype!=null) - str += "-> ${node.returntype.name.lowercase()}" + str += "-> ${node.returntype}" str } is PtVariable -> { - val split = if(node.type in SplitWordArrayTypes) "@split" else "" + val split = if(node.type.isSplitWordArray) "@split" else "" val align = when(node.align) { 0u -> "" 2u -> "@alignword" @@ -140,15 +141,15 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni else -> throw IllegalArgumentException("invalid alignment size") } val str = if(node.arraySize!=null) { - val eltType = ArrayToElementTypes.getValue(node.type) - "${eltType.name.lowercase()}[${node.arraySize}] $split $align ${node.name}" + val eltType = node.type.elementType() + "${eltType}[${node.arraySize}] $split $align ${node.name}" } - else if(node.type in ArrayDatatypes) { - val eltType = ArrayToElementTypes.getValue(node.type) - "${eltType.name.lowercase()}[] $split $align ${node.name}" + else if(node.type.isArray) { + val eltType = node.type.elementType() + "${eltType}[] $split $align ${node.name}" } else - "${node.type.name.lowercase()} ${node.name}" + "${node.type} ${node.name}" if(node.value!=null) str + " = " + txt(node.value) else @@ -161,7 +162,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni is PtReturn -> "return" is PtSubroutineParameter -> { val reg = if(node.register!=null) "@${node.register}" else "" - "${node.type.name.lowercase()} ${node.name} $reg" + "${node.type} ${node.name} $reg" } is PtWhen -> "when" is PtWhenChoice -> { diff --git a/codeCore/src/prog8/code/ast/AstStatements.kt b/codeCore/src/prog8/code/ast/AstStatements.kt index 6de67dbac..bb5b142ac 100644 --- a/codeCore/src/prog8/code/ast/AstStatements.kt +++ b/codeCore/src/prog8/code/ast/AstStatements.kt @@ -30,9 +30,9 @@ class PtSub( ) : PtNamedNode(name, position), IPtSubroutine, IPtStatementContainer { init { // params and return value should not be str - if(parameters.any{ it.type !in NumericDatatypes && it.type!=DataType.BOOL }) + if(parameters.any{ !it.type.isNumericOrBool }) throw AssemblyError("non-numeric/non-bool parameter") - if(returntype!=null && returntype !in NumericDatatypes && returntype!=DataType.BOOL) + if(returntype!=null && !returntype.isNumericOrBool) throw AssemblyError("non-numeric/non-bool returntype $returntype") parameters.forEach { it.parent=this } } @@ -172,7 +172,7 @@ class PtConstant(name: String, override val type: DataType, val value: Double, p class PtMemMapped(name: String, override val type: DataType, val address: UInt, val arraySize: UInt?, position: Position) : PtNamedNode(name, position), IPtVariable { init { - require(type!=DataType.BOOL && type!=DataType.ARRAY_BOOL) + require(!type.isBool && !type.isBoolArray) } } diff --git a/codeCore/src/prog8/code/core/BuiltinFunctions.kt b/codeCore/src/prog8/code/core/BuiltinFunctions.kt index f1dc37f3a..d8f480f72 100644 --- a/codeCore/src/prog8/code/core/BuiltinFunctions.kt +++ b/codeCore/src/prog8/code/core/BuiltinFunctions.kt @@ -1,7 +1,7 @@ package prog8.code.core -class ReturnConvention(val dt: DataType?, val reg: RegisterOrPair?) -class ParamConvention(val dt: DataType, val reg: RegisterOrPair?, val variable: Boolean) +class ReturnConvention(val dt: BaseDataType?, val reg: RegisterOrPair?) +class ParamConvention(val dt: BaseDataType, val reg: RegisterOrPair?, val variable: Boolean) class CallConvention(val params: List, val returns: ReturnConvention) { override fun toString(): String { val paramConvs = params.mapIndexed { index, it -> @@ -21,26 +21,34 @@ class CallConvention(val params: List, val returns: ReturnConve } } -class FParam(val name: String, vararg val possibleDatatypes: DataType) +class FParam(val name: String, vararg val possibleDatatypes: BaseDataType) + + +private val IterableDatatypes = arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW) +private val IntegerDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG) +private val NumericDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT) +private val ByteDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE) +private val ArrayDatatypes = arrayOf(BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW) + class FSignature(val pure: Boolean, // does it have side effects? - val returnType: DataType?, + val returnType: BaseDataType?, vararg val parameters: FParam) { - fun callConvention(actualParamTypes: List): CallConvention { + fun callConvention(actualParamTypes: List): CallConvention { val returns: ReturnConvention = when (returnType) { - DataType.UBYTE, DataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A) - DataType.UWORD, DataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY) - DataType.FLOAT -> ReturnConvention(returnType, RegisterOrPair.FAC1) - in PassByReferenceDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY) + BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A) + BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY) + BaseDataType.FLOAT -> ReturnConvention(returnType, RegisterOrPair.FAC1) + in IterableDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY) null -> ReturnConvention(null, null) else -> { // return type depends on arg type when (val paramType = actualParamTypes.first()) { - DataType.UBYTE, DataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A) - DataType.UWORD, DataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY) - DataType.FLOAT -> ReturnConvention(paramType, RegisterOrPair.FAC1) - in PassByReferenceDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY) + BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A) + BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY) + BaseDataType.FLOAT -> ReturnConvention(paramType, RegisterOrPair.FAC1) + in IterableDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY) else -> ReturnConvention(paramType, null) } } @@ -53,21 +61,21 @@ class FSignature(val pure: Boolean, // does it have side effects? // this avoids repeated code for every caller to store the value in the subroutine's argument variable. // (that store is still done, but only coded once at the start at the subroutine itself rather than at every call site). 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) // NOTE: for builtin functions, floating point arguments are passed by reference (so you get a pointer in AY) - in PassByReferenceDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false) + BaseDataType.UBYTE, BaseDataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false) + BaseDataType.UWORD, BaseDataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false) + BaseDataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) // NOTE: for builtin functions, floating point arguments are passed by reference (so you get a pointer in AY) + in IterableDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false) else -> ParamConvention(paramType, null, false) } CallConvention(listOf(paramConv), returns) } - actualParamTypes.size==2 && (actualParamTypes[0] in ByteDatatypes && actualParamTypes[1] in WordDatatypes) -> { + actualParamTypes.size==2 && (actualParamTypes[0] in ByteDatatypes && actualParamTypes[1].isWord) -> { TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet") } - actualParamTypes.size==2 && (actualParamTypes[0] in WordDatatypes && actualParamTypes[1] in ByteDatatypes) -> { + actualParamTypes.size==2 && (actualParamTypes[0].isWord && actualParamTypes[1].isByte) -> { TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet") } - actualParamTypes.size==3 && actualParamTypes.all { it in ByteDatatypes } -> { + actualParamTypes.size==3 && actualParamTypes.all { it.isByte } -> { TODO("opportunity to pass 3 byte arguments in A,Y and X registers but not implemented yet") } else -> { @@ -80,65 +88,65 @@ class FSignature(val pure: Boolean, // does it have side effects? } val BuiltinFunctions: Map = mapOf( - "setlsb" to FSignature(false, null, FParam("variable", DataType.WORD, DataType.UWORD), FParam("value", DataType.BYTE, DataType.UBYTE)), - "setmsb" to FSignature(false, null, FParam("variable", DataType.WORD, DataType.UWORD), FParam("value", DataType.BYTE, DataType.UBYTE)), - "rol" to FSignature(false, null, FParam("item", DataType.UBYTE, DataType.UWORD)), - "ror" to FSignature(false, null, FParam("item", DataType.UBYTE, DataType.UWORD)), - "rol2" to FSignature(false, null, FParam("item", DataType.UBYTE, DataType.UWORD)), - "ror2" to FSignature(false, null, FParam("item", DataType.UBYTE, DataType.UWORD)), + "setlsb" to FSignature(false, null, FParam("variable", BaseDataType.WORD, BaseDataType.UWORD), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)), + "setmsb" to FSignature(false, null, FParam("variable", BaseDataType.WORD, BaseDataType.UWORD), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)), + "rol" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)), + "ror" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)), + "rol2" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)), + "ror2" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)), "cmp" to FSignature(false, null, FParam("value1", *IntegerDatatypes), FParam("value2", *NumericDatatypes)), // cmp returns a status in the carry flag, but not a proper return value - "prog8_lib_stringcompare" to FSignature(true, DataType.BYTE, FParam("str1", DataType.STR), FParam("str2", DataType.STR)), - "prog8_lib_square_byte" to FSignature(true, DataType.UBYTE, FParam("value", DataType.BYTE, DataType.UBYTE)), - "prog8_lib_square_word" to FSignature(true, DataType.UWORD, FParam("value", DataType.WORD, DataType.UWORD)), - "prog8_ifelse_bittest_set" to FSignature(true, DataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", DataType.UBYTE)), - "prog8_ifelse_bittest_notset" to FSignature(true, DataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", DataType.UBYTE)), + "prog8_lib_stringcompare" to FSignature(true, BaseDataType.BYTE, FParam("str1", BaseDataType.STR), FParam("str2", BaseDataType.STR)), + "prog8_lib_square_byte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)), + "prog8_lib_square_word" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.WORD, BaseDataType.UWORD)), + "prog8_ifelse_bittest_set" to FSignature(true, BaseDataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", BaseDataType.UBYTE)), + "prog8_ifelse_bittest_notset" to FSignature(true, BaseDataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", BaseDataType.UBYTE)), "abs" to FSignature(true, null, FParam("value", *NumericDatatypes)), - "abs__byte" to FSignature(true, DataType.BYTE, FParam("value", DataType.BYTE)), - "abs__word" to FSignature(true, DataType.WORD, FParam("value", DataType.WORD)), - "abs__float" to FSignature(true, DataType.FLOAT, FParam("value", DataType.FLOAT)), - "len" to FSignature(true, DataType.UWORD, FParam("values", *IterableDatatypes)), - "sizeof" to FSignature(true, DataType.UBYTE, FParam("object", *DataType.entries.toTypedArray())), - "sgn" to FSignature(true, DataType.BYTE, FParam("value", *NumericDatatypes)), + "abs__byte" to FSignature(true, BaseDataType.BYTE, FParam("value", BaseDataType.BYTE)), + "abs__word" to FSignature(true, BaseDataType.WORD, FParam("value", BaseDataType.WORD)), + "abs__float" to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)), + "len" to FSignature(true, BaseDataType.UWORD, FParam("values", *IterableDatatypes)), + "sizeof" to FSignature(true, BaseDataType.UBYTE, FParam("object", *BaseDataType.entries.toTypedArray())), + "sgn" to FSignature(true, BaseDataType.BYTE, FParam("value", *NumericDatatypes)), "sqrt" to FSignature(true, null, FParam("value", *NumericDatatypes)), - "sqrt__ubyte" to FSignature(true, DataType.UBYTE, FParam("value", DataType.UBYTE)), - "sqrt__uword" to FSignature(true, DataType.UBYTE, FParam("value", DataType.UWORD)), - "sqrt__float" to FSignature(true, DataType.FLOAT, FParam("value", DataType.FLOAT)), - "divmod" to FSignature(false, null, FParam("dividend", DataType.UBYTE, DataType.UWORD), FParam("divisor", DataType.UBYTE, DataType.UWORD), FParam("quotient", DataType.UBYTE, DataType.UWORD), FParam("remainder", DataType.UBYTE, DataType.UWORD)), - "divmod__ubyte" to FSignature(false, null, FParam("dividend", DataType.UBYTE), FParam("divisor", DataType.UBYTE), FParam("quotient", DataType.UBYTE), FParam("remainder", DataType.UBYTE)), - "divmod__uword" to FSignature(false, null, FParam("dividend", DataType.UWORD), FParam("divisor", DataType.UWORD), FParam("quotient", DataType.UWORD), FParam("remainder", DataType.UWORD)), - "lsb" to FSignature(true, DataType.UBYTE, FParam("value", DataType.UWORD, DataType.WORD, DataType.LONG)), - "lsw" to FSignature(true, DataType.UWORD, FParam("value", DataType.UWORD, DataType.WORD, DataType.LONG)), - "msb" to FSignature(true, DataType.UBYTE, FParam("value", DataType.UWORD, DataType.WORD, DataType.LONG)), - "msw" to FSignature(true, DataType.UWORD, FParam("value", DataType.UWORD, DataType.WORD, DataType.LONG)), - "mkword" to FSignature(true, DataType.UWORD, FParam("msb", DataType.UBYTE), FParam("lsb", DataType.UBYTE)), - "clamp" to FSignature(true, null, FParam("value", DataType.BYTE), FParam("minimum", DataType.BYTE), FParam("maximum", DataType.BYTE)), - "clamp__byte" to FSignature(true, DataType.BYTE, FParam("value", DataType.BYTE), FParam("minimum", DataType.BYTE), FParam("maximum", DataType.BYTE)), - "clamp__ubyte" to FSignature(true, DataType.UBYTE, FParam("value", DataType.UBYTE), FParam("minimum", DataType.UBYTE), FParam("maximum", DataType.UBYTE)), - "clamp__word" to FSignature(true, DataType.WORD, FParam("value", DataType.WORD), FParam("minimum", DataType.WORD), FParam("maximum", DataType.WORD)), - "clamp__uword" to FSignature(true, DataType.UWORD, FParam("value", DataType.UWORD), FParam("minimum", DataType.UWORD), FParam("maximum", DataType.UWORD)), - "min" to FSignature(true, null, FParam("val1", DataType.BYTE), FParam("val2", DataType.BYTE)), - "min__byte" to FSignature(true, DataType.BYTE, FParam("val1", DataType.BYTE), FParam("val2", DataType.BYTE)), - "min__ubyte" to FSignature(true, DataType.UBYTE, FParam("val1", DataType.UBYTE), FParam("val2", DataType.UBYTE)), - "min__word" to FSignature(true, DataType.WORD, FParam("val1", DataType.WORD), FParam("val2", DataType.WORD)), - "min__uword" to FSignature(true, DataType.UWORD, FParam("val1", DataType.UWORD), FParam("val2", DataType.UWORD)), - "max" to FSignature(true, null, FParam("val1", DataType.BYTE), FParam("val2", DataType.BYTE)), - "max__byte" to FSignature(true, DataType.BYTE, FParam("val1", DataType.BYTE), FParam("val2", DataType.BYTE)), - "max__ubyte" to FSignature(true, DataType.UBYTE, FParam("val1", DataType.UBYTE), FParam("val2", DataType.UBYTE)), - "max__word" to FSignature(true, DataType.WORD, FParam("val1", DataType.WORD), FParam("val2", DataType.WORD)), - "max__uword" to FSignature(true, DataType.UWORD, FParam("val1", DataType.UWORD), FParam("val2", DataType.UWORD)), - "peek" to FSignature(true, DataType.UBYTE, FParam("address", DataType.UWORD)), - "peekw" to FSignature(true, DataType.UWORD, FParam("address", DataType.UWORD)), - "peekf" to FSignature(true, DataType.FLOAT, FParam("address", DataType.UWORD)), - "poke" to FSignature(false, null, FParam("address", DataType.UWORD), FParam("value", DataType.UBYTE)), - "pokew" to FSignature(false, null, FParam("address", DataType.UWORD), FParam("value", DataType.UWORD)), - "pokef" to FSignature(false, null, FParam("address", DataType.UWORD), FParam("value", DataType.FLOAT)), - "pokemon" to FSignature(false, DataType.UBYTE, FParam("address", DataType.UWORD), FParam("value", DataType.UBYTE)), + "sqrt__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE)), + "sqrt__uword" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD)), + "sqrt__float" to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)), + "divmod" to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("divisor", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("quotient", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("remainder", BaseDataType.UBYTE, BaseDataType.UWORD)), + "divmod__ubyte" to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE), FParam("divisor", BaseDataType.UBYTE), FParam("quotient", BaseDataType.UBYTE), FParam("remainder", BaseDataType.UBYTE)), + "divmod__uword" to FSignature(false, null, FParam("dividend", BaseDataType.UWORD), FParam("divisor", BaseDataType.UWORD), FParam("quotient", BaseDataType.UWORD), FParam("remainder", BaseDataType.UWORD)), + "lsb" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)), + "lsw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)), + "msb" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)), + "msw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)), + "mkword" to FSignature(true, BaseDataType.UWORD, FParam("msb", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)), + "clamp" to FSignature(true, null, FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)), + "clamp__byte" to FSignature(true, BaseDataType.BYTE, FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)), + "clamp__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE), FParam("minimum", BaseDataType.UBYTE), FParam("maximum", BaseDataType.UBYTE)), + "clamp__word" to FSignature(true, BaseDataType.WORD, FParam("value", BaseDataType.WORD), FParam("minimum", BaseDataType.WORD), FParam("maximum", BaseDataType.WORD)), + "clamp__uword" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD), FParam("minimum", BaseDataType.UWORD), FParam("maximum", BaseDataType.UWORD)), + "min" to FSignature(true, null, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)), + "min__byte" to FSignature(true, BaseDataType.BYTE, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)), + "min__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)), + "min__word" to FSignature(true, BaseDataType.WORD, FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)), + "min__uword" to FSignature(true, BaseDataType.UWORD, FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)), + "max" to FSignature(true, null, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)), + "max__byte" to FSignature(true, BaseDataType.BYTE, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)), + "max__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)), + "max__word" to FSignature(true, BaseDataType.WORD, FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)), + "max__uword" to FSignature(true, BaseDataType.UWORD, FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)), + "peek" to FSignature(true, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD)), + "peekw" to FSignature(true, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)), + "peekf" to FSignature(true, BaseDataType.FLOAT, FParam("address", BaseDataType.UWORD)), + "poke" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)), + "pokew" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UWORD)), + "pokef" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.FLOAT)), + "pokemon" to FSignature(false, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)), "rsave" to FSignature(false, null), "rrestore" to FSignature(false, null), - "memory" to FSignature(true, DataType.UWORD, FParam("name", DataType.STR), FParam("size", DataType.UWORD), FParam("alignment", DataType.UWORD)), - "callfar" to FSignature(false, DataType.UWORD, FParam("bank", DataType.UBYTE), FParam("address", DataType.UWORD), FParam("arg", DataType.UWORD)), - "callfar2" to FSignature(false, DataType.UWORD, FParam("bank", DataType.UBYTE), FParam("address", DataType.UWORD), FParam("argA", DataType.UBYTE), FParam("argX", DataType.UBYTE), FParam("argY", DataType.UBYTE), FParam("argC", DataType.BOOL)), - "call" to FSignature(false, DataType.UWORD, FParam("address", DataType.UWORD)), + "memory" to FSignature(true, BaseDataType.UWORD, FParam("name", BaseDataType.STR), FParam("size", BaseDataType.UWORD), FParam("alignment", BaseDataType.UWORD)), + "callfar" to FSignature(false, BaseDataType.UWORD, FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD), FParam("arg", BaseDataType.UWORD)), + "callfar2" to FSignature(false, BaseDataType.UWORD, FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD), FParam("argA", BaseDataType.UBYTE), FParam("argX", BaseDataType.UBYTE), FParam("argY", BaseDataType.UBYTE), FParam("argC", BaseDataType.BOOL)), + "call" to FSignature(false, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)), ) val InplaceModifyingBuiltinFunctions = setOf( diff --git a/codeCore/src/prog8/code/core/Enumerations.kt b/codeCore/src/prog8/code/core/Enumerations.kt index 17ba9cc5a..5ad61f6e9 100644 --- a/codeCore/src/prog8/code/core/Enumerations.kt +++ b/codeCore/src/prog8/code/core/Enumerations.kt @@ -1,6 +1,8 @@ package prog8.code.core -enum class DataType { +import java.util.Objects + +enum class BaseDataType { UBYTE, // pass by value 8 bits unsigned BYTE, // pass by value 8 bits signed UWORD, // pass by value 16 bits unsigned @@ -9,55 +11,246 @@ enum class DataType { FLOAT, // pass by value machine dependent BOOL, // pass by value bit 0 of an 8-bit byte STR, // pass by reference - ARRAY_UB, // pass by reference - ARRAY_B, // pass by reference - ARRAY_UW, // pass by reference - ARRAY_UW_SPLIT, // pass by reference, lo/hi byte split - ARRAY_W, // pass by reference - ARRAY_W_SPLIT, // pass by reference, lo/hi byte split - ARRAY_F, // pass by reference - ARRAY_BOOL, // pass by reference + ARRAY, // pass by reference, subtype is the element type + ARRAY_SPLITW, // pass by reference, split word layout, subtype is the element type (restricted to word types) UNDEFINED; - /** - * is the type assignable to the given other type (perhaps via a typecast) without loss of precision? - */ - infix fun isAssignableTo(targetType: DataType) = - when(this) { - BOOL -> targetType == BOOL - UBYTE -> targetType.oneOf(UBYTE, WORD, UWORD, LONG, FLOAT) - BYTE -> targetType.oneOf(BYTE, WORD, LONG, FLOAT) - UWORD -> targetType.oneOf(UWORD, LONG, FLOAT) - WORD -> targetType.oneOf(WORD, LONG, FLOAT) - LONG -> targetType.oneOf(LONG, FLOAT) - FLOAT -> targetType.oneOf(FLOAT) - STR -> targetType.oneOf(STR, UWORD) - in ArrayDatatypes -> targetType == this - else -> false - } - fun oneOf(vararg types: DataType) = this in types - - infix fun largerThan(other: DataType) = + fun largerSizeThan(other: BaseDataType) = when { this == other -> false - this in ByteDatatypesWithBoolean -> false - this in WordDatatypes -> other in ByteDatatypesWithBoolean - this == LONG -> other in ByteDatatypesWithBoolean+WordDatatypes + this.isByteOrBool -> false + this.isWord -> other.isByteOrBool + this == LONG -> other.isByteOrBool || other.isWord this == STR && other == UWORD || this == UWORD && other == STR -> false + this.isArray -> other != FLOAT + this == STR -> other != FLOAT else -> true } - infix fun equalsSize(other: DataType) = + fun equalsSize(other: BaseDataType) = when { this == other -> true - this in ByteDatatypesWithBoolean -> other in ByteDatatypesWithBoolean - this in WordDatatypes -> other in WordDatatypes - this== STR && other== UWORD || this== UWORD && other== STR -> true + this.isByteOrBool -> other.isByteOrBool + this.isWord -> other.isWord + this == STR && other== UWORD || this== UWORD && other== STR -> true + this == STR && other.isArray -> true + this.isArray && other == STR -> true else -> false } } +val BaseDataType.isByte get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE) +val BaseDataType.isByteOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.BOOL) +val BaseDataType.isWord get() = this in arrayOf(BaseDataType.UWORD, BaseDataType.WORD) +val BaseDataType.isInteger get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG) +val BaseDataType.isIntegerOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.BOOL) +val BaseDataType.isNumeric get() = this == BaseDataType.FLOAT || this.isInteger +val BaseDataType.isNumericOrBool get() = this == BaseDataType.BOOL || this.isNumeric +val BaseDataType.isSigned get() = this in arrayOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT) +val BaseDataType.isArray get() = this == BaseDataType.ARRAY || this == BaseDataType.ARRAY_SPLITW +val BaseDataType.isSplitWordArray get() = this == BaseDataType.ARRAY_SPLITW +val BaseDataType.isIterable get() = this in arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW) +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) + } +} + +private data object SubUnsignedByte: SubType(BaseDataType.UBYTE) +private data object SubSignedByte: SubType(BaseDataType.BYTE) +private data object SubUnsignedWord: SubType(BaseDataType.UWORD) +private data object SubSignedWord: SubType(BaseDataType.WORD) +private data object SubBool: SubType(BaseDataType.BOOL) +private data object SubFloat: SubType(BaseDataType.FLOAT) + + +class DataType private constructor(val base: BaseDataType, val sub: SubType?) { + + init { + if(base.isArray) { + require(sub != null) + if(base.isSplitWordArray) + require(sub.dt == BaseDataType.UWORD || sub.dt == BaseDataType.WORD) + } + else if(base==BaseDataType.STR) + require(sub?.dt==BaseDataType.UBYTE) { "STR subtype should be ubyte" } + else + require(sub == null) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is DataType) return false + return base == other.base && sub == other.sub + } + + override fun hashCode(): Int = Objects.hash(base, sub) + + companion object { + private val simpletypes = mapOf( + BaseDataType.UBYTE to DataType(BaseDataType.UBYTE, null), + BaseDataType.BYTE to DataType(BaseDataType.BYTE, null), + BaseDataType.UWORD to DataType(BaseDataType.UWORD, null), + BaseDataType.WORD to DataType(BaseDataType.WORD, null), + 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.UNDEFINED to DataType(BaseDataType.UNDEFINED, null) + ) + + fun forDt(dt: BaseDataType) = simpletypes.getValue(dt) + + fun arrayFor(elementDt: BaseDataType, split: Boolean=false): DataType { + val actualElementDt = if(elementDt==BaseDataType.STR) BaseDataType.UWORD else elementDt // array of strings is actually just an array of UWORD pointers + if(split) return DataType(BaseDataType.ARRAY_SPLITW, SubType.forDt(actualElementDt)) + else return DataType(BaseDataType.ARRAY, SubType.forDt(actualElementDt)) + } + } + + fun elementToArray(split: Boolean = false): DataType { + if(split) { + return if (base == BaseDataType.UWORD || base == BaseDataType.WORD || base == BaseDataType.STR) arrayFor(base, true) + else throw IllegalArgumentException("invalid split array elt dt") + } + return arrayFor(base) + } + + fun elementType(): DataType = + if(base.isArray || base==BaseDataType.STR) + forDt(sub!!.dt) + 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.ARRAY_SPLITW -> { + when(sub) { + SubSignedWord -> "@split word[]" + SubUnsignedWord -> "@split uword[]" + else -> throw IllegalArgumentException("invalid sub type") + } + } + else -> base.name.lowercase() + } + + fun sourceString(): String = when (base) { + BaseDataType.BOOL -> "bool" + BaseDataType.UBYTE -> "ubyte" + BaseDataType.BYTE -> "byte" + BaseDataType.UWORD -> "uword" + BaseDataType.WORD -> "word" + BaseDataType.LONG -> "long" + BaseDataType.FLOAT -> "float" + BaseDataType.STR -> "str" + BaseDataType.ARRAY -> { + when(sub) { + SubUnsignedByte -> "ubyte[" + SubUnsignedWord -> "uword[" + SubBool -> "bool[" + SubSignedByte -> "byte[" + SubSignedWord -> "word[" + SubFloat -> "float[" + null -> throw IllegalArgumentException("invalid sub type") + } + } + BaseDataType.ARRAY_SPLITW -> { + when(sub) { + SubUnsignedWord -> "@split uword[" + SubSignedWord -> "@split word[" + else -> throw IllegalArgumentException("invalid sub type") + } + } + BaseDataType.UNDEFINED -> throw IllegalArgumentException("wrong dt") + } + + // is the type assignable to the given other type (perhaps via a typecast) without loss of precision? + infix fun isAssignableTo(targetType: DataType) = + when(base) { + BaseDataType.BOOL -> targetType.base == BaseDataType.BOOL + BaseDataType.UBYTE -> targetType.base in arrayOf(BaseDataType.UBYTE, BaseDataType.WORD, BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT) + BaseDataType.BYTE -> targetType.base in arrayOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT) + BaseDataType.UWORD -> targetType.base in arrayOf(BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT) + BaseDataType.WORD -> targetType.base in arrayOf(BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT) + BaseDataType.LONG -> targetType.base in arrayOf(BaseDataType.LONG, BaseDataType.FLOAT) + BaseDataType.FLOAT -> targetType.base in arrayOf(BaseDataType.FLOAT) + BaseDataType.STR -> targetType.base in arrayOf(BaseDataType.STR, BaseDataType.UWORD) + BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW -> targetType.base in arrayOf(BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW) && targetType.sub == sub + BaseDataType.UNDEFINED -> false + } + + fun largerSizeThan(other: DataType): Boolean { + if(isArray) throw IllegalArgumentException("cannot compare size of array types") + return base.largerSizeThan(other.base) + } + fun equalsSize(other: DataType): Boolean { + if(isArray) throw IllegalArgumentException("cannot compare size of array types") + return base.equalsSize(other.base) + } + + val isUndefined = base == BaseDataType.UNDEFINED + val isByte = base.isByte + val isUnsignedByte = base == BaseDataType.UBYTE + val isSignedByte = base == BaseDataType.BYTE + val isByteOrBool = base.isByteOrBool + val isWord = base.isWord + val isUnsignedWord = base == BaseDataType.UWORD + val isSignedWord = base == BaseDataType.WORD + val isInteger = base.isInteger + val isIntegerOrBool = base.isIntegerOrBool + val isNumeric = base.isNumeric + val isNumericOrBool = base.isNumericOrBool + 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 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 isSplitWordArray = base.isSplitWordArray + val isSplitUnsignedWordArray = base.isSplitWordArray && sub?.dt == BaseDataType.UWORD + val isSplitSignedWordArray = base.isSplitWordArray && sub?.dt == BaseDataType.WORD + val isIterable = base.isIterable + val isPassByRef = base.isPassByRef + val isPassByValue = base.isPassByValue +} + + enum class CpuRegister { A, X, @@ -97,11 +290,11 @@ enum class RegisterOrPair { fun asScopedNameVirtualReg(type: DataType?): List { require(this in Cx16VirtualRegisters) - val suffix = when(type) { - DataType.UBYTE, DataType.BOOL -> "L" - DataType.BYTE -> "sL" - DataType.WORD -> "s" - DataType.UWORD, null -> "" + val suffix = when(type?.base) { + BaseDataType.UBYTE, BaseDataType.BOOL -> "L" + BaseDataType.BYTE -> "sL" + BaseDataType.WORD -> "s" + BaseDataType.UWORD, null -> "" else -> throw kotlin.IllegalArgumentException("invalid register param type") } return listOf("cx16", name.lowercase()+suffix) @@ -134,48 +327,6 @@ enum class BranchCondition { VC } - -val ByteDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE) -val ByteDatatypesWithBoolean = ByteDatatypes + DataType.BOOL -val WordDatatypes = arrayOf(DataType.UWORD, DataType.WORD) -val IntegerDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.LONG) -val IntegerDatatypesWithBoolean = IntegerDatatypes + DataType.BOOL -val NumericDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.LONG, DataType.FLOAT) -val NumericDatatypesWithBoolean = NumericDatatypes + DataType.BOOL -val SignedDatatypes = arrayOf(DataType.BYTE, DataType.WORD, DataType.LONG, DataType.FLOAT) -val ArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W, DataType.ARRAY_W_SPLIT, DataType.ARRAY_F, DataType.ARRAY_BOOL) -val StringlyDatatypes = arrayOf(DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.UWORD) -val SplitWordArrayTypes = arrayOf(DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT) -val IterableDatatypes = arrayOf( - DataType.STR, - DataType.ARRAY_UB, DataType.ARRAY_B, - DataType.ARRAY_UW, DataType.ARRAY_W, - DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT, - DataType.ARRAY_F, DataType.ARRAY_BOOL -) -val PassByValueDatatypes = NumericDatatypesWithBoolean -val PassByReferenceDatatypes = IterableDatatypes -val ArrayToElementTypes = mapOf( - DataType.STR to DataType.UBYTE, - DataType.ARRAY_B to DataType.BYTE, - DataType.ARRAY_UB to DataType.UBYTE, - DataType.ARRAY_W to DataType.WORD, - DataType.ARRAY_UW to DataType.UWORD, - DataType.ARRAY_W_SPLIT to DataType.WORD, - DataType.ARRAY_UW_SPLIT to DataType.UWORD, - DataType.ARRAY_F to DataType.FLOAT, - DataType.ARRAY_BOOL to DataType.BOOL -) -val ElementToArrayTypes = mapOf( - DataType.BYTE to DataType.ARRAY_B, - DataType.UBYTE to DataType.ARRAY_UB, - DataType.WORD to DataType.ARRAY_W, - DataType.UWORD to DataType.ARRAY_UW, - DataType.FLOAT to DataType.ARRAY_F, - DataType.BOOL to DataType.ARRAY_BOOL, - DataType.STR to DataType.ARRAY_UW // array of str is just an array of pointers -) - val Cx16VirtualRegisters = arrayOf( RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, RegisterOrPair.R3, RegisterOrPair.R4, RegisterOrPair.R5, RegisterOrPair.R6, RegisterOrPair.R7, diff --git a/codeCore/src/prog8/code/core/IMemSizer.kt b/codeCore/src/prog8/code/core/IMemSizer.kt index 84f4d6c68..214aed0d1 100644 --- a/codeCore/src/prog8/code/core/IMemSizer.kt +++ b/codeCore/src/prog8/code/core/IMemSizer.kt @@ -1,6 +1,6 @@ package prog8.code.core interface IMemSizer { - fun memorySize(dt: DataType): Int - fun memorySize(arrayDt: DataType, numElements: Int): Int + fun memorySize(dt: DataType, numElements: Int?): Int + fun memorySize(dt: SubType): Int } diff --git a/codeCore/src/prog8/code/core/MemoryRegions.kt b/codeCore/src/prog8/code/core/MemoryRegions.kt index 00214e8c0..9698cf496 100644 --- a/codeCore/src/prog8/code/core/MemoryRegions.kt +++ b/codeCore/src/prog8/code/core/MemoryRegions.kt @@ -70,9 +70,9 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) { return Err(MemAllocationError("zero page usage has been disabled")) val size: Int = - when (datatype) { - in IntegerDatatypesWithBoolean -> options.compTarget.memorySize(datatype) - DataType.STR, in ArrayDatatypes -> { + when { + datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null) + datatype.isString || datatype.isArray -> { val memsize = options.compTarget.memorySize(datatype, numElements!!) if(position!=null) errors.warn("allocating a large value in zeropage; str/array $memsize bytes", position) @@ -80,9 +80,9 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) { errors.warn("$name: allocating a large value in zeropage; str/array $memsize bytes", Position.DUMMY) memsize } - DataType.FLOAT -> { + datatype.isFloat -> { if (options.floats) { - val memsize = options.compTarget.memorySize(DataType.FLOAT) + val memsize = options.compTarget.memorySize(DataType.forDt(BaseDataType.FLOAT), null) if(position!=null) errors.warn("allocating a large value in zeropage; float $memsize bytes", position) else @@ -118,10 +118,10 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) { require(size>=0) free.removeAll(address until address+size.toUInt()) if(name.isNotEmpty()) { - allocatedVariables[name] = when(datatype) { - in NumericDatatypes, DataType.BOOL -> VarAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments - DataType.STR -> VarAllocation(address, datatype, size) - in ArrayDatatypes -> VarAllocation(address, datatype, size) + allocatedVariables[name] = when { + datatype.isNumericOrBool -> VarAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments + datatype.isString -> VarAllocation(address, datatype, size) + datatype.isArray -> VarAllocation(address, datatype, size) else -> throw AssemblyError("invalid dt") } } @@ -150,14 +150,13 @@ class GoldenRam(options: CompilationOptions, val region: UIntRange): MemoryAlloc errors: IErrorReporter): Result { val size: Int = - when (datatype) { - in IntegerDatatypesWithBoolean -> options.compTarget.memorySize(datatype) - DataType.STR, in ArrayDatatypes -> { - options.compTarget.memorySize(datatype, numElements!!) - } - DataType.FLOAT -> { + when { + datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null) + datatype.isString -> numElements!! + datatype.isArray -> options.compTarget.memorySize(datatype, numElements!!) + datatype.isFloat -> { if (options.floats) { - options.compTarget.memorySize(DataType.FLOAT) + options.compTarget.memorySize(DataType.forDt(BaseDataType.FLOAT), null) } else return Err(MemAllocationError("floating point option not enabled")) } else -> throw MemAllocationError("weird dt") diff --git a/codeCore/src/prog8/code/optimize/Optimizer.kt b/codeCore/src/prog8/code/optimize/Optimizer.kt index 74e39f4e5..65618b1a4 100644 --- a/codeCore/src/prog8/code/optimize/Optimizer.kt +++ b/codeCore/src/prog8/code/optimize/Optimizer.kt @@ -60,7 +60,7 @@ private fun optimizeAssignTargets(program: PtProgram, st: SymbolTable, errors: I if(node.children.dropLast(1).all { (it as PtAssignTarget).void }) { // all targets are now void, the whole assignment can be discarded and replaced by just a (void) call to the subroutine val index = node.parent.children.indexOf(node) - val voidCall = PtFunctionCall(functionName, true, DataType.UNDEFINED, value.position) + val voidCall = PtFunctionCall(functionName, true, DataType.forDt(BaseDataType.UNDEFINED), value.position) value.children.forEach { voidCall.add(it) } node.parent.children[index] = voidCall voidCall.parent = node.parent @@ -81,12 +81,12 @@ private fun optimizeBitTest(program: PtProgram, options: CompilationOptions): In fun makeBittestCall(condition: PtBinaryExpression, and: PtBinaryExpression, variable: PtIdentifier, bitmask: Int): PtBuiltinFunctionCall { require(bitmask==128 || bitmask==64) val setOrNot = if(condition.operator=="!=") "set" else "notset" - val bittestCall = PtBuiltinFunctionCall("prog8_ifelse_bittest_$setOrNot", false, true, DataType.BOOL, condition.position) + val bittestCall = PtBuiltinFunctionCall("prog8_ifelse_bittest_$setOrNot", false, true, DataType.forDt(BaseDataType.BOOL), condition.position) bittestCall.add(variable) if(bitmask==128) - bittestCall.add(PtNumber(DataType.UBYTE, 7.0, and.right.position)) + bittestCall.add(PtNumber(BaseDataType.UBYTE, 7.0, and.right.position)) else - bittestCall.add(PtNumber(DataType.UBYTE, 6.0, and.right.position)) + bittestCall.add(PtNumber(BaseDataType.UBYTE, 6.0, and.right.position)) return bittestCall } @@ -94,17 +94,17 @@ private fun optimizeBitTest(program: PtProgram, options: CompilationOptions): In if(condition!=null && (condition.operator=="==" || condition.operator=="!=")) { if (condition.right.asConstInteger() == 0) { val and = condition.left as? PtBinaryExpression - if (and != null && and.operator == "&" && and.type == DataType.UBYTE) { + if (and != null && and.operator == "&" && and.type.isUnsignedByte) { val bitmask = and.right.asConstInteger() if(bitmask==128 || bitmask==64) { val variable = and.left as? PtIdentifier - if (variable != null && variable.type in ByteDatatypes) { + if (variable != null && variable.type.isByte) { return Triple(and, variable, bitmask) } val typecast = and.left as? PtTypeCast - if (typecast != null && typecast.type == DataType.UBYTE) { + if (typecast != null && typecast.type.isUnsignedByte) { val castedVariable = typecast.value as? PtIdentifier - if(castedVariable!=null && castedVariable.type in ByteDatatypes) + if(castedVariable!=null && castedVariable.type.isByte) return Triple(and, castedVariable, bitmask) } } @@ -165,12 +165,12 @@ internal fun isSame(identifier: PtIdentifier, type: DataType, returnedRegister: cx16.r?sL BYTE cx16.r?sH BYTE */ - if(identifier.type in ByteDatatypes && type in ByteDatatypes) { + if(identifier.type.isByte && type.isByte) { if(identifier.name.startsWith("cx16.$regname") && identifierRegName.startsWith(regname)) { return identifierRegName.substring(2) in arrayOf("", "L", "sL") // note: not the -H (msb) variants! } } - else if(identifier.type in WordDatatypes && type in WordDatatypes) { + else if(identifier.type.isWord && type.isWord) { if(identifier.name.startsWith("cx16.$regname") && identifierRegName.startsWith(regname)) { return identifierRegName.substring(2) in arrayOf("", "s") } diff --git a/codeCore/src/prog8/code/target/AtariTarget.kt b/codeCore/src/prog8/code/target/AtariTarget.kt index 929001be9..e65038449 100644 --- a/codeCore/src/prog8/code/target/AtariTarget.kt +++ b/codeCore/src/prog8/code/target/AtariTarget.kt @@ -13,19 +13,25 @@ class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { const val NAME = "atari" } - override fun memorySize(dt: DataType): Int { - return when(dt) { - in ByteDatatypesWithBoolean -> 1 - in WordDatatypes, in PassByReferenceDatatypes -> 2 - DataType.FLOAT -> machine.FLOAT_MEM_SIZE - else -> throw IllegalArgumentException("invalid datatype") + override fun memorySize(dt: DataType, numElements: Int?): Int { + if(dt.isArray) { + require(numElements!=null) + return when(dt.sub?.dt) { + BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements + BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2 + BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE + else -> throw IllegalArgumentException("invalid sub type") + } + } + + return when { + dt.isByteOrBool -> 1 * (numElements ?: 1) + dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) + else -> 2 * (numElements ?: 1) } } - override fun memorySize(arrayDt: DataType, numElements: Int) = - if(arrayDt==DataType.UWORD) - numElements // pointer to bytes. - else - memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements - + 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 1b14a4164..07225daae 100644 --- a/codeCore/src/prog8/code/target/Neo6502Target.kt +++ b/codeCore/src/prog8/code/target/Neo6502Target.kt @@ -13,18 +13,25 @@ class Neo6502Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { const val NAME = "neo" } - override fun memorySize(dt: DataType): Int { - return when(dt) { - in ByteDatatypesWithBoolean -> 1 - in WordDatatypes, in PassByReferenceDatatypes -> 2 - DataType.FLOAT -> machine.FLOAT_MEM_SIZE - else -> throw IllegalArgumentException("invalid datatype") + override fun memorySize(dt: DataType, numElements: Int?): Int { + if(dt.isArray) { + require(numElements!=null) + return when(dt.sub?.dt) { + BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements + BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2 + BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE + else -> throw IllegalArgumentException("invalid sub type") + } + } + + return when { + dt.isByteOrBool -> 1 * (numElements ?: 1) + dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) + else -> 2 * (numElements ?: 1) } } - override fun memorySize(arrayDt: DataType, numElements: Int) = - if(arrayDt== DataType.UWORD) - numElements // pointer to bytes. - else - memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements + 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 783d22be3..f9736fdc5 100644 --- a/codeCore/src/prog8/code/target/VMTarget.kt +++ b/codeCore/src/prog8/code/target/VMTarget.kt @@ -12,18 +12,25 @@ class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { const val NAME = "virtual" } - override fun memorySize(dt: DataType): Int { - return when(dt) { - in ByteDatatypesWithBoolean -> 1 - in WordDatatypes, in PassByReferenceDatatypes -> 2 - DataType.FLOAT -> machine.FLOAT_MEM_SIZE - else -> throw IllegalArgumentException("invalid datatype") + override fun memorySize(dt: DataType, numElements: Int?): Int { + if(dt.isArray) { + require(numElements!=null) + return when(dt.sub?.dt) { + BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements + BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2 + BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE + else -> throw IllegalArgumentException("invalid sub type") + } + } + return when { + dt.isByteOrBool -> 1 * (numElements ?: 1) + dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) + else -> 2 * (numElements ?: 1) } } - override fun memorySize(arrayDt: DataType, numElements: Int) = - if(arrayDt==DataType.UWORD) - numElements // pointer to bytes. - else - memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements + 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/c64/C64Zeropage.kt b/codeCore/src/prog8/code/target/c64/C64Zeropage.kt index 5aed2e05a..18a31eed2 100644 --- a/codeCore/src/prog8/code/target/c64/C64Zeropage.kt +++ b/codeCore/src/prog8/code/target/c64/C64Zeropage.kt @@ -85,12 +85,12 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) { // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer) // The base addres is $04. Unfortunately it cannot be the same as on the Commander X16 ($02). for(reg in 0..15) { - allocatedVariables["cx16.r${reg}"] = VarAllocation((4+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 - allocatedVariables["cx16.r${reg}s"] = VarAllocation((4+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s - allocatedVariables["cx16.r${reg}L"] = VarAllocation((4+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L - allocatedVariables["cx16.r${reg}H"] = VarAllocation((5+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H - allocatedVariables["cx16.r${reg}sL"] = VarAllocation((4+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL - allocatedVariables["cx16.r${reg}sH"] = VarAllocation((5+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH + allocatedVariables["cx16.r${reg}"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15 + allocatedVariables["cx16.r${reg}s"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s + allocatedVariables["cx16.r${reg}L"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L + allocatedVariables["cx16.r${reg}H"] = VarAllocation((5+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H + allocatedVariables["cx16.r${reg}sL"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL + allocatedVariables["cx16.r${reg}sH"] = VarAllocation((5+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH free.remove((4+reg*2).toUInt()) free.remove((5+reg*2).toUInt()) } diff --git a/codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt b/codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt index 0ce323da4..789067f79 100644 --- a/codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt +++ b/codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt @@ -1,21 +1,30 @@ package prog8.code.target.cbm -import prog8.code.core.* +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): Int { - return when(dt) { - in ByteDatatypesWithBoolean -> 1 - in WordDatatypes, in PassByReferenceDatatypes -> 2 - DataType.FLOAT -> Mflpt5.FLOAT_MEM_SIZE - else -> throw IllegalArgumentException("invalid datatype") + override fun memorySize(dt: DataType, numElements: Int?): Int { + if(dt.isArray) { + require(numElements!=null) + return when(dt.sub?.dt) { + BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements + BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2 + BaseDataType.FLOAT-> numElements * Mflpt5.FLOAT_MEM_SIZE + else -> throw IllegalArgumentException("invalid sub type") + } + } + return when { + dt.isByteOrBool -> 1 * (numElements ?: 1) + dt.isFloat -> Mflpt5.FLOAT_MEM_SIZE * (numElements ?: 1) + else -> 2 * (numElements ?: 1) } } - override fun memorySize(arrayDt: DataType, numElements: Int) = - if(arrayDt==DataType.UWORD) - numElements // pointer to bytes. - else - memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements + 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/cx16/CX16Zeropage.kt b/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt index 2d44c112c..c4d3cf251 100644 --- a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt +++ b/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt @@ -57,12 +57,12 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) { // However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well. // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer) for(reg in 0..15) { - allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 - allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s - allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L - allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H - allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL - allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH + allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15 + allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s + allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L + allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H + allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL + allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH } } } \ No newline at end of file diff --git a/codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt b/codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt index 3b77b6774..a020501e4 100644 --- a/codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt +++ b/codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt @@ -37,12 +37,12 @@ class Neo6502Zeropage(options: CompilationOptions) : Zeropage(options) { // However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well. // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer) for(reg in 0..15) { - allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 - allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s - allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L - allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H - allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL - allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH + allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15 + allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s + allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L + allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H + allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL + allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH } } } \ 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 c06385c5f..d8f4744df 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -64,7 +64,7 @@ class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSeque } is PtIdentifier -> { var lookupName = node.name - if(node.type in SplitWordArrayTypes && (lookupName.endsWith("_lsb") || lookupName.endsWith("_msb"))) { + if(node.type.isSplitWordArray && (lookupName.endsWith("_lsb") || lookupName.endsWith("_msb"))) { lookupName = lookupName.dropLast(4) } val stNode = st.lookup(lookupName) ?: throw AssemblyError("unknown identifier $node") @@ -413,17 +413,17 @@ class AsmGen6502Internal ( internal val tempVarsCounters = mutableMapOf( - DataType.BOOL to 0, - DataType.BYTE to 0, - DataType.UBYTE to 0, - DataType.WORD to 0, - DataType.UWORD to 0, - DataType.FLOAT to 0 + BaseDataType.BOOL to 0, + BaseDataType.BYTE to 0, + BaseDataType.UBYTE to 0, + BaseDataType.WORD to 0, + BaseDataType.UWORD to 0, + BaseDataType.FLOAT to 0 ) - internal fun buildTempVarName(dt: DataType, counter: Int): String = "prog8_tmpvar_${dt.toString().lowercase()}_$counter" + internal fun buildTempVarName(dt: BaseDataType, counter: Int): String = "prog8_tmpvar_${dt.toString().lowercase()}_$counter" - internal fun getTempVarName(dt: DataType): String { + internal fun getTempVarName(dt: BaseDataType): String { tempVarsCounters[dt] = tempVarsCounters.getValue(dt)+1 return buildTempVarName(dt, tempVarsCounters.getValue(dt)) } @@ -627,7 +627,7 @@ class AsmGen6502Internal ( val indexValue = if(expr.splitWords) indexnum else - indexnum * options.compTarget.memorySize(expr.type) + indexnum * options.compTarget.memorySize(expr.type, null) out(" ld$reg #$indexValue") return } @@ -637,11 +637,11 @@ class AsmGen6502Internal ( return } - when (expr.type) { - in ByteDatatypesWithBoolean -> { + when { + expr.type.isByteOrBool -> { assignExpressionToRegister(expr.index, RegisterOrPair.fromCpuRegister(register), false) } - in WordDatatypes -> { + expr.type.isWord -> { assignExpressionToRegister(expr.index, RegisterOrPair.A, false) out(" asl a") when (register) { @@ -650,8 +650,8 @@ class AsmGen6502Internal ( CpuRegister.Y -> out(" tay") } } - DataType.FLOAT -> { - require(options.compTarget.memorySize(DataType.FLOAT) == 5) {"invalid float size ${expr.position}"} + expr.type.isFloat -> { + require(options.compTarget.machine.FLOAT_MEM_SIZE == 5) {"invalid float size ${expr.position}"} assignExpressionToRegister(expr.index, RegisterOrPair.A, false) out(""" sta P8ZP_SCRATCH_REG @@ -670,7 +670,7 @@ class AsmGen6502Internal ( } } - internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): DataType? = + internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): BaseDataType? = builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultRegister) internal fun translateFunctionCall(functionCallExpr: PtFunctionCall) = @@ -692,7 +692,7 @@ class AsmGen6502Internal ( when(reg) { RegisterOrPair.A, RegisterOrPair.X, - RegisterOrPair.Y -> assignmentAsmGen.assignRegisterByte(target, reg.asCpuRegister(), target.datatype in SignedDatatypes, true) + RegisterOrPair.Y -> assignmentAsmGen.assignRegisterByte(target, reg.asCpuRegister(), target.datatype.isSigned, true) RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY, @@ -704,8 +704,8 @@ class AsmGen6502Internal ( } internal fun assignExpressionTo(value: PtExpression, target: AsmAssignTarget) { - when (target.datatype) { - in ByteDatatypesWithBoolean -> { + when { + target.datatype.isByteOrBool -> { if (value.asConstInteger()==0) { when(target.kind) { TargetStorageKind.VARIABLE -> { @@ -725,7 +725,7 @@ class AsmGen6502Internal ( } } TargetStorageKind.REGISTER -> { - val zero = PtNumber(DataType.UBYTE, 0.0, value.position) + val zero = PtNumber(BaseDataType.UBYTE, 0.0, value.position) zero.parent = value assignExpressionToRegister(zero, target.register!!, false) return @@ -737,7 +737,7 @@ class AsmGen6502Internal ( assignExpressionToRegister(value, RegisterOrPair.A) assignRegister(RegisterOrPair.A, target) } - in WordDatatypes, in PassByReferenceDatatypes -> { + target.datatype.isWord || target.datatype.isPassByRef -> { assignExpressionToRegister(value, RegisterOrPair.AY) translateNormalAssignment( AsmAssignment( @@ -746,7 +746,7 @@ class AsmGen6502Internal ( ), value.definingISub() ) } - DataType.FLOAT -> { + target.datatype.isFloat -> { assignExpressionToRegister(value, RegisterOrPair.FAC1) assignRegister(RegisterOrPair.FAC1, target) } @@ -798,25 +798,25 @@ class AsmGen6502Internal ( val symbol = symbolTable.lookup((stmt.count as PtIdentifier).name) val vardecl = symbol!!.astNode as IPtVariable val name = asmVariableName(stmt.count as PtIdentifier) - when(vardecl.type) { - DataType.UBYTE, DataType.BYTE -> { + when { + vardecl.type.isByte -> { assignVariableToRegister(name, RegisterOrPair.Y, stmt.definingISub(), stmt.count.position) repeatCountInY(stmt, endLabel) } - DataType.UWORD, DataType.WORD -> { + vardecl.type.isWord -> { assignVariableToRegister(name, RegisterOrPair.AY, stmt.definingISub(), stmt.count.position) repeatWordCountInAY(endLabel, stmt) } - else -> throw AssemblyError("invalid loop variable datatype $vardecl") + else -> throw AssemblyError("invalid loop variable datatype ${vardecl.type}") } } else -> { - when (stmt.count.type) { - in ByteDatatypes -> { + when { + stmt.count.type.isByte -> { assignExpressionToRegister(stmt.count, RegisterOrPair.Y) repeatCountInY(stmt, endLabel) } - in WordDatatypes -> { + stmt.count.type.isWord -> { assignExpressionToRegister(stmt.count, RegisterOrPair.AY) repeatWordCountInAY(endLabel, stmt) } @@ -831,7 +831,7 @@ class AsmGen6502Internal ( private fun repeatWordCount(iterations: Int, stmt: PtRepeatLoop) { require(iterations in 257..65536) { "invalid repeat count ${stmt.position}" } val repeatLabel = makeLabel("repeat") - val counterVar = createRepeatCounterVar(DataType.UWORD, isTargetCpu(CpuType.CPU65c02), stmt) + val counterVar = createRepeatCounterVar(BaseDataType.UWORD, isTargetCpu(CpuType.CPU65c02), stmt) val loopcount = if(iterations==65536) 0 else if(iterations and 0x00ff == 0) iterations else iterations + 0x0100 // so that the loop can simply use a double-dec out(""" ldy #>$loopcount @@ -851,7 +851,7 @@ $repeatLabel""") // note: A/Y must have been loaded with the number of iterations! // the iny + double dec is microoptimization of the 16 bit loop val repeatLabel = makeLabel("repeat") - val counterVar = createRepeatCounterVar(DataType.UWORD, false, stmt) + val counterVar = createRepeatCounterVar(BaseDataType.UWORD, false, stmt) out(""" cmp #0 beq + @@ -874,13 +874,13 @@ $repeatLabel""") require(count in 2..256) { "invalid repeat count ${stmt.position}" } val repeatLabel = makeLabel("repeat") if(isTargetCpu(CpuType.CPU65c02)) { - val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt) + val counterVar = createRepeatCounterVar(BaseDataType.UBYTE, true, stmt) out(" lda #${count and 255} | sta $counterVar") out(repeatLabel) translate(stmt.statements) out(" dec $counterVar | bne $repeatLabel") } else { - val counterVar = createRepeatCounterVar(DataType.UBYTE, false, stmt) + val counterVar = createRepeatCounterVar(BaseDataType.UBYTE, false, stmt) out(" lda #${count and 255} | sta $counterVar") out(repeatLabel) translate(stmt.statements) @@ -892,13 +892,13 @@ $repeatLabel""") val repeatLabel = makeLabel("repeat") out(" cpy #0") if(isTargetCpu(CpuType.CPU65c02)) { - val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt) + val counterVar = createRepeatCounterVar(BaseDataType.UBYTE, true, stmt) out(" beq $endLabel | sty $counterVar") out(repeatLabel) translate(stmt.statements) out(" dec $counterVar | bne $repeatLabel") } else { - val counterVar = createRepeatCounterVar(DataType.UBYTE, false, stmt) + val counterVar = createRepeatCounterVar(BaseDataType.UBYTE, false, stmt) out(" beq $endLabel | sty $counterVar") out(repeatLabel) translate(stmt.statements) @@ -907,7 +907,7 @@ $repeatLabel""") out(endLabel) } - private fun createRepeatCounterVar(dt: DataType, preferZeropage: Boolean, stmt: PtRepeatLoop): String { + private fun createRepeatCounterVar(dt: BaseDataType, preferZeropage: Boolean, stmt: PtRepeatLoop): String { val scope = stmt.definingISub()!! val asmInfo = subroutineExtra(scope) var parent = stmt.parent @@ -929,8 +929,8 @@ $repeatLabel""") val counterVar = makeLabel("counter") when(dt) { - DataType.UBYTE, DataType.UWORD -> { - val result = zeropage.allocate(counterVar, dt, null, stmt.position, errors) + BaseDataType.UBYTE, BaseDataType.UWORD -> { + val result = zeropage.allocate(counterVar, DataType.forDt(dt), null, stmt.position, errors) result.fold( success = { (address, _, _) -> asmInfo.extraVars.add(Triple(dt, counterVar, address)) }, failure = { asmInfo.extraVars.add(Triple(dt, counterVar, null)) } // allocate normally @@ -945,7 +945,7 @@ $repeatLabel""") val endLabel = makeLabel("choice_end") val choiceBlocks = mutableListOf>() val conditionDt = stmt.value.type - if(conditionDt in ByteDatatypes) + if(conditionDt.isByte) assignExpressionToRegister(stmt.value, RegisterOrPair.A) else assignExpressionToRegister(stmt.value, RegisterOrPair.AY) @@ -959,7 +959,7 @@ $repeatLabel""") choiceBlocks.add(choiceLabel to choice.statements) for (cv in choice.values.children) { val value = (cv as PtNumber).number.toInt() - if(conditionDt in ByteDatatypes) { + if(conditionDt.isByte) { out(" cmp #${value.toHex()} | beq $choiceLabel") } else { out(""" @@ -1051,17 +1051,15 @@ $repeatLabel""") ret.value?.let { returnvalue -> val sub = ret.definingSub()!! val returnReg = sub.returnRegister()!! - when (sub.returntype) { - in NumericDatatypes, DataType.BOOL -> { - assignExpressionToRegister(returnvalue, returnReg.registerOrPair!!) - } - else -> { - // all else take its address and assign that also to AY register pair - val addrofValue = PtAddressOf(returnvalue.position) - addrofValue.add(returnvalue as PtIdentifier) - addrofValue.parent = ret.parent - assignmentAsmGen.assignExpressionToRegister(addrofValue, returnReg.registerOrPair!!, false) - } + if (sub.returntype?.isNumericOrBool==true) { + assignExpressionToRegister(returnvalue, returnReg.registerOrPair!!) + } + else { + // all else take its address and assign that also to AY register pair + val addrofValue = PtAddressOf(returnvalue.position) + addrofValue.add(returnvalue as PtIdentifier) + addrofValue.parent = ret.parent + assignmentAsmGen.assignExpressionToRegister(addrofValue, returnReg.registerOrPair!!, false) } } out(" rts") @@ -1098,11 +1096,11 @@ $repeatLabel""") } } - internal fun signExtendAYlsb(valueDt: DataType) { + internal fun signExtendAYlsb(valueDt: BaseDataType) { // sign extend signed byte in A to full word in AY when(valueDt) { - DataType.UBYTE -> out(" ldy #0") - DataType.BYTE -> out(""" + BaseDataType.UBYTE -> out(" ldy #0") + BaseDataType.BYTE -> out(""" ldy #0 cmp #$80 bcc + @@ -1113,16 +1111,16 @@ $repeatLabel""") } } - internal fun signExtendVariableLsb(asmvar: String, valueDt: DataType) { + internal fun signExtendVariableLsb(asmvar: String, valueDt: BaseDataType) { // sign extend signed byte in a var to a full word in that variable when(valueDt) { - DataType.UBYTE -> { + BaseDataType.UBYTE -> { if(isTargetCpu(CpuType.CPU65c02)) out(" stz $asmvar+1") else out(" lda #0 | sta $asmvar+1") } - DataType.BYTE -> { + BaseDataType.BYTE -> { out(""" lda $asmvar ora #$7f @@ -1155,24 +1153,24 @@ $repeatLabel""") if (operator != "+") return null val leftDt = left.type val rightDt = right.type - if(leftDt == DataType.UWORD && rightDt == DataType.UBYTE) + if(leftDt.isUnsignedWord && rightDt.isUnsignedByte) return Pair(left, right) - if(leftDt == DataType.UBYTE && rightDt == DataType.UWORD) + if(leftDt.isUnsignedByte && rightDt.isUnsignedWord) return Pair(right, left) - if(leftDt == DataType.UWORD && rightDt == DataType.UWORD) { + if(leftDt.isUnsignedWord && rightDt.isUnsignedWord) { // could be that the index was a constant numeric byte but converted to word, check that val constIdx = right as? PtNumber if(constIdx!=null && constIdx.number.toInt()>=0 && constIdx.number.toInt()<=255) { - val num = PtNumber(DataType.UBYTE, constIdx.number, constIdx.position) + val num = PtNumber(BaseDataType.UBYTE, constIdx.number, constIdx.position) num.parent = right.parent return Pair(left, num) } // could be that the index was typecasted into uword, check that val rightTc = right as? PtTypeCast - if(rightTc!=null && rightTc.value.type == DataType.UBYTE) + if(rightTc!=null && rightTc.value.type.isUnsignedByte) return Pair(left, rightTc.value) val leftTc = left as? PtTypeCast - if(leftTc!=null && leftTc.value.type == DataType.UBYTE) + if(leftTc!=null && leftTc.value.type.isUnsignedByte) return Pair(right, leftTc.value) } return null @@ -1182,8 +1180,7 @@ $repeatLabel""") // optimize pointer,indexregister if possible fun evalBytevalueWillClobberA(expr: PtExpression): Boolean { - val dt = expr.type - if(dt != DataType.UBYTE && dt != DataType.BYTE) + if(!expr.type.isByte) return true return when(expr) { is PtIdentifier -> false @@ -1222,14 +1219,14 @@ $repeatLabel""") if(saveA) out(" pha") if(ptrAndIndex.second.isSimple()) { - assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD) + assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD)) assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) if(saveA) out(" pla") out(" sta (P8ZP_SCRATCH_W2),y") } else { - pushCpuStack(DataType.UBYTE, ptrAndIndex.second) - assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD) + pushCpuStack(BaseDataType.UBYTE, ptrAndIndex.second) + assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD)) restoreRegisterStack(CpuRegister.Y, true) if(saveA) out(" pla") @@ -1243,12 +1240,12 @@ $repeatLabel""") } else { // copy the pointer var to zp first if(ptrAndIndex.second.isSimple()) { - assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD) + assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD)) assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) out(" lda (P8ZP_SCRATCH_W2),y") } else { - pushCpuStack(DataType.UBYTE, ptrAndIndex.second) - assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD) + pushCpuStack(BaseDataType.UBYTE, ptrAndIndex.second) + assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD)) restoreRegisterStack(CpuRegister.Y, false) out(" lda (P8ZP_SCRATCH_W2),y") } @@ -1273,22 +1270,22 @@ $repeatLabel""") internal fun assignByteOperandsToAAndVar(left: PtExpression, right: PtExpression, rightVarName: String) { if(left.isSimple()) { - assignExpressionToVariable(right, rightVarName, DataType.UBYTE) + assignExpressionToVariable(right, rightVarName, DataType.forDt(BaseDataType.UBYTE)) assignExpressionToRegister(left, RegisterOrPair.A) } else { - pushCpuStack(DataType.UBYTE, left) - assignExpressionToVariable(right, rightVarName, DataType.UBYTE) + pushCpuStack(BaseDataType.UBYTE, left) + assignExpressionToVariable(right, rightVarName, DataType.forDt(BaseDataType.UBYTE)) out(" pla") } } internal fun assignWordOperandsToAYAndVar(left: PtExpression, right: PtExpression, rightVarname: String) { if(left.isSimple()) { - assignExpressionToVariable(right, rightVarname, DataType.UWORD) + assignExpressionToVariable(right, rightVarname, DataType.forDt(BaseDataType.UWORD)) assignExpressionToRegister(left, RegisterOrPair.AY) } else { - pushCpuStack(DataType.UWORD, left) - assignExpressionToVariable(right, rightVarname, DataType.UWORD) + pushCpuStack(BaseDataType.UWORD, left) + assignExpressionToVariable(right, rightVarname, DataType.forDt(BaseDataType.UWORD)) restoreRegisterStack(CpuRegister.Y, false) restoreRegisterStack(CpuRegister.A, false) } @@ -1297,7 +1294,7 @@ $repeatLabel""") internal fun translateDirectMemReadExpressionToRegA(expr: PtMemoryByte) { fun assignViaExprEval() { - assignExpressionToVariable(expr.address, "P8ZP_SCRATCH_W2", DataType.UWORD) + assignExpressionToVariable(expr.address, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD)) if (isTargetCpu(CpuType.CPU65c02)) { out(" lda (P8ZP_SCRATCH_W2)") } else { @@ -1324,12 +1321,12 @@ $repeatLabel""") } } - internal fun pushCpuStack(dt: DataType, value: PtExpression) { - val signed = value.type.oneOf(DataType.BYTE, DataType.WORD) - if(dt in ByteDatatypesWithBoolean) { + internal fun pushCpuStack(dt: BaseDataType, value: PtExpression) { + val signed = value.type.isSigned + if(dt.isByteOrBool) { assignExpressionToRegister(value, RegisterOrPair.A, signed) out(" pha") - } else if(dt in WordDatatypes) { + } else if(dt.isWord) { assignExpressionToRegister(value, RegisterOrPair.AY, signed) if (isTargetCpu(CpuType.CPU65c02)) out(" pha | phy") @@ -1400,5 +1397,5 @@ internal class SubroutineExtraAsmInfo { var usedFloatEvalResultVar1 = false var usedFloatEvalResultVar2 = false - val extraVars = mutableListOf>() + val extraVars = mutableListOf>() } \ No newline at end of file diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 4c77ed4e5..89e8b307f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -9,7 +9,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private val asmgen: AsmGen6502Internal, private val assignAsmGen: AssignmentAsmGen) { - internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): DataType? { + internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): BaseDataType? { return translateFunctioncall(fcall, discardResult = false, resultRegister = resultRegister) } @@ -17,7 +17,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, translateFunctioncall(fcall, discardResult = true, resultRegister = null) } - private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultRegister: RegisterOrPair?): DataType? { + private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultRegister: RegisterOrPair?): BaseDataType? { if (discardResult && fcall.hasNoSideEffects) return null // can just ignore the whole function call altogether @@ -55,7 +55,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, memread.parent = fcall asmgen.assignExpressionToRegister(memread, RegisterOrPair.A, false) asmgen.out(" pha") - val memtarget = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.UBYTE, fcall.definingISub(), fcall.position, memory=memread) + val memtarget = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingISub(), fcall.position, memory=memread) asmgen.assignExpressionTo(fcall.args[1], memtarget) asmgen.out(" pla") } @@ -69,25 +69,25 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, "prog8_ifelse_bittest_set" -> throw AssemblyError("prog8_ifelse_bittest_set() should have been translated as part of an ifElse statement") "prog8_ifelse_bittest_notset" -> throw AssemblyError("prog8_ifelse_bittest_notset() should have been translated as part of an ifElse statement") "prog8_lib_stringcompare" -> funcStringCompare(fcall, resultRegister) - "prog8_lib_square_byte" -> funcSquare(fcall, DataType.UBYTE, resultRegister) - "prog8_lib_square_word" -> funcSquare(fcall, DataType.UWORD, resultRegister) + "prog8_lib_square_byte" -> funcSquare(fcall, BaseDataType.UBYTE, resultRegister) + "prog8_lib_square_word" -> funcSquare(fcall, BaseDataType.UWORD, resultRegister) else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}") } return BuiltinFunctions.getValue(fcall.name).returnType } - private fun funcSquare(fcall: PtBuiltinFunctionCall, resultType: DataType, resultRegister: RegisterOrPair?) { + private fun funcSquare(fcall: PtBuiltinFunctionCall, resultType: BaseDataType, resultRegister: RegisterOrPair?) { // square of word value is faster with dedicated routine, square of byte just use the regular multiplication routine. when (resultType) { - DataType.UBYTE -> { + BaseDataType.UBYTE -> { asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) asmgen.out(" tay | jsr prog8_math.multiply_bytes") if(resultRegister!=null) { assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister, false, fcall.position, null, asmgen), CpuRegister.A, false, false) } } - DataType.UWORD -> { + BaseDataType.UWORD -> { asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY) asmgen.out(" jsr prog8_math.square") if(resultRegister!=null) { @@ -109,8 +109,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.out(" jsr prog8_math.divmod_ub_asm") val var2name = asmgen.asmVariableName(fcall.args[2] as PtIdentifier) val var3name = asmgen.asmVariableName(fcall.args[3] as PtIdentifier) - val divisionTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UBYTE, fcall.definingISub(), fcall.args[2].position, var2name) - val remainderTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UBYTE, fcall.definingISub(), fcall.args[3].position, var3name) + val divisionTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingISub(), fcall.args[2].position, var2name) + val remainderTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingISub(), fcall.args[3].position, var3name) assignAsmGen.assignRegisterByte(remainderTarget, CpuRegister.A, false, false) assignAsmGen.assignRegisterByte(divisionTarget, CpuRegister.Y, false, false) } @@ -122,7 +122,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, // output: P8ZP_SCRATCH_W2 in ZP: 16-bit remainder, A/Y: 16 bit division result asmgen.out(" jsr prog8_math.divmod_uw_asm") val var2name = asmgen.asmVariableName(fcall.args[2] as PtIdentifier) - val divisionTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UBYTE, fcall.definingISub(), fcall.args[2].position, var2name) + val divisionTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingISub(), fcall.args[2].position, var2name) val remainderVar = asmgen.asmVariableName(fcall.args[3] as PtIdentifier) assignAsmGen.assignRegisterpairWord(divisionTarget, RegisterOrPair.AY) asmgen.out(""" @@ -198,7 +198,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, return } - asmgen.assignExpressionToVariable(fcall.args[0], asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD) // jump address + asmgen.assignExpressionToVariable(fcall.args[0], asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.forDt(BaseDataType.UWORD)) // jump address asmgen.out(""" ; push a return address so the jmp becomes indirect jsr lda #>((+)-1) @@ -305,8 +305,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcCmp(fcall: PtBuiltinFunctionCall) { val arg1 = fcall.args[0] val arg2 = fcall.args[1] - if(arg1.type in ByteDatatypes) { - if(arg2.type in ByteDatatypes) { + if(arg1.type.isByte) { + if(arg2.type.isByte) { when (arg2) { is PtIdentifier -> { asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A) @@ -338,7 +338,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, throw AssemblyError("args for cmp() should have same dt") } else { // arg1 is a word - if(arg2.type in WordDatatypes) { + if(arg2.type.isWord) { when (arg2) { is PtIdentifier -> { asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY) @@ -376,11 +376,11 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, throw AssemblyError("should not discard result of memory allocation at $fcall") val name = (fcall.args[0] as PtString).value require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name ${fcall.position}"} - val slabname = PtIdentifier("prog8_slabs.prog8_memoryslab_$name", DataType.UWORD, fcall.position) + val slabname = PtIdentifier("prog8_slabs.prog8_memoryslab_$name", DataType.forDt(BaseDataType.UWORD), fcall.position) val addressOf = PtAddressOf(fcall.position) addressOf.add(slabname) addressOf.parent = fcall - val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = addressOf) + val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.forDt(BaseDataType.UWORD), expression = addressOf) val target = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen) val assign = AsmAssignment(src, target, program.memsizer, fcall.position) asmgen.translateNormalAssignment(assign, fcall.definingISub()) @@ -388,16 +388,16 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcSqrt(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { translateArguments(fcall, scope) - when(fcall.args[0].type) { - DataType.UBYTE -> { + when(fcall.args[0].type.base) { + BaseDataType.UBYTE -> { asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_into_A") assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false, false) } - DataType.UWORD -> { + BaseDataType.UWORD -> { asmgen.out(" jsr prog8_lib.func_sqrt16_into_A") assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false, false) } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { asmgen.out(" jsr floats.func_sqrt_into_FAC1") assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen)) } @@ -407,8 +407,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcRor2(fcall: PtBuiltinFunctionCall) { val what = fcall.args.single() - when (what.type) { - DataType.UBYTE -> { + when (what.type.base) { + BaseDataType.UBYTE -> { when (what) { is PtArrayIndexer -> { asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X) @@ -431,7 +431,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, else -> throw AssemblyError("weird type") } } - DataType.UWORD -> { + BaseDataType.UWORD -> { when (what) { is PtArrayIndexer -> { asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X) @@ -454,8 +454,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcRor(fcall: PtBuiltinFunctionCall) { val what = fcall.args.single() - when (what.type) { - DataType.UBYTE -> { + when (what.type.base) { + BaseDataType.UBYTE -> { when (what) { is PtArrayIndexer -> { if(!what.index.isSimple()) asmgen.out(" php") // save Carry @@ -498,7 +498,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, else -> throw AssemblyError("weird type") } } - DataType.UWORD -> { + BaseDataType.UWORD -> { when (what) { is PtArrayIndexer -> { if(!what.index.isSimple()) asmgen.out(" php") // save Carry @@ -523,8 +523,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcRol2(fcall: PtBuiltinFunctionCall) { val what = fcall.args.single() - when (what.type) { - DataType.UBYTE -> { + when (what.type.base) { + BaseDataType.UBYTE -> { when (what) { is PtArrayIndexer -> { asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X) @@ -547,7 +547,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, else -> throw AssemblyError("weird type") } } - DataType.UWORD -> { + BaseDataType.UWORD -> { when (what) { is PtArrayIndexer -> { asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X) @@ -570,8 +570,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcRol(fcall: PtBuiltinFunctionCall) { val what = fcall.args.single() - when (what.type) { - DataType.UBYTE -> { + when (what.type.base) { + BaseDataType.UBYTE -> { when (what) { is PtArrayIndexer -> { if(!what.index.isSimple()) asmgen.out(" php") // save Carry @@ -614,7 +614,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, else -> throw AssemblyError("weird type") } } - DataType.UWORD -> { + BaseDataType.UWORD -> { when (what) { is PtArrayIndexer -> { if(!what.index.isSimple()) asmgen.out(" php") // save Carry @@ -642,27 +642,27 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, when(fcall.args[0]) { is PtIdentifier -> { val varname = asmgen.asmVariableName(fcall.args[0] as PtIdentifier) + if(msb) "+1" else "" - target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UBYTE, fcall.definingSub(), fcall.position, variableAsmName = varname) + target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, variableAsmName = varname) } is PtNumber -> { val num = (fcall.args[0] as PtNumber).number + if(msb) 1 else 0 val mem = PtMemoryByte(fcall.position) - mem.add(PtNumber(DataType.UBYTE, num, fcall.position)) - target = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.UBYTE, fcall.definingSub(), fcall.position, memory = mem) + mem.add(PtNumber(BaseDataType.UBYTE, num, fcall.position)) + target = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, memory = mem) } is PtAddressOf -> { val mem = PtMemoryByte(fcall.position) if((fcall.args[0] as PtAddressOf).isFromArrayElement) TODO("address-of arrayelement") if(msb) { - val address = PtBinaryExpression("+", DataType.UWORD, fcall.args[0].position) + val address = PtBinaryExpression("+", DataType.forDt(BaseDataType.UWORD), fcall.args[0].position) address.add(fcall.args[0]) - address.add(PtNumber(address.type, 1.0, fcall.args[0].position)) + address.add(PtNumber(address.type.base, 1.0, fcall.args[0].position)) mem.add(address) } else { mem.add(fcall.args[0]) } - target = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.UBYTE, fcall.definingSub(), fcall.position, memory = mem) + target = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, memory = mem) } is PtArrayIndexer -> { val indexer = fcall.args[0] as PtArrayIndexer @@ -670,7 +670,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, val msbAdd: Int if(indexer.splitWords) { val arrayVariable = indexer.variable - indexer.children[0] = PtIdentifier(arrayVariable.name + if(msb) "_msb" else "_lsb", DataType.ARRAY_UB, arrayVariable.position) + indexer.children[0] = PtIdentifier(arrayVariable.name + if(msb) "_msb" else "_lsb", DataType.arrayFor(BaseDataType.UBYTE), arrayVariable.position) indexer.children[0].parent = indexer elementSize = 1 msbAdd = 0 @@ -682,7 +682,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, // double the index because of word array (if not split), add one if msb (if not split) val constIndexNum = (indexer.index as? PtNumber)?.number if(constIndexNum!=null) { - indexer.children[1] = PtNumber(indexer.index.type, constIndexNum*elementSize + msbAdd, indexer.position) + indexer.children[1] = PtNumber(indexer.index.type.base, constIndexNum*elementSize + msbAdd, indexer.position) indexer.children[1].parent = indexer } else { val multipliedIndex: PtExpression @@ -691,12 +691,12 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } else { multipliedIndex = PtBinaryExpression("<<", indexer.index.type, indexer.position) multipliedIndex.add(indexer.index) - multipliedIndex.add(PtNumber(DataType.UBYTE, 1.0, indexer.position)) + multipliedIndex.add(PtNumber(BaseDataType.UBYTE, 1.0, indexer.position)) } if(msbAdd>0) { val msbIndex = PtBinaryExpression("+", indexer.index.type, indexer.position) msbIndex.add(multipliedIndex) - msbIndex.add(PtNumber(DataType.UBYTE, msbAdd.toDouble(), indexer.position)) + msbIndex.add(PtNumber(BaseDataType.UBYTE, msbAdd.toDouble(), indexer.position)) indexer.children[1] = msbIndex msbIndex.parent = indexer } else { @@ -704,7 +704,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, multipliedIndex.parent=indexer } } - target = AsmAssignTarget(TargetStorageKind.ARRAY, asmgen, DataType.UBYTE, fcall.definingSub(), fcall.position, array = indexer) + target = AsmAssignTarget(TargetStorageKind.ARRAY, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, array = indexer) } else -> throw AssemblyError("setlsb/setmsb on weird target ${fcall.args[0]}") } @@ -719,12 +719,12 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcSgn(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { translateArguments(fcall, scope) - when (val dt = fcall.args.single().type) { - DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A") - DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A") - DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A") - DataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_into_A") - DataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A") + when (val dt = fcall.args.single().type.base) { + BaseDataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A") + BaseDataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A") + BaseDataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A") + BaseDataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_into_A") + BaseDataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A") else -> throw AssemblyError("weird type $dt") } assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, true, true) @@ -732,24 +732,24 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcAbs(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { translateArguments(fcall, scope) - val dt = fcall.args.single().type + val dt = fcall.args.single().type.base when (dt) { - DataType.BYTE -> { + BaseDataType.BYTE -> { asmgen.out(" jsr prog8_lib.abs_b_into_A") assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A,false, true) } - DataType.WORD -> { + BaseDataType.WORD -> { asmgen.out(" jsr prog8_lib.abs_w_into_AY") assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, scope, asmgen), RegisterOrPair.AY) } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { asmgen.out(" jsr floats.func_abs_f_into_FAC1") assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen)) } - DataType.UBYTE -> { + BaseDataType.UBYTE -> { asmgen.assignRegister(RegisterOrPair.A, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.A, false, fcall.position, scope, asmgen)) } - DataType.UWORD -> { + BaseDataType.UWORD -> { asmgen.assignRegister(RegisterOrPair.AY, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.AY, false, fcall.position, scope, asmgen)) } else -> throw AssemblyError("weird type") @@ -775,8 +775,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.assignConstFloatToPointerAY(number) } else -> { - val tempvar = asmgen.getTempVarName(DataType.FLOAT) - asmgen.assignExpressionToVariable(fcall.args[1], tempvar, DataType.FLOAT) + val tempvar = asmgen.getTempVarName(BaseDataType.FLOAT) + asmgen.assignExpressionToVariable(fcall.args[1], tempvar, DataType.forDt(BaseDataType.FLOAT)) asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY) asmgen.out(""" pha @@ -851,7 +851,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.out(" jsr floats.MOVFM") if(resultRegister!=null) { assignAsmGen.assignFAC1float( - AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.FLOAT, fcall.definingISub(), fcall.position, null, null, null, resultRegister, null)) + AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.FLOAT), fcall.definingISub(), fcall.position, null, null, null, resultRegister, null)) } } @@ -919,9 +919,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } private fun funcClamp(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { - val signed = fcall.type in SignedDatatypes - when(fcall.type) { - in ByteDatatypes -> { + val signed = fcall.type.isSigned + when { + fcall.type.isByte -> { assignAsmGen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W1", fcall.args[1].type) // minimum assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W1+1", fcall.args[2].type) // maximum assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A, signed) // value @@ -929,7 +929,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen) assignAsmGen.assignRegisterByte(targetReg, CpuRegister.A, signed, true) } - in WordDatatypes -> { + fcall.type.isWord -> { assignAsmGen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W1", fcall.args[1].type) // minimum assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W2", fcall.args[2].type) // maximum assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY, signed) // value @@ -942,9 +942,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } private fun funcMin(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { - val signed = fcall.type in SignedDatatypes - when (fcall.type) { - in ByteDatatypes -> { + val signed = fcall.type.isSigned + when { + fcall.type.isByte -> { asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_B1", fcall.type) // right asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // left asmgen.out(" cmp P8ZP_SCRATCH_B1") @@ -955,7 +955,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen) asmgen.assignRegister(RegisterOrPair.A, targetReg) } - in WordDatatypes -> { + fcall.type.isWord -> { asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", fcall.type) // left asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", fcall.type) // right if(signed) { @@ -1000,8 +1000,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } private fun funcMax(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { - val signed = fcall.type in SignedDatatypes - if(fcall.type in ByteDatatypes) { + val signed = fcall.type.isSigned + if(fcall.type.isByte) { asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_B1", fcall.type) // left asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // right asmgen.out(" cmp P8ZP_SCRATCH_B1") @@ -1011,7 +1011,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, +""") val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen) asmgen.assignRegister(RegisterOrPair.A, targetReg) - } else if(fcall.type in WordDatatypes) { + } else if(fcall.type.isWord) { asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", fcall.type) // left asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", fcall.type) // right if(signed) { @@ -1102,7 +1102,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcMsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { val arg = fcall.args.single() - if (arg.type !in WordDatatypes) + if (!arg.type.isWord) throw AssemblyError("msb required word argument") if (arg is PtNumber) throw AssemblyError("msb(const) should have been const-folded away") @@ -1201,7 +1201,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcLsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { val arg = fcall.args.single() - if (arg.type !in WordDatatypes) + if (!arg.type.isWord) throw AssemblyError("lsb required word argument") if (arg is PtNumber) throw AssemblyError("lsb(const) should have been const-folded away") @@ -1284,7 +1284,10 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun translateArguments(call: PtBuiltinFunctionCall, scope: IPtSubroutine?) { val signature = BuiltinFunctions.getValue(call.name) - val callConv = signature.callConvention(call.args.map { it.type}) + val callConv = signature.callConvention(call.args.map { + require(it.type.isNumericOrBool) + it.type.base + }) fun getSourceForFloat(value: PtExpression): AsmAssignSource { return when (value) { @@ -1302,11 +1305,11 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, throw AssemblyError("cannot use float arguments outside of a subroutine scope") asmgen.subroutineExtra(scope).usedFloatEvalResultVar2 = true - val variable = PtIdentifier(subroutineFloatEvalResultVar2, DataType.FLOAT, value.position) + val variable = PtIdentifier(subroutineFloatEvalResultVar2, DataType.forDt(BaseDataType.FLOAT), value.position) val addr = PtAddressOf(value.position) addr.add(variable) addr.parent = call - asmgen.assignExpressionToVariable(value, asmgen.asmVariableName(variable), DataType.FLOAT) + asmgen.assignExpressionToVariable(value, asmgen.asmVariableName(variable), DataType.forDt(BaseDataType.FLOAT)) AsmAssignSource.fromAstSource(addr, program, asmgen) } } @@ -1319,9 +1322,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, when { conv.variable -> { val varname = "prog8_lib.func_${call.name}._arg_${paramName}" - val src = when (conv.dt) { - DataType.FLOAT -> getSourceForFloat(value) - in PassByReferenceDatatypes -> { + val src = when { + conv.dt==BaseDataType.FLOAT -> getSourceForFloat(value) + conv.dt.isPassByRef -> { // put the address of the argument in AY val addr = PtAddressOf(value.position) addr.add(value) @@ -1332,14 +1335,14 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, AsmAssignSource.fromAstSource(value, program, asmgen) } } - val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, conv.dt, null, value.position, variableAsmName = varname) + val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(conv.dt), null, value.position, variableAsmName = varname) val assign = AsmAssignment(src, tgt, program.memsizer, value.position) asmgen.translateNormalAssignment(assign, scope) } conv.reg != null -> { - val src = when (conv.dt) { - DataType.FLOAT -> getSourceForFloat(value) - in PassByReferenceDatatypes -> { + val src = when { + conv.dt==BaseDataType.FLOAT -> getSourceForFloat(value) + conv.dt.isPassByRef -> { // put the address of the argument in AY val addr = PtAddressOf(value.position) addr.add(value) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt index e6ac38b26..11e4ad8b1 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt @@ -3,7 +3,9 @@ package prog8.codegen.cpu6502 import prog8.code.ast.IPtSubroutine import prog8.code.ast.PtAsmSub import prog8.code.ast.PtSub -import prog8.code.core.* +import prog8.code.core.DataType +import prog8.code.core.RegisterOrPair +import prog8.code.core.RegisterOrStatusflag internal fun IPtSubroutine.returnsWhatWhere(): List> { @@ -16,10 +18,10 @@ internal fun IPtSubroutine.returnsWhatWhere(): List RegisterOrStatusflag(RegisterOrPair.A, null) - in WordDatatypes -> RegisterOrStatusflag(RegisterOrPair.AY, null) - DataType.FLOAT -> RegisterOrStatusflag(RegisterOrPair.FAC1, null) + val register = when { + returntype!!.isByteOrBool -> RegisterOrStatusflag(RegisterOrPair.A, null) + returntype!!.isWord -> RegisterOrStatusflag(RegisterOrPair.AY, null) + returntype!!.isFloat -> RegisterOrStatusflag(RegisterOrPair.FAC1, null) else -> RegisterOrStatusflag(RegisterOrPair.AY, null) } listOf(Pair(register, returntype!!)) @@ -30,11 +32,11 @@ internal fun IPtSubroutine.returnsWhatWhere(): List RegisterOrStatusflag(RegisterOrPair.A, null) - in WordDatatypes -> RegisterOrStatusflag(RegisterOrPair.AY, null) - DataType.FLOAT -> RegisterOrStatusflag(RegisterOrPair.FAC1, null) - null -> null + return when { + returntype?.isByteOrBool==true -> RegisterOrStatusflag(RegisterOrPair.A, null) + returntype?.isWord==true -> RegisterOrStatusflag(RegisterOrPair.AY, null) + returntype?.isFloat==true -> RegisterOrStatusflag(RegisterOrPair.FAC1, null) + returntype==null -> null else -> RegisterOrStatusflag(RegisterOrPair.AY, null) } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt index 4223a0078..51adbb5a9 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt @@ -46,10 +46,10 @@ internal class ForLoopsAsmGen( throw AssemblyError("for unsigned loop variable it's not possible to count down with step != -1 from a non-const value to exactly zero due to value wrapping") } - when(iterableDt) { - DataType.ARRAY_B, DataType.ARRAY_UB -> { + when { + iterableDt.isByteArray -> { val varname = asmgen.asmVariableName(stmt.variable) - asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt)) + asmgen.assignExpressionToVariable(range.from, varname, iterableDt.elementType()) if (stepsize==-1 && range.to.asConstInteger()==0) { // simple loop downto 0 step -1 asmgen.out(loopLabel) @@ -75,7 +75,7 @@ internal class ForLoopsAsmGen( // loop over byte range via loopvar asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false) // pre-check for end already reached - if(iterableDt==DataType.ARRAY_B) { + if(iterableDt.isSignedByteArray) { asmgen.out(" sta $modifiedLabel+1") if(stepsize<0) { asmgen.out(""" @@ -121,7 +121,7 @@ $modifiedLabel cmp #0 ; modified // loop over byte range via loopvar asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false) // pre-check for end already reached - if(iterableDt==DataType.ARRAY_B) { + if(iterableDt.isSignedByteArray) { asmgen.out(" sta $modifiedLabel+1") if(stepsize<0) asmgen.out(""" @@ -171,7 +171,7 @@ $modifiedLabel cmp #0 ; modified asmgen.out(endLabel) } } - DataType.ARRAY_W, DataType.ARRAY_UW -> { + iterableDt.isWordArray && !iterableDt.isSplitWordArray -> { val varname = asmgen.asmVariableName(stmt.variable) assignLoopvarWord(stmt, range) if(stepsize==-1 && range.to.asConstInteger()==0) { @@ -249,7 +249,7 @@ $modifiedLabel2 cmp #0 ; modified $loopLabel""") asmgen.translate(stmt.statements) - if (iterableDt == DataType.ARRAY_UW) { + if (iterableDt.isUnsignedWordArray) { asmgen.out(""" lda $varname clc @@ -324,7 +324,7 @@ $endLabel""") private fun precheckFromToWord(iterableDt: DataType, stepsize: Int, fromVar: String, endLabel: String) { // pre-check for end already reached. // 'to' is in AY, do NOT clobber this! - if(iterableDt==DataType.ARRAY_W) { + if(iterableDt.isSignedWordArray) { if(stepsize<0) asmgen.out(""" sta P8ZP_SCRATCH_W2 ; to @@ -381,8 +381,8 @@ $endLabel""") is StMemVar -> symbol.length!! else -> 0 } - when(iterableDt) { - DataType.STR -> { + when { + iterableDt.isString -> { asmgen.out(""" lda #<$iterableName ldy #>$iterableName @@ -399,7 +399,7 @@ $loopLabel lda ${65535.toHex()} ; modified bne $loopLabel $endLabel""") } - DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_BOOL -> { + iterableDt.isByteArray || iterableDt.isBoolArray -> { val indexVar = asmgen.makeLabel("for_index") asmgen.out(""" ldy #0 @@ -424,7 +424,7 @@ $loopLabel sty $indexVar } if(numElements>=16) { // allocate index var on ZP if possible - val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) + val result = zeropage.allocate(indexVar, DataType.forDt(BaseDataType.UBYTE), null, stmt.position, asmgen.errors) result.fold( success = { (address, _, _)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, failure = { asmgen.out("$indexVar .byte 0") } @@ -434,7 +434,45 @@ $loopLabel sty $indexVar } asmgen.out(endLabel) } - DataType.ARRAY_W, DataType.ARRAY_UW -> { + iterableDt.isSplitWordArray -> { + val indexVar = asmgen.makeLabel("for_index") + val loopvarName = asmgen.asmVariableName(stmt.variable) + asmgen.out(""" + ldy #0 +$loopLabel sty $indexVar + lda ${iterableName}_lsb,y + sta $loopvarName + lda ${iterableName}_msb,y + sta $loopvarName+1""") + asmgen.translate(stmt.statements) + if(numElements<=255) { + asmgen.out(""" + ldy $indexVar + iny + cpy #$numElements + beq $endLabel + bne $loopLabel""") + } else { + // length is 256 + asmgen.out(""" + ldy $indexVar + iny + bne $loopLabel + beq $endLabel""") + } + if(numElements>=16) { + // allocate index var on ZP if possible + val result = zeropage.allocate(indexVar, DataType.forDt(BaseDataType.UBYTE), null, stmt.position, asmgen.errors) + result.fold( + success = { (address,_,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, + failure = { asmgen.out("$indexVar .byte 0") } + ) + } else { + asmgen.out("$indexVar .byte 0") + } + asmgen.out(endLabel) + } + iterableDt.isWordArray -> { val length = numElements * 2 val indexVar = asmgen.makeLabel("for_index") val loopvarName = asmgen.asmVariableName(stmt.variable) @@ -465,7 +503,7 @@ $loopLabel sty $indexVar } if(length>=16) { // allocate index var on ZP if possible - val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) + val result = zeropage.allocate(indexVar, DataType.forDt(BaseDataType.UBYTE), null, stmt.position, asmgen.errors) result.fold( success = { (address,_,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, failure = { asmgen.out("$indexVar .byte 0") } @@ -475,45 +513,7 @@ $loopLabel sty $indexVar } asmgen.out(endLabel) } - DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT -> { - val indexVar = asmgen.makeLabel("for_index") - val loopvarName = asmgen.asmVariableName(stmt.variable) - asmgen.out(""" - ldy #0 -$loopLabel sty $indexVar - lda ${iterableName}_lsb,y - sta $loopvarName - lda ${iterableName}_msb,y - sta $loopvarName+1""") - asmgen.translate(stmt.statements) - if(numElements<=255) { - asmgen.out(""" - ldy $indexVar - iny - cpy #$numElements - beq $endLabel - bne $loopLabel""") - } else { - // length is 256 - asmgen.out(""" - ldy $indexVar - iny - bne $loopLabel - beq $endLabel""") - } - if(numElements>=16) { - // allocate index var on ZP if possible - val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors) - result.fold( - success = { (address,_,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, - failure = { asmgen.out("$indexVar .byte 0") } - ) - } else { - asmgen.out("$indexVar .byte 0") - } - asmgen.out(endLabel) - } - DataType.ARRAY_F -> { + iterableDt.isFloatArray -> { throw AssemblyError("for loop with floating point variables is not supported") } else -> throw AssemblyError("can't iterate over $iterableDt") @@ -524,12 +524,12 @@ $loopLabel sty $indexVar private fun translateForOverConstRange(stmt: PtForLoop, iterableDt: DataType, range: IntProgression) { if (range.isEmpty() || range.step==0) throw AssemblyError("empty range or step 0") - if(iterableDt==DataType.ARRAY_B || iterableDt==DataType.ARRAY_UB) { + if(iterableDt.isByteArray) { if(range.last==range.first) return translateForSimpleByteRangeAsc(stmt, range) if(range.step==1 && range.last>range.first) return translateForSimpleByteRangeAsc(stmt, range) - if(range.step==-1 && range.lastrange.first) return translateForSimpleWordRangeAsc(stmt, range) if(range.step==-1 && range.last { + when { + iterableDt.isByteArray -> { // loop over byte range via loopvar, step >= 2 or <= -2 val varname = asmgen.asmVariableName(stmt.variable) asmgen.out(""" @@ -605,7 +605,7 @@ $loopLabel""") } asmgen.out(endLabel) } - DataType.ARRAY_W, DataType.ARRAY_UW -> { + iterableDt.isWordArray && !iterableDt.isSplitWordArray -> { // loop over word range via loopvar, step >= 2 or <= -2 val varname = asmgen.asmVariableName(stmt.variable) when (range.step) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index 586ab12f5..8d28165f0 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -17,8 +17,8 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as internal fun optimizeIntArgsViaCpuRegisters(params: List) = when(params.size) { - 1 -> params[0].type in IntegerDatatypesWithBoolean - 2 -> params[0].type in ByteDatatypesWithBoolean && params[1].type in ByteDatatypesWithBoolean + 1 -> params[0].type.isIntegerOrBool + 2 -> params[0].type.isByteOrBool && params[1].type.isByteOrBool else -> false } @@ -153,11 +153,11 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as val params = sub.parameters when(params.size) { 1 -> { - val register = if (params[0].type in ByteDatatypesWithBoolean) RegisterOrPair.A else RegisterOrPair.AY + val register = if (params[0].type.isByteOrBool) RegisterOrPair.A else RegisterOrPair.AY argumentViaRegister(sub, IndexedValue(0, params[0]), args[0], register) } 2 -> { - if(params[0].type in ByteDatatypesWithBoolean && params[1].type in ByteDatatypesWithBoolean) { + if(params[0].type.isByteOrBool && params[1].type.isByteOrBool) { // 2 byte params, second in Y, first in A argumentViaRegister(sub, IndexedValue(0, params[0]), args[0], RegisterOrPair.A) if(asmgen.needAsaveForExpr(args[1])) @@ -259,7 +259,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as val register = paramRegister.registerOrPair val requiredDt = parameter.value.type if(requiredDt!=value.type) { - if(value.type largerThan requiredDt) + if(value.type.largerSizeThan(requiredDt)) throw AssemblyError("can only convert byte values to word param types") } if (statusflag!=null) { @@ -298,21 +298,20 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as else { // via register or register pair register!! - if(requiredDt largerThan value.type) { + if(requiredDt.largerSizeThan(value.type)) { // we need to sign extend the source, do this via temporary word variable - asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", DataType.UBYTE) - asmgen.signExtendVariableLsb("P8ZP_SCRATCH_W1", value.type) + asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", DataType.forDt(BaseDataType.UBYTE)) + asmgen.signExtendVariableLsb("P8ZP_SCRATCH_W1", value.type.base) asmgen.assignVariableToRegister("P8ZP_SCRATCH_W1", register, null, Position.DUMMY) } else { val scope = value.definingISub() val target: AsmAssignTarget = - if(parameter.value.type in ByteDatatypes && (register==RegisterOrPair.AX || register == RegisterOrPair.AY || register==RegisterOrPair.XY || register in Cx16VirtualRegisters)) + if(parameter.value.type.isByte && (register==RegisterOrPair.AX || register == RegisterOrPair.AY || register==RegisterOrPair.XY || register in Cx16VirtualRegisters)) AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, parameter.value.type, scope, value.position, register = register) else { - val signed = parameter.value.type == DataType.BYTE || parameter.value.type == DataType.WORD - AsmAssignTarget.fromRegisters(register, signed, value.position, scope, asmgen) + AsmAssignTarget.fromRegisters(register, parameter.value.type.isSigned, value.position, scope, asmgen) } - val src = if(value.type in PassByReferenceDatatypes) { + val src = if(value.type.isPassByRef) { if(value is PtIdentifier) { val addr = PtAddressOf(Position.DUMMY) addr.add(value) @@ -333,18 +332,18 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as private fun isArgumentTypeCompatible(argType: DataType, paramType: DataType): Boolean { if(argType isAssignableTo paramType) return true - if(argType==DataType.BOOL && paramType==DataType.BOOL) + if(argType.isBool && paramType.isBool) return true - if(argType in ByteDatatypes && paramType in ByteDatatypes) + if(argType.isByte && paramType.isByte) return true - if(argType in WordDatatypes && paramType in WordDatatypes) + if(argType.isWord && paramType.isWord) return true // we have a special rule for some types. // strings are assignable to UWORD, for example, and vice versa - if(argType==DataType.STR && paramType==DataType.UWORD) + if(argType.isString && paramType.isUnsignedWord) return true - if(argType==DataType.UWORD && paramType == DataType.STR) + if(argType.isUnsignedWord && paramType.isString) return true return false diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt index ec3130397..562ba1ae9 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt @@ -16,7 +16,7 @@ internal class IfElseAsmGen(private val program: PtProgram, private val errors: IErrorReporter) { fun translate(stmt: PtIfElse) { - require(stmt.condition.type== DataType.BOOL) + require(stmt.condition.type.isBool) checkNotExtsubReturnsStatusReg(stmt.condition) val jumpAfterIf = stmt.ifScope.children.singleOrNull() as? PtJump @@ -33,10 +33,11 @@ internal class IfElseAsmGen(private val program: PtProgram, val compareCond = stmt.condition as? PtBinaryExpression if(compareCond!=null) { - return when(compareCond.right.type) { - in ByteDatatypesWithBoolean -> translateIfByte(stmt, jumpAfterIf) - in WordDatatypes -> translateIfWord(stmt, compareCond, jumpAfterIf) - DataType.FLOAT -> translateIfFloat(stmt, compareCond, jumpAfterIf) + val rightDt = compareCond.right.type + return when { + rightDt.isByteOrBool -> translateIfByte(stmt, jumpAfterIf) + rightDt.isWord -> translateIfWord(stmt, compareCond, jumpAfterIf) + rightDt.isFloat -> translateIfFloat(stmt, compareCond, jumpAfterIf) else -> throw AssemblyError("weird dt") } } @@ -64,8 +65,8 @@ internal class IfElseAsmGen(private val program: PtProgram, val falseLabel = asmgen.makeLabel("ifexpr_false") val endLabel = asmgen.makeLabel("ifexpr_end") evalIfExpressionConditonAndBranchWhenFalse(expr.condition, falseLabel) - when(expr.type) { - in ByteDatatypesWithBoolean -> { + when { + expr.type.isByteOrBool -> { asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.A, false) asmgen.jmp(endLabel) asmgen.out(falseLabel) @@ -73,7 +74,7 @@ internal class IfElseAsmGen(private val program: PtProgram, asmgen.out(endLabel) assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, false, false) } - in WordDatatypes -> { + expr.type.isWord -> { asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.AY, false) asmgen.jmp(endLabel) asmgen.out(falseLabel) @@ -81,7 +82,7 @@ internal class IfElseAsmGen(private val program: PtProgram, asmgen.out(endLabel) assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY) } - DataType.FLOAT -> { + expr.type.isFloat -> { asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.FAC1, true) asmgen.jmp(endLabel) asmgen.out(falseLabel) @@ -95,10 +96,11 @@ internal class IfElseAsmGen(private val program: PtProgram, private fun evalIfExpressionConditonAndBranchWhenFalse(condition: PtExpression, falseLabel: String) { if (condition is PtBinaryExpression) { - return when(condition.right.type) { - in ByteDatatypesWithBoolean -> translateIfExpressionByteConditionBranch(condition, falseLabel) - in WordDatatypes -> translateIfExpressionWordConditionBranch(condition, falseLabel) - DataType.FLOAT -> translateIfExpressionFloatConditionBranch(condition, falseLabel) + val rightDt = condition.right.type + return when { + rightDt.isByteOrBool -> translateIfExpressionByteConditionBranch(condition, falseLabel) + rightDt.isWord -> translateIfExpressionWordConditionBranch(condition, falseLabel) + rightDt.isFloat -> translateIfExpressionFloatConditionBranch(condition, falseLabel) else -> throw AssemblyError("weird dt") } } @@ -138,7 +140,7 @@ internal class IfElseAsmGen(private val program: PtProgram, private fun checkNotExtsubReturnsStatusReg(condition: PtExpression) { val fcall = condition as? PtFunctionCall - if(fcall!=null && fcall.type==DataType.BOOL) { + if(fcall!=null && fcall.type.isBool) { val extsub = st.lookup(fcall.name) as? StExtSub if(extsub!=null && extsub.returns.any { it.register.statusflag!=null }) { throw AssemblyError("if extsub() returning a status register boolean should have been changed into a Conditional branch such as if_cc") @@ -158,7 +160,7 @@ internal class IfElseAsmGen(private val program: PtProgram, is PtIfExpression, is PtBinaryExpression -> { /* no cmp necessary the lda has been done just prior */ } is PtTypeCast -> { - if(condition.value.type !in ByteDatatypes && condition.value.type !in WordDatatypes) + if(!condition.value.type.isByte && !condition.value.type.isWord) asmgen.out(" cmp #0") } else -> asmgen.out(" cmp #0") @@ -281,7 +283,7 @@ internal class IfElseAsmGen(private val program: PtProgram, private fun translateIfByte(stmt: PtIfElse, jumpAfterIf: PtJump?) { val condition = stmt.condition as PtBinaryExpression - val signed = condition.left.type in SignedDatatypes + val signed = condition.left.type.isSigned val constValue = condition.right.asConstInteger() if(constValue==0) { return translateIfCompareWithZeroByte(stmt, signed, jumpAfterIf) @@ -340,7 +342,7 @@ internal class IfElseAsmGen(private val program: PtProgram, } } in LogicalOperators -> { - val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.BOOL, stmt.definingISub(), condition.position, register=RegisterOrPair.A) + val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.BOOL), stmt.definingISub(), condition.position, register=RegisterOrPair.A) if (assignmentAsmGen.optimizedLogicalExpr(condition, regAtarget)) { if (jumpAfterIf != null) translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope) @@ -360,7 +362,7 @@ internal class IfElseAsmGen(private val program: PtProgram, } private fun translateIfExpressionByteConditionBranch(condition: PtBinaryExpression, falseLabel: String) { - val signed = condition.left.type in SignedDatatypes + val signed = condition.left.type.isSigned val constValue = condition.right.asConstInteger() if(constValue==0) { return translateIfCompareWithZeroByteBranch(condition, signed, falseLabel) @@ -380,7 +382,7 @@ internal class IfElseAsmGen(private val program: PtProgram, asmgen.out(" beq $falseLabel") } in LogicalOperators -> { - val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.BOOL, condition.definingISub(), condition.position, register=RegisterOrPair.A) + val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.BOOL), condition.definingISub(), condition.position, register=RegisterOrPair.A) if (assignmentAsmGen.optimizedLogicalExpr(condition, regAtarget)) { asmgen.out(" beq $falseLabel") } else { @@ -734,7 +736,7 @@ internal class IfElseAsmGen(private val program: PtProgram, is PtArrayIndexer -> { val constIndex = value.index.asConstInteger() if(constIndex!=null) { - val offset = constIndex * program.memsizer.memorySize(value.type) + val offset = program.memsizer.memorySize(value.type, constIndex) if(offset<256) { return asmgen.out(" ldy #$offset | $compare ${asmgen.asmVariableName(value.variable)},y") } @@ -828,7 +830,7 @@ internal class IfElseAsmGen(private val program: PtProgram, } private fun translateIfWord(stmt: PtIfElse, condition: PtBinaryExpression, jumpAfterIf: PtJump?) { - val signed = condition.left.type in SignedDatatypes + val signed = condition.left.type.isSigned val constValue = condition.right.asConstInteger() if(constValue==0) { // optimized comparisons with zero @@ -1221,7 +1223,7 @@ _jump jmp ($asmLabel) if(value.splitWords) { return compareLsbMsb("${varname}_lsb+$constIndex", "${varname}_msb+$constIndex") } else { - val offset = constIndex * program.memsizer.memorySize(value.type) + val offset = program.memsizer.memorySize(value.type, constIndex) return compareLsbMsb("$varname+$offset", "$varname+$offset+1") } } else { @@ -1358,7 +1360,7 @@ _jump jmp ($asmLabel) if(value.splitWords) { return compareLsbMsb("${varname}_lsb+$constIndex", "${varname}_msb+$constIndex") } else { - val offset = constIndex * program.memsizer.memorySize(value.type) + val offset = program.memsizer.memorySize(value.type, constIndex) return compareLsbMsb("$varname+$offset", "$varname+$offset+1") } } else { @@ -1465,7 +1467,7 @@ _jump jmp ($asmLabel) if(value.splitWords) { return translateLoadFromVarSplitw(varName, constIndex, "bne", "beq") } - val offset = constIndex * program.memsizer.memorySize(value.type) + val offset = program.memsizer.memorySize(value.type, constIndex) if (offset < 256) { return translateLoadFromVar("$varName+$offset", "bne", "beq") } @@ -1486,7 +1488,7 @@ _jump jmp ($asmLabel) if(value.splitWords) { return translateLoadFromVarSplitw(varName, constIndex, "beq", "bne") } - val offset = constIndex * program.memsizer.memorySize(value.type) + val offset = program.memsizer.memorySize(value.type, constIndex) if (offset < 256) { return translateLoadFromVar("$varName+$offset", "beq", "bne") } @@ -1841,7 +1843,7 @@ _jump jmp ($asmLabel) else translateAYEquals("${varName}_lsb+$constIndex", "${varName}_msb+$constIndex") } - val offset = constIndex * program.memsizer.memorySize(left.type) + val offset = program.memsizer.memorySize(left.type, constIndex) if(offset<256) { return if(notEquals) translateAYNotEquals("$varName+$offset", "$varName+$offset+1") @@ -2116,7 +2118,7 @@ _jump jmp ($asmLabel) is PtIdentifier -> equalf(asmgen.asmVariableName(left), asmgen.asmVariableName(right)) is PtNumber -> equalf(asmgen.asmVariableName(left), allocator.getFloatAsmConst(right.number)) else -> { - asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT) + asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT)) equalf(asmgen.asmVariableName(left), subroutineFloatEvalResultVar1) asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true } @@ -2126,7 +2128,7 @@ _jump jmp ($asmLabel) is PtIdentifier -> equalf(left, asmgen.asmVariableName(right)) is PtNumber -> equalf(left, allocator.getFloatAsmConst(right.number)) else -> { - asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT) + asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT)) equalf(left, subroutineFloatEvalResultVar1) asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true } @@ -2161,7 +2163,7 @@ _jump jmp ($asmLabel) is PtIdentifier -> lessf(asmgen.asmVariableName(left), asmgen.asmVariableName(right)) is PtNumber -> lessf(asmgen.asmVariableName(left), allocator.getFloatAsmConst(right.number)) else -> { - asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT) + asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT)) lessf(asmgen.asmVariableName(left), subroutineFloatEvalResultVar1) asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true } @@ -2171,7 +2173,7 @@ _jump jmp ($asmLabel) is PtIdentifier -> lessf(left, asmgen.asmVariableName(right)) is PtNumber -> lessf(left, allocator.getFloatAsmConst(right.number)) else -> { - asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT) + asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT)) lessf(left, subroutineFloatEvalResultVar1) asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index 768f5042a..5d6f7e283 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -198,12 +198,12 @@ internal class ProgramAndVarsGen( for(num in 1..count) { val name = asmgen.buildTempVarName(dt, num) when (dt) { - DataType.BOOL -> asmgen.out("$name .byte ?") - DataType.BYTE -> asmgen.out("$name .char ?") - DataType.UBYTE -> asmgen.out("$name .byte ?") - DataType.WORD -> asmgen.out("$name .sint ?") - DataType.UWORD -> asmgen.out("$name .word ?") - DataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}") + BaseDataType.BOOL -> asmgen.out("$name .byte ?") + BaseDataType.BYTE -> asmgen.out("$name .char ?") + BaseDataType.UBYTE -> asmgen.out("$name .byte ?") + BaseDataType.WORD -> asmgen.out("$name .sint ?") + BaseDataType.UWORD -> asmgen.out("$name .word ?") + BaseDataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}") else -> throw AssemblyError("weird dt for extravar $dt") } } @@ -435,7 +435,7 @@ internal class ProgramAndVarsGen( 1 -> { val dt = params[0].type val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, sub, params[0].position, variableAsmName = varname(params[0])) - if(dt in ByteDatatypesWithBoolean) + if(dt.isByteOrBool) asmgen.assignRegister(RegisterOrPair.A, target) // single byte in A else asmgen.assignRegister(RegisterOrPair.AY, target) // word in AY @@ -443,7 +443,7 @@ internal class ProgramAndVarsGen( 2 -> { val target1 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, params[0].type, sub, params[0].position, variableAsmName = varname(params[0])) val target2 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, params[1].type, sub, params[1].position, variableAsmName = varname(params[1])) - if(params[0].type in ByteDatatypesWithBoolean && params[1].type in ByteDatatypesWithBoolean) { + if(params[0].type.isByteOrBool && params[1].type.isByteOrBool) { // 2 byte args, first in A, second in Y asmgen.assignRegister(RegisterOrPair.A, target1) asmgen.assignRegister(RegisterOrPair.Y, target2) @@ -463,9 +463,9 @@ internal class ProgramAndVarsGen( if(addr!=null) asmgen.out("$name = $addr") else when(dt) { - DataType.UBYTE -> asmgen.out("$name .byte ?") - DataType.UWORD -> asmgen.out("$name .word ?") - DataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}") + BaseDataType.UBYTE -> asmgen.out("$name .byte ?") + BaseDataType.UWORD -> asmgen.out("$name .word ?") + BaseDataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}") else -> throw AssemblyError("weird dt for extravar $dt") } } @@ -557,7 +557,7 @@ internal class ProgramAndVarsGen( private fun getZpStringVarsWithInitvalue(): Collection { val result = mutableListOf() - val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR } + val vars = allocator.zeropageVars.filter { it.value.dt.isString } for (variable in vars) { val scopedName = variable.key val svar = symboltable.lookup(scopedName) as? StStaticVariable @@ -569,7 +569,7 @@ internal class ProgramAndVarsGen( private fun getZpArrayVarsWithInitvalue(): Collection { val result = mutableListOf() - val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes } + val vars = allocator.zeropageVars.filter { it.value.dt.isArray } for (variable in vars) { val scopedName = variable.key val svar = symboltable.lookup(scopedName) as? StStaticVariable @@ -585,7 +585,7 @@ internal class ProgramAndVarsGen( if (scopedName.startsWith("cx16.r")) continue // The 16 virtual registers of the cx16 are not actual variables in zp, they're memory mapped val variable = symboltable.flat.getValue(scopedName) as StStaticVariable - if(variable.dt in SplitWordArrayTypes) { + if(variable.dt.isSplitWordArray) { val lsbAddr = zpvar.address val msbAddr = zpvar.address + (zpvar.size/2).toUInt() asmgen.out("${scopedName.substringAfterLast('.')}_lsb \t= $lsbAddr \t; zp ${zpvar.dt} (lsbs)") @@ -603,10 +603,10 @@ internal class ProgramAndVarsGen( asmgen.out("; non-zeropage variables") asmgen.out(" .section BSS") val (notAligned, aligned) = varsNoInit.partition { it.align==0 } - notAligned.sortedWith(compareBy { it.name }.thenBy { it.dt }).forEach { + notAligned.sortedWith(compareBy { it.name }.thenBy { it.dt.base }).forEach { uninitializedVariable2asm(it) } - aligned.sortedWith(compareBy { it.align }.thenBy { it.name }.thenBy { it.dt }).forEach { + aligned.sortedWith(compareBy { it.align }.thenBy { it.name }.thenBy { it.dt.base }).forEach { uninitializedVariable2asm(it) } asmgen.out(" .send BSS") @@ -614,7 +614,7 @@ internal class ProgramAndVarsGen( if(varsWithInit.isNotEmpty()) { asmgen.out("; non-zeropage variables with init value") - val (stringvars, othervars) = varsWithInit.sortedBy { it.name }.partition { it.dt == DataType.STR } + val (stringvars, othervars) = varsWithInit.sortedBy { it.name }.partition { it.dt.isString } val (notAlignedStrings, alignedStrings) = stringvars.partition { it.align==0 } val (notAlignedOther, alignedOther) = othervars.partition { it.align==0 } notAlignedStrings.forEach { @@ -644,19 +644,20 @@ internal class ProgramAndVarsGen( } private fun uninitializedVariable2asm(variable: StStaticVariable) { - when (variable.dt) { - DataType.BOOL, DataType.UBYTE -> asmgen.out("${variable.name}\t.byte ?") - DataType.BYTE -> asmgen.out("${variable.name}\t.char ?") - DataType.UWORD -> asmgen.out("${variable.name}\t.word ?") - DataType.WORD -> asmgen.out("${variable.name}\t.sint ?") - DataType.FLOAT -> asmgen.out("${variable.name}\t.fill ${compTarget.machine.FLOAT_MEM_SIZE}") - in SplitWordArrayTypes -> { + val dt = variable.dt + when { + dt.isBool || dt.isUnsignedByte -> asmgen.out("${variable.name}\t.byte ?") + dt.isSignedByte -> asmgen.out("${variable.name}\t.char ?") + dt.isUnsignedWord -> asmgen.out("${variable.name}\t.word ?") + dt.isSignedWord -> asmgen.out("${variable.name}\t.sint ?") + dt.isFloat -> asmgen.out("${variable.name}\t.fill ${compTarget.machine.FLOAT_MEM_SIZE}") + dt.isSplitWordArray -> { alignVar(variable.align) val numbytesPerHalf = compTarget.memorySize(variable.dt, variable.length!!) / 2 asmgen.out("${variable.name}_lsb\t.fill $numbytesPerHalf") asmgen.out("${variable.name}_msb\t.fill $numbytesPerHalf") } - in ArrayDatatypes -> { + dt.isArray -> { alignVar(variable.align) val numbytes = compTarget.memorySize(variable.dt, variable.length!!) asmgen.out("${variable.name}\t.fill $numbytes") @@ -675,18 +676,19 @@ internal class ProgramAndVarsGen( private fun staticVariable2asm(variable: StStaticVariable) { val initialValue: Number = if(variable.initializationNumericValue!=null) { - if(variable.dt== DataType.FLOAT) + if(variable.dt.isFloat) variable.initializationNumericValue!! else variable.initializationNumericValue!!.toInt() } else 0 - when (variable.dt) { - DataType.BOOL, DataType.UBYTE -> asmgen.out("${variable.name}\t.byte ${initialValue.toHex()}") - DataType.BYTE -> asmgen.out("${variable.name}\t.char $initialValue") - DataType.UWORD -> asmgen.out("${variable.name}\t.word ${initialValue.toHex()}") - DataType.WORD -> asmgen.out("${variable.name}\t.sint $initialValue") - DataType.FLOAT -> { + val dt=variable.dt + when { + dt.isBool || dt.isUnsignedByte -> asmgen.out("${variable.name}\t.byte ${initialValue.toHex()}") + dt.isSignedByte -> asmgen.out("${variable.name}\t.char $initialValue") + dt.isUnsignedWord -> asmgen.out("${variable.name}\t.word ${initialValue.toHex()}") + dt.isSignedWord -> asmgen.out("${variable.name}\t.sint $initialValue") + dt.isFloat -> { if(initialValue==0) { asmgen.out("${variable.name}\t.byte 0,0,0,0,0 ; float") } else { @@ -694,10 +696,10 @@ internal class ProgramAndVarsGen( asmgen.out("${variable.name}\t.byte $floatFill ; float $initialValue") } } - DataType.STR -> { + dt.isString -> { throw AssemblyError("all string vars should have been interned into prog") } - in ArrayDatatypes -> { + dt.isArray -> { arrayVariable2asm(variable.name, variable.dt, variable.align, variable.initializationArrayValue, variable.length) } else -> { @@ -708,8 +710,8 @@ internal class ProgramAndVarsGen( private fun arrayVariable2asm(varname: String, dt: DataType, align: Int, value: StArray?, orNumberOfZeros: Int?) { alignVar(align) - when(dt) { - DataType.ARRAY_UB, DataType.ARRAY_BOOL -> { + when { + dt.isUnsignedByteArray || dt.isBoolArray -> { val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros) if (data.size <= 16) asmgen.out("$varname\t.byte ${data.joinToString()}") @@ -719,7 +721,7 @@ internal class ProgramAndVarsGen( asmgen.out(" .byte " + chunk.joinToString()) } } - DataType.ARRAY_B -> { + dt.isSignedByteArray -> { val data = makeArrayFillDataSigned(dt, value, orNumberOfZeros) if (data.size <= 16) asmgen.out("$varname\t.char ${data.joinToString()}") @@ -729,7 +731,20 @@ internal class ProgramAndVarsGen( asmgen.out(" .char " + chunk.joinToString()) } } - DataType.ARRAY_UW -> { + dt.isSplitWordArray -> { + if(dt.elementType().isUnsignedWord) { + val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros) + asmgen.out("_array_$varname := ${data.joinToString()}") + asmgen.out("${varname}_lsb\t.byte <_array_$varname") + asmgen.out("${varname}_msb\t.byte >_array_$varname") + } else { + val data = makeArrayFillDataSigned(dt, value, orNumberOfZeros) + asmgen.out("_array_$varname := ${data.joinToString()}") + asmgen.out("${varname}_lsb\t.byte <_array_$varname") + asmgen.out("${varname}_msb\t.byte >_array_$varname") + } + } + dt.isUnsignedWordArray -> { val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros) if (data.size <= 16) asmgen.out("$varname\t.word ${data.joinToString()}") @@ -739,7 +754,7 @@ internal class ProgramAndVarsGen( asmgen.out(" .word " + chunk.joinToString()) } } - DataType.ARRAY_W -> { + dt.isSignedWordArray -> { val data = makeArrayFillDataSigned(dt, value, orNumberOfZeros) if (data.size <= 16) asmgen.out("$varname\t.sint ${data.joinToString()}") @@ -749,19 +764,7 @@ internal class ProgramAndVarsGen( asmgen.out(" .sint " + chunk.joinToString()) } } - DataType.ARRAY_UW_SPLIT -> { - val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros) - asmgen.out("_array_$varname := ${data.joinToString()}") - asmgen.out("${varname}_lsb\t.byte <_array_$varname") - asmgen.out("${varname}_msb\t.byte >_array_$varname") - } - DataType.ARRAY_W_SPLIT -> { - val data = makeArrayFillDataSigned(dt, value, orNumberOfZeros) - asmgen.out("_array_$varname := ${data.joinToString()}") - asmgen.out("${varname}_lsb\t.byte <_array_$varname") - asmgen.out("${varname}_msb\t.byte >_array_$varname") - } - DataType.ARRAY_F -> { + dt.isFloatArray -> { val array = value ?: zeroFilledArray(orNumberOfZeros!!) val floatFills = array.map { compTarget.machine.getFloatAsmBytes(it.number!!) @@ -787,7 +790,7 @@ internal class ProgramAndVarsGen( asmgen.out(" ${it.name} = ${it.address.toHex()}") } consts.sortedBy { it.name }.forEach { - if(it.dt==DataType.FLOAT) + if(it.dt==BaseDataType.FLOAT) asmgen.out(" ${it.name} = ${it.value}") else asmgen.out(" ${it.name} = ${it.value.toHex()}") @@ -818,8 +821,8 @@ internal class ProgramAndVarsGen( private fun makeArrayFillDataUnsigned(dt: DataType, value: StArray?, orNumberOfZeros: Int?): List { val array = value ?: zeroFilledArray(orNumberOfZeros!!) - return when (dt) { - DataType.ARRAY_BOOL -> + return when { + dt.isBoolArray -> // byte array can never contain pointer-to types, so treat values as all integers array.map { if(it.boolean!=null) @@ -829,13 +832,13 @@ internal class ProgramAndVarsGen( if(number==0.0) "0" else "1" } } - DataType.ARRAY_UB -> + dt.isUnsignedByteArray -> // byte array can never contain pointer-to types, so treat values as all integers array.map { val number = it.number!!.toInt() "$"+number.toString(16).padStart(2, '0') } - DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> array.map { + dt.isArray && dt.elementType().isUnsignedWord -> array.map { if(it.number!=null) { "$" + it.number!!.toInt().toString(16).padStart(4, '0') } @@ -851,14 +854,14 @@ internal class ProgramAndVarsGen( private fun makeArrayFillDataSigned(dt: DataType, value: StArray?, orNumberOfZeros: Int?): List { val array = value ?: zeroFilledArray(orNumberOfZeros!!) - return when (dt) { + return when { // byte array can never contain pointer-to types, so treat values as all integers - DataType.ARRAY_UB -> + dt.isUnsignedByteArray -> array.map { val number = it.number!!.toInt() "$"+number.toString(16).padStart(2, '0') } - DataType.ARRAY_B -> + dt.isSignedByteArray -> array.map { val number = it.number!!.toInt() val hexnum = number.absoluteValue.toString(16).padStart(2, '0') @@ -867,11 +870,11 @@ internal class ProgramAndVarsGen( else "-$$hexnum" } - DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> array.map { + dt.isArray && dt.elementType().isUnsignedWord -> array.map { val number = it.number!!.toInt() "$" + number.toString(16).padStart(4, '0') } - DataType.ARRAY_W, DataType.ARRAY_W_SPLIT -> array.map { + dt.isArray && dt.elementType().isSignedWord -> array.map { val number = it.number!!.toInt() val hexnum = number.absoluteValue.toString(16).padStart(4, '0') if(number>=0) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt index fbcb0f26c..889feeb04 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt @@ -91,7 +91,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable, if(errors.noErrors()) { val sortedList = varsDontCareWithoutAlignment.sortedByDescending { it.scopedName } for (variable in sortedList) { - if(variable.dt in IntegerDatatypesWithBoolean) { + if(variable.dt.isIntegerOrBool) { if(zeropage.free.isEmpty()) { break } else { @@ -124,6 +124,6 @@ internal class VariableAllocator(private val symboltable: SymbolTable, } } collect(st) - return vars.sortedBy { it.dt } + return vars.sortedBy { it.dt.base } } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt index 697289132..6fdf4c62d 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt @@ -17,28 +17,28 @@ internal class AnyExprAsmGen( private val asmgen: AsmGen6502Internal ) { fun assignAnyExpressionUsingStack(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { - when(expr.type) { - in ByteDatatypesWithBoolean -> { - if(expr.left.type in ByteDatatypesWithBoolean && expr.right.type in ByteDatatypesWithBoolean) + when { + expr.type.isByteOrBool -> { + if(expr.left.type.isByteOrBool && expr.right.type.isByteOrBool) return assignByteBinExpr(expr, assign) - if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { + if (expr.left.type.isWord && expr.right.type.isWord) { require(expr.operator in ComparisonOperators) throw AssemblyError("words operands comparison -> byte, should have been handled elsewhere") } - if (expr.left.type==DataType.FLOAT && expr.right.type==DataType.FLOAT) { + if (expr.left.type.isFloat && expr.right.type.isFloat) { require(expr.operator in ComparisonOperators) return assignFloatBinExpr(expr, assign) } throw AssemblyError("weird expr operand types: ${expr.left.type} and ${expr.right.type}") } - in WordDatatypes -> { - require(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { + expr.type.isWord -> { + require(expr.left.type.isWord && expr.right.type.isWord) { "both operands must be words" } throw AssemblyError("expression should have been handled otherwise: word ${expr.operator} at ${expr.position}") } - DataType.FLOAT -> { - require(expr.left.type==DataType.FLOAT && expr.right.type==DataType.FLOAT) { + expr.type.isFloat -> { + require(expr.left.type.isFloat && expr.right.type.isFloat) { "both operands must be floats" } return assignFloatBinExpr(expr, assign) @@ -52,7 +52,7 @@ internal class AnyExprAsmGen( "+" -> { asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.out(" pha") - asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE)) asmgen.out(" pla | clc | adc P8ZP_SCRATCH_B1") asmgen.assignRegister(RegisterOrPair.A, assign.target) return true @@ -60,7 +60,7 @@ internal class AnyExprAsmGen( "-" -> { asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.out(" pha") - asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE)) asmgen.out(" pla | sec | sbc P8ZP_SCRATCH_B1") asmgen.assignRegister(RegisterOrPair.A, assign.target) return true @@ -75,7 +75,7 @@ internal class AnyExprAsmGen( "&" -> { asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.out(" pha") - asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE)) asmgen.out(" pla | and P8ZP_SCRATCH_B1") asmgen.assignRegister(RegisterOrPair.A, assign.target) return true @@ -83,7 +83,7 @@ internal class AnyExprAsmGen( "|" -> { asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.out(" pha") - asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE)) asmgen.out(" pla | ora P8ZP_SCRATCH_B1") asmgen.assignRegister(RegisterOrPair.A, assign.target) return true @@ -91,7 +91,7 @@ internal class AnyExprAsmGen( "^", "xor" -> { asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.out(" pha") - asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE)) asmgen.out(" pla | eor P8ZP_SCRATCH_B1") asmgen.assignRegister(RegisterOrPair.A, assign.target) return true @@ -197,7 +197,7 @@ internal class AnyExprAsmGen( private fun setupFloatComparisonFAC1vsVarAY(expr: PtBinaryExpression) { asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true) if(!expr.right.isSimple()) asmgen.pushFAC1() - asmgen.assignExpressionToVariable(expr.right, "floats.floats_temp_var", DataType.FLOAT) + asmgen.assignExpressionToVariable(expr.right, "floats.floats_temp_var", DataType.forDt(BaseDataType.FLOAT)) if(!expr.right.isSimple()) asmgen.popFAC1() asmgen.out(" lda #floats.floats_temp_var") } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt index 17373302c..5ab4318c6 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt @@ -44,7 +44,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, } init { - if(register!=null && datatype !in NumericDatatypesWithBoolean) + if(register!=null && !datatype.isNumericOrBool) throw AssemblyError("must be numeric type") } @@ -77,12 +77,20 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, when(registers) { RegisterOrPair.A, RegisterOrPair.X, - RegisterOrPair.Y -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.BYTE else DataType.UBYTE, scope, pos, register = registers) + RegisterOrPair.Y -> { + val dt = DataType.forDt(if(signed) BaseDataType.BYTE else BaseDataType.UBYTE) + AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers) + } RegisterOrPair.AX, RegisterOrPair.AY, - RegisterOrPair.XY -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, pos, register = registers) + RegisterOrPair.XY -> { + val dt = DataType.forDt(if(signed) BaseDataType.WORD else BaseDataType.UWORD) + AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers) + } RegisterOrPair.FAC1, - RegisterOrPair.FAC2 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.FLOAT, scope, pos, register = registers) + RegisterOrPair.FAC2 -> { + AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.FLOAT), scope, pos, register = registers) + } RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, @@ -98,7 +106,10 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, RegisterOrPair.R12, RegisterOrPair.R13, RegisterOrPair.R14, - RegisterOrPair.R15 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, pos, register = registers) + RegisterOrPair.R15 -> { + val dt = DataType.forDt(if(signed) BaseDataType.WORD else BaseDataType.UWORD) + AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers) + } } } @@ -151,7 +162,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind, return AsmAssignSource(SourceStorageKind.LITERALNUMBER, program, asmgen, cv.type, number = cv) val bv = value as? PtBool if(bv!=null) - return AsmAssignSource(SourceStorageKind.LITERALBOOLEAN, program, asmgen, DataType.BOOL, boolean = bv) + return AsmAssignSource(SourceStorageKind.LITERALBOOLEAN, program, asmgen, DataType.forDt(BaseDataType.BOOL), boolean = bv) return when(value) { // checked above: is PtNumber -> throw AssemblyError("should have been constant value") @@ -163,7 +174,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind, 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 - if(value.type == DataType.UWORD && varName.lowercase().startsWith("cx16.r")) { + if(value.type.isUnsignedWord && varName.lowercase().startsWith("cx16.r")) { val regStr = varName.lowercase().substring(5) val reg = RegisterOrPair.valueOf(regStr.uppercase()) AsmAssignSource(SourceStorageKind.REGISTER, program, asmgen, value.type, register = reg) @@ -172,7 +183,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind, } } is PtMemoryByte -> { - AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.UBYTE, memory = value) + AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.forDt(BaseDataType.UBYTE), memory = value) } is PtArrayIndexer -> { AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, value.type, array = value) @@ -202,9 +213,9 @@ internal class AsmAssignSource(val kind: SourceStorageKind, AsmAssignSource(kind, program, asmgen, newType, variableAsmName, array, memory, register, number, boolean, expression) if(target.datatype!=datatype) { - if(target.datatype in ByteDatatypes && datatype in ByteDatatypes) { + if(target.datatype.isByte && datatype.isByte) { return withAdjustedDt(target.datatype) - } else if(target.datatype in WordDatatypes && datatype in WordDatatypes) { + } else if(target.datatype.isWord && datatype.isWord) { return withAdjustedDt(target.datatype) } } @@ -220,8 +231,9 @@ internal sealed class AsmAssignmentBase(val source: AsmAssignSource, val position: Position) { init { if(target.register !in arrayOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY)) - require(source.datatype != DataType.UNDEFINED) { "must not be placeholder/undefined datatype at $position" } - require(memsizer.memorySize(source.datatype) <= memsizer.memorySize(target.datatype)) { + require(!source.datatype.isUndefined) { "must not be placeholder/undefined datatype at $position" } + if(!source.datatype.isArray && !target.datatype.isArray) + require(memsizer.memorySize(source.datatype, null) <= memsizer.memorySize(target.datatype, null)) { "source dt size must be less or equal to target dt size at $position srcdt=${source.datatype} targetdt=${target.datatype}" } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 797e089d9..e01b63255 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -43,7 +43,7 @@ internal class AssignmentAsmGen( ?: throw AssemblyError("only asmsubs can return multiple values") require(sub.returns.size>=2) - if(sub.returns.any { it.type==DataType.FLOAT }) + if(sub.returns.any { it.type.isFloat }) TODO("deal with (multiple?) FP return registers") asmgen.translate(values) @@ -129,15 +129,15 @@ internal class AssignmentAsmGen( val targetMem = target.memory if(targetIdent!=null || targetMem!=null) { val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen) - when(returns.type) { - in ByteDatatypesWithBoolean -> { + when { + returns.type.isByteOrBool -> { if(returns.register.registerOrPair in Cx16VirtualRegisters) { assignVirtualRegister(tgt, returns.register.registerOrPair!!) } else { assignRegisterByte(tgt, returns.register.registerOrPair!!.asCpuRegister(), false, false) } } - in WordDatatypes -> { + returns.type.isWord -> { assignRegisterpairWord(tgt, returns.register.registerOrPair!!) } else -> throw AssemblyError("weird dt") @@ -197,43 +197,46 @@ internal class AssignmentAsmGen( when(assign.source.kind) { SourceStorageKind.LITERALBOOLEAN -> { // simple case: assign a constant boolean (0 or 1) + require(assign.target.datatype.isNumericOrBool) val num = assign.source.boolean!!.asInt() - when (assign.target.datatype) { - DataType.BOOL, DataType.UBYTE, DataType.BYTE -> assignConstantByte(assign.target, num) - DataType.UWORD, DataType.WORD -> assignConstantWord(assign.target, num) - DataType.FLOAT -> assignConstantFloat(assign.target, num.toDouble()) + when (assign.target.datatype.base) { + BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> assignConstantByte(assign.target, num) + BaseDataType.UWORD, BaseDataType.WORD -> assignConstantWord(assign.target, num) + BaseDataType.FLOAT -> assignConstantFloat(assign.target, num.toDouble()) else -> throw AssemblyError("weird numval type") } } SourceStorageKind.LITERALNUMBER -> { // simple case: assign a constant number + require(assign.target.datatype.isNumericOrBool) val num = assign.source.number!!.number - when (assign.target.datatype) { - DataType.BOOL -> assignConstantByte(assign.target, if(num==0.0) 0 else 1) - DataType.UBYTE, DataType.BYTE -> assignConstantByte(assign.target, num.toInt()) - DataType.UWORD, DataType.WORD -> assignConstantWord(assign.target, num.toInt()) - DataType.FLOAT -> assignConstantFloat(assign.target, num) + when (assign.target.datatype.base) { + BaseDataType.BOOL -> assignConstantByte(assign.target, if(num==0.0) 0 else 1) + BaseDataType.UBYTE, BaseDataType.BYTE -> assignConstantByte(assign.target, num.toInt()) + BaseDataType.UWORD, BaseDataType.WORD -> assignConstantWord(assign.target, num.toInt()) + BaseDataType.FLOAT -> assignConstantFloat(assign.target, num) else -> throw AssemblyError("weird numval type") } } SourceStorageKind.VARIABLE -> { // simple case: assign from another variable val variable = assign.source.asmVarname - when (assign.target.datatype) { - DataType.BOOL -> { - if (assign.source.datatype == DataType.BOOL) assignVariableByte(assign.target, variable) + val targetDt = assign.target.datatype + when { + targetDt.isBool -> { + if (assign.source.datatype.isBool) assignVariableByte(assign.target, variable) else throw AssemblyError("assigning non-bool variable to boolean, should have been typecasted") } - DataType.UBYTE, DataType.BYTE -> assignVariableByte(assign.target, variable) - DataType.WORD -> assignVariableWord(assign.target, variable, assign.source.datatype) - DataType.UWORD -> { - if(assign.source.datatype in PassByReferenceDatatypes) + targetDt.isByte -> assignVariableByte(assign.target, variable) + targetDt.isSignedWord -> assignVariableWord(assign.target, variable, assign.source.datatype) + targetDt.isUnsignedWord -> { + if(assign.source.datatype.isPassByRef) assignAddressOf(assign.target, variable, null, null) else assignVariableWord(assign.target, variable, assign.source.datatype) } - DataType.FLOAT -> assignVariableFloat(assign.target, variable) - DataType.STR -> assignVariableString(assign.target, variable) + targetDt.isFloat -> assignVariableFloat(assign.target, variable) + targetDt.isString -> assignVariableString(assign.target, variable) else -> throw AssemblyError("unsupported assignment target type ${assign.target.datatype}") } } @@ -244,7 +247,7 @@ internal class AssignmentAsmGen( val constIndex = value.index.asConstInteger() if(value.splitWords) { - require(elementDt in WordDatatypes) + require(elementDt.isWord) if(constIndex!=null) { asmgen.out(" lda ${arrayVarName}_lsb+$constIndex | ldy ${arrayVarName}_msb+$constIndex") assignRegisterpairWord(assign.target, RegisterOrPair.AY) @@ -258,17 +261,17 @@ internal class AssignmentAsmGen( if (constIndex!=null) { // constant array index value - val indexValue = constIndex * program.memsizer.memorySize(elementDt) - when (elementDt) { - in ByteDatatypesWithBoolean -> { + val indexValue = program.memsizer.memorySize(elementDt, constIndex) + when { + elementDt.isByteOrBool -> { asmgen.out(" lda $arrayVarName+$indexValue") - assignRegisterByte(assign.target, CpuRegister.A, elementDt in SignedDatatypes, false) + assignRegisterByte(assign.target, CpuRegister.A, elementDt.isSigned, false) } - in WordDatatypes -> { + elementDt.isWord -> { asmgen.out(" lda $arrayVarName+$indexValue | ldy $arrayVarName+$indexValue+1") assignRegisterpairWord(assign.target, RegisterOrPair.AY) } - DataType.FLOAT -> { + elementDt.isFloat -> { asmgen.out(" lda #<($arrayVarName+$indexValue) | ldy #>($arrayVarName+$indexValue)") assignFloatFromAY(assign.target) } @@ -276,18 +279,18 @@ internal class AssignmentAsmGen( throw AssemblyError("weird array type") } } else { - when (elementDt) { - in ByteDatatypesWithBoolean -> { + when { + elementDt.isByteOrBool -> { asmgen.loadScaledArrayIndexIntoRegister(value, CpuRegister.Y) asmgen.out(" lda $arrayVarName,y") - assignRegisterByte(assign.target, CpuRegister.A, elementDt in SignedDatatypes, true) + assignRegisterByte(assign.target, CpuRegister.A, elementDt.isSigned, true) } - in WordDatatypes -> { + elementDt.isWord -> { asmgen.loadScaledArrayIndexIntoRegister(value, CpuRegister.Y) asmgen.out(" lda $arrayVarName,y | ldx $arrayVarName+1,y") assignRegisterpairWord(assign.target, RegisterOrPair.AX) } - DataType.FLOAT -> { + elementDt.isFloat -> { asmgen.loadScaledArrayIndexIntoRegister(value, CpuRegister.A) asmgen.out(""" ldy #>$arrayVarName @@ -335,7 +338,7 @@ internal class AssignmentAsmGen( private fun assignByteFromAddressExpression(address: PtExpression, target: AsmAssignTarget) { if(address is PtBinaryExpression) { - if(address.operator=="+" && address.right.type==DataType.UWORD) { + if(address.operator=="+" && address.right.type.isUnsignedWord) { if (address.left is PtIdentifier) { // use (zp),Y instead of explicitly calculating the full zp pointer value val pointer = (address.left as PtIdentifier).name @@ -376,7 +379,7 @@ internal class AssignmentAsmGen( // // does this ever occur? we could optimize it too, but it seems like a pathological case // } } - assignExpressionToVariable(address, "P8ZP_SCRATCH_W2", DataType.UWORD) + assignExpressionToVariable(address, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD)) asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2", false) assignRegisterByte(target, CpuRegister.A, false, true) } @@ -384,7 +387,7 @@ internal class AssignmentAsmGen( private fun storeByteInAToAddressExpression(address: PtExpression, saveA: Boolean) { if(address is PtBinaryExpression) { if(address.operator=="+") { - if (address.left is PtIdentifier && address.right.type==DataType.UWORD) { + if (address.left is PtIdentifier && address.right.type.isUnsignedWord) { // use (zp),Y instead of explicitly calculating the full zp pointer value val pointer = (address.left as PtIdentifier).name when(val index=address.right) { @@ -427,7 +430,7 @@ internal class AssignmentAsmGen( // } } if(saveA) asmgen.out(" pha") - assignExpressionToVariable(address, "P8ZP_SCRATCH_W2", DataType.UWORD) + assignExpressionToVariable(address, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD)) if(saveA) asmgen.out(" pla") asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2", false) } @@ -451,29 +454,30 @@ internal class AssignmentAsmGen( val sub = symbol!!.astNode as IPtSubroutine asmgen.translateFunctionCall(value) val returnValue = sub.returnsWhatWhere().singleOrNull { it.first.registerOrPair!=null } ?: sub.returnsWhatWhere().single { it.first.statusflag!=null } - when (returnValue.second) { - DataType.STR -> { - when(assign.target.datatype) { - DataType.UWORD -> { + when { + returnValue.second.isString -> { + val targetDt = assign.target.datatype + when { + targetDt.isUnsignedWord -> { // assign the address of the string result value assignRegisterpairWord(assign.target, RegisterOrPair.AY) } - DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B -> { + targetDt.isString || targetDt.isUnsignedByteArray || targetDt.isByteArray -> { throw AssemblyError("stringvalue assignment should have been replaced by a call to strcpy") } else -> throw AssemblyError("weird target dt") } } - DataType.FLOAT -> { + returnValue.second.isFloat -> { // float result from function sits in FAC1 assignFAC1float(assign.target) } else -> { // do NOT restore X register before assigning the result values first when (returnValue.first.registerOrPair) { - RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A, returnValue.second in SignedDatatypes, true) - RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X, returnValue.second in SignedDatatypes, true) - RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y, returnValue.second in SignedDatatypes, true) + RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A, returnValue.second.isSigned, true) + RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X, returnValue.second.isSigned, true) + RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y, returnValue.second.isSigned, true) RegisterOrPair.AX -> assignVirtualRegister(assign.target, RegisterOrPair.AX) RegisterOrPair.AY -> assignVirtualRegister(assign.target, RegisterOrPair.AY) RegisterOrPair.XY -> assignVirtualRegister(assign.target, RegisterOrPair.XY) @@ -508,12 +512,13 @@ internal class AssignmentAsmGen( val returnDt = asmgen.translateBuiltinFunctionCallExpression(value, assign.target.register) if(assign.target.register==null) { // still need to assign the result to the target variable/etc. - when(returnDt) { - in ByteDatatypesWithBoolean -> assignRegisterByte(assign.target, CpuRegister.A, returnDt in SignedDatatypes, false) // function's byte result is in A - in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) // function's word result is in AY - DataType.STR -> { - when (assign.target.datatype) { - DataType.STR -> { + when { + returnDt?.isByteOrBool==true -> assignRegisterByte(assign.target, CpuRegister.A, returnDt.isSigned, false) // function's byte result is in A + returnDt?.isWord==true -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) // function's word result is in AY + returnDt==BaseDataType.STR -> { + val targetDt = assign.target.datatype + when { + targetDt.isString -> { asmgen.out(""" tax lda #<${assign.target.asmVarname} @@ -523,11 +528,11 @@ internal class AssignmentAsmGen( txa jsr prog8_lib.strcpy""") } - DataType.UWORD -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) + targetDt.isUnsignedWord -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) else -> throw AssemblyError("str return value type mismatch with target") } } - DataType.FLOAT -> { + returnDt==BaseDataType.FLOAT -> { // float result from function sits in FAC1 assignFAC1float(assign.target) } @@ -537,10 +542,10 @@ internal class AssignmentAsmGen( } is PtPrefix -> { if(assign.target.array==null) { - if(assign.source.datatype isAssignableTo assign.target.datatype || (assign.source.datatype==DataType.BOOL && assign.target.datatype in ByteDatatypes)) { - if(assign.source.datatype in IntegerDatatypesWithBoolean) { - val signed = assign.source.datatype in SignedDatatypes - if(assign.source.datatype in ByteDatatypesWithBoolean) { + if(assign.source.datatype isAssignableTo assign.target.datatype || (assign.source.datatype.isBool && assign.target.datatype.isByte)) { + if(assign.source.datatype.isIntegerOrBool) { + val signed = assign.source.datatype.isSigned + if(assign.source.datatype.isByteOrBool) { assignExpressionToRegister(value.value, RegisterOrPair.A, signed) when(value.operator) { "+" -> {} @@ -596,7 +601,7 @@ internal class AssignmentAsmGen( } } else { // use a temporary variable - val tempvar = if(value.type in ByteDatatypesWithBoolean) "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_W1" + val tempvar = if(value.type.isByteOrBool) "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_W1" assignExpressionToVariable(value.value, tempvar, value.type) when (value.operator) { "+" -> {} @@ -619,7 +624,7 @@ internal class AssignmentAsmGen( } else -> throw AssemblyError("invalid prefix operator") } - if(value.type in ByteDatatypesWithBoolean) + if(value.type.isByteOrBool) assignVariableByte(assign.target, tempvar) else assignVariableWord(assign.target, tempvar, value.type) @@ -646,28 +651,29 @@ internal class AssignmentAsmGen( private fun assignPrefixedExpressionToArrayElt(assign: AsmAssignment, scope: IPtSubroutine?) { require(assign.source.expression is PtPrefix) - if(assign.source.datatype==DataType.FLOAT) { + if(assign.source.datatype.isFloat) { // floatarray[x] = -value ... just use FAC1 to calculate the expression into and then store that back into the array. assignExpressionToRegister(assign.source.expression, RegisterOrPair.FAC1, true) assignFAC1float(assign.target) } else { - val register = if(assign.source.datatype in ByteDatatypesWithBoolean) RegisterOrPair.A else RegisterOrPair.AY + val register = if(assign.source.datatype.isByteOrBool) RegisterOrPair.A else RegisterOrPair.AY val assignToRegister = AsmAssignment(assign.source, AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, assign.target.datatype, assign.target.scope, assign.target.position, register = register, origAstTarget = assign.target.origAstTarget), program.memsizer, assign.position) asmgen.translateNormalAssignment(assignToRegister, scope) - val signed = assign.target.datatype in SignedDatatypes - when(assign.target.datatype) { - in ByteDatatypesWithBoolean -> assignRegisterByte(assign.target, CpuRegister.A, signed, false) - in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) + val signed = assign.target.datatype.isSigned + val targetDt = assign.target.datatype + when { + targetDt.isByteOrBool -> assignRegisterByte(assign.target, CpuRegister.A, signed, false) + targetDt.isWord -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) else -> throw AssemblyError("weird dt") } } } private fun assignVirtualRegister(target: AsmAssignTarget, register: RegisterOrPair) { - when(target.datatype) { - in ByteDatatypesWithBoolean -> { + when { + target.datatype.isByteOrBool -> { if(register in Cx16VirtualRegisters) { asmgen.out(" lda cx16.${register.toString().lowercase()}L") } else { @@ -675,7 +681,7 @@ internal class AssignmentAsmGen( } assignRegisterByte(target, CpuRegister.A, false, false) } - in WordDatatypes -> assignRegisterpairWord(target, register) + target.datatype.isWord -> assignRegisterpairWord(target, register) else -> throw AssemblyError("expected byte or word") } } @@ -702,16 +708,15 @@ internal class AssignmentAsmGen( private fun optimizedComparison(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { if(expr.right.asConstInteger() == 0) { if(expr.operator == "==" || expr.operator=="!=") { - when(assign.target.datatype) { - in ByteDatatypesWithBoolean -> if(attemptAssignToByteCompareZero(expr, assign)) return true - else -> { - // do nothing, this is handled by a type cast. - } + if (assign.target.datatype.isByteOrBool) { + if(attemptAssignToByteCompareZero(expr, assign)) return true + } else { + // do nothing, this is handled by a type cast. } } } - if(expr.left.type==DataType.UBYTE) { + if(expr.left.type.isUnsignedByte) { if(expr.operator=="<") { assignExpressionToRegister(expr.left, RegisterOrPair.A, false) when(val right = expr.right) { @@ -826,7 +831,7 @@ internal class AssignmentAsmGen( val exprClone: PtBinaryExpression if(!asmgen.isTargetCpu(CpuType.VIRTUAL) && (expr.operator==">" || expr.operator=="<=") - && expr.right.type in WordDatatypes) { + && expr.right.type.isWord) { // word X>Y -> X Y>=X , easier to do in 6502 (codegen also expects these to no longe exist!) exprClone = PtBinaryExpression(if(expr.operator==">") "<" else ">=", expr.type, expr.position) exprClone.children.add(expr.children[1]) // doesn't seem to need a deep clone @@ -855,7 +860,7 @@ internal class AssignmentAsmGen( } else { when(assign.target.kind) { TargetStorageKind.VARIABLE -> { - if(assign.target.datatype in WordDatatypes) { + if(assign.target.datatype.isWord) { assignTrue = if(asmgen.isTargetCpu(CpuType.CPU65c02)) { PtInlineAssembly(""" lda #1 @@ -901,7 +906,7 @@ internal class AssignmentAsmGen( val exprClone: PtBinaryExpression if(!asmgen.isTargetCpu(CpuType.VIRTUAL) && (expr.operator==">" || expr.operator=="<=") - && expr.right.type in WordDatatypes) { + && expr.right.type.isWord) { // word X>Y -> X Y>=X , easier to do in 6502 (codegen also expects these to no longe exist!) exprClone = PtBinaryExpression(if(expr.operator==">") "<" else ">=", expr.type, expr.position) exprClone.children.add(expr.children[1]) // doesn't seem to need a deep clone @@ -930,8 +935,8 @@ internal class AssignmentAsmGen( } private fun optimizedRemainderExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { - when(expr.type) { - DataType.UBYTE -> { + when { + expr.type.isUnsignedByte -> { assignExpressionToRegister(expr.left, RegisterOrPair.A, false) if(!directIntoY(expr.right)) asmgen.out(" pha") assignExpressionToRegister(expr.right, RegisterOrPair.Y, false) @@ -943,10 +948,10 @@ internal class AssignmentAsmGen( assignRegisterByte(target, CpuRegister.A, false, true) return true } - DataType.UWORD -> { + expr.type.isUnsignedWord -> { asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") asmgen.out(" jsr prog8_math.divmod_uw_asm") - assignVariableWord(target, "P8ZP_SCRATCH_W2", DataType.UWORD) + assignVariableWord(target, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD)) return true } else -> return false @@ -955,8 +960,8 @@ internal class AssignmentAsmGen( private fun optimizedDivideExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { // replacing division by shifting is done in an optimizer step. - when(expr.type) { - DataType.UBYTE -> { + when { + expr.type.isUnsignedByte -> { assignExpressionToRegister(expr.left, RegisterOrPair.A, false) if(!directIntoY(expr.right)) asmgen.out(" pha") assignExpressionToRegister(expr.right, RegisterOrPair.Y, false) @@ -965,7 +970,7 @@ internal class AssignmentAsmGen( assignRegisterByte(target, CpuRegister.Y, false, true) return true } - DataType.BYTE -> { + expr.type.isSignedByte -> { assignExpressionToRegister(expr.left, RegisterOrPair.A, true) if(!directIntoY(expr.right)) asmgen.out(" pha") assignExpressionToRegister(expr.right, RegisterOrPair.Y, true) @@ -974,13 +979,13 @@ internal class AssignmentAsmGen( assignRegisterByte(target, CpuRegister.Y, true, true) return true } - DataType.UWORD -> { + expr.type.isUnsignedWord -> { asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") asmgen.out(" jsr prog8_math.divmod_uw_asm") assignRegisterpairWord(target, RegisterOrPair.AY) return true } - DataType.WORD -> { + expr.type.isSignedWord -> { asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") asmgen.out(" jsr prog8_math.divmod_w_asm") assignRegisterpairWord(target, RegisterOrPair.AY) @@ -993,27 +998,27 @@ internal class AssignmentAsmGen( private fun optimizedMultiplyExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { val value = expr.right.asConstInteger() if(value==null) { - when(expr.type) { - in ByteDatatypes -> { - assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type in SignedDatatypes) + when { + expr.type.isByte -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type.isSigned) if(!directIntoY(expr.right)) asmgen.out(" pha") - assignExpressionToRegister(expr.right, RegisterOrPair.Y, expr.type in SignedDatatypes) + assignExpressionToRegister(expr.right, RegisterOrPair.Y, expr.type.isSigned) if(!directIntoY(expr.right)) asmgen.out(" pla") asmgen.out(" jsr prog8_math.multiply_bytes") assignRegisterByte(target, CpuRegister.A, false, true) return true } - in WordDatatypes -> { + expr.type.isWord -> { if(expr.definingBlock()!!.options.veraFxMuls) { // cx16 verafx hardware mul if(expr.right.isSimple()) { - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.R0, expr.left.type in SignedDatatypes) - asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.R1, expr.left.type in SignedDatatypes) + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.R0, expr.left.type.isSigned) + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.R1, expr.left.type.isSigned) } else { - asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.left.type in SignedDatatypes) + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.left.type.isSigned) asmgen.out(" pha") asmgen.saveRegisterStack(CpuRegister.Y, false) - asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.R1, expr.left.type in SignedDatatypes) + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.R1, expr.left.type.isSigned) asmgen.restoreRegisterStack(CpuRegister.Y, false) asmgen.out(" pla") asmgen.out(" sta cx16.r0 | sty cx16.r0+1") @@ -1031,9 +1036,9 @@ internal class AssignmentAsmGen( else -> return false } } else { - when (expr.type) { - in ByteDatatypes -> { - assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type in SignedDatatypes) + when { + expr.type.isByte -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type.isSigned) if (value in asmgen.optimizedByteMultiplications) asmgen.out(" jsr prog8_math.mul_byte_${value}") else @@ -1041,9 +1046,9 @@ internal class AssignmentAsmGen( assignRegisterByte(target, CpuRegister.A, false, true) return true } - in WordDatatypes -> { + expr.type.isWord -> { if (value in asmgen.optimizedWordMultiplications) { - assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.type in SignedDatatypes) + assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.type.isSigned) asmgen.out(" jsr prog8_math.mul_word_${value}") } else { @@ -1068,16 +1073,16 @@ internal class AssignmentAsmGen( } private fun optimizedBitshiftExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { - val signed = expr.left.type in SignedDatatypes + val signed = expr.left.type.isSigned val shifts = expr.right.asConstInteger() val dt = expr.left.type if(shifts==null) { // bit shifts with variable shifts - when(expr.right.type) { - in ByteDatatypes -> { + when { + expr.right.type.isByte -> { assignExpressionToRegister(expr.right, RegisterOrPair.A, false) } - in WordDatatypes -> { + expr.right.type.isWord -> { assignExpressionToRegister(expr.right, RegisterOrPair.AY, false) asmgen.out(""" cpy #0 @@ -1088,7 +1093,7 @@ internal class AssignmentAsmGen( else -> throw AssemblyError("weird shift value type") } asmgen.out(" pha") - if(dt in ByteDatatypes) { + if(dt.isByte) { assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) asmgen.restoreRegisterStack(CpuRegister.Y, true) if(expr.operator==">>") @@ -1116,7 +1121,7 @@ internal class AssignmentAsmGen( } else { // bit shift with constant value - if(dt in ByteDatatypes) { + if(dt.isByte) { assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) when (shifts) { in 0..7 -> { @@ -1149,7 +1154,7 @@ internal class AssignmentAsmGen( return true } } - } else if(dt in WordDatatypes) { + } else if(dt.isWord) { assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed) when (shifts) { in 0..7 -> { @@ -1224,20 +1229,20 @@ internal class AssignmentAsmGen( val dt = expr.type val left = expr.left val right = expr.right - if(dt in ByteDatatypes) { + if(dt.isByte) { when (right) { is PtIdentifier -> { - assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) + assignExpressionToRegister(left, RegisterOrPair.A, dt.isSigned) val symname = asmgen.asmVariableName(right) if(expr.operator=="+") asmgen.out(" clc | adc $symname") else asmgen.out(" sec | sbc $symname") - assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true) + assignRegisterByte(target, CpuRegister.A, dt.isSigned, true) return true } is PtNumber -> { - assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) + assignExpressionToRegister(left, RegisterOrPair.A, dt.isSigned) if(right.number==1.0 && asmgen.isTargetCpu(CpuType.CPU65c02)) { if (expr.operator == "+") asmgen.out(" inc a") @@ -1249,7 +1254,7 @@ internal class AssignmentAsmGen( else asmgen.out(" sec | sbc #${right.number.toHex()}") } - assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true) + assignRegisterByte(target, CpuRegister.A, dt.isSigned, true) return true } else -> { @@ -1257,18 +1262,18 @@ internal class AssignmentAsmGen( val rightMemByte = expr.right as? PtMemoryByte val leftArrayIndexer = expr.left as? PtArrayIndexer val rightArrayIndexer = expr.right as? PtArrayIndexer - if(expr.operator=="+" && leftArrayIndexer!=null && leftArrayIndexer.type in ByteDatatypes && right.type in ByteDatatypes) { + if(expr.operator=="+" && leftArrayIndexer!=null && leftArrayIndexer.type.isByte && right.type.isByte) { // special optimization for bytearray[y] + bytevalue : no need to use a tempvar, just use adc array,y - assignExpressionToRegister(right, RegisterOrPair.A, right.type==DataType.BYTE) + assignExpressionToRegister(right, RegisterOrPair.A, right.type.isSigned) if(!leftArrayIndexer.index.isSimple()) asmgen.out(" pha") asmgen.assignExpressionToRegister(leftArrayIndexer.index, RegisterOrPair.Y, false) if(!leftArrayIndexer.index.isSimple()) asmgen.out(" pla") val arrayvarname = asmgen.asmSymbolName(leftArrayIndexer.variable) asmgen.out(" clc | adc $arrayvarname,y") - assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true) - } else if(rightArrayIndexer!=null && rightArrayIndexer.type in ByteDatatypes && left.type in ByteDatatypes) { + assignRegisterByte(target, CpuRegister.A, dt.isSigned, true) + } else if(rightArrayIndexer!=null && rightArrayIndexer.type.isByte && left.type.isByte) { // special optimization for bytevalue +/- bytearray[y] : no need to use a tempvar, just use adc array,y or sbc array,y - assignExpressionToRegister(left, RegisterOrPair.A, left.type==DataType.BYTE) + assignExpressionToRegister(left, RegisterOrPair.A, left.type.isSigned) if(!rightArrayIndexer.index.isSimple()) asmgen.out(" pha") asmgen.assignExpressionToRegister(rightArrayIndexer.index, RegisterOrPair.Y, false) if(!rightArrayIndexer.index.isSimple()) asmgen.out(" pla") @@ -1277,17 +1282,17 @@ internal class AssignmentAsmGen( asmgen.out(" clc | adc $arrayvarname,y") else asmgen.out(" sec | sbc $arrayvarname,y") - assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true) - } else if(expr.operator=="+" && leftMemByte!=null && right.type in ByteDatatypes && optimizedPointerIndexPlusMinusByteIntoA(right, "+", leftMemByte)) { - assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true) + assignRegisterByte(target, CpuRegister.A, dt.isSigned, true) + } else if(expr.operator=="+" && leftMemByte!=null && right.type.isByte && optimizedPointerIndexPlusMinusByteIntoA(right, "+", leftMemByte)) { + assignRegisterByte(target, CpuRegister.A, dt.isSigned, true) return true - } else if(rightMemByte!=null && left.type in ByteDatatypes && optimizedPointerIndexPlusMinusByteIntoA(left, expr.operator, rightMemByte)) { - assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true) + } else if(rightMemByte!=null && left.type.isByte && optimizedPointerIndexPlusMinusByteIntoA(left, expr.operator, rightMemByte)) { + assignRegisterByte(target, CpuRegister.A, dt.isSigned, true) return true } else { - assignExpressionToRegister(left, RegisterOrPair.A, left.type==DataType.BYTE) + assignExpressionToRegister(left, RegisterOrPair.A, left.type.isSigned) if(directIntoY(right)) { - assignExpressionToRegister(right, RegisterOrPair.Y, left.type==DataType.BYTE) + assignExpressionToRegister(right, RegisterOrPair.Y, left.type.isSigned) asmgen.out(" sty P8ZP_SCRATCH_B1") } else { asmgen.out(" pha") @@ -1298,12 +1303,12 @@ internal class AssignmentAsmGen( asmgen.out(" clc | adc P8ZP_SCRATCH_B1") else asmgen.out(" sec | sbc P8ZP_SCRATCH_B1") - assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true) + assignRegisterByte(target, CpuRegister.A, dt.isSigned, true) } return true } } - } else if(dt in WordDatatypes) { + } else if(dt.isWord) { fun doAddOrSubWordExpr() { asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") @@ -1334,7 +1339,7 @@ internal class AssignmentAsmGen( if(right.isFromArrayElement) { TODO("address-of array element $symbol at ${right.position}") } else { - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned) if(expr.operator=="+") asmgen.out(""" clc @@ -1359,7 +1364,7 @@ internal class AssignmentAsmGen( } is PtIdentifier -> { val symname = asmgen.asmVariableName(right) - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned) if(expr.operator=="+") asmgen.out(""" clc @@ -1382,7 +1387,7 @@ internal class AssignmentAsmGen( return true } is PtNumber -> { - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned) if(right.number==1.0 && asmgen.isTargetCpu(CpuType.CPU65c02)) { if(expr.operator=="+") { asmgen.out(""" @@ -1398,7 +1403,7 @@ internal class AssignmentAsmGen( dey +""") } - } else if(dt!=DataType.WORD && right.number.toInt() in 0..255) { + } else if(!dt.isSignedWord && right.number.toInt() in 0..255) { if(expr.operator=="+") { asmgen.out(""" clc @@ -1439,11 +1444,11 @@ internal class AssignmentAsmGen( } is PtTypeCast -> { val castedValue = right.value - if(right.type in WordDatatypes && castedValue.type in ByteDatatypes && castedValue is PtIdentifier) { - if(right.type in SignedDatatypes) { + if(right.type.isWord && castedValue.type.isByte && castedValue is PtIdentifier) { + if(right.type.isSigned) { // we need to sign extend, do this via temporary word variable - asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W1", DataType.WORD) - assignExpressionToRegister(left, RegisterOrPair.AY, dt == DataType.WORD) + asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W1", DataType.forDt(BaseDataType.WORD)) + assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned) if(expr.operator=="+") { asmgen.out(""" clc @@ -1464,7 +1469,7 @@ internal class AssignmentAsmGen( txa""") } } else { - assignExpressionToRegister(left, RegisterOrPair.AY, dt == DataType.WORD) + assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned) val castedSymname = asmgen.asmVariableName(castedValue) if (expr.operator == "+") asmgen.out( @@ -1506,7 +1511,7 @@ internal class AssignmentAsmGen( if(address is PtBinaryExpression) { val constOffset = address.right.asConstInteger() // check that the offset is actually a byte (so that it fits in a single register) - if(constOffset==null && address.right.type !in ByteDatatypes) + if(constOffset==null && !address.right.type.isByte) return false if(constOffset!=null && constOffset !in -128..255) return false @@ -1521,7 +1526,7 @@ internal class AssignmentAsmGen( asmgen.out(" clc | adc ($pointername),y") else asmgen.out(" sec | sbc ($pointername),y") - } else if (address.right.type in ByteDatatypes) { + } else if (address.right.type.isByte) { // we have @(ptr + bytevar) ++ , or @(ptr+bytevar)-- asmgen.out(" pha") assignExpressionToRegister(address.right, RegisterOrPair.Y, false) @@ -1530,7 +1535,7 @@ internal class AssignmentAsmGen( asmgen.out(" clc | adc ($pointername),y") else asmgen.out(" sec | sbc ($pointername),y") - } else if ((address.right as? PtTypeCast)?.value?.type in ByteDatatypes) { + } else if ((address.right as? PtTypeCast)?.value?.type?.isByte==true) { // we have @(ptr + bytevar as uword) ++ , or @(ptr+bytevar as uword)-- asmgen.out(" pha") assignExpressionToRegister((address.right as PtTypeCast).value, RegisterOrPair.Y, false) @@ -1547,7 +1552,7 @@ internal class AssignmentAsmGen( } private fun optimizedBitwiseExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { - if (expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes) { + if (expr.left.type.isByte && expr.right.type.isByte) { if (expr.right.isSimple()) { if (expr.right is PtNumber || expr.right is PtIdentifier) { assignBitwiseWithSimpleRightOperandByte(target, expr.left, expr.operator, expr.right) @@ -1563,7 +1568,7 @@ internal class AssignmentAsmGen( val constIndex = rightArray.index.asConstInteger() if(constIndex!=null) { assignExpressionToRegister(expr.left, RegisterOrPair.A, false) - val valueVarname = "${asmgen.asmSymbolName(rightArray.variable)} + ${constIndex*program.memsizer.memorySize(rightArray.type)}" + val valueVarname = "${asmgen.asmSymbolName(rightArray.variable)} + ${program.memsizer.memorySize(rightArray.type, constIndex)}" when(expr.operator) { "&" -> asmgen.out(" and $valueVarname") "|" -> asmgen.out(" ora $valueVarname") @@ -1581,7 +1586,7 @@ internal class AssignmentAsmGen( asmgen.out(" sty P8ZP_SCRATCH_B1") } else { asmgen.out(" pha") - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE)) asmgen.out(" pla") } when (expr.operator) { @@ -1593,7 +1598,7 @@ internal class AssignmentAsmGen( assignRegisterByte(target, CpuRegister.A, false, true) return true } - else if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { + else if (expr.left.type.isWord && expr.right.type.isWord) { if (expr.right.isSimple()) { if (expr.right is PtNumber || expr.right is PtIdentifier) { assignBitwiseWithSimpleRightOperandWord(target, expr.left, expr.operator, expr.right) @@ -1634,7 +1639,7 @@ internal class AssignmentAsmGen( asmgen.out(" sty P8ZP_SCRATCH_B1") } else { asmgen.out(" pha") - assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE)) asmgen.out(" pla") } when (operator) { @@ -1672,7 +1677,7 @@ internal class AssignmentAsmGen( is PtArrayIndexer -> { val constIndex = right.index.asConstInteger() if(constIndex!=null) { - val valueVarname = "${asmgen.asmSymbolName(right.variable)} + ${constIndex*program.memsizer.memorySize(right.type)}" + val valueVarname = "${asmgen.asmSymbolName(right.variable)} + ${program.memsizer.memorySize(right.type, constIndex)}" when(operator) { "and" -> asmgen.out(" and $valueVarname") "or" -> asmgen.out(" ora $valueVarname") @@ -1763,10 +1768,11 @@ internal class AssignmentAsmGen( private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { when (expr.operator) { "==" -> { - when(val dt = expr.left.type) { - DataType.BOOL -> TODO("compare bool to 0") - in ByteDatatypes -> { - assignExpressionToRegister(expr.left, RegisterOrPair.A, dt==DataType.BYTE) + val dt = expr.left.type + when { + dt.isBool -> TODO("compare bool to 0") + dt.isByte -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, dt.isSigned) asmgen.out(""" cmp #0 beq + @@ -1775,8 +1781,8 @@ internal class AssignmentAsmGen( assignRegisterByte(assign.target, CpuRegister.A, false, false) return true } - in WordDatatypes -> { - assignExpressionToRegister(expr.left, RegisterOrPair.AY, dt==DataType.WORD) + dt.isWord -> { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, dt.isSigned) asmgen.out(""" sty P8ZP_SCRATCH_B1 ora P8ZP_SCRATCH_B1 @@ -1786,7 +1792,7 @@ internal class AssignmentAsmGen( assignRegisterByte(assign.target, CpuRegister.A, false, false) return true } - DataType.FLOAT -> { + dt.isFloat -> { assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true) asmgen.out(" jsr floats.SIGN | and #1 | eor #1") assignRegisterByte(assign.target, CpuRegister.A, false, false) @@ -1798,24 +1804,25 @@ internal class AssignmentAsmGen( } } "!=" -> { - when(val dt = expr.left.type) { - DataType.BOOL -> TODO("compare bool to 0") - in ByteDatatypes -> { - assignExpressionToRegister(expr.left, RegisterOrPair.A, dt==DataType.BYTE) + val dt = expr.left.type + when { + dt.isBool -> TODO("compare bool to 0") + dt.isByte -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, dt.isSigned) asmgen.out(" beq + | lda #1") asmgen.out("+") assignRegisterByte(assign.target, CpuRegister.A, false, false) return true } - in WordDatatypes -> { - assignExpressionToRegister(expr.left, RegisterOrPair.AY, dt==DataType.WORD) + dt.isWord -> { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, dt.isSigned) asmgen.out(" sty P8ZP_SCRATCH_B1 | ora P8ZP_SCRATCH_B1") asmgen.out(" beq + | lda #1") asmgen.out("+") assignRegisterByte(assign.target, CpuRegister.A, false, false) return true } - DataType.FLOAT -> { + dt.isFloat -> { assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true) asmgen.out(" jsr floats.SIGN") assignRegisterByte(assign.target, CpuRegister.A, true, false) @@ -1838,10 +1845,10 @@ internal class AssignmentAsmGen( if(it is PtBool) it.asInt() else (it as PtNumber).number.toInt() } - when(elementDt) { - in ByteDatatypesWithBoolean -> { + when { + elementDt.isByteOrBool -> { require(haystack.size in 0..PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_BYTE) - assignExpressionToRegister(containment.needle, RegisterOrPair.A, elementDt == DataType.BYTE) + assignExpressionToRegister(containment.needle, RegisterOrPair.A, elementDt.isSigned) for(number in haystack) { asmgen.out(""" cmp #$number @@ -1853,9 +1860,9 @@ internal class AssignmentAsmGen( + lda #1 +""") } - in WordDatatypes -> { + elementDt.isWord -> { require(haystack.size in 0..PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_WORD) - assignExpressionToRegister(containment.needle, RegisterOrPair.AY, elementDt == DataType.WORD) + assignExpressionToRegister(containment.needle, RegisterOrPair.AY, elementDt.isSigned) val gottemLabel = asmgen.makeLabel("gottem") val endLabel = asmgen.makeLabel("end") for(number in haystack) { @@ -1872,7 +1879,7 @@ internal class AssignmentAsmGen( $gottemLabel lda #1 $endLabel""") } - DataType.FLOAT -> throw AssemblyError("containmentchecks for floats should always be done on an array variable with subroutine") + elementDt.isFloat -> throw AssemblyError("containmentchecks for floats should always be done on an array variable with subroutine") else -> throw AssemblyError("weird dt $elementDt") } @@ -1884,34 +1891,34 @@ $endLabel""") val (dt, numElements) = when(symbol) { is StStaticVariable -> symbol.dt to symbol.length!! is StMemVar -> symbol.dt to symbol.length!! - else -> DataType.UNDEFINED to 0 + else -> DataType.forDt(BaseDataType.UNDEFINED) to 0 } - when(dt) { - DataType.STR -> { - assignExpressionToRegister(containment.needle, RegisterOrPair.A, elementDt == DataType.BYTE) + when { + dt.isString -> { + assignExpressionToRegister(containment.needle, RegisterOrPair.A, elementDt.isSigned) asmgen.out(" pha") // need to keep the scratch var safe so we have to do it in this order - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position,"P8ZP_SCRATCH_W1"), symbolName, null, null) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position,"P8ZP_SCRATCH_W1"), symbolName, null, null) asmgen.out(" pla") asmgen.out(" ldy #${numElements-1}") asmgen.out(" jsr prog8_lib.containment_bytearray") } - DataType.ARRAY_F -> { + dt.isFloatArray -> { assignExpressionToRegister(containment.needle, RegisterOrPair.FAC1, true) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, null, null) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, null, null) asmgen.out(" ldy #$numElements") asmgen.out(" jsr floats.containment_floatarray") } - DataType.ARRAY_B, DataType.ARRAY_UB, DataType.ARRAY_BOOL -> { - assignExpressionToRegister(containment.needle, RegisterOrPair.A, elementDt == DataType.BYTE) + dt.isByteArray -> { + assignExpressionToRegister(containment.needle, RegisterOrPair.A, elementDt.isSigned) asmgen.out(" pha") // need to keep the scratch var safe so we have to do it in this order - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, null, null) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, null, null) asmgen.out(" pla") asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_bytearray") } - DataType.ARRAY_W, DataType.ARRAY_UW -> { + dt.isWordArray && !dt.isSplitWordArray -> { assignExpressionToVariable(containment.needle, "P8ZP_SCRATCH_W1", elementDt) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, null, null) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, null, null) asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_wordarray") } @@ -1959,22 +1966,22 @@ $endLabel""") when(value) { is PtIdentifier -> { - if(targetDt in WordDatatypes) { - if(valueDt==DataType.UBYTE || valueDt==DataType.BOOL) { + if(targetDt.isWord) { + if(valueDt.isUnsignedByte || valueDt.isBool) { assignVariableUByteIntoWord(target, value) return } - if(valueDt==DataType.BYTE) { + if(valueDt.isSignedByte) { assignVariableByteIntoWord(target, value) return } } } is PtMemoryByte -> { - if(targetDt in WordDatatypes) { + if(targetDt.isWord) { fun assignViaExprEval(addressExpression: PtExpression) { - asmgen.assignExpressionToVariable(addressExpression, "P8ZP_SCRATCH_W2", DataType.UWORD) + asmgen.assignExpressionToVariable(addressExpression, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD)) asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2", false) asmgen.out(" ldy #0") assignRegisterpairWord(target, RegisterOrPair.AY) @@ -2006,10 +2013,10 @@ $endLabel""") } is PtNumber, is PtBool -> throw AssemblyError("a cast of a literal value should have been const-folded away") is PtArrayIndexer -> { - if(targetDt in ByteDatatypes && valueDt in WordDatatypes) { + if(targetDt.isByte && valueDt.isWord) { // just assign the lsb from the array value return assignCastViaLsbFunc(value, target) - } else if(targetDt==DataType.BOOL && valueDt in WordDatatypes) { + } else if(targetDt.isBool && valueDt.isWord) { return assignWordToBool(value, target) } } @@ -2019,12 +2026,12 @@ $endLabel""") // special case optimizations if(target.kind == TargetStorageKind.VARIABLE) { - if(value is PtIdentifier && valueDt != DataType.UNDEFINED) + if(value is PtIdentifier && !valueDt.isUndefined) return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), valueDt) - when (valueDt) { - DataType.BOOL -> { - if(targetDt in IntegerDatatypes) { + when { + valueDt.isBool -> { + if(targetDt.isInteger) { // optimization to assign boolean expression to integer target (just assign the 0 or 1 directly) val assignDirect = AsmAssignment( AsmAssignSource.fromAstSource(value, program, asmgen), @@ -2037,19 +2044,19 @@ $endLabel""") TODO("assign bool to non-integer type $targetDt") } } - in ByteDatatypes -> { - assignExpressionToRegister(value, RegisterOrPair.A, valueDt==DataType.BYTE) - assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.A, valueDt) + valueDt.isByte -> { + assignExpressionToRegister(value, RegisterOrPair.A, valueDt.isSigned) + assignTypeCastedRegisters(target.asmVarname, targetDt.base, RegisterOrPair.A, valueDt.base) } - in WordDatatypes -> { - assignExpressionToRegister(value, RegisterOrPair.AY, valueDt==DataType.WORD) - assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.AY, valueDt) + valueDt.isWord -> { + assignExpressionToRegister(value, RegisterOrPair.AY, valueDt.isSigned) + assignTypeCastedRegisters(target.asmVarname, targetDt.base, RegisterOrPair.AY, valueDt.base) } - DataType.FLOAT -> { + valueDt.isFloat -> { assignExpressionToRegister(value, RegisterOrPair.FAC1, true) - assignTypeCastedFloatFAC1(target.asmVarname, targetDt) + assignTypeCastedFloatFAC1(target.asmVarname, targetDt.base) } - in PassByReferenceDatatypes -> { + valueDt.isPassByRef -> { // str/array value cast (most likely to UWORD, take address-of) assignExpressionToVariable(value, target.asmVarname, targetDt) } @@ -2058,39 +2065,39 @@ $endLabel""") return } - if(valueDt in WordDatatypes && origTypeCastExpression.type == DataType.UBYTE) { + if(valueDt.isWord && origTypeCastExpression.type.isUnsignedByte) { val parentTc = origTypeCastExpression.parent as? PtTypeCast - if(parentTc!=null && parentTc.type==DataType.UWORD) { + if(parentTc!=null && parentTc.type.isUnsignedWord) { // typecast a word value to ubyte and directly back to uword // generate code for lsb(value) here instead of the ubyte typecast return assignCastViaLsbFunc(value, target) } } - if(valueDt in ByteDatatypesWithBoolean) { + if(valueDt.isByteOrBool) { when(target.register) { RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y -> { // 'cast' an ubyte value to a byte register; no cast needed at all - return assignExpressionToRegister(value, target.register, valueDt in SignedDatatypes) + return assignExpressionToRegister(value, target.register, valueDt.isSigned) } RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY, in Cx16VirtualRegisters -> { assignExpressionToRegister(value, RegisterOrPair.A, false) - assignRegisterByte(target, CpuRegister.A, valueDt in SignedDatatypes, true) + assignRegisterByte(target, CpuRegister.A, valueDt.isSigned, true) return } else -> {} } - } else if(valueDt==DataType.UWORD) { + } else if(valueDt.isUnsignedWord) { when(target.register) { RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y -> { - return if(targetDt==DataType.BOOL) + return if(targetDt.isBool) assignWordToBool(value, target) else // cast an uword to a byte register, do this via lsb(value) @@ -2102,86 +2109,86 @@ $endLabel""") RegisterOrPair.XY, in Cx16VirtualRegisters -> { // 'cast' uword into a 16 bits register, just assign it - return assignExpressionToRegister(value, target.register!!, targetDt in SignedDatatypes) + return assignExpressionToRegister(value, target.register!!, targetDt.isSigned) } else -> {} } } if(target.kind==TargetStorageKind.REGISTER) { - if(valueDt==DataType.FLOAT && target.datatype!=DataType.FLOAT) { + if(valueDt.isFloat && !target.datatype.isFloat) { // have to typecast the float number on the fly down to an integer - assignExpressionToRegister(value, RegisterOrPair.FAC1, targetDt in SignedDatatypes) - assignTypeCastedFloatFAC1("P8ZP_SCRATCH_W1", targetDt) - assignVariableToRegister("P8ZP_SCRATCH_W1", target.register!!, targetDt in SignedDatatypes, origTypeCastExpression.definingISub(), target.position) + assignExpressionToRegister(value, RegisterOrPair.FAC1, targetDt.isSigned) + assignTypeCastedFloatFAC1("P8ZP_SCRATCH_W1", targetDt.base) + assignVariableToRegister("P8ZP_SCRATCH_W1", target.register!!, targetDt.isSigned, origTypeCastExpression.definingISub(), target.position) return } else { if(!(valueDt isAssignableTo targetDt)) { - return if(valueDt in WordDatatypes && targetDt in ByteDatatypes) { + return if(valueDt.isWord && targetDt.isByte) { // word to byte, just take the lsb assignCastViaLsbFunc(value, target) - } else if(valueDt in WordDatatypes && targetDt==DataType.BOOL) { + } else if(valueDt.isWord && targetDt.isBool) { // word to bool assignWordToBool(value, target) - } else if(valueDt in WordDatatypes && targetDt in WordDatatypes) { + } else if(valueDt.isWord && targetDt.isWord) { // word to word, just assign - assignExpressionToRegister(value, target.register!!, valueDt in SignedDatatypes) - } else if(valueDt in ByteDatatypesWithBoolean && targetDt in ByteDatatypes) { + assignExpressionToRegister(value, target.register!!, valueDt.isSigned) + } else if(valueDt.isByteOrBool && targetDt.isByte) { // byte to byte, just assign - assignExpressionToRegister(value, target.register!!, valueDt in SignedDatatypes) - } else if(valueDt in ByteDatatypesWithBoolean && targetDt in WordDatatypes) { + assignExpressionToRegister(value, target.register!!, valueDt.isSigned) + } else if(valueDt.isByteOrBool && targetDt.isWord) { // byte to word, just assign - assignExpressionToRegister(value, target.register!!, valueDt==DataType.WORD) + assignExpressionToRegister(value, target.register!!, valueDt.isSigned) } else throw AssemblyError("can't cast $valueDt to $targetDt, this should have been checked in the astchecker") } } } - if(targetDt in IntegerDatatypes && valueDt in IntegerDatatypesWithBoolean && valueDt.isAssignableTo(targetDt)) { - require(targetDt in WordDatatypes && valueDt in ByteDatatypesWithBoolean) { + if(targetDt.isInteger && valueDt.isIntegerOrBool && valueDt.isAssignableTo(targetDt)) { + require(targetDt.isWord && valueDt.isByteOrBool) { "should be byte to word assignment ${origTypeCastExpression.position}" } when(target.kind) { // TargetStorageKind.VARIABLE -> { // This has been handled already earlier on line 961. // // byte to word, just assign to registers first, then assign to variable -// assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==DataType.WORD) +// assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==BaseDataType.WORD) // assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.AY, targetDt) // return // } TargetStorageKind.ARRAY -> { // byte to word, just assign to registers first, then assign into array - assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==DataType.WORD) + assignExpressionToRegister(value, RegisterOrPair.AY, targetDt.isSigned) assignRegisterpairWord(target, RegisterOrPair.AY) return } TargetStorageKind.REGISTER -> { // byte to word, just assign to registers - assignExpressionToRegister(value, target.register!!, targetDt==DataType.WORD) + assignExpressionToRegister(value, target.register!!, targetDt.isSigned) return } else -> throw AssemblyError("weird target") } } - if(targetDt==DataType.FLOAT && (target.register==RegisterOrPair.FAC1 || target.register==RegisterOrPair.FAC2)) { + if(targetDt.isFloat && (target.register==RegisterOrPair.FAC1 || target.register==RegisterOrPair.FAC2)) { if(target.register==RegisterOrPair.FAC2) asmgen.pushFAC1() - when(valueDt) { - DataType.UBYTE -> { + when { + valueDt.isUnsignedByte -> { assignExpressionToRegister(value, RegisterOrPair.Y, false) asmgen.out(" jsr floats.FREADUY") } - DataType.BYTE -> { + valueDt.isSignedByte -> { assignExpressionToRegister(value, RegisterOrPair.A, true) asmgen.out(" jsr floats.FREADSA") } - DataType.UWORD -> { + valueDt.isUnsignedWord -> { assignExpressionToRegister(value, RegisterOrPair.AY, false) asmgen.out(" jsr floats.GIVUAYFAY") } - DataType.WORD -> { + valueDt.isSignedWord -> { assignExpressionToRegister(value, RegisterOrPair.AY, true) asmgen.out(" jsr floats.GIVAYFAY") } @@ -2201,10 +2208,10 @@ $endLabel""") } private fun assignCastViaLsbFunc(value: PtExpression, target: AsmAssignTarget) { - val lsb = PtBuiltinFunctionCall("lsb", false, true, DataType.UBYTE, value.position) + val lsb = PtBuiltinFunctionCall("lsb", false, true, DataType.forDt(BaseDataType.UBYTE), value.position) lsb.parent = value.parent lsb.add(value) - val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UBYTE, expression = lsb) + val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.forDt(BaseDataType.UBYTE), expression = lsb) val assign = AsmAssignment(src, target, program.memsizer, value.position) translateNormalAssignment(assign, value.definingISub()) } @@ -2220,17 +2227,17 @@ $endLabel""") assignRegisterByte(target, CpuRegister.A, false, false) } - private fun assignTypeCastedFloatFAC1(targetAsmVarName: String, targetDt: DataType) { + private fun assignTypeCastedFloatFAC1(targetAsmVarName: String, targetDt: BaseDataType) { - if(targetDt==DataType.FLOAT) + if(targetDt==BaseDataType.FLOAT) throw AssemblyError("typecast to identical type") when(targetDt) { - DataType.BOOL -> asmgen.out(" jsr floats.cast_FAC1_as_bool_into_a | sta $targetAsmVarName") - DataType.UBYTE -> asmgen.out(" jsr floats.cast_FAC1_as_uw_into_ya | sty $targetAsmVarName") - DataType.BYTE -> asmgen.out(" jsr floats.cast_FAC1_as_w_into_ay | sta $targetAsmVarName") - DataType.UWORD -> asmgen.out(" jsr floats.cast_FAC1_as_uw_into_ya | sty $targetAsmVarName | sta $targetAsmVarName+1") - DataType.WORD -> asmgen.out(" jsr floats.cast_FAC1_as_w_into_ay | sta $targetAsmVarName | sty $targetAsmVarName+1") + BaseDataType.BOOL -> asmgen.out(" jsr floats.cast_FAC1_as_bool_into_a | sta $targetAsmVarName") + BaseDataType.UBYTE -> asmgen.out(" jsr floats.cast_FAC1_as_uw_into_ya | sty $targetAsmVarName") + BaseDataType.BYTE -> asmgen.out(" jsr floats.cast_FAC1_as_w_into_ay | sta $targetAsmVarName") + BaseDataType.UWORD -> asmgen.out(" jsr floats.cast_FAC1_as_uw_into_ya | sty $targetAsmVarName | sta $targetAsmVarName+1") + BaseDataType.WORD -> asmgen.out(" jsr floats.cast_FAC1_as_w_into_ay | sta $targetAsmVarName | sty $targetAsmVarName+1") else -> throw AssemblyError("weird type") } } @@ -2242,26 +2249,26 @@ $endLabel""") throw AssemblyError("typecast to identical type") // also see: PtExpressionAsmGen, fun translateExpression(typecast: PtTypeCast) - when(sourceDt) { - DataType.UBYTE, DataType.BOOL -> { - when(targetDt) { - DataType.BOOL -> { + when { + sourceDt.isUnsignedByte || sourceDt.isBool -> { + when(targetDt.base) { + BaseDataType.BOOL -> { asmgen.out(""" lda $sourceAsmVarName beq + lda #1 + sta $targetAsmVarName""") } - DataType.UBYTE, DataType.BYTE -> { + BaseDataType.UBYTE, BaseDataType.BYTE -> { asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName") } - DataType.UWORD, DataType.WORD -> { + BaseDataType.UWORD, BaseDataType.WORD -> { if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | stz $targetAsmVarName+1") else asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda #0 | sta $targetAsmVarName+1") } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { asmgen.out(""" lda #<$targetAsmVarName ldy #>$targetAsmVarName @@ -2273,22 +2280,22 @@ $endLabel""") else -> throw AssemblyError("weird type $targetDt") } } - DataType.BYTE -> { - when(targetDt) { - DataType.UBYTE, DataType.BOOL -> { + sourceDt.isSignedByte -> { + when(targetDt.base) { + BaseDataType.UBYTE, BaseDataType.BOOL -> { asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName") } - DataType.UWORD -> { + BaseDataType.UWORD -> { if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | stz $targetAsmVarName+1") else asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda #0 | sta $targetAsmVarName+1") } - DataType.WORD -> { + BaseDataType.WORD -> { asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName") - asmgen.signExtendVariableLsb(targetAsmVarName, DataType.BYTE) + asmgen.signExtendVariableLsb(targetAsmVarName, BaseDataType.BYTE) } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { asmgen.out(""" lda #<$targetAsmVarName ldy #>$targetAsmVarName @@ -2300,9 +2307,9 @@ $endLabel""") else -> throw AssemblyError("weird type") } } - DataType.UWORD -> { - when(targetDt) { - DataType.BOOL -> { + sourceDt.isUnsignedWord -> { + when(targetDt.base) { + BaseDataType.BOOL -> { asmgen.out(""" lda $sourceAsmVarName ora $sourceAsmVarName+1 @@ -2310,13 +2317,13 @@ $endLabel""") lda #1 + sta $targetAsmVarName""") } - DataType.BYTE, DataType.UBYTE -> { + BaseDataType.BYTE, BaseDataType.UBYTE -> { asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName") } - DataType.WORD -> { + BaseDataType.WORD -> { asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName+1 | sta $targetAsmVarName+1") } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { asmgen.out(""" lda #<$targetAsmVarName ldy #>$targetAsmVarName @@ -2329,9 +2336,9 @@ $endLabel""") else -> throw AssemblyError("weird type") } } - DataType.WORD -> { - when(targetDt) { - DataType.BOOL -> { + sourceDt.isSignedWord -> { + when(targetDt.base) { + BaseDataType.BOOL -> { asmgen.out(""" lda $sourceAsmVarName ora $sourceAsmVarName+1 @@ -2339,13 +2346,13 @@ $endLabel""") lda #1 + sta $targetAsmVarName""") } - DataType.BYTE, DataType.UBYTE -> { + BaseDataType.BYTE, BaseDataType.UBYTE -> { asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName") } - DataType.UWORD -> { + BaseDataType.UWORD -> { asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName+1 | sta $targetAsmVarName+1") } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { asmgen.out(""" lda #<$targetAsmVarName ldy #>$targetAsmVarName @@ -2358,49 +2365,47 @@ $endLabel""") else -> throw AssemblyError("weird type") } } - DataType.FLOAT -> { + sourceDt.isFloat -> { asmgen.out(" lda #<$sourceAsmVarName | ldy #>$sourceAsmVarName") - when(targetDt) { - DataType.BOOL -> asmgen.out(" jsr floats.cast_as_bool_into_a | sta $targetAsmVarName") - DataType.UBYTE -> asmgen.out(" jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName") - DataType.BYTE -> asmgen.out(" jsr floats.cast_as_w_into_ay | sta $targetAsmVarName") - DataType.UWORD -> asmgen.out(" jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName | sta $targetAsmVarName+1") - DataType.WORD -> asmgen.out(" jsr floats.cast_as_w_into_ay | sta $targetAsmVarName | sty $targetAsmVarName+1") + when(targetDt.base) { + BaseDataType.BOOL -> asmgen.out(" jsr floats.cast_as_bool_into_a | sta $targetAsmVarName") + BaseDataType.UBYTE -> asmgen.out(" jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName") + BaseDataType.BYTE -> asmgen.out(" jsr floats.cast_as_w_into_ay | sta $targetAsmVarName") + BaseDataType.UWORD -> asmgen.out(" jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName | sta $targetAsmVarName+1") + BaseDataType.WORD -> asmgen.out(" jsr floats.cast_as_w_into_ay | sta $targetAsmVarName | sty $targetAsmVarName+1") else -> throw AssemblyError("weird type") } } - DataType.STR -> throw AssemblyError("cannot typecast a string value") + sourceDt.isString -> throw AssemblyError("cannot typecast a string value") else -> throw AssemblyError("weird type") } } - private fun assignTypeCastedRegisters(targetAsmVarName: String, targetDt: DataType, - regs: RegisterOrPair, sourceDt: DataType) { + private fun assignTypeCastedRegisters(targetAsmVarName: String, targetDt: BaseDataType, + regs: RegisterOrPair, sourceDt: BaseDataType) { if(sourceDt == targetDt) throw AssemblyError("typecast to identical type") // also see: PtExpressionAsmGen, fun translateExpression(typecast: PtTypeCast) when(sourceDt) { - DataType.BOOL -> { - when (targetDt) { - in ByteDatatypesWithBoolean -> asmgen.out(" st${regs.toString().lowercase()} $targetAsmVarName") - else -> throw AssemblyError("assign bool to non-byte variable") - } + BaseDataType.BOOL -> { + if (targetDt.isByteOrBool) asmgen.out(" st${regs.toString().lowercase()} $targetAsmVarName") + else throw AssemblyError("assign bool to non-byte variable") } - DataType.UBYTE -> { + BaseDataType.UBYTE -> { when(targetDt) { - DataType.BOOL -> { + BaseDataType.BOOL -> { asmgen.out(""" cp${regs.toString().lowercase()} #0 beq + ld${regs.toString().lowercase()} #1 + st${regs.toString().lowercase()} $targetAsmVarName""") } - DataType.BYTE -> { + BaseDataType.BYTE -> { asmgen.out(" st${regs.toString().lowercase()} $targetAsmVarName") } - DataType.UWORD, DataType.WORD -> { + BaseDataType.UWORD, BaseDataType.WORD -> { if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out( " st${regs.toString().lowercase()} $targetAsmVarName | stz $targetAsmVarName+1") @@ -2408,7 +2413,7 @@ $endLabel""") asmgen.out( " st${regs.toString().lowercase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1") } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { when(regs) { RegisterOrPair.A -> asmgen.out(" tay") RegisterOrPair.X -> asmgen.out(" txa | tay") @@ -2425,13 +2430,13 @@ $endLabel""") else -> throw AssemblyError("weird type") } } - DataType.BYTE -> { + BaseDataType.BYTE -> { when(targetDt) { - DataType.BOOL -> TODO("assign byte to bool") - DataType.UBYTE -> { + BaseDataType.BOOL -> TODO("assign byte to bool") + BaseDataType.UBYTE -> { asmgen.out(" st${regs.toString().lowercase()} $targetAsmVarName") } - DataType.UWORD -> { + BaseDataType.UWORD -> { if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out( " st${ @@ -2443,7 +2448,7 @@ $endLabel""") regs.toString().lowercase() } $targetAsmVarName | lda #0 | sta $targetAsmVarName+1") } - DataType.WORD -> { + BaseDataType.WORD -> { when(regs) { RegisterOrPair.A -> {} RegisterOrPair.X -> asmgen.out(" txa") @@ -2453,7 +2458,7 @@ $endLabel""") asmgen.signExtendAYlsb(sourceDt) asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1") } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { when(regs) { RegisterOrPair.A -> {} RegisterOrPair.X -> asmgen.out(" txa") @@ -2470,13 +2475,13 @@ $endLabel""") else -> throw AssemblyError("weird type") } } - DataType.UWORD -> { + BaseDataType.UWORD -> { when(targetDt) { - DataType.BOOL -> TODO("assign uword to bool") - DataType.BYTE, DataType.UBYTE -> { + BaseDataType.BOOL -> TODO("assign uword to bool") + BaseDataType.BYTE, BaseDataType.UBYTE -> { asmgen.out(" st${regs.toString().lowercase().first()} $targetAsmVarName") } - DataType.WORD -> { + BaseDataType.WORD -> { when(regs) { RegisterOrPair.AX -> asmgen.out(" sta $targetAsmVarName | stx $targetAsmVarName+1") RegisterOrPair.AY -> asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1") @@ -2484,7 +2489,7 @@ $endLabel""") else -> throw AssemblyError("non-word regs") } } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { if(regs!=RegisterOrPair.AY) throw AssemblyError("only supports AY here") asmgen.out(""" @@ -2499,13 +2504,13 @@ $endLabel""") else -> throw AssemblyError("weird type") } } - DataType.WORD -> { + BaseDataType.WORD -> { when(targetDt) { - DataType.BOOL -> TODO("assign word to bool") - DataType.BYTE, DataType.UBYTE -> { + BaseDataType.BOOL -> TODO("assign word to bool") + BaseDataType.BYTE, BaseDataType.UBYTE -> { asmgen.out(" st${regs.toString().lowercase().first()} $targetAsmVarName") } - DataType.UWORD -> { + BaseDataType.UWORD -> { when(regs) { RegisterOrPair.AX -> asmgen.out(" sta $targetAsmVarName | stx $targetAsmVarName+1") RegisterOrPair.AY -> asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1") @@ -2513,7 +2518,7 @@ $endLabel""") else -> throw AssemblyError("non-word regs") } } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { if(regs!=RegisterOrPair.AY) throw AssemblyError("only supports AY here") asmgen.out(""" @@ -2528,17 +2533,17 @@ $endLabel""") else -> throw AssemblyError("weird type") } } - DataType.STR -> throw AssemblyError("cannot typecast a string value") + BaseDataType.STR -> throw AssemblyError("cannot typecast a string value") else -> throw AssemblyError("weird type") } } private fun assignAddressOf(target: AsmAssignTarget, sourceName: String, arrayDt: DataType?, arrayIndexExpr: PtExpression?) { if(arrayIndexExpr!=null) { - require(arrayDt !in SplitWordArrayTypes) + require(arrayDt?.isSplitWordArray!=true) val constIndex = arrayIndexExpr.asConstInteger() if(constIndex!=null) { - if (arrayDt == DataType.UWORD) { + if (arrayDt?.isUnsignedWord==true) { assignVariableToRegister(sourceName, RegisterOrPair.AY, false, arrayIndexExpr.definingISub(), arrayIndexExpr.position) if(constIndex>0) asmgen.out(""" @@ -2559,11 +2564,11 @@ $endLabel""") assignRegisterpairWord(target, RegisterOrPair.AY) return } else { - if (arrayDt == DataType.UWORD) { + if (arrayDt?.isUnsignedWord==true) { assignVariableToRegister(sourceName, RegisterOrPair.AY, false, arrayIndexExpr.definingISub(), arrayIndexExpr.position) asmgen.saveRegisterStack(CpuRegister.A, false) asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(arrayIndexExpr, "P8ZP_SCRATCH_REG", DataType.UBYTE) + assignExpressionToVariable(arrayIndexExpr, "P8ZP_SCRATCH_REG", DataType.forDt(BaseDataType.UBYTE)) asmgen.restoreRegisterStack(CpuRegister.Y, false) asmgen.restoreRegisterStack(CpuRegister.A, false) asmgen.out(""" @@ -2625,8 +2630,8 @@ $endLabel""") private fun assignVariableString(target: AsmAssignTarget, sourceName: String) { when(target.kind) { TargetStorageKind.VARIABLE -> { - when(target.datatype) { - DataType.UWORD -> { + when { + target.datatype.isUnsignedWord -> { asmgen.out(""" lda #<$sourceName ldy #>$sourceName @@ -2634,7 +2639,7 @@ $endLabel""") sty ${target.asmVarname}+1 """) } - DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B -> { + target.datatype.isString || target.datatype.isUnsignedByteArray || target.datatype.isByteArray -> { asmgen.out(""" lda #<${target.asmVarname} ldy #>${target.asmVarname} @@ -2652,17 +2657,17 @@ $endLabel""") } private fun assignVariableWord(target: AsmAssignTarget, sourceName: String, sourceDt: DataType) { - if(sourceDt==DataType.BYTE) { + if(sourceDt.isSignedByte) { // need to sign extend asmgen.out(" lda $sourceName") - asmgen.signExtendAYlsb(DataType.BYTE) + asmgen.signExtendAYlsb(BaseDataType.BYTE) assignRegisterpairWord(target, RegisterOrPair.AY) return } - require(sourceDt in WordDatatypes || sourceDt==DataType.UBYTE || sourceDt==DataType.BOOL) { "weird source dt for word variable" } + require(sourceDt.isWord || sourceDt.isUnsignedByte || sourceDt.isBool) { "weird source dt for word variable" } when(target.kind) { TargetStorageKind.VARIABLE -> { - if(sourceDt==DataType.UBYTE || sourceDt==DataType.BOOL) { + if(sourceDt.isUnsignedByte || sourceDt.isBool) { asmgen.out(" lda $sourceName | sta ${target.asmVarname}") if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(" stz ${target.asmVarname}+1") @@ -2680,15 +2685,15 @@ $endLabel""") throw AssemblyError("assign word to memory ${target.memory} should have gotten a typecast") } TargetStorageKind.ARRAY -> { - if(sourceDt==DataType.UBYTE) TODO("assign byte to word array") + if(sourceDt.isUnsignedByte) TODO("assign byte to word array") target.array!! if(target.constArrayIndexValue!=null) { - val scaledIdx = target.constArrayIndexValue!! * program.memsizer.memorySize(target.datatype).toUInt() - when(target.datatype) { - in ByteDatatypes -> { + val scaledIdx = program.memsizer.memorySize(target.datatype, target.constArrayIndexValue!!.toInt()) + when { + target.datatype.isByte -> { asmgen.out(" lda $sourceName | sta ${target.asmVarname}+$scaledIdx") } - in WordDatatypes -> { + target.datatype.isWord -> { if(target.array.splitWords) asmgen.out(""" lda $sourceName @@ -2707,12 +2712,12 @@ $endLabel""") } else { - when(target.datatype) { - DataType.UBYTE, DataType.BYTE -> { + when { + target.datatype.isByte -> { asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.Y) asmgen.out(" lda $sourceName | sta ${target.asmVarname},y") } - DataType.UWORD, DataType.WORD -> { + target.datatype.isWord -> { asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.Y) if(target.array.splitWords) asmgen.out(""" @@ -2732,7 +2737,7 @@ $endLabel""") } } TargetStorageKind.REGISTER -> { - if(sourceDt==DataType.UBYTE) { + if(sourceDt.isUnsignedByte) { when(target.register!!) { RegisterOrPair.AX -> asmgen.out(" ldx #0 | lda $sourceName") RegisterOrPair.AY -> asmgen.out(" ldy #0 | lda $sourceName") @@ -2889,7 +2894,7 @@ $endLabel""") if(target.array!!.splitWords) TODO("assign into split words ${target.position}") if (target.constArrayIndexValue!=null) { - val scaledIdx = target.constArrayIndexValue!! * program.memsizer.memorySize(target.datatype).toUInt() + val scaledIdx = program.memsizer.memorySize(target.datatype, target.constArrayIndexValue!!.toInt()) asmgen.out(" lda $sourceName | sta ${target.asmVarname}+$scaledIdx") } else { @@ -2940,13 +2945,13 @@ $endLabel""") if (wordtarget.constArrayIndexValue!=null) { val scaledIdx = wordtarget.constArrayIndexValue!! * 2u asmgen.out(" lda $sourceName") - asmgen.signExtendAYlsb(DataType.BYTE) + asmgen.signExtendAYlsb(BaseDataType.BYTE) asmgen.out(" sta ${wordtarget.asmVarname}+$scaledIdx | sty ${wordtarget.asmVarname}+$scaledIdx+1") } else { asmgen.loadScaledArrayIndexIntoRegister(wordtarget.array, CpuRegister.X) asmgen.out(" lda $sourceName") - asmgen.signExtendAYlsb(DataType.BYTE) + asmgen.signExtendAYlsb(BaseDataType.BYTE) asmgen.out(" sta ${wordtarget.asmVarname},x | inx | tya | sta ${wordtarget.asmVarname},x") } } @@ -3080,16 +3085,16 @@ $endLabel""") } internal fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister, signed: Boolean, extendWord: Boolean) { - val assignAsWord = target.datatype in WordDatatypes + val assignAsWord = target.datatype.isWord when(target.kind) { TargetStorageKind.VARIABLE -> { asmgen.out(" st${register.name.lowercase()} ${target.asmVarname}") if(assignAsWord && extendWord) { - if(target.datatype in SignedDatatypes) { + if(target.datatype.isSigned) { if(register!=CpuRegister.A) asmgen.out(" t${register.name.lowercase()}a") - asmgen.signExtendAYlsb(if(target.datatype in SignedDatatypes) DataType.BYTE else DataType.UBYTE) + asmgen.signExtendAYlsb(if(target.datatype.isSigned) BaseDataType.BYTE else BaseDataType.UBYTE) asmgen.out(" sty ${target.asmVarname}+1") } else { if(asmgen.isTargetCpu(CpuType.CPU65c02)) @@ -3115,7 +3120,7 @@ $endLabel""") CpuRegister.Y -> asmgen.out(" tya") } if(extendWord) { - asmgen.signExtendAYlsb(if(target.datatype in SignedDatatypes) DataType.BYTE else DataType.UBYTE) + asmgen.signExtendAYlsb(if(target.datatype.isSigned) BaseDataType.BYTE else BaseDataType.UBYTE) } else { asmgen.out(" ldy #0") } @@ -3310,7 +3315,7 @@ $endLabel""") if(indexVar!=null) { asmgen.out(" ldy ${asmgen.asmVariableName(indexVar)} | sta ${target.asmVarname},y") } else { - require(target.array.index.type in ByteDatatypesWithBoolean) + require(target.array.index.type.isByteOrBool) asmgen.saveRegisterStack(register, false) asmgen.assignExpressionToRegister(target.array.index, RegisterOrPair.Y, false) asmgen.out(" pla | sta ${target.asmVarname},y") @@ -3319,10 +3324,10 @@ $endLabel""") } internal fun assignRegisterpairWord(target: AsmAssignTarget, regs: RegisterOrPair) { - require(target.datatype in NumericDatatypes || target.datatype in PassByReferenceDatatypes) { + require(target.datatype.isNumeric || target.datatype.isPassByRef) { "assign target must be word type ${target.position}" } - if(target.datatype==DataType.FLOAT) + if(target.datatype.isFloat) throw AssemblyError("float value should be from FAC1 not from registerpair memory pointer") when(target.kind) { @@ -3965,7 +3970,7 @@ $endLabel""") } internal fun assignExpressionToVariable(expr: PtExpression, asmVarName: String, dt: DataType) { - if(expr.type==DataType.FLOAT && dt!=DataType.FLOAT) { + if(expr.type.isFloat && !dt.isFloat) { throw AssemblyError("can't directly assign a FLOAT expression to an integer variable $expr") } else { val src = AsmAssignSource.fromAstSource(expr, program, asmgen) @@ -3984,9 +3989,10 @@ $endLabel""") internal fun inplaceInvert(assign: AsmAssignment, scope: IPtSubroutine?) { val target = assign.target - when (assign.target.datatype) { - DataType.UBYTE, DataType.BOOL -> { - val eorValue = if(assign.target.datatype==DataType.BOOL) 1 else 255 + val targetDt = assign.target.datatype + when { + targetDt.isUnsignedByte || targetDt.isBool -> { + val eorValue = if(assign.target.datatype.isBool) 1 else 255 when (target.kind) { TargetStorageKind.VARIABLE -> { asmgen.out(""" @@ -4010,7 +4016,7 @@ $endLabel""") asmgen.storeAIntoPointerVar(memory.address as PtIdentifier) } else -> { - asmgen.assignExpressionToVariable(memory.address, "P8ZP_SCRATCH_W2", DataType.UWORD) + asmgen.assignExpressionToVariable(memory.address, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD)) if(asmgen.isTargetCpu(CpuType.CPU65c02)) { asmgen.out(""" lda (P8ZP_SCRATCH_W2) @@ -4034,12 +4040,12 @@ $endLabel""") } } TargetStorageKind.ARRAY -> { - val invertOperator = if(assign.target.datatype==DataType.BOOL) "not" else "~" + val invertOperator = if(assign.target.datatype.isBool) "not" else "~" assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign(invertOperator, assign), scope) } } } - DataType.UWORD -> { + targetDt.isUnsignedWord -> { when (target.kind) { TargetStorageKind.VARIABLE -> { asmgen.out(""" @@ -4070,14 +4076,14 @@ $endLabel""") internal fun inplaceNegate(assign: AsmAssignment, ignoreDatatype: Boolean, scope: IPtSubroutine?) { val target = assign.target val datatype = if(ignoreDatatype) { - when(target.datatype) { - DataType.UBYTE, DataType.BYTE -> DataType.BYTE - DataType.UWORD, DataType.WORD -> DataType.WORD + when { + target.datatype.isByte -> DataType.forDt(BaseDataType.BYTE) + target.datatype.isWord -> DataType.forDt(BaseDataType.WORD) else -> target.datatype } } else target.datatype - when (datatype) { - DataType.BYTE -> { + when { + datatype.isSignedByte -> { when (target.kind) { TargetStorageKind.VARIABLE -> { if(asmgen.isTargetCpu(CpuType.CPU65c02)) @@ -4110,7 +4116,7 @@ $endLabel""") TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign), scope) } } - DataType.WORD -> { + datatype.isSignedWord -> { when (target.kind) { TargetStorageKind.VARIABLE -> { asmgen.out(""" @@ -4168,7 +4174,7 @@ $endLabel""") TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign), scope) } } - DataType.FLOAT -> { + datatype.isFloat -> { when (target.kind) { TargetStorageKind.REGISTER -> { when(target.register!!) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index 8c0cbdfc0..db2c039ec 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -58,20 +58,20 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, // the asm-gen code can deal with situations where you want to assign a byte into a word. // it will create the most optimized code to do this (so it type-extends for us). // But we can't deal with writing a word into a byte - explicit typeconversion should be done - if(program.memsizer.memorySize(value.datatype) > program.memsizer.memorySize(target.datatype)) + if(program.memsizer.memorySize(value.datatype, null) > program.memsizer.memorySize(target.datatype, null)) throw AssemblyError("missing type cast: value type > target type ${target.position}") fun regName(v: AsmAssignSource) = "cx16.${v.register!!.name.lowercase()}" when (target.kind) { TargetStorageKind.VARIABLE -> { - when (target.datatype) { - in ByteDatatypesWithBoolean -> { + when { + target.datatype.isByteOrBool -> { when(value.kind) { SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(target.asmVarname, target.datatype, operator, value.boolean!!.asInt()) SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(target.asmVarname, target.datatype, operator, value.number!!.number.toInt()) - SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(target.asmVarname, target.datatype, operator, value.asmVarname) - SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(target.asmVarname, target.datatype, operator, regName(value)) + SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(target.asmVarname, target.datatype.isSigned, operator, value.asmVarname) + SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(target.asmVarname, target.datatype.isSigned, operator, regName(value)) SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(target.asmVarname, target.datatype, operator, value.memory!!) SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(target.asmVarname, target.datatype, operator, value.array!!) SourceStorageKind.EXPRESSION -> { @@ -84,7 +84,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } } - in WordDatatypes -> { + target.datatype.isWord -> { val block = target.origAstTarget?.definingBlock() when(value.kind) { SourceStorageKind.LITERALBOOLEAN -> inplacemodificationWordWithLiteralval(target.asmVarname, target.datatype, operator, value.boolean!!.asInt(), block) @@ -104,7 +104,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } } - DataType.FLOAT -> { + target.datatype.isFloat -> { when(value.kind) { SourceStorageKind.LITERALBOOLEAN -> inplacemodificationFloatWithLiteralval(target.asmVarname, operator, value.boolean!!.asInt().toDouble()) SourceStorageKind.LITERALNUMBER -> inplacemodificationFloatWithLiteralval(target.asmVarname, operator, value.number!!.number) @@ -131,18 +131,18 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, is PtNumber -> { val addr = (memory.address as PtNumber).number.toInt() when(value.kind) { - SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(addr.toHex(), DataType.UBYTE, operator, value.boolean!!.asInt()) - SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(addr.toHex(), DataType.UBYTE, operator, value.number!!.number.toInt()) - SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(addr.toHex(), DataType.UBYTE, operator, value.asmVarname) - SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(addr.toHex(), DataType.UBYTE, operator, regName(value)) - SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(addr.toHex(), DataType.UBYTE, operator, value.memory!!) - SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(addr.toHex(), DataType.UBYTE, operator, value.array!!) + SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.boolean!!.asInt()) + SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.number!!.number.toInt()) + SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(addr.toHex(), false, operator, value.asmVarname) + SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(addr.toHex(), false, operator, regName(value)) + SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.memory!!) + SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.array!!) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return - inplacemodificationByteVariableWithValue(addr.toHex(), DataType.UBYTE, operator, value.expression) + inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.expression) } else { - inplacemodificationByteVariableWithValue(addr.toHex(), DataType.UBYTE, operator, value.expression!!) + inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.expression!!) } } } @@ -192,21 +192,21 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } SourceStorageKind.MEMORY -> { asmgen.out(" sta P8ZP_SCRATCH_B1") - inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.memory!!) + inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), operator, value.memory!!) asmgen.out(" ldx P8ZP_SCRATCH_B1") } SourceStorageKind.ARRAY -> { asmgen.out(" sta P8ZP_SCRATCH_B1") - inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.array!!) + inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), operator, value.array!!) asmgen.out(" ldx P8ZP_SCRATCH_B1") } SourceStorageKind.EXPRESSION -> { - val tempVar = asmgen.getTempVarName(DataType.UBYTE) + val tempVar = asmgen.getTempVarName(BaseDataType.UBYTE) asmgen.out(" sta $tempVar") if(value.expression is PtTypeCast) - inplacemodificationByteVariableWithValue(tempVar, DataType.UBYTE, operator, value.expression) + inplacemodificationByteVariableWithValue(tempVar, DataType.forDt(BaseDataType.UBYTE), operator, value.expression) else - inplacemodificationByteVariableWithValue(tempVar, DataType.UBYTE, operator, value.expression!!) + inplacemodificationByteVariableWithValue(tempVar, DataType.forDt(BaseDataType.UBYTE), operator, value.expression!!) asmgen.out(" ldx $tempVar") } } @@ -235,14 +235,14 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, return } // normal array - val targetVarName = "${target.asmVarname} + ${index*program.memsizer.memorySize(target.datatype)}" - when (target.datatype) { - in ByteDatatypesWithBoolean -> { + val targetVarName = "${target.asmVarname} + ${index*program.memsizer.memorySize(target.datatype, null)}" + when { + target.datatype.isByteOrBool -> { when(value.kind) { SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(targetVarName, target.datatype, operator, value.boolean!!.asInt()) SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(targetVarName, target.datatype, operator, value.number!!.number.toInt()) - SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(targetVarName, target.datatype, operator, value.asmVarname) - SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(targetVarName, target.datatype, operator, regName(value)) + SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(targetVarName, target.datatype.isSigned, operator, value.asmVarname) + SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(targetVarName, target.datatype.isSigned, operator, regName(value)) SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(targetVarName, target.datatype, operator, value.memory!!) SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(targetVarName, target.datatype, operator, value.array!!) SourceStorageKind.EXPRESSION -> { @@ -256,7 +256,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } - in WordDatatypes -> { + target.datatype.isWord -> { val block = target.origAstTarget?.definingBlock() when(value.kind) { SourceStorageKind.LITERALBOOLEAN -> inplacemodificationWordWithLiteralval(targetVarName, target.datatype, operator, value.boolean!!.asInt(), block) @@ -276,7 +276,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } - DataType.FLOAT -> { + target.datatype.isFloat -> { when(value.kind) { SourceStorageKind.LITERALBOOLEAN -> inplacemodificationFloatWithLiteralval(targetVarName, operator, value.boolean!!.asInt().toDouble()) SourceStorageKind.LITERALNUMBER -> inplacemodificationFloatWithLiteralval(targetVarName, operator, value.number!!.number) @@ -305,8 +305,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, && tryIndexedIncDec(target.array, operator)) return - when (target.datatype) { - in ByteDatatypesWithBoolean -> { + when { + target.datatype.isByteOrBool -> { if(value.kind==SourceStorageKind.EXPRESSION && value.expression is PtTypeCast && tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) @@ -316,21 +316,21 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, asmgen.out(" lda ${target.array.variable.name},y") when(value.kind) { SourceStorageKind.LITERALBOOLEAN -> { - inplacemodificationRegisterAwithVariable(operator, "#${value.boolean!!.asInt()}", target.datatype in SignedDatatypes) + inplacemodificationRegisterAwithVariable(operator, "#${value.boolean!!.asInt()}", target.datatype.isSigned) asmgen.restoreRegisterStack(CpuRegister.Y, true) } SourceStorageKind.LITERALNUMBER -> { - inplacemodificationRegisterAwithVariable(operator, "#${value.number!!.number.toInt()}", target.datatype in SignedDatatypes) + inplacemodificationRegisterAwithVariable(operator, "#${value.number!!.number.toInt()}", target.datatype.isSigned) asmgen.restoreRegisterStack(CpuRegister.Y, true) } SourceStorageKind.VARIABLE -> { - inplacemodificationRegisterAwithVariable(operator, value.asmVarname, target.datatype in SignedDatatypes) + inplacemodificationRegisterAwithVariable(operator, value.asmVarname, target.datatype.isSigned) asmgen.restoreRegisterStack(CpuRegister.Y, true) } SourceStorageKind.REGISTER -> { - inplacemodificationRegisterAwithVariable(operator, regName(value), target.datatype in SignedDatatypes) + inplacemodificationRegisterAwithVariable(operator, regName(value), target.datatype.isSigned) asmgen.restoreRegisterStack(CpuRegister.Y, true) } @@ -349,7 +349,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } SourceStorageKind.EXPRESSION -> { - val tempVar = asmgen.getTempVarName(DataType.UBYTE) + val tempVar = asmgen.getTempVarName(BaseDataType.UBYTE) asmgen.out(" sta $tempVar") if(value.expression is PtTypeCast) inplacemodificationByteVariableWithValue(tempVar, target.datatype, operator, value.expression) @@ -362,7 +362,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, asmgen.out(" sta ${target.array.variable.name},y") } - in WordDatatypes -> { + target.datatype.isWord -> { if(value.kind==SourceStorageKind.EXPRESSION && value.expression is PtTypeCast && tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) @@ -399,7 +399,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, if(!inplacemodificationRegisterAXwithVariable( operator, value.asmVarname, - value.datatype + value.datatype.base )) { asmgen.out(" sta P8ZP_SCRATCH_W1 | stx P8ZP_SCRATCH_W1+1") inplacemodificationWordWithVariable("P8ZP_SCRATCH_W1", target.datatype, operator, value.asmVarname, value.datatype, block) @@ -411,7 +411,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, if(!inplacemodificationRegisterAXwithVariable( operator, regName(value), - value.datatype + value.datatype.base )) { asmgen.out(" sta P8ZP_SCRATCH_W1 | stx P8ZP_SCRATCH_W1+1") inplacemodificationWordWithVariable("P8ZP_SCRATCH_W1", target.datatype, operator, regName(value), value.datatype, block) @@ -432,7 +432,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } SourceStorageKind.EXPRESSION -> { - val tempVar = asmgen.getTempVarName(DataType.UWORD) + val tempVar = asmgen.getTempVarName(BaseDataType.UWORD) asmgen.out(" sta $tempVar | stx $tempVar+1") if(value.expression is PtTypeCast) inplacemodificationWordWithValue(tempVar, target.datatype, operator, value.expression, block) @@ -448,9 +448,9 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, asmgen.out(" sta ${target.array.variable.name},y | txa | sta ${target.array.variable.name}+1,y") } - DataType.FLOAT -> { + target.datatype.isFloat -> { // copy array value into tempvar - val tempvar = asmgen.getTempVarName(DataType.FLOAT) + val tempvar = asmgen.getTempVarName(BaseDataType.FLOAT) asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.A) asmgen.out(""" ldy #>${target.asmVarname} @@ -508,8 +508,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, private fun tryIndexedIncDec(array: PtArrayIndexer, operator: String): Boolean { val arrayvar = asmgen.asmVariableName(array.variable) - when (array.type) { - in ByteDatatypes -> { + when { + array.type.isByte -> { asmgen.loadScaledArrayIndexIntoRegister(array, CpuRegister.X) if (operator == "+") asmgen.out(" inc $arrayvar,x") @@ -517,7 +517,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, asmgen.out(" dec $arrayvar,x") return true } - in WordDatatypes -> { + array.type.isWord -> { asmgen.loadScaledArrayIndexIntoRegister(array, CpuRegister.X) if(array.splitWords) { if(operator=="+") { @@ -551,7 +551,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, return true } } - DataType.FLOAT -> { + array.type.isFloat -> { asmgen.loadScaledArrayIndexIntoRegister(array, CpuRegister.A) asmgen.out(""" ldy #>$arrayvar @@ -568,7 +568,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } private fun tryOptimizedMemoryInplace(address: PtBinaryExpression, operator: String, value: AsmAssignSource): Boolean { - if(value.datatype !in ByteDatatypes || operator !in "|&^+-") + if(!value.datatype.isByte || operator !in "|&^+-") return false fun addrIntoZpPointer(): String { @@ -583,7 +583,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, fun assignValueToA() { val assignValue = AsmAssignment(value, - AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.UBYTE, + AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.UBYTE), address.definingISub(), Position.DUMMY, register = RegisterOrPair.A), program.memsizer, Position.DUMMY) assignmentAsmGen.translateNormalAssignment(assignValue, address.definingISub()) // calculate value into A @@ -591,7 +591,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, val rightTc = address.right as? PtTypeCast val constOffset = (address.right as? PtNumber)?.number?.toInt() - if(address.operator=="+" && (address.right.type in ByteDatatypes || (rightTc!=null && rightTc.value.type in ByteDatatypes) || (constOffset!=null && constOffset<256)) ) { + if(address.operator=="+" && (address.right.type.isByte || (rightTc!=null && rightTc.value.type.isByte) || (constOffset!=null && constOffset<256)) ) { if(constOffset!=null) { val zpPointerVarName = addrIntoZpPointer() if(value.number==null) assignValueToA() @@ -677,10 +677,10 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, inplacemodificationSomeWordWithLiteralval("${arrayVar}_lsb+$index", "${arrayVar}_msb+$index", dt, operator, value, null) } - private fun inplacemodificationRegisterAXwithVariable(operator: String, variable: String, varDt: DataType): Boolean { + private fun inplacemodificationRegisterAXwithVariable(operator: String, variable: String, varDt: BaseDataType): Boolean { when(operator) { "+" -> { - return if(varDt in WordDatatypes) { + return if(varDt.isWord) { asmgen.out(""" clc adc $variable @@ -704,7 +704,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } "-" -> { - return if(varDt in WordDatatypes) { + return if(varDt.isWord) { asmgen.out(""" sec sbc $variable @@ -882,7 +882,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, private fun tryInplaceModifyWithRemovedRedundantCast(value: PtTypeCast, target: AsmAssignTarget, operator: String): Boolean { if (target.datatype == value.type) { val childDt = value.value.type - if (value.type!=DataType.FLOAT && (value.type.equalsSize(childDt) || value.type.largerThan(childDt))) { + if (!value.type.isFloat && (value.type.equalsSize(childDt) || value.type.largerSizeThan(childDt))) { // this typecast is redundant here; the rest of the code knows how to deal with the uncasted value. // (works for integer types, not for float.) val src = AsmAssignSource.fromAstSource(value.value, program, asmgen) @@ -894,7 +894,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } private fun inplacemodificationBytePointerWithValue(pointervar: PtIdentifier, operator: String, value: PtExpression) { - asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE)) inplacemodificationBytePointerWithVariable(pointervar, operator, "P8ZP_SCRATCH_B1") } @@ -1058,6 +1058,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } private fun inplacemodificationByteVariableWithValue(name: String, dt: DataType, operator: String, value: PtExpression) { + require(dt.isByteOrBool) if(!value.isSimple()) { // attempt short-circuit (McCarthy) evaluation when (operator) { @@ -1065,7 +1066,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, // short-circuit LEFT and RIGHT --> if LEFT then RIGHT else LEFT (== if !LEFT then LEFT else RIGHT) val shortcutLabel = asmgen.makeLabel("shortcut") asmgen.out(" lda $name | beq $shortcutLabel") - asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes) + asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt.isSigned) asmgen.out(""" and $name sta $name @@ -1076,7 +1077,7 @@ $shortcutLabel:""") // short-circuit LEFT or RIGHT --> if LEFT then LEFT else RIGHT val shortcutLabel = asmgen.makeLabel("shortcut") asmgen.out(" lda $name | bne $shortcutLabel") - asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes) + asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt.isSigned) asmgen.out(""" ora $name sta $name @@ -1089,25 +1090,25 @@ $shortcutLabel:""") if(asmgen.isTargetCpu(CpuType.CPU65c02)) { if(operator=="&" && value is PtPrefix && value.operator=="~") { // M &= ~A --> use TRB 65c02 instruction for that - asmgen.assignExpressionToRegister(value.value, RegisterOrPair.A, dt in SignedDatatypes) + asmgen.assignExpressionToRegister(value.value, RegisterOrPair.A, dt.isSigned) asmgen.out(" trb $name") return } else if(operator=="|") { // M |= A --> use TSB 65c02 instruction for that - asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes) + asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt.isSigned) asmgen.out(" tsb $name") return } } // normal evaluation - asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes) - inplacemodificationRegisterAwithVariableWithSwappedOperands(operator, name, dt in SignedDatatypes) + asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt.isSigned) + inplacemodificationRegisterAwithVariableWithSwappedOperands(operator, name, dt.isSigned) asmgen.out(" sta $name") } - private fun inplacemodificationByteVariableWithVariable(name: String, dt: DataType, operator: String, otherName: String) { + private fun inplacemodificationByteVariableWithVariable(name: String, signed: Boolean, operator: String, otherName: String) { // note: no logical and/or shortcut here, not worth it due to simple right operand if(asmgen.isTargetCpu(CpuType.CPU65c02)) { @@ -1119,7 +1120,7 @@ $shortcutLabel:""") } asmgen.out(" lda $name") - inplacemodificationRegisterAwithVariable(operator, otherName, dt in SignedDatatypes) + inplacemodificationRegisterAwithVariable(operator, otherName, signed) asmgen.out(" sta $name") } @@ -1467,6 +1468,7 @@ $shortcutLabel:""") private fun inplacemodificationByteVariableWithLiteralval(name: String, dt: DataType, operator: String, value: Int) { // note: this contains special optimized cases because we know the exact value. Don't replace this with another routine. // note: no logical and/or shortcut here, not worth it due to simple right operand + require(dt.isByteOrBool) when (operator) { "+" -> { if(value==1) asmgen.out(" inc $name") @@ -1484,13 +1486,13 @@ $shortcutLabel:""") } "/" -> { // replacing division by shifting is done in an optimizer step. - if (dt == DataType.UBYTE) + if (dt.isUnsignedByte) asmgen.out(" lda $name | ldy #$value | jsr prog8_math.divmod_ub_asm | sty $name") else asmgen.out(" lda $name | ldy #$value | jsr prog8_math.divmod_b_asm | sty $name") } "%" -> { - if(dt==DataType.BYTE) + if(dt.isSignedByte) throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") asmgen.out(""" lda $name @@ -1509,7 +1511,7 @@ $shortcutLabel:""") } ">>" -> { if(value>0) { - if (dt == DataType.UBYTE) { + if (dt.isUnsignedByte) { if(value>=8) { if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(" stz $name") @@ -1560,7 +1562,7 @@ $shortcutLabel:""") + sta $name""") } "<" -> { - if(dt==DataType.UBYTE) { + if(dt.isUnsignedByte) { asmgen.out(""" lda #0 ldy $name @@ -1585,7 +1587,7 @@ $shortcutLabel:""") } } "<=" -> { - if(dt==DataType.UBYTE) { + if(dt.isUnsignedByte) { asmgen.out(""" lda #0 ldy #$value @@ -1608,7 +1610,7 @@ $shortcutLabel:""") } } ">" -> { - if(dt==DataType.UBYTE) { + if(dt.isUnsignedByte) { asmgen.out(""" lda #0 ldy $name @@ -1632,7 +1634,7 @@ $shortcutLabel:""") } } ">=" -> { - if(dt==DataType.UBYTE) { + if(dt.isUnsignedByte) { asmgen.out(""" lda #0 ldy $name @@ -1675,6 +1677,7 @@ $shortcutLabel:""") } private fun inplacemodificationWordWithMemread(name: String, dt: DataType, operator: String, memread: PtMemoryByte) { + require(dt.isInteger) when (operator) { "+" -> { asmgen.translateDirectMemReadExpressionToRegA(memread) @@ -1707,7 +1710,7 @@ $shortcutLabel:""") "&" -> { asmgen.translateDirectMemReadExpressionToRegA(memread) asmgen.out(" and $name | sta $name") - if(dt in WordDatatypes) { + if(dt.isWord) { if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(" stz $name+1") else @@ -1732,6 +1735,7 @@ $shortcutLabel:""") } private fun inplacemodificationSomeWordWithLiteralval(lsb: String, msb: String, dt: DataType, operator: String, value: Int, block: PtBlock?) { + require(dt.isWord) when (operator) { "+" -> { when { @@ -1836,7 +1840,7 @@ $shortcutLabel:""") if(value==0) { throw AssemblyError("division by zero") } else { - if(dt==DataType.WORD) { + if(dt.isSignedWord) { asmgen.out(""" lda $lsb ldy $msb @@ -1867,7 +1871,7 @@ $shortcutLabel:""") "%" -> { if(value==0) throw AssemblyError("division by zero") - if(dt==DataType.WORD) + if(dt.isSignedWord) throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") asmgen.out(""" lda $lsb @@ -1910,7 +1914,7 @@ $shortcutLabel:""") } ">>" -> { if (value > 0) { - if(dt==DataType.UWORD) { + if(dt.isUnsignedWord) { when { value>=16 -> { if(asmgen.isTargetCpu(CpuType.CPU65c02)) @@ -2050,7 +2054,7 @@ $shortcutLabel:""") sta $msb""") } "<" -> { - if(dt==DataType.UWORD) { + if(dt.isUnsignedWord) { asmgen.out(""" lda $msb cmp #>$value @@ -2091,7 +2095,7 @@ $shortcutLabel:""") } } "<=" -> { - if(dt==DataType.UWORD) { + if(dt.isUnsignedWord) { asmgen.out(""" lda $msb cmp #>$value @@ -2134,7 +2138,7 @@ $shortcutLabel:""") } ">" -> { // word > value --> value < word - if(dt==DataType.UWORD) { + if(dt.isUnsignedWord) { asmgen.out(""" lda #>$value cmp $msb @@ -2176,7 +2180,7 @@ $shortcutLabel:""") } ">=" -> { // word >= value --> value <= word - if(dt==DataType.UWORD) { + if(dt.isUnsignedWord) { asmgen.out(""" lda #>$value cmp $msb @@ -2222,12 +2226,14 @@ $shortcutLabel:""") } private fun inplacemodificationWordWithVariable(name: String, dt: DataType, operator: String, otherName: String, valueDt: DataType, block: PtBlock?) { - when (valueDt) { - in ByteDatatypes -> { + require(dt.isWord) + require(valueDt.isInteger) + when { + valueDt.isByte -> { // the other variable is a BYTE type so optimize for that when (operator) { "+" -> { - if(valueDt==DataType.UBYTE) + if(valueDt.isUnsignedByte) asmgen.out(""" lda $name clc @@ -2250,7 +2256,7 @@ $shortcutLabel:""") sta $name+1""") } "-" -> { - if(valueDt==DataType.UBYTE) + if(valueDt.isUnsignedByte) asmgen.out(""" lda $name sec @@ -2276,7 +2282,7 @@ $shortcutLabel:""") "*" -> { if(block?.options?.veraFxMuls==true) { // cx16 verafx hardware muls - if(valueDt==DataType.UBYTE) { + if(valueDt.isUnsignedByte) { asmgen.out(" lda $otherName | sta cx16.r1") if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(" stz cx16.r1+1") @@ -2284,7 +2290,7 @@ $shortcutLabel:""") asmgen.out(" lda #0 | sta cx16.r1+1") } else { asmgen.out(" lda $otherName") - asmgen.signExtendAYlsb(valueDt) + asmgen.signExtendAYlsb(valueDt.base) asmgen.out(" sta cx16.r1 | sty cx16.r1+1") } asmgen.out(""" @@ -2296,7 +2302,7 @@ $shortcutLabel:""") sta $name sty $name+1""") } else { - if(valueDt==DataType.UBYTE) { + if(valueDt.isUnsignedByte) { asmgen.out(" lda $otherName | sta prog8_math.multiply_words.multiplier") if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(" stz prog8_math.multiply_words.multiplier+1") @@ -2304,7 +2310,7 @@ $shortcutLabel:""") asmgen.out(" lda #0 | sta prog8_math.multiply_words.multiplier+1") } else { asmgen.out(" lda $otherName") - asmgen.signExtendAYlsb(valueDt) + asmgen.signExtendAYlsb(valueDt.base) asmgen.out(" sta prog8_math.multiply_words.multiplier | sty prog8_math.multiply_words.multiplier+1") } asmgen.out(""" @@ -2316,7 +2322,7 @@ $shortcutLabel:""") } } "/" -> { - if(dt==DataType.UWORD) { + if(dt.isUnsignedWord) { asmgen.out(""" lda $name ldy $name+1 @@ -2343,7 +2349,7 @@ $shortcutLabel:""") } } "%" -> { - if(valueDt!=DataType.UBYTE || dt!=DataType.UWORD) + if(!valueDt.isUnsignedByte || !dt.isUnsignedWord) throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") asmgen.out(""" lda $name @@ -2370,7 +2376,7 @@ $shortcutLabel:""") +""") } ">>" -> { - if(dt==DataType.UWORD) { + if(dt.isUnsignedWord) { asmgen.out(""" ldy $otherName beq + @@ -2394,7 +2400,7 @@ $shortcutLabel:""") } "&" -> { asmgen.out(" lda $otherName | and $name | sta $name") - if(dt in WordDatatypes) { + if(dt.isWord) { if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(" stz $name+1") else @@ -2436,7 +2442,7 @@ $shortcutLabel:""") else -> throw AssemblyError("invalid operator for in-place modification $operator") } } - in WordDatatypes -> { + valueDt.isWord -> { // the value is a proper 16-bit word, so use both bytes of it. when (operator) { "+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name | lda $name+1 | adc $otherName+1 | sta $name+1") @@ -2469,7 +2475,7 @@ $shortcutLabel:""") sty $name+1""") } "/" -> { - if(dt==DataType.WORD) { + if(dt.isSignedWord) { asmgen.out(""" lda $name ldy $name+1 @@ -2495,7 +2501,7 @@ $shortcutLabel:""") } } "%" -> { - if(dt==DataType.WORD) + if(dt.isSignedWord) throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") asmgen.out(""" lda $name @@ -2548,7 +2554,7 @@ $shortcutLabel:""") sta $name+1""") } "<" -> { - val compareRoutine = if(dt==DataType.UWORD) "reg_less_uw" else "reg_less_w" + val compareRoutine = if(dt.isUnsignedWord) "reg_less_uw" else "reg_less_w" asmgen.out(""" lda $otherName ldy $otherName+1 @@ -2563,7 +2569,7 @@ $shortcutLabel:""") } ">" -> { // a > b --> b < a - val compareRoutine = if(dt==DataType.UWORD) "reg_less_uw" else "reg_less_w" + val compareRoutine = if(dt.isUnsignedWord) "reg_less_uw" else "reg_less_w" asmgen.out(""" lda $name ldy $name+1 @@ -2577,7 +2583,7 @@ $shortcutLabel:""") sta $name+1""") } "<=" -> { - if(dt==DataType.UWORD) { + if(dt.isUnsignedWord) { asmgen.out(""" lda $otherName ldy $otherName+1 @@ -2606,7 +2612,7 @@ $shortcutLabel:""") } ">=" -> { // a>=b --> b<=a - if(dt==DataType.UWORD) { + if(dt.isUnsignedWord) { asmgen.out(""" lda $name ldy $name+1 @@ -2645,6 +2651,7 @@ $shortcutLabel:""") } private fun inplacemodificationWordWithValue(name: String, dt: DataType, operator: String, value: PtExpression, block: PtBlock?) { + require(dt.isWord) fun multiplyVarByWordInAY() { if(block?.options?.veraFxMuls==true) // cx16 verafx hardware muls @@ -2679,7 +2686,7 @@ $shortcutLabel:""") lda $name+1 sta P8ZP_SCRATCH_W1+1 txa""") - if (dt == DataType.WORD) + if (dt.isSignedWord) asmgen.out(" jsr prog8_math.divmod_w_asm") else asmgen.out(" jsr prog8_math.divmod_uw_asm") @@ -2687,7 +2694,7 @@ $shortcutLabel:""") } fun remainderVarByWordInAY() { - if(dt==DataType.WORD) + if(dt.isSignedWord) throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") asmgen.out(""" tax @@ -2703,14 +2710,14 @@ $shortcutLabel:""") sty $name+1 """) } - - when (val valueDt = value.type) { - in ByteDatatypes -> { + val valueDt = value.type + when { + valueDt.isByte -> { // the other variable is a BYTE type so optimize for that when (operator) { "+" -> { // name += byteexpression - if(valueDt==DataType.UBYTE) { + if(valueDt.isUnsignedByte) { asmgen.assignExpressionToRegister(value, RegisterOrPair.A, false) asmgen.out(""" clc @@ -2737,7 +2744,7 @@ $shortcutLabel:""") "-" -> { // name -= byteexpression asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", valueDt) - if(valueDt==DataType.UBYTE) + if(valueDt.isUnsignedByte) asmgen.out(""" lda $name sec @@ -2764,21 +2771,21 @@ $shortcutLabel:""") // value is (u) byte value, sign extend that and proceed with regular 16 bit operation // TODO use an optimized word * byte multiplication routine? asmgen.assignExpressionToRegister(value, RegisterOrPair.A) - asmgen.signExtendAYlsb(valueDt) + asmgen.signExtendAYlsb(valueDt.base) multiplyVarByWordInAY() } "/" -> { // value is (u) byte value, sign extend that and proceed with regular 16 bit operation // TODO use an optimized word / byte divmod routine? asmgen.assignExpressionToRegister(value, RegisterOrPair.A) - asmgen.signExtendAYlsb(valueDt) + asmgen.signExtendAYlsb(valueDt.base) divideVarByWordInAY() } "%" -> { // value is (u) byte value, sign extend that and proceed with regular 16 bit operation // TODO use an optimized word / byte divmod routine? asmgen.assignExpressionToRegister(value, RegisterOrPair.A) - asmgen.signExtendAYlsb(valueDt) + asmgen.signExtendAYlsb(valueDt.base) remainderVarByWordInAY() } "<<" -> { @@ -2793,7 +2800,7 @@ $shortcutLabel:""") } ">>" -> { asmgen.assignExpressionToRegister(value, RegisterOrPair.Y) - if(dt==DataType.UWORD) + if(dt.isUnsignedWord) asmgen.out(""" beq + - lsr $name+1 @@ -2815,7 +2822,7 @@ $shortcutLabel:""") "&" -> { asmgen.assignExpressionToRegister(value, RegisterOrPair.A) asmgen.out(" and $name | sta $name") - if(dt in WordDatatypes) { + if(dt.isWord) { if(asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(" stz $name+1") else @@ -2863,7 +2870,7 @@ $shortcutLabel:""") else -> throw AssemblyError("invalid operator for in-place modification $operator") } } - in WordDatatypes -> { + valueDt.isWord -> { // the value is a proper 16-bit word, so use both bytes of it. when (operator) { "+" -> { @@ -2889,9 +2896,9 @@ $shortcutLabel:""") } "<<", ">>" -> { if(value is PtNumber && value.number<=255) { - when (dt) { - in WordDatatypes -> TODO("shift a word var by ${value.number}") - in ByteDatatypes -> TODO("shift a byte var by ${value.number}") + when { + dt.isWord -> TODO("shift a word var by ${value.number}") + dt.isByte -> TODO("shift a byte var by ${value.number}") else -> throw AssemblyError("weird dt for shift") } } else { diff --git a/codeGenCpu6502/test/Dummies.kt b/codeGenCpu6502/test/Dummies.kt index 5df17ddbb..6d9b9d174 100644 --- a/codeGenCpu6502/test/Dummies.kt +++ b/codeGenCpu6502/test/Dummies.kt @@ -4,16 +4,25 @@ import prog8.code.core.* internal object DummyMemsizer : IMemSizer { - override fun memorySize(dt: DataType) = when(dt) { - in ByteDatatypesWithBoolean -> 1 - DataType.FLOAT -> 5 - else -> 2 + override fun memorySize(dt: DataType, numElements: Int?): Int { + if(dt.isArray) { + require(numElements != null) + return when(dt.sub?.dt) { + BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements + BaseDataType.UWORD, BaseDataType.WORD -> numElements*2 + BaseDataType.FLOAT -> numElements*5 + else -> throw IllegalArgumentException("invalid sub type") + } + } + return when { + dt.isByteOrBool -> 1 * (numElements ?: 1) + dt.isFloat -> 5 * (numElements ?: 1) + else -> 2 * (numElements ?: 1) + } } - override fun memorySize(arrayDt: DataType, numElements: Int) = when(arrayDt) { - DataType.ARRAY_UW -> numElements*2 - DataType.ARRAY_W -> numElements*2 - DataType.ARRAY_F -> numElements*5 - else -> numElements + + override fun memorySize(dt: SubType): Int { + return memorySize(DataType.forDt(dt.dt), null) } } diff --git a/codeGenCpu6502/test/TestCodegen.kt b/codeGenCpu6502/test/TestCodegen.kt index b3a57c0f3..d4e836c45 100644 --- a/codeGenCpu6502/test/TestCodegen.kt +++ b/codeGenCpu6502/test/TestCodegen.kt @@ -50,16 +50,16 @@ class TestCodegen: FunSpec({ val sub = PtSub("start", emptyList(), null, Position.DUMMY) sub.add(PtVariable( "pi", - DataType.UBYTE, + DataType.forDt(BaseDataType.UBYTE), ZeropageWish.DONTCARE, 0u, - PtNumber(DataType.UBYTE, 0.0, Position.DUMMY), + PtNumber(BaseDataType.UBYTE, 0.0, Position.DUMMY), null, Position.DUMMY )) sub.add(PtVariable( "particleX", - DataType.ARRAY_UB, + DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, 0u, null, @@ -68,7 +68,7 @@ class TestCodegen: FunSpec({ )) sub.add(PtVariable( "particleDX", - DataType.ARRAY_UB, + DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, 0u, null, @@ -77,51 +77,51 @@ class TestCodegen: FunSpec({ )) sub.add(PtVariable( "xx", - DataType.WORD, + DataType.forDt(BaseDataType.WORD), ZeropageWish.DONTCARE, 0u, - PtNumber(DataType.WORD, 1.0, Position.DUMMY), + PtNumber(BaseDataType.WORD, 1.0, Position.DUMMY), null, Position.DUMMY )) val assign = PtAugmentedAssign("+=", Position.DUMMY) val target = PtAssignTarget(false, Position.DUMMY).also { - val targetIdx = PtArrayIndexer(DataType.UBYTE, Position.DUMMY).also { idx -> - idx.add(PtIdentifier("main.start.particleX", DataType.ARRAY_UB, Position.DUMMY)) - idx.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY)) + val targetIdx = PtArrayIndexer(DataType.forDt(BaseDataType.UBYTE), Position.DUMMY).also { idx -> + idx.add(PtIdentifier("main.start.particleX", DataType.arrayFor(BaseDataType.UBYTE), Position.DUMMY)) + idx.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY)) } it.add(targetIdx) } - val value = PtArrayIndexer(DataType.UBYTE, Position.DUMMY) - value.add(PtIdentifier("main.start.particleDX", DataType.ARRAY_UB, Position.DUMMY)) - value.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY)) + val value = PtArrayIndexer(DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) + value.add(PtIdentifier("main.start.particleDX", DataType.arrayFor(BaseDataType.UBYTE), Position.DUMMY)) + value.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY)) assign.add(target) assign.add(value) sub.add(assign) val prefixAssign = PtAugmentedAssign("-", Position.DUMMY) val prefixTarget = PtAssignTarget(false, Position.DUMMY).also { - it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY)) + it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY)) } prefixAssign.add(prefixTarget) - prefixAssign.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY)) + prefixAssign.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY)) sub.add(prefixAssign) val numberAssign = PtAugmentedAssign("-=", Position.DUMMY) val numberAssignTarget = PtAssignTarget(false, Position.DUMMY).also { - it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY)) + it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY)) } numberAssign.add(numberAssignTarget) - numberAssign.add(PtNumber(DataType.WORD, 42.0, Position.DUMMY)) + numberAssign.add(PtNumber(BaseDataType.WORD, 42.0, Position.DUMMY)) sub.add(numberAssign) val cxregAssign = PtAugmentedAssign("+=", Position.DUMMY) val cxregAssignTarget = PtAssignTarget(false, Position.DUMMY).also { - it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY)) + it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY)) } cxregAssign.add(cxregAssignTarget) - cxregAssign.add(PtIdentifier("cx16.r0", DataType.UWORD, Position.DUMMY)) + cxregAssign.add(PtIdentifier("cx16.r0", DataType.forDt(BaseDataType.UWORD), Position.DUMMY)) sub.add(cxregAssign) block.add(sub) @@ -129,7 +129,7 @@ class TestCodegen: FunSpec({ // define the "cx16.r0" virtual register val cx16block = PtBlock("cx16", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY) - cx16block.add(PtMemMapped("r0", DataType.UWORD, 100u, null, Position.DUMMY)) + cx16block.add(PtMemMapped("r0", DataType.forDt(BaseDataType.UWORD), 100u, null, Position.DUMMY)) program.add(cx16block) val options = getTestOptions() diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index aaaf6437a..85b365a4c 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -83,7 +83,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val symbol = target.identifier?.name val array = target.array val value = augAssign.value - val signed = target.type in SignedDatatypes + val signed = target.type.isSigned val chunks = when (augAssign.operator) { "+=" -> operatorPlusInplace(symbol, array, constAddress, memTarget, targetDt, value) @@ -182,7 +182,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } private fun inplacePrefixArray(operator: String, array: PtArrayIndexer): IRCodeChunks { - val eltSize = codeGen.program.memsizer.memorySize(array.type) + val eltSize = codeGen.program.memsizer.memorySize(array.type, null) val result = mutableListOf() val vmDt = irType(array.type) val constIndex = array.index.asConstInteger() @@ -336,7 +336,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express addToResult(result, tr, valueRegister, -1) if(extendByteToWord) { valueRegister = codeGen.registers.nextFree() - val opcode = if(assignment.value.type in SignedDatatypes) Opcode.EXTS else Opcode.EXT + val opcode = if(assignment.value.type.isSigned) Opcode.EXTS else Opcode.EXT addInstr(result, IRInstruction(opcode, IRDataType.BYTE, reg1=valueRegister, reg2=tr.resultReg), null) } } @@ -357,7 +357,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } else if(targetArray!=null) { val variable = targetArray.variable.name - val itemsize = codeGen.program.memsizer.memorySize(targetArray.type) + val itemsize = codeGen.program.memsizer.memorySize(targetArray.type, null) val fixedIndex = targetArray.index.asConstInteger() val arrayLength = codeGen.symbolTable.getLength(targetArray.variable.name) @@ -465,10 +465,10 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } val offsetTypecast = ptrWithOffset?.right as? PtTypeCast if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier - && (ptrWithOffset.right.type in ByteDatatypes || offsetTypecast?.value?.type in ByteDatatypes)) { + && (ptrWithOffset.right.type.isByte || offsetTypecast?.value?.type?.isByte==true)) { // STOREIX only works with byte index. - val tr = if(offsetTypecast?.value?.type in ByteDatatypes) - expressionEval.translateExpression(offsetTypecast!!.value) + val tr = if(offsetTypecast?.value?.type?.isByte==true) + expressionEval.translateExpression(offsetTypecast.value) else expressionEval.translateExpression(ptrWithOffset.right) addToResult(result, tr, tr.resultReg, -1) @@ -498,9 +498,9 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express addToResult(result, tr, tr.resultReg, -1) return Pair(result, tr.resultReg) } - val mult: PtExpression = PtBinaryExpression("*", DataType.UBYTE, array.position) + val mult: PtExpression = PtBinaryExpression("*", DataType.forDt(BaseDataType.UBYTE), array.position) mult.children += array.index - mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position) + mult.children += PtNumber(BaseDataType.UBYTE, itemsize.toDouble(), array.position) val tr = expressionEval.translateExpression(mult) addToResult(result, tr, tr.resultReg, -1) return Pair(result, tr.resultReg) @@ -511,7 +511,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val result = mutableListOf() val constIndex = array.index.asConstInteger() val constValue = operand.asConstInteger() - val eltSize = codeGen.program.memsizer.memorySize(array.type) + val eltSize = codeGen.program.memsizer.memorySize(array.type, null) if(constIndex!=null && constValue!=null) { if(array.splitWords) { val valueRegLsb = codeGen.registers.nextFree() @@ -551,7 +551,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val result = mutableListOf() val constIndex = array.index.asConstInteger() val constValue = operand.asConstInteger() - val eltSize = codeGen.program.memsizer.memorySize(array.type) + val eltSize = codeGen.program.memsizer.memorySize(array.type, null) if(constIndex!=null && constValue!=null) { if(array.splitWords) { val valueRegLsb = codeGen.registers.nextFree() @@ -611,7 +611,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val result = mutableListOf() val constIndex = array.index.asConstInteger() val constValue = operand.asConstInteger() - val eltSize = codeGen.program.memsizer.memorySize(array.type) + val eltSize = codeGen.program.memsizer.memorySize(array.type, null) if(constIndex!=null && constValue!=null) { if(array.splitWords) { val valueRegLsb = codeGen.registers.nextFree() @@ -651,7 +651,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val result = mutableListOf() val constIndex = array.index.asConstInteger() val constValue = operand.asConstInteger() - val eltSize = codeGen.program.memsizer.memorySize(array.type) + val eltSize = codeGen.program.memsizer.memorySize(array.type, null) if(constIndex!=null && constValue!=null) { if(array.splitWords) { val valueRegLsb = codeGen.registers.nextFree() @@ -716,7 +716,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val result = mutableListOf() val constFactorRight = operand as? PtNumber if(vmDt==IRDataType.FLOAT) { - if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { + if(constFactorRight!=null && !constFactorRight.type.isFloat) { val factor = constFactorRight.number result += codeGen.divideByConstFloatInplace(constAddress, symbol, factor) } else { @@ -737,7 +737,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express addInstr(result, ins, null) } } else { - if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { + if(constFactorRight!=null && !constFactorRight.type.isFloat) { val factor = constFactorRight.number.toInt() result += codeGen.divideByConstInplace(vmDt, constAddress, symbol, factor, signed) } else { @@ -763,7 +763,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express private fun operatorMultiplyInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { if(array!=null) { - val eltSize = codeGen.program.memsizer.memorySize(array.type) + val eltSize = codeGen.program.memsizer.memorySize(array.type, null) val result = mutableListOf() if(array.splitWords) return operatorMultiplyInplaceSplitArray(array, operand) @@ -801,7 +801,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express , null) } } else { - if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { + if(constFactorRight!=null && !constFactorRight.type.isFloat) { val factor = constFactorRight.number.toInt() result += codeGen.multiplyByConstInplace(vmDt, constAddress, symbol, factor) } else { @@ -819,7 +819,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express private fun operatorMinusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { if(array!=null) { - val eltSize = codeGen.program.memsizer.memorySize(array.type) + val eltSize = codeGen.program.memsizer.memorySize(array.type, null) val result = mutableListOf() if(array.splitWords) return operatorMinusInplaceSplitArray(array, operand) @@ -915,7 +915,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val result = mutableListOf() if(array.splitWords) return operatorPlusInplaceSplitArray(array, operand) - val eltSize = codeGen.program.memsizer.memorySize(array.type) + val eltSize = codeGen.program.memsizer.memorySize(array.type, null) val elementDt = irType(array.type) val constIndex = array.index.asConstInteger() val constValue = operand.asConstInteger() @@ -1055,7 +1055,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val result = mutableListOf() val constIndex = array.index.asConstInteger() val constValue = operand.asConstInteger() - val eltSize = codeGen.program.memsizer.memorySize(array.type) + val eltSize = codeGen.program.memsizer.memorySize(array.type, null) if(constIndex!=null && constValue!=null) { if(array.splitWords) { val valueRegLsb = codeGen.registers.nextFree() @@ -1369,10 +1369,10 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } private fun createInplaceArrayComparison(array: PtArrayIndexer, value: PtExpression, comparisonOperator: String): IRCodeChunks? { - if(array.type==DataType.FLOAT) + if(array.type.isFloat) return null // TODO("optimized in-place compare on float arrays")) - val eltSize = codeGen.program.memsizer.memorySize(array.type) + val eltSize = codeGen.program.memsizer.memorySize(array.type, null) val result = mutableListOf() if(array.splitWords) TODO("inplace compare for split word array") diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index fe15e96e8..1ce7f6ee0 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -1,7 +1,8 @@ package prog8.codegen.intermediate import prog8.code.ast.* -import prog8.code.core.* +import prog8.code.core.AssemblyError +import prog8.code.core.BaseDataType import prog8.intermediate.* @@ -169,13 +170,13 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe private fun funcAbs(call: PtBuiltinFunctionCall): ExpressionCodeResult { val sourceDt = call.args.single().type val result = mutableListOf() - if(sourceDt==DataType.UWORD) + if(sourceDt.isUnsignedWord) return ExpressionCodeResult.EMPTY val tr = exprGen.translateExpression(call.args[0]) addToResult(result, tr, tr.resultReg, -1) - when (sourceDt) { - DataType.BYTE -> { + when (sourceDt.base) { + BaseDataType.BYTE -> { val notNegativeLabel = codeGen.createLabelName() val compareReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { @@ -186,7 +187,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe result += IRCodeChunk(notNegativeLabel, null) return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1) } - DataType.WORD -> { + BaseDataType.WORD -> { val notNegativeLabel = codeGen.createLabelName() val compareReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { @@ -197,7 +198,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe result += IRCodeChunk(notNegativeLabel, null) return ExpressionCodeResult(result, IRDataType.WORD, tr.resultReg, -1) } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { val resultFpReg = codeGen.registers.nextFreeFloat() addInstr(result, IRInstruction(Opcode.FABS, IRDataType.FLOAT, fpReg1 = resultFpReg, fpReg2 = tr.resultFpReg), null) return ExpressionCodeResult(result, IRDataType.FLOAT, -1, resultFpReg) @@ -229,8 +230,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe val result = mutableListOf() val tr = exprGen.translateExpression(call.args.single()) val dt = call.args[0].type - when(dt) { - DataType.UBYTE -> { + when(dt.base) { + BaseDataType.UBYTE -> { addToResult(result, tr, tr.resultReg, -1) val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { @@ -238,7 +239,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe } return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } - DataType.UWORD -> { + BaseDataType.UWORD -> { addToResult(result, tr, tr.resultReg, -1) val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { @@ -246,7 +247,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe } return ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1) } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { addToResult(result, tr, -1, tr.resultFpReg) val resultFpReg = codeGen.registers.nextFreeFloat() result += IRCodeChunk(null, null).also { @@ -296,11 +297,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe ) return ExpressionCodeResult(result, type, -1, valueTr.resultFpReg) } else { - val syscall = when(call.type) { - DataType.UBYTE -> IMSyscall.CLAMP_UBYTE - DataType.BYTE -> IMSyscall.CLAMP_BYTE - DataType.UWORD -> IMSyscall.CLAMP_UWORD - DataType.WORD -> IMSyscall.CLAMP_WORD + val syscall = when(call.type.base) { + BaseDataType.UBYTE -> IMSyscall.CLAMP_UBYTE + BaseDataType.BYTE -> IMSyscall.CLAMP_BYTE + BaseDataType.UWORD -> IMSyscall.CLAMP_UWORD + BaseDataType.WORD -> IMSyscall.CLAMP_WORD else -> throw AssemblyError("invalid dt") } result += codeGen.makeSyscall(syscall, listOf( @@ -320,7 +321,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe addToResult(result, leftTr, leftTr.resultReg, -1) val rightTr = exprGen.translateExpression(call.args[1]) addToResult(result, rightTr, rightTr.resultReg, -1) - val comparisonOpcode = if(call.type in SignedDatatypes) Opcode.BGTSR else Opcode.BGTR + val comparisonOpcode = if(call.type.isSigned) Opcode.BGTSR else Opcode.BGTR val after = codeGen.createLabelName() result += IRCodeChunk(null, null).also { it += IRInstruction(comparisonOpcode, type, reg1 = rightTr.resultReg, reg2 = leftTr.resultReg, labelSymbol = after) @@ -339,7 +340,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe addToResult(result, leftTr, leftTr.resultReg, -1) val rightTr = exprGen.translateExpression(call.args[1]) addToResult(result, rightTr, rightTr.resultReg, -1) - val comparisonOpcode = if(call.type in SignedDatatypes) Opcode.BGTSR else Opcode.BGTR + val comparisonOpcode = if(call.type.isSigned) Opcode.BGTSR else Opcode.BGTR val after = codeGen.createLabelName() result += IRCodeChunk(null, null).also { it += IRInstruction(comparisonOpcode, type, reg1 = leftTr.resultReg, reg2 = rightTr.resultReg, labelSymbol = after) @@ -546,8 +547,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe if(arr!=null && index!=null) { if(arr.splitWords) TODO("IR rol/ror on split words array") val variable = arr.variable.name - val itemsize = codeGen.program.memsizer.memorySize(arr.type) - addInstr(result, IRInstruction(opcodeMemAndReg.first, vmDt, labelSymbol = variable, symbolOffset = index*itemsize), null) + val offset = codeGen.program.memsizer.memorySize(arr.type, index) + addInstr(result, IRInstruction(opcodeMemAndReg.first, vmDt, labelSymbol = variable, symbolOffset = offset), null) return ExpressionCodeResult(result, vmDt, -1, -1) } @@ -632,7 +633,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe } } else { - val eltSize = codeGen.program.memsizer.memorySize(target.type) + val eltSize = codeGen.program.memsizer.memorySize(target.type, null) val constIndex = target.index.asConstInteger() if(isConstZeroValue) { if(constIndex!=null) { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index a6d9ff4c1..3e9b35503 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -53,7 +53,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } is PtIdentifier -> { val code = IRCodeChunk(null, null) - if (expr.type in PassByValueDatatypes) { + if (expr.type.isPassByValue) { val vmDt = irType(expr.type) if(vmDt==IRDataType.FLOAT) { val resultFpRegister = codeGen.registers.nextFreeFloat() @@ -67,7 +67,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } } else { // for strings and arrays etc., load the *address* of the value instead - val vmDt = if(expr.type==DataType.UNDEFINED) IRDataType.WORD else irType(expr.type) + val vmDt = if(expr.type.isUndefined) IRDataType.WORD else irType(expr.type) val resultRegister = codeGen.registers.nextFree() code += IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = expr.name) ExpressionCodeResult(code, vmDt, resultRegister, -1) @@ -131,13 +131,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val result = mutableListOf() val resultRegister = codeGen.registers.nextFree() if(expr.isFromArrayElement) { - require(expr.identifier.type !in SplitWordArrayTypes) + require(!expr.identifier.type.isSplitWordArray) addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol), null) val indexTr2 = translateExpression(expr.arrayIndexExpr!!) addToResult(result, indexTr2, indexTr2.resultReg, -1) val indexWordReg = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=indexWordReg, reg2=indexTr2.resultReg), null) - if(expr.identifier.type == DataType.UWORD) { + if(expr.identifier.type.isUnsignedWord) { result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = symbol) it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=resultRegister, reg2=indexWordReg) @@ -184,10 +184,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } val offsetTypecast = ptrWithOffset?.right as? PtTypeCast if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier - && (ptrWithOffset.right.type in ByteDatatypes || offsetTypecast?.value?.type in ByteDatatypes)) { + && (ptrWithOffset.right.type.isByte || offsetTypecast?.value?.type?.isByte==true)) { // LOADIX only works with byte index. - val tr = if(offsetTypecast?.value?.type in ByteDatatypes) - translateExpression(offsetTypecast!!.value) + val tr = if(offsetTypecast?.value?.type?.isByte==true) + translateExpression(offsetTypecast.value) else translateExpression(ptrWithOffset.right) addToResult(result, tr, tr.resultReg, -1) @@ -211,10 +211,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { if(it is PtBool) it.asInt() else (it as PtNumber).number.toInt() } - when(elementDt) { - in IntegerDatatypesWithBoolean -> { - if (elementDt in ByteDatatypesWithBoolean) require(haystack.size in 0..PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_BYTE) - if (elementDt in WordDatatypes) require(haystack.size in 0..PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_WORD) + when { + elementDt.isIntegerOrBool -> { + if (elementDt.isByteOrBool) require(haystack.size in 0..PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_BYTE) + if (elementDt.isWord) require(haystack.size in 0..PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_WORD) val gottemLabel = codeGen.createLabelName() val endLabel = codeGen.createLabelName() val elementTr = translateExpression(check.needle) @@ -231,14 +231,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { result += IRCodeChunk(endLabel, null) return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1) } - DataType.FLOAT -> throw AssemblyError("containmentchecks for floats should always be done on an array variable with subroutine") + elementDt.isFloat -> throw AssemblyError("containmentchecks for floats should always be done on an array variable with subroutine") else -> throw AssemblyError("weird dt $elementDt") } } val haystackVar = check.haystackHeapVar!! - when(haystackVar.type) { - DataType.STR -> { + when { + haystackVar.type.isString -> { addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null) val elementTr = translateExpression(check.needle) addToResult(result, elementTr, elementTr.resultReg, -1) @@ -248,7 +248,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=elementTr.resultReg, immediate = 0), null) return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1) } - DataType.ARRAY_UB, DataType.ARRAY_B -> { + haystackVar.type.isByteArray -> { addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null) val elementTr = translateExpression(check.needle) addToResult(result, elementTr, elementTr.resultReg, -1) @@ -261,7 +261,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=elementTr.resultReg, immediate = 0), null) return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1) } - DataType.ARRAY_UW, DataType.ARRAY_W -> { + haystackVar.type.isWordArray -> { addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null) val elementTr = translateExpression(check.needle) addToResult(result, elementTr, elementTr.resultReg, -1) @@ -274,7 +274,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=elementTr.resultReg, immediate = 0), null) return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1) } - DataType.ARRAY_F -> { + haystackVar.type.isFloatArray -> { addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null) val elementTr = translateExpression(check.needle) addToResult(result, elementTr, -1, elementTr.resultFpReg) @@ -293,7 +293,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } private fun translate(arrayIx: PtArrayIndexer): ExpressionCodeResult { - val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type) + val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type, null) val vmDt = irType(arrayIx.type) val result = mutableListOf() val arrayVarSymbol = arrayIx.variable.name @@ -384,18 +384,19 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addToResult(result, tr, tr.resultReg, tr.resultFpReg) var actualResultReg2 = -1 var actualResultFpReg2 = -1 - when(cast.type) { - DataType.BOOL -> { - when (cast.value.type) { - in ByteDatatypes -> { + val valueDt = cast.value.type + when(cast.type.base) { + BaseDataType.BOOL -> { + when { + valueDt.isByte -> { actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.SNZ, IRDataType.BYTE, reg1=actualResultReg2, reg2=tr.resultReg), null) } - in WordDatatypes -> { + valueDt.isWord -> { actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.SNZ, IRDataType.WORD, reg1=actualResultReg2, reg2=tr.resultReg), null) } - DataType.FLOAT -> { + valueDt.isFloat -> { actualResultReg2 = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.SGN, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg) @@ -405,87 +406,87 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { else -> throw AssemblyError("weird cast value type") } } - DataType.UBYTE -> { - when(cast.value.type) { - DataType.BOOL, DataType.BYTE, DataType.UWORD, DataType.WORD -> { + BaseDataType.UBYTE -> { + when(valueDt.base) { + BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD -> { actualResultReg2 = tr.resultReg // just keep the LSB as it is } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.FTOUB, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null) } else -> throw AssemblyError("weird cast value type") } } - DataType.BYTE -> { - when(cast.value.type) { - DataType.BOOL, DataType.UBYTE, DataType.UWORD, DataType.WORD -> { + BaseDataType.BYTE -> { + when(valueDt.base) { + BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.WORD -> { actualResultReg2 = tr.resultReg // just keep the LSB as it is } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.FTOSB, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null) } else -> throw AssemblyError("weird cast value type") } } - DataType.UWORD -> { - when(cast.value.type) { - DataType.BYTE -> { + BaseDataType.UWORD -> { + when(valueDt.base) { + BaseDataType.BYTE -> { // byte -> uword: sign extend actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = actualResultReg2, reg2 = tr.resultReg), null) } - DataType.BOOL, DataType.UBYTE -> { + BaseDataType.BOOL, BaseDataType.UBYTE -> { // ubyte -> uword: sign extend actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg2, reg2 = tr.resultReg), null) } - DataType.WORD -> { + BaseDataType.WORD -> { actualResultReg2 = tr.resultReg } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.FTOUW, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null) } else -> throw AssemblyError("weird cast value type") } } - DataType.WORD -> { - when(cast.value.type) { - DataType.BYTE -> { + BaseDataType.WORD -> { + when(valueDt.base) { + BaseDataType.BYTE -> { // byte -> word: sign extend actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = actualResultReg2, reg2=tr.resultReg), null) } - DataType.BOOL, DataType.UBYTE -> { + BaseDataType.BOOL, BaseDataType.UBYTE -> { // byte -> word: sign extend actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg2, reg2=tr.resultReg), null) } - DataType.UWORD -> { + BaseDataType.UWORD -> { actualResultReg2 = tr.resultReg } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.FTOSW, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null) } else -> throw AssemblyError("weird cast value type") } } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { actualResultFpReg2 = codeGen.registers.nextFreeFloat() - when(cast.value.type) { - DataType.BOOL, DataType.UBYTE -> { + when(valueDt.base) { + BaseDataType.BOOL, BaseDataType.UBYTE -> { addInstr(result, IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null) } - DataType.BYTE -> { + BaseDataType.BYTE -> { addInstr(result, IRInstruction(Opcode.FFROMSB, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null) } - DataType.UWORD -> { + BaseDataType.UWORD -> { addInstr(result, IRInstruction(Opcode.FFROMUW, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null) } - DataType.WORD -> { + BaseDataType.WORD -> { addInstr(result, IRInstruction(Opcode.FFROMSW, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null) } else -> throw AssemblyError("weird cast value type") @@ -499,7 +500,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { private fun translate(binExpr: PtBinaryExpression): ExpressionCodeResult { val vmDt = irType(binExpr.left.type) - val signed = binExpr.left.type in SignedDatatypes + val signed = binExpr.left.type.isSigned return when(binExpr.operator) { "+" -> operatorPlus(binExpr, vmDt) "-" -> operatorMinus(binExpr, vmDt) @@ -592,7 +593,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { fcallArgs = FunctionCallArgs(argRegisters, if(returnRegSpec==null) emptyList() else listOf(returnRegSpec))), null) return if(fcall.void) ExpressionCodeResult(result, IRDataType.BYTE, -1, -1) - else if(fcall.type==DataType.FLOAT) + else if(fcall.type.isFloat) ExpressionCodeResult(result, returnRegSpec!!.dt, -1, returnRegSpec.registerNum) else ExpressionCodeResult(result, returnRegSpec!!.dt, returnRegSpec.registerNum, -1) @@ -705,7 +706,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { return if(fcall.void) ExpressionCodeResult(result, IRDataType.BYTE, -1, -1) - else if(fcall.type==DataType.FLOAT) + else if(fcall.type.isFloat) ExpressionCodeResult(result, returnRegSpec!!.dt, -1, finalReturnRegister) else ExpressionCodeResult(result, returnRegSpec!!.dt, finalReturnRegister, -1) @@ -768,7 +769,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { ): ExpressionCodeResult { // return multiple values val returnRegisters = callTarget.returns.map { - val regnum = if(it.type==DataType.FLOAT) codeGen.registers.nextFreeFloat() else codeGen.registers.nextFree() + val regnum = if(it.type.isFloat) codeGen.registers.nextFreeFloat() else codeGen.registers.nextFree() FunctionCallArgs.RegSpec(irType(it.type), regnum, it.register) } // create the call @@ -817,7 +818,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1=cmpResultReg, reg2 = resultRegister, reg3 = zeroRegister), null) return ExpressionCodeResult(result, IRDataType.BYTE, cmpResultReg, -1) } else { - if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) { + if(binExpr.left.type.isString || binExpr.right.type.isString) { throw AssemblyError("str compares should have been replaced with builtin function call to do the compare") } else { val leftTr = translateExpression(binExpr.left) @@ -860,7 +861,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1=cmpResultRegister, reg2 = resultRegister, reg3 = zeroRegister), null) return ExpressionCodeResult(result, IRDataType.BYTE, cmpResultRegister, -1) } else { - if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) { + if(binExpr.left.type.isString || binExpr.right.type.isString) { throw AssemblyError("str compares should have been replaced with builtin function call to do the compare") } else { val leftTr = translateExpression(binExpr.left) @@ -901,7 +902,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { result += IRCodeChunk(label, null) return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1) } else { - if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) { + if(binExpr.left.type.isString || binExpr.right.type.isString) { throw AssemblyError("str compares should have been replaced with builtin function call to do the compare") } else { return if(binExpr.right.asConstValue()==0.0) { @@ -1073,7 +1074,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val result = mutableListOf() val constFactorRight = binExpr.right as? PtNumber if(vmDt==IRDataType.FLOAT) { - if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { + if(constFactorRight!=null && !constFactorRight.type.isFloat) { val tr = translateExpression(binExpr.left) addToResult(result, tr, -1, tr.resultFpReg) val factor = constFactorRight.number @@ -1092,7 +1093,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { return ExpressionCodeResult(result, vmDt, -1, leftTr.resultFpReg) } } else { - return if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { + return if(constFactorRight!=null && !constFactorRight.type.isFloat) { val tr = translateExpression(binExpr.left) addToResult(result, tr, tr.resultReg, -1) val factor = constFactorRight.number.toInt() @@ -1150,13 +1151,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { ExpressionCodeResult(result, vmDt, -1, leftTr.resultFpReg) } } else { - return if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) { + return if(constFactorLeft!=null && !constFactorLeft.type.isFloat) { val tr = translateExpression(binExpr.right) addToResult(result, tr, tr.resultReg, -1) val factor = constFactorLeft.number.toInt() result += codeGen.multiplyByConst(vmDt, tr.resultReg, factor) ExpressionCodeResult(result, vmDt, tr.resultReg, -1) - } else if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { + } else if(constFactorRight!=null && !constFactorRight.type.isFloat) { val tr = translateExpression(binExpr.left) addToResult(result, tr, tr.resultReg, -1) val factor = constFactorRight.number.toInt() diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index b3868fc1f..45d83d040 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -432,8 +432,8 @@ class IRCodeGen( val tmpReg = registers.nextFree() val loopLabel = createLabelName() val endLabel = createLabelName() - when (iterable.type) { - DataType.STR -> { + when { + iterable.type.isString -> { // iterate over a zero-terminated string addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null) result += IRCodeChunk(loopLabel, null).also { @@ -448,10 +448,10 @@ class IRCodeGen( result += jumpChunk result += IRCodeChunk(endLabel, null) } - in SplitWordArrayTypes -> { + iterable.type.isSplitWordArray -> { // iterate over lsb/msb split word array - val elementDt = ArrayToElementTypes.getValue(iterable.type) - if(elementDt !in WordDatatypes) + val elementDt = iterable.type.elementType() + if(!elementDt.isWord) throw AssemblyError("weird dt") addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) result += IRCodeChunk(loopLabel, null).also { @@ -475,13 +475,14 @@ class IRCodeGen( } else -> { // iterate over regular array - val elementDt = ArrayToElementTypes.getValue(iterable.type) - val elementSize = program.memsizer.memorySize(elementDt) + val element = iterable.type.sub!! + val elementDt = element.dt + val elementSize = program.memsizer.memorySize(element) val lengthBytes = iterableLength!! * elementSize addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) result += IRCodeChunk(loopLabel, null).also { - it += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name) - it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol) + it += IRInstruction(Opcode.LOADX, irType(DataType.forDt(elementDt)), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name) + it += IRInstruction(Opcode.STOREM, irType(DataType.forDt(elementDt)), reg1=tmpReg, labelSymbol = loopvarSymbol) } result += translateNode(forLoop.statements) result += addConstReg(IRDataType.BYTE, indexReg, elementSize) @@ -548,7 +549,7 @@ class IRCodeGen( addToResult(result, fromTr, fromTr.resultReg, -1) val labelAfterFor = createLabelName() - val precheckInstruction = if(loopvarDt in SignedDatatypes) { + val precheckInstruction = if(loopvarDt.isSigned) { if(step>0) IRInstruction(Opcode.BGTSR, loopvarDtIr, fromTr.resultReg, toTr.resultReg, labelSymbol=labelAfterFor) else @@ -616,7 +617,7 @@ class IRCodeGen( val chunk2 = addConstMem(loopvarDtIr, null, loopvarSymbol, iterable.step) if(loopvarDtIr==IRDataType.BYTE && iterable.step==-1 && iterable.last==0) { // downto 0 optimization (byte) - if(loopvarDt==DataType.BYTE || iterable.first<=127) { + if(loopvarDt.isSignedByte || iterable.first<=127) { chunk2 += IRInstruction(Opcode.BSTPOS, labelSymbol = loopLabel) } else { chunk2 += IRInstruction(Opcode.LOADM, loopvarDtIr, reg1 = indexReg, labelSymbol = loopvarSymbol) @@ -977,7 +978,7 @@ class IRCodeGen( private fun translateIfFollowedByJustGoto(ifElse: PtIfElse, goto: PtJump): MutableList { val condition = ifElse.condition as? PtBinaryExpression - if(condition==null || condition.left.type!=DataType.FLOAT) { + if(condition==null || !condition.left.type.isFloat) { return if(isIndirectJump(goto)) ifWithOnlyIndirectJump_IntegerCond(ifElse, goto) else @@ -1082,7 +1083,7 @@ class IRCodeGen( val leftTr = expressionEval.translateExpression(condition.left) val irDt = leftTr.dt - val signed = condition.left.type in SignedDatatypes + val signed = condition.left.type.isSigned addToResult(result, leftTr, leftTr.resultReg, -1) val number = (condition.right as? PtNumber)?.number?.toInt() if(number!=null) { @@ -1170,7 +1171,7 @@ class IRCodeGen( when(val cond = ifElse.condition) { is PtTypeCast -> { - require(cond.type==DataType.BOOL && cond.value.type in NumericDatatypes) + require(cond.type.isBool && cond.value.type.isNumeric) val tr = expressionEval.translateExpression(cond) result += tr.chunks addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = afterIfLabel), null) @@ -1212,7 +1213,7 @@ class IRCodeGen( val leftTr = expressionEval.translateExpression(condition.left) val irDt = leftTr.dt - val signed = condition.left.type in SignedDatatypes + val signed = condition.left.type.isSigned addToResult(result, leftTr, leftTr.resultReg, -1) val number = (condition.right as? PtNumber)?.number?.toInt() if(number!=null) { @@ -1301,7 +1302,7 @@ class IRCodeGen( when(val cond = ifElse.condition) { is PtTypeCast -> { - require(cond.type==DataType.BOOL && cond.value.type in NumericDatatypes) + require(cond.type.isBool && cond.value.type.isNumeric) val tr = expressionEval.translateExpression(cond) result += tr.chunks addInstr(result, branchInstr(goto, Opcode.BSTNE), null) @@ -1328,7 +1329,7 @@ class IRCodeGen( throw AssemblyError("not prefix in ifelse should have been replaced by swapped if-else blocks") val condition = ifElse.condition as? PtBinaryExpression - if(condition==null || condition.left.type != DataType.FLOAT) { + if(condition==null || !condition.left.type.isFloat) { return ifWithElse_IntegerCond(ifElse) } @@ -1421,7 +1422,7 @@ class IRCodeGen( if(condition.operator in LogicalOperators) return translateSimple(condition, Opcode.BSTEQ, false) - val signed = condition.left.type in SignedDatatypes + val signed = condition.left.type.isSigned val elseBranchFirstReg: Int val elseBranchSecondReg: Int val number = (condition.right as? PtNumber)?.number?.toInt() @@ -1562,7 +1563,7 @@ class IRCodeGen( translateSimple(cond, Opcode.BSTEQ, false) } is PtTypeCast -> { - require(cond.type==DataType.BOOL && cond.value.type in NumericDatatypes) + require(cond.type.isBool && cond.value.type.isNumeric) translateSimple(cond, Opcode.BSTEQ, false) } is PtIdentifier, is PtArrayIndexer, is PtContainmentCheck -> { @@ -1589,7 +1590,7 @@ class IRCodeGen( 1 -> return translateGroup(repeat.children) 256 -> { // 256 iterations can still be done with just a byte counter if you set it to zero as starting value. - repeat.children[0] = PtNumber(DataType.UBYTE, 0.0, repeat.count.position) + repeat.children[0] = PtNumber(BaseDataType.UBYTE, 0.0, repeat.count.position) } } @@ -1662,7 +1663,7 @@ class IRCodeGen( if(value==null) { addInstr(result, IRInstruction(Opcode.RETURN), null) } else { - if(value.type==DataType.FLOAT) { + if(value.type.isFloat) { if(value is PtNumber) { addInstr(result, IRInstruction(Opcode.RETURNI, IRDataType.FLOAT, immediateFp = value.number), null) } else { diff --git a/codeGenIntermediate/test/Dummies.kt b/codeGenIntermediate/test/Dummies.kt index 950a37c36..2e4cccf51 100644 --- a/codeGenIntermediate/test/Dummies.kt +++ b/codeGenIntermediate/test/Dummies.kt @@ -2,16 +2,25 @@ import prog8.code.core.* internal object DummyMemsizer : IMemSizer { - override fun memorySize(dt: DataType) = when(dt) { - in ByteDatatypesWithBoolean -> 1 - DataType.FLOAT -> 5 - else -> 2 + override fun memorySize(dt: DataType, numElements: Int?): Int { + if(dt.isArray || dt.isSplitWordArray) { + require(numElements!=null) + return when(dt.sub?.dt) { + BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements + BaseDataType.UWORD, BaseDataType.WORD -> numElements*2 + BaseDataType.FLOAT -> numElements*5 + else -> throw IllegalArgumentException("invalid sub type") + } + } + return when { + dt.isByteOrBool -> 1 * (numElements ?: 1) + dt.isFloat -> 5 * (numElements ?: 1) + else -> 2 * (numElements ?: 1) + } } - override fun memorySize(arrayDt: DataType, numElements: Int) = when(arrayDt) { - DataType.ARRAY_UW -> numElements*2 - DataType.ARRAY_W -> numElements*2 - DataType.ARRAY_F -> numElements*5 - else -> numElements + + override fun memorySize(dt: SubType): Int { + return memorySize(DataType.forDt(dt.dt), null) } } diff --git a/codeGenIntermediate/test/TestVmCodeGen.kt b/codeGenIntermediate/test/TestVmCodeGen.kt index b35fbf5bd..a229fd6f7 100644 --- a/codeGenIntermediate/test/TestVmCodeGen.kt +++ b/codeGenIntermediate/test/TestVmCodeGen.kt @@ -47,16 +47,16 @@ class TestVmCodeGen: FunSpec({ val sub = PtSub("start", emptyList(), null, Position.DUMMY) sub.add(PtVariable( "pi", - DataType.UBYTE, + DataType.forDt(BaseDataType.UBYTE), ZeropageWish.DONTCARE, 0u, - PtNumber(DataType.UBYTE, 0.0, Position.DUMMY), + PtNumber(BaseDataType.UBYTE, 0.0, Position.DUMMY), null, Position.DUMMY )) sub.add(PtVariable( "particleX", - DataType.ARRAY_UB, + DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, 0u, null, @@ -65,7 +65,7 @@ class TestVmCodeGen: FunSpec({ )) sub.add(PtVariable( "particleDX", - DataType.ARRAY_UB, + DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, 0u, null, @@ -74,51 +74,55 @@ class TestVmCodeGen: FunSpec({ )) sub.add(PtVariable( "xx", - DataType.WORD, + DataType.forDt(BaseDataType.WORD), ZeropageWish.DONTCARE, 0u, - PtNumber(DataType.WORD, 1.0, Position.DUMMY), + PtNumber(BaseDataType.WORD, 1.0, Position.DUMMY), null, Position.DUMMY )) val assign = PtAugmentedAssign("+=", Position.DUMMY) val target = PtAssignTarget(false, Position.DUMMY).also { - val targetIdx = PtArrayIndexer(DataType.UBYTE, Position.DUMMY).also { idx -> - idx.add(PtIdentifier("main.start.particleX", DataType.ARRAY_UB, Position.DUMMY)) - idx.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY)) + val targetIdx = PtArrayIndexer(DataType.forDt(BaseDataType.UBYTE), Position.DUMMY).also { idx -> + idx.add(PtIdentifier("main.start.particleX", + DataType.arrayFor(BaseDataType.UBYTE), + Position.DUMMY)) + idx.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY)) } it.add(targetIdx) } - val value = PtArrayIndexer(DataType.UBYTE, Position.DUMMY) - value.add(PtIdentifier("main.start.particleDX", DataType.ARRAY_UB, Position.DUMMY)) - value.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY)) + val value = PtArrayIndexer(DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) + value.add(PtIdentifier("main.start.particleDX", + DataType.arrayFor(BaseDataType.UBYTE), + Position.DUMMY)) + value.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY)) assign.add(target) assign.add(value) sub.add(assign) val prefixAssign = PtAugmentedAssign("-", Position.DUMMY) val prefixTarget = PtAssignTarget(false, Position.DUMMY).also { - it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY)) + it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY)) } prefixAssign.add(prefixTarget) - prefixAssign.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY)) + prefixAssign.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY)) sub.add(prefixAssign) val numberAssign = PtAugmentedAssign("+=", Position.DUMMY) val numberAssignTarget = PtAssignTarget(false, Position.DUMMY).also { - it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY)) + it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY)) } numberAssign.add(numberAssignTarget) - numberAssign.add(PtNumber(DataType.WORD, 42.0, Position.DUMMY)) + numberAssign.add(PtNumber(BaseDataType.WORD, 42.0, Position.DUMMY)) sub.add(numberAssign) val cxregAssign = PtAugmentedAssign("+=", Position.DUMMY) val cxregAssignTarget = PtAssignTarget(false, Position.DUMMY).also { - it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY)) + it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY)) } cxregAssign.add(cxregAssignTarget) - cxregAssign.add(PtIdentifier("cx16.r0", DataType.UWORD, Position.DUMMY)) + cxregAssign.add(PtIdentifier("cx16.r0", DataType.forDt(BaseDataType.UWORD), Position.DUMMY)) sub.add(cxregAssign) block.add(sub) @@ -126,7 +130,7 @@ class TestVmCodeGen: FunSpec({ // define the "cx16.r0" virtual register val cx16block = PtBlock("cx16", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY) - cx16block.add(PtMemMapped("r0", DataType.UWORD, 100u, null, Position.DUMMY)) + cx16block.add(PtMemMapped("r0", DataType.forDt(BaseDataType.UWORD), 100u, null, Position.DUMMY)) program.add(cx16block) val options = getTestOptions() @@ -158,7 +162,7 @@ class TestVmCodeGen: FunSpec({ val sub = PtSub("start", emptyList(), null, Position.DUMMY) sub.add(PtVariable( "f1", - DataType.FLOAT, + DataType.forDt(BaseDataType.FLOAT), ZeropageWish.DONTCARE, 0u, null, @@ -166,33 +170,33 @@ class TestVmCodeGen: FunSpec({ Position.DUMMY )) val if1 = PtIfElse(Position.DUMMY) - val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY) - cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY)) - cmp1.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY)) + val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp1.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) + cmp1.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY)) if1.add(cmp1) if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if1) val if2 = PtIfElse(Position.DUMMY) - val cmp2 = PtBinaryExpression("!=", DataType.BOOL, Position.DUMMY) - cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY)) - cmp2.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY)) + val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp2.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) + cmp2.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY)) if2.add(cmp2) if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if2) val if3 = PtIfElse(Position.DUMMY) - val cmp3 = PtBinaryExpression("<", DataType.BOOL, Position.DUMMY) - cmp3.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY)) - cmp3.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY)) + val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp3.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) + cmp3.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY)) if3.add(cmp3) if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if3) val if4 = PtIfElse(Position.DUMMY) - val cmp4 = PtBinaryExpression(">", DataType.BOOL, Position.DUMMY) - cmp4.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY)) - cmp4.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY)) + val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp4.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) + cmp4.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY)) if4.add(cmp4) if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) @@ -229,7 +233,7 @@ class TestVmCodeGen: FunSpec({ val sub = PtSub("start", emptyList(), null, Position.DUMMY) sub.add(PtVariable( "f1", - DataType.FLOAT, + DataType.forDt(BaseDataType.FLOAT), ZeropageWish.DONTCARE, 0u, null, @@ -237,33 +241,33 @@ class TestVmCodeGen: FunSpec({ Position.DUMMY )) val if1 = PtIfElse(Position.DUMMY) - val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY) - cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY)) - cmp1.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY)) + val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp1.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) + cmp1.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY)) if1.add(cmp1) if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if1) val if2 = PtIfElse(Position.DUMMY) - val cmp2 = PtBinaryExpression("!=", DataType.BOOL, Position.DUMMY) - cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY)) - cmp2.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY)) + val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp2.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) + cmp2.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY)) if2.add(cmp2) if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if2) val if3 = PtIfElse(Position.DUMMY) - val cmp3 = PtBinaryExpression("<", DataType.BOOL, Position.DUMMY) - cmp3.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY)) - cmp3.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY)) + val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp3.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) + cmp3.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY)) if3.add(cmp3) if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if3) val if4 = PtIfElse(Position.DUMMY) - val cmp4 = PtBinaryExpression(">", DataType.BOOL, Position.DUMMY) - cmp4.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY)) - cmp4.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY)) + val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp4.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) + cmp4.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY)) if4.add(cmp4) if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) @@ -296,7 +300,7 @@ class TestVmCodeGen: FunSpec({ val sub = PtSub("start", emptyList(), null, Position.DUMMY) sub.add(PtVariable( "f1", - DataType.FLOAT, + DataType.forDt(BaseDataType.FLOAT), ZeropageWish.DONTCARE, 0u, null, @@ -304,17 +308,17 @@ class TestVmCodeGen: FunSpec({ Position.DUMMY )) val if1 = PtIfElse(Position.DUMMY) - val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY) - cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY)) - cmp1.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY)) + val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp1.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) + cmp1.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY)) if1.add(cmp1) if1.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, Position.DUMMY)) }) if1.add(PtNodeGroup()) sub.add(if1) val if2 = PtIfElse(Position.DUMMY) - val cmp2 = PtBinaryExpression(">", DataType.BOOL, Position.DUMMY) - cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY)) - cmp2.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY)) + val cmp2 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp2.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) + cmp2.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY)) if2.add(cmp2) if2.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, Position.DUMMY)) }) if2.add(PtNodeGroup()) @@ -351,7 +355,7 @@ class TestVmCodeGen: FunSpec({ val sub = PtSub("start", emptyList(), null, Position.DUMMY) sub.add(PtVariable( "sb1", - DataType.BYTE, + DataType.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, 0u, null, @@ -359,33 +363,33 @@ class TestVmCodeGen: FunSpec({ Position.DUMMY )) val if1 = PtIfElse(Position.DUMMY) - val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY) - cmp1.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY)) - cmp1.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY)) + val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp1.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY)) + cmp1.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY)) if1.add(cmp1) if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if1) val if2 = PtIfElse(Position.DUMMY) - val cmp2 = PtBinaryExpression("!=", DataType.BOOL, Position.DUMMY) - cmp2.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY)) - cmp2.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY)) + val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp2.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY)) + cmp2.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY)) if2.add(cmp2) if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if2) val if3 = PtIfElse(Position.DUMMY) - val cmp3 = PtBinaryExpression("<", DataType.BOOL, Position.DUMMY) - cmp3.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY)) - cmp3.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY)) + val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp3.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY)) + cmp3.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY)) if3.add(cmp3) if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if3) val if4 = PtIfElse(Position.DUMMY) - val cmp4 = PtBinaryExpression(">", DataType.BOOL, Position.DUMMY) - cmp4.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY)) - cmp4.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY)) + val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp4.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY)) + cmp4.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY)) if4.add(cmp4) if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) @@ -422,7 +426,7 @@ class TestVmCodeGen: FunSpec({ val sub = PtSub("start", emptyList(), null, Position.DUMMY) sub.add(PtVariable( "sb1", - DataType.BYTE, + DataType.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, 0u, null, @@ -430,33 +434,33 @@ class TestVmCodeGen: FunSpec({ Position.DUMMY )) val if1 = PtIfElse(Position.DUMMY) - val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY) - cmp1.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY)) - cmp1.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY)) + val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp1.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY)) + cmp1.add(PtNumber(BaseDataType.BYTE, 42.0, Position.DUMMY)) if1.add(cmp1) if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if1) val if2 = PtIfElse(Position.DUMMY) - val cmp2 = PtBinaryExpression("!=", DataType.BOOL, Position.DUMMY) - cmp2.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY)) - cmp2.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY)) + val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp2.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY)) + cmp2.add(PtNumber(BaseDataType.BYTE, 42.0, Position.DUMMY)) if2.add(cmp2) if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if2) val if3 = PtIfElse(Position.DUMMY) - val cmp3 = PtBinaryExpression("<", DataType.BOOL, Position.DUMMY) - cmp3.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY)) - cmp3.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY)) + val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp3.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY)) + cmp3.add(PtNumber(BaseDataType.BYTE, 42.0, Position.DUMMY)) if3.add(cmp3) if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) sub.add(if3) val if4 = PtIfElse(Position.DUMMY) - val cmp4 = PtBinaryExpression(">", DataType.BOOL, Position.DUMMY) - cmp4.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY)) - cmp4.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY)) + val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp4.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY)) + cmp4.add(PtNumber(BaseDataType.BYTE, 42.0, Position.DUMMY)) if4.add(cmp4) if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) }) @@ -489,7 +493,7 @@ class TestVmCodeGen: FunSpec({ val sub = PtSub("start", emptyList(), null, Position.DUMMY) sub.add(PtVariable( "ub1", - DataType.UBYTE, + DataType.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, 0u, null, @@ -497,17 +501,17 @@ class TestVmCodeGen: FunSpec({ Position.DUMMY )) val if1 = PtIfElse(Position.DUMMY) - val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY) - cmp1.add(PtIdentifier("main.start.ub1", DataType.UBYTE, Position.DUMMY)) - cmp1.add(PtNumber(DataType.UBYTE, 42.0, Position.DUMMY)) + val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp1.add(PtIdentifier("main.start.ub1", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY)) + cmp1.add(PtNumber(BaseDataType.UBYTE, 42.0, Position.DUMMY)) if1.add(cmp1) if1.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, Position.DUMMY)) }) if1.add(PtNodeGroup()) sub.add(if1) val if2 = PtIfElse(Position.DUMMY) - val cmp2 = PtBinaryExpression(">", DataType.BOOL, Position.DUMMY) - cmp2.add(PtIdentifier("main.start.ub1", DataType.UBYTE, Position.DUMMY)) - cmp2.add(PtNumber(DataType.UBYTE, 42.0, Position.DUMMY)) + val cmp2 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY) + cmp2.add(PtIdentifier("main.start.ub1", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY)) + cmp2.add(PtNumber(BaseDataType.UBYTE, 42.0, Position.DUMMY)) if2.add(cmp2) if2.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, Position.DUMMY)) }) if2.add(PtNodeGroup()) @@ -537,7 +541,7 @@ class TestVmCodeGen: FunSpec({ val extsub = PtAsmSub("routine", PtAsmSub.Address(null, null, 0x5000u), setOf(CpuRegister.Y), emptyList(), emptyList(), false, Position.DUMMY) block.add(extsub) val sub = PtSub("start", emptyList(), null, Position.DUMMY) - val call = PtFunctionCall("main.routine", true, DataType.UNDEFINED, Position.DUMMY) + val call = PtFunctionCall("main.routine", true, DataType.forDt(BaseDataType.UNDEFINED), Position.DUMMY) sub.add(call) block.add(sub) program.add(block) diff --git a/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt b/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt index 3910cca6b..d3abc9e5e 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt @@ -5,10 +5,10 @@ import prog8.ast.base.ExpressionError import prog8.ast.base.FatalAstException import prog8.ast.expressions.FunctionCallExpression import prog8.ast.expressions.NumericLiteral -import prog8.code.core.DataType -import prog8.code.core.IntegerDatatypes -import prog8.code.core.IntegerDatatypesWithBoolean +import prog8.code.core.BaseDataType import prog8.code.core.Position +import prog8.code.core.isInteger +import prog8.code.core.isIntegerOrBool import kotlin.math.* @@ -44,10 +44,10 @@ class ConstExprEvaluator { } private fun shiftedright(left: NumericLiteral, amount: NumericLiteral): NumericLiteral { - if(left.type !in IntegerDatatypes || amount.type !in IntegerDatatypes) + if(!left.type.isInteger || !amount.type.isInteger) throw ExpressionError("cannot compute $left >> $amount", left.position) val result = - if(left.type== DataType.UBYTE || left.type== DataType.UWORD) + if(left.type == BaseDataType.UBYTE || left.type == BaseDataType.UWORD) left.number.toInt().ushr(amount.number.toInt()) else left.number.toInt().shr(amount.number.toInt()) @@ -55,7 +55,7 @@ class ConstExprEvaluator { } private fun shiftedleft(left: NumericLiteral, amount: NumericLiteral): NumericLiteral { - if(left.type !in IntegerDatatypes || amount.type !in IntegerDatatypes) + if(!left.type.isInteger || !amount.type.isInteger) throw ExpressionError("cannot compute $left << $amount", left.position) val result = left.number.toInt().shl(amount.number.toInt()) // when(left.type) { @@ -70,33 +70,34 @@ class ConstExprEvaluator { } private fun bitwiseXor(left: NumericLiteral, right: NumericLiteral): NumericLiteral { - if(left.type==DataType.UBYTE || left.type==DataType.BOOL) { - if(right.type in IntegerDatatypesWithBoolean) { - return NumericLiteral(DataType.UBYTE, (left.number.toInt() xor (right.number.toInt() and 255)).toDouble(), left.position) + if(left.type==BaseDataType.UBYTE || left.type==BaseDataType.BOOL) { + if(right.type.isIntegerOrBool) { + return NumericLiteral(BaseDataType.UBYTE, (left.number.toInt() xor (right.number.toInt() and 255)).toDouble(), left.position) } - } else if(left.type==DataType.UWORD) { - if(right.type in IntegerDatatypes) { - return NumericLiteral(DataType.UWORD, (left.number.toInt() xor right.number.toInt() and 65535).toDouble(), left.position) + } else if(left.type==BaseDataType.UWORD) { + if(right.type.isInteger) { + return NumericLiteral(BaseDataType.UWORD, (left.number.toInt() xor right.number.toInt() and 65535).toDouble(), left.position) } - } else if(left.type==DataType.LONG) { - if(right.type in IntegerDatatypes) { + } else if(left.type==BaseDataType.LONG) { + if(right.type.isInteger) { return NumericLiteral.optimalNumeric((left.number.toInt() xor right.number.toInt()).toDouble(), left.position) } } + throw ExpressionError("cannot calculate $left ^ $right", left.position) } private fun bitwiseOr(left: NumericLiteral, right: NumericLiteral): NumericLiteral { - if(left.type==DataType.UBYTE || left.type==DataType.BOOL) { - if(right.type in IntegerDatatypesWithBoolean) { - return NumericLiteral(DataType.UBYTE, (left.number.toInt() or (right.number.toInt() and 255)).toDouble(), left.position) + if(left.type==BaseDataType.UBYTE || left.type==BaseDataType.BOOL) { + if(right.type.isIntegerOrBool) { + return NumericLiteral(BaseDataType.UBYTE, (left.number.toInt() or (right.number.toInt() and 255)).toDouble(), left.position) } - } else if(left.type==DataType.UWORD) { - if(right.type in IntegerDatatypes) { - return NumericLiteral(DataType.UWORD, (left.number.toInt() or right.number.toInt() and 65535).toDouble(), left.position) + } else if(left.type==BaseDataType.UWORD) { + if(right.type.isInteger) { + return NumericLiteral(BaseDataType.UWORD, (left.number.toInt() or right.number.toInt() and 65535).toDouble(), left.position) } - } else if(left.type==DataType.LONG) { - if(right.type in IntegerDatatypes) { + } else if(left.type==BaseDataType.LONG) { + if(right.type.isInteger) { return NumericLiteral.optimalNumeric((left.number.toInt() or right.number.toInt()).toDouble(), left.position) } } @@ -104,16 +105,16 @@ class ConstExprEvaluator { } private fun bitwiseAnd(left: NumericLiteral, right: NumericLiteral): NumericLiteral { - if(left.type==DataType.UBYTE || left.type==DataType.BOOL) { - if(right.type in IntegerDatatypesWithBoolean) { - return NumericLiteral(DataType.UBYTE, (left.number.toInt() and (right.number.toInt() and 255)).toDouble(), left.position) + if(left.type==BaseDataType.UBYTE || left.type==BaseDataType.BOOL) { + if(right.type.isIntegerOrBool) { + return NumericLiteral(BaseDataType.UBYTE, (left.number.toInt() and (right.number.toInt() and 255)).toDouble(), left.position) } - } else if(left.type==DataType.UWORD) { - if(right.type in IntegerDatatypes) { - return NumericLiteral(DataType.UWORD, (left.number.toInt() and right.number.toInt() and 65535).toDouble(), left.position) + } else if(left.type==BaseDataType.UWORD) { + if(right.type.isInteger) { + return NumericLiteral(BaseDataType.UWORD, (left.number.toInt() and right.number.toInt() and 65535).toDouble(), left.position) } - } else if(left.type== DataType.LONG) { - if(right.type in IntegerDatatypes) { + } else if(left.type==BaseDataType.LONG) { + if(right.type.isInteger) { return NumericLiteral.optimalNumeric((left.number.toInt() and right.number.toInt()).toDouble(), left.position) } } @@ -131,15 +132,15 @@ class ConstExprEvaluator { private fun plus(left: NumericLiteral, right: NumericLiteral): NumericLiteral { val error = "cannot add $left and $right" - return when (left.type) { - in IntegerDatatypes -> when (right.type) { - in IntegerDatatypes -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() + right.number.toInt(), left.position) - DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number.toInt() + right.number, left.position) + return when { + left.type.isInteger -> when { + right.type.isInteger -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() + right.number.toInt(), left.position) + right.type == BaseDataType.FLOAT -> NumericLiteral(BaseDataType.FLOAT, left.number.toInt() + right.number, left.position) else -> throw ExpressionError(error, left.position) } - DataType.FLOAT -> when (right.type) { - in IntegerDatatypes -> NumericLiteral(DataType.FLOAT, left.number + right.number.toInt(), left.position) - DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number + right.number, left.position) + left.type == BaseDataType.FLOAT -> when { + right.type.isInteger -> NumericLiteral(BaseDataType.FLOAT, left.number + right.number.toInt(), left.position) + right.type == BaseDataType.FLOAT -> NumericLiteral(BaseDataType.FLOAT, left.number + right.number, left.position) else -> throw ExpressionError(error, left.position) } else -> throw ExpressionError(error, left.position) @@ -148,15 +149,15 @@ class ConstExprEvaluator { private fun minus(left: NumericLiteral, right: NumericLiteral): NumericLiteral { val error = "cannot subtract $left and $right" - return when (left.type) { - in IntegerDatatypes -> when (right.type) { - in IntegerDatatypes -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() - right.number.toInt(), left.position) - DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number.toInt() - right.number, left.position) + return when { + left.type.isInteger -> when { + right.type.isInteger -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() - right.number.toInt(), left.position) + right.type == BaseDataType.FLOAT -> NumericLiteral(BaseDataType.FLOAT, left.number.toInt() - right.number, left.position) else -> throw ExpressionError(error, left.position) } - DataType.FLOAT -> when (right.type) { - in IntegerDatatypes -> NumericLiteral(DataType.FLOAT, left.number - right.number.toInt(), left.position) - DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number - right.number, left.position) + left.type == BaseDataType.FLOAT -> when { + right.type.isInteger -> NumericLiteral(BaseDataType.FLOAT, left.number - right.number.toInt(), left.position) + right.type == BaseDataType.FLOAT -> NumericLiteral(BaseDataType.FLOAT, left.number - right.number, left.position) else -> throw ExpressionError(error, left.position) } else -> throw ExpressionError(error, left.position) @@ -165,15 +166,15 @@ class ConstExprEvaluator { private fun multiply(left: NumericLiteral, right: NumericLiteral): NumericLiteral { val error = "cannot multiply ${left.type} and ${right.type}" - return when (left.type) { - in IntegerDatatypes -> when (right.type) { - in IntegerDatatypes -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() * right.number.toInt(), left.position) - DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number.toInt() * right.number, left.position) + return when { + left.type.isInteger -> when { + right.type.isInteger -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() * right.number.toInt(), left.position) + right.type == BaseDataType.FLOAT -> NumericLiteral(BaseDataType.FLOAT, left.number.toInt() * right.number, left.position) else -> throw ExpressionError(error, left.position) } - DataType.FLOAT -> when (right.type) { - in IntegerDatatypes -> NumericLiteral(DataType.FLOAT, left.number * right.number.toInt(), left.position) - DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number * right.number, left.position) + left.type == BaseDataType.FLOAT -> when { + right.type.isInteger -> NumericLiteral(BaseDataType.FLOAT, left.number * right.number.toInt(), left.position) + right.type == BaseDataType.FLOAT -> NumericLiteral(BaseDataType.FLOAT, left.number * right.number, left.position) else -> throw ExpressionError(error, left.position) } else -> throw ExpressionError(error, left.position) @@ -185,27 +186,27 @@ class ConstExprEvaluator { private fun divide(left: NumericLiteral, right: NumericLiteral): NumericLiteral { val error = "cannot divide $left by $right" - return when (left.type) { - in IntegerDatatypes -> when (right.type) { - in IntegerDatatypes -> { + return when { + left.type.isInteger -> when { + right.type.isInteger -> { if(right.number.toInt()==0) divideByZeroError(right.position) val result: Int = left.number.toInt() / right.number.toInt() NumericLiteral.optimalInteger(left.type, right.type, result, left.position) } - DataType.FLOAT -> { + right.type == BaseDataType.FLOAT -> { if(right.number==0.0) divideByZeroError(right.position) - NumericLiteral(DataType.FLOAT, left.number.toInt() / right.number, left.position) + NumericLiteral(BaseDataType.FLOAT, left.number.toInt() / right.number, left.position) } else -> throw ExpressionError(error, left.position) } - DataType.FLOAT -> when (right.type) { - in IntegerDatatypes -> { + left.type == BaseDataType.FLOAT -> when { + right.type.isInteger -> { if(right.number.toInt()==0) divideByZeroError(right.position) - NumericLiteral(DataType.FLOAT, left.number / right.number.toInt(), left.position) + NumericLiteral(BaseDataType.FLOAT, left.number / right.number.toInt(), left.position) } - DataType.FLOAT -> { + right.type == BaseDataType.FLOAT -> { if(right.number ==0.0) divideByZeroError(right.position) - NumericLiteral(DataType.FLOAT, left.number / right.number, left.position) + NumericLiteral(BaseDataType.FLOAT, left.number / right.number, left.position) } else -> throw ExpressionError(error, left.position) } @@ -215,26 +216,26 @@ class ConstExprEvaluator { private fun remainder(left: NumericLiteral, right: NumericLiteral): NumericLiteral { val error = "cannot compute remainder of $left by $right" - return when (left.type) { - in IntegerDatatypes -> when (right.type) { - in IntegerDatatypes -> { + return when { + left.type.isInteger -> when { + right.type.isInteger -> { if(right.number.toInt()==0) divideByZeroError(right.position) NumericLiteral.optimalNumeric(left.type, right.type, left.number.toInt().toDouble() % right.number.toInt().toDouble(), left.position) } - DataType.FLOAT -> { + right.type == BaseDataType.FLOAT -> { if(right.number ==0.0) divideByZeroError(right.position) - NumericLiteral(DataType.FLOAT, left.number.toInt() % right.number, left.position) + NumericLiteral(BaseDataType.FLOAT, left.number.toInt() % right.number, left.position) } else -> throw ExpressionError(error, left.position) } - DataType.FLOAT -> when (right.type) { - in IntegerDatatypes -> { + left.type == BaseDataType.FLOAT -> when { + right.type.isInteger -> { if(right.number.toInt()==0) divideByZeroError(right.position) - NumericLiteral(DataType.FLOAT, left.number % right.number.toInt(), left.position) + NumericLiteral(BaseDataType.FLOAT, left.number % right.number.toInt(), left.position) } - DataType.FLOAT -> { + right.type == BaseDataType.FLOAT -> { if(right.number ==0.0) divideByZeroError(right.position) - NumericLiteral(DataType.FLOAT, left.number % right.number, left.position) + NumericLiteral(BaseDataType.FLOAT, left.number % right.number, left.position) } else -> throw ExpressionError(error, left.position) } @@ -290,50 +291,50 @@ class ConstExprEvaluator { return if(result==null) null else - NumericLiteral(DataType.FLOAT, result, func.position) + NumericLiteral(BaseDataType.FLOAT, result, func.position) } private fun evalMath(func: FunctionCallExpression, args: List): NumericLiteral? { return when(func.target.nameInSource[1]) { "sin8u" -> { val value = truncate(128.0 + 127.5 * sin(args.single().number / 256.0 * 2 * PI)) - NumericLiteral(DataType.UBYTE, value, func.position) + NumericLiteral(BaseDataType.UBYTE, value, func.position) } "cos8u" -> { val value = truncate(128.0 + 127.5 * cos(args.single().number / 256.0 * 2 * PI)) - NumericLiteral(DataType.UBYTE, value, func.position) + NumericLiteral(BaseDataType.UBYTE, value, func.position) } "sin8" -> { val value = truncate(127.0 * sin(args.single().number / 256.0 * 2 * PI)) - NumericLiteral(DataType.BYTE, value, func.position) + NumericLiteral(BaseDataType.BYTE, value, func.position) } "cos8" -> { val value = truncate(127.0 * cos(args.single().number / 256.0 * 2 * PI)) - NumericLiteral(DataType.BYTE, value, func.position) + NumericLiteral(BaseDataType.BYTE, value, func.position) } "sinr8u" -> { val value = truncate(128.0 + 127.5 * sin(args.single().number / 180.0 * 2 * PI)) - NumericLiteral(DataType.UBYTE, value, func.position) + NumericLiteral(BaseDataType.UBYTE, value, func.position) } "cosr8u" -> { val value = truncate(128.0 + 127.5 * cos(args.single().number / 180.0 * 2 * PI)) - NumericLiteral(DataType.UBYTE, value, func.position) + NumericLiteral(BaseDataType.UBYTE, value, func.position) } "sinr8" -> { val value = truncate(127.0 * sin(args.single().number / 180.0 * 2 * PI)) - NumericLiteral(DataType.BYTE, value, func.position) + NumericLiteral(BaseDataType.BYTE, value, func.position) } "cosr8" -> { val value = truncate(127.0 * cos(args.single().number / 180.0 * 2 * PI)) - NumericLiteral(DataType.BYTE, value, func.position) + NumericLiteral(BaseDataType.BYTE, value, func.position) } "log2" -> { val value = truncate(log2(args.single().number)) - NumericLiteral(DataType.UBYTE, value, func.position) + NumericLiteral(BaseDataType.UBYTE, value, func.position) } "log2w" -> { val value = truncate(log2(args.single().number)) - NumericLiteral(DataType.UWORD, value, func.position) + NumericLiteral(BaseDataType.UWORD, value, func.position) } "atan2" -> { val x1f = args[0].number @@ -343,19 +344,19 @@ class ConstExprEvaluator { var radians = atan2(y2f-y1f, x2f-x1f) if(radians<0) radians+=2*PI - NumericLiteral(DataType.UWORD, floor(radians/2.0/PI*256.0), func.position) + NumericLiteral(BaseDataType.UWORD, floor(radians/2.0/PI*256.0), func.position) } "diff" -> { val n1 = args[0].number val n2 = args[1].number val value = if(n1>n2) n1-n2 else n2-n1 - NumericLiteral(DataType.UBYTE, value, func.position) + NumericLiteral(BaseDataType.UBYTE, value, func.position) } "diffw" -> { val n1 = args[0].number val n2 = args[1].number val value = if(n1>n2) n1-n2 else n2-n1 - NumericLiteral(DataType.UWORD, value, func.position) + NumericLiteral(BaseDataType.UWORD, value, func.position) } else -> null } diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 3e5026d5c..a9e89621a 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -9,7 +9,7 @@ import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification import prog8.code.core.AssociativeOperators -import prog8.code.core.DataType +import prog8.code.core.BaseDataType import prog8.code.core.IErrorReporter import kotlin.math.floor @@ -35,18 +35,18 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: override fun after(numLiteral: NumericLiteral, parent: Node): Iterable { - if(numLiteral.type==DataType.LONG) { + if(numLiteral.type==BaseDataType.LONG) { // see if LONG values may be reduced to something smaller val smaller = NumericLiteral.optimalInteger(numLiteral.number.toInt(), numLiteral.position) - if(smaller.type!=DataType.LONG) { + if(smaller.type!=BaseDataType.LONG) { return listOf(IAstModification.ReplaceNode(numLiteral, smaller, parent)) } } if(parent is Assignment) { val iDt = parent.target.inferType(program) - if(iDt.isKnown && !iDt.isBool && !iDt.istype(numLiteral.type)) { - val casted = numLiteral.cast(iDt.getOr(DataType.UNDEFINED), true) + if(iDt.isKnown && !iDt.isBool && !(iDt issimpletype numLiteral.type)) { + val casted = numLiteral.cast(iDt.getOrUndef().base, true) if(casted.isValid) { return listOf(IAstModification.ReplaceNode(numLiteral, casted.valueOrZero(), parent)) } @@ -89,7 +89,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: val leftconst = expr.left.constValue(program) val rightconst = expr.right.constValue(program) - if(expr.left.inferType(program) istype DataType.STR) { + if(expr.left.inferType(program).isStringLy) { if(expr.operator=="+" && expr.left is StringLiteral && expr.right is StringLiteral) { // concatenate two strings. val leftString = expr.left as StringLiteral @@ -164,7 +164,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: } } - if(expr.inferType(program) istype DataType.FLOAT) { + if(expr.inferType(program) issimpletype BaseDataType.FLOAT) { val subExpr: BinaryExpression? = when { leftconst != null -> expr.right as? BinaryExpression rightconst != null -> expr.left as? BinaryExpression @@ -235,7 +235,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: val newExpr = BinaryExpression(leftBinExpr.left, "*", constants, expr.position) return listOf(IAstModification.ReplaceNode(expr, newExpr, parent)) } else if (leftBinExpr.operator=="/") { - if(expr.inferType(program).istype(DataType.FLOAT)) { + if(expr.inferType(program) issimpletype BaseDataType.FLOAT) { // (X / C2) * rightConst --> X * (rightConst/C2) only valid for floating point val constants = BinaryExpression(rightconst, "/", c2, c2.position) val newExpr = BinaryExpression(leftBinExpr.left, "*", constants, expr.position) @@ -313,7 +313,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: } else { val arrayDt = array.guessDatatype(program) if (arrayDt.isKnown) { - val newArray = array.cast(arrayDt.getOr(DataType.UNDEFINED)) + val newArray = array.cast(arrayDt.getOrUndef()) if (newArray != null && newArray != array) return listOf(IAstModification.ReplaceNode(array, newArray, parent)) } @@ -361,7 +361,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: } override fun after(forLoop: ForLoop, parent: Node): Iterable { - fun adjustRangeDt(rangeFrom: NumericLiteral, targetDt: DataType, rangeTo: NumericLiteral, stepLiteral: NumericLiteral?, range: RangeExpression): RangeExpression? { + fun adjustRangeDt(rangeFrom: NumericLiteral, targetDt: BaseDataType, rangeTo: NumericLiteral, stepLiteral: NumericLiteral?, range: RangeExpression): RangeExpression? { val fromCast = rangeFrom.cast(targetDt, true) val toCast = rangeTo.cast(targetDt, true) if(!fromCast.isValid || !toCast.isValid) @@ -390,35 +390,37 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: val loopvar = forLoop.loopVar.targetVarDecl(program) ?: return noModifications val stepLiteral = iterableRange.step as? NumericLiteral - when(loopvar.datatype) { - DataType.UBYTE -> { - if(rangeFrom.type!= DataType.UBYTE) { + require(loopvar.datatype.sub == null) + val loopvarSimpleDt = loopvar.datatype.base + when(loopvarSimpleDt) { + BaseDataType.UBYTE -> { + if(rangeFrom.type != BaseDataType.UBYTE) { // attempt to translate the iterable into ubyte values - val newIter = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) + val newIter = adjustRangeDt(rangeFrom, loopvarSimpleDt, rangeTo, stepLiteral, iterableRange) if(newIter!=null) return listOf(IAstModification.ReplaceNode(forLoop.iterable, newIter, forLoop)) } } - DataType.BYTE -> { - if(rangeFrom.type!= DataType.BYTE) { + BaseDataType.BYTE -> { + if(rangeFrom.type != BaseDataType.BYTE) { // attempt to translate the iterable into byte values - val newIter = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) + val newIter = adjustRangeDt(rangeFrom, loopvarSimpleDt, rangeTo, stepLiteral, iterableRange) if(newIter!=null) return listOf(IAstModification.ReplaceNode(forLoop.iterable, newIter, forLoop)) } } - DataType.UWORD -> { - if(rangeFrom.type!= DataType.UWORD) { + BaseDataType.UWORD -> { + if(rangeFrom.type != BaseDataType.UWORD) { // attempt to translate the iterable into uword values - val newIter = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) + val newIter = adjustRangeDt(rangeFrom, loopvarSimpleDt, rangeTo, stepLiteral, iterableRange) if(newIter!=null) return listOf(IAstModification.ReplaceNode(forLoop.iterable, newIter, forLoop)) } } - DataType.WORD -> { - if(rangeFrom.type!= DataType.WORD) { + BaseDataType.WORD -> { + if(rangeFrom.type != BaseDataType.WORD) { // attempt to translate the iterable into word values - val newIter = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) + val newIter = adjustRangeDt(rangeFrom, loopvarSimpleDt, rangeTo, stepLiteral, iterableRange) if(newIter!=null) return listOf(IAstModification.ReplaceNode(forLoop.iterable, newIter, forLoop)) } @@ -433,11 +435,11 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: val numval = decl.value as? NumericLiteral if(decl.type== VarDeclType.CONST && numval!=null) { val valueDt = numval.inferType(program) - if(valueDt istype DataType.LONG) { + if(valueDt issimpletype BaseDataType.LONG) { return noModifications // this is handled in the numericalvalue case } - if(valueDt isnot decl.datatype) { - val cast = numval.cast(decl.datatype, true) + if(!(valueDt istype decl.datatype)) { + val cast = numval.cast(decl.datatype.base, true) if (cast.isValid) { return listOf(IAstModification.ReplaceNode(numval, cast.valueOrZero(), decl)) } @@ -581,7 +583,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: return IAstModification.ReplaceNode(expr, change, expr.parent) } } - else if(expr.operator=="*" && subExpr.operator=="/" && subExpr.inferType(program).istype(DataType.FLOAT)) { + else if(expr.operator=="*" && subExpr.operator=="/" && subExpr.inferType(program) issimpletype BaseDataType.FLOAT) { // division optimizations only valid for floats if(leftIsConst) { val change = if(subleftIsConst) { diff --git a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt index b67a95038..e0335e899 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -31,8 +31,8 @@ class VarConstantValueTypeAdjuster( try { val declConstValue = decl.value?.constValue(program) if(declConstValue!=null && (decl.type== VarDeclType.VAR || decl.type==VarDeclType.CONST) - && declConstValue.type != decl.datatype) { - if(decl.datatype in IntegerDatatypes && declConstValue.type == DataType.FLOAT) { + && declConstValue.type != decl.datatype.base) { + if(decl.datatype.isInteger && declConstValue.type == BaseDataType.FLOAT) { // avoid silent float roundings errors.err("refused truncating of float to avoid loss of precision", decl.value!!.position) } @@ -43,7 +43,7 @@ class VarConstantValueTypeAdjuster( // replace variables by constants, if possible if(options.optimize) { - if (decl.sharedWithAsm || decl.type != VarDeclType.VAR || decl.origin != VarDeclOrigin.USERCODE || decl.datatype !in NumericDatatypes) + if (decl.sharedWithAsm || decl.type != VarDeclType.VAR || decl.origin != VarDeclOrigin.USERCODE || !decl.datatype.isNumeric) return noModifications if (decl.value != null && decl.value!!.constValue(program) == null) return noModifications @@ -149,9 +149,9 @@ class VarConstantValueTypeAdjuster( val t1 = functionCallExpr.args[0].inferType(program) if(t1.isKnown) { val replaceFunc = if(t1.isBytes) { - if(t1.istype(DataType.BYTE)) "clamp__byte" else "clamp__ubyte" + if(t1 issimpletype BaseDataType.BYTE) "clamp__byte" else "clamp__ubyte" } else if(t1.isInteger) { - if(t1.istype(DataType.WORD)) "clamp__word" else "clamp__uword" + if(t1 issimpletype BaseDataType.WORD) "clamp__word" else "clamp__uword" } else { errors.err("clamp builtin not supported for floats, use floats.clamp", functionCallExpr.position) return noModifications @@ -168,12 +168,12 @@ class VarConstantValueTypeAdjuster( val funcName = func[0] val replaceFunc: String if(t1.isBytes && t2.isBytes) { - replaceFunc = if(t1.istype(DataType.BYTE) || t2.istype(DataType.BYTE)) + replaceFunc = if(t1 issimpletype BaseDataType.BYTE || t2 issimpletype BaseDataType.BYTE) "${funcName}__byte" else "${funcName}__ubyte" } else if(t1.isInteger && t2.isInteger) { - replaceFunc = if(t1.istype(DataType.WORD) || t2.istype(DataType.WORD)) + replaceFunc = if(t1 issimpletype BaseDataType.WORD || t2 issimpletype BaseDataType.WORD) "${funcName}__word" else "${funcName}__uword" @@ -193,11 +193,11 @@ class VarConstantValueTypeAdjuster( val t1 = functionCallExpr.args[0].inferType(program) if(t1.isKnown) { val dt = t1.getOrElse { throw InternalCompilerException("invalid dt") } - val replaceFunc = when(dt) { - DataType.BYTE -> "abs__byte" - DataType.WORD -> "abs__word" - DataType.FLOAT -> "abs__float" - DataType.UBYTE, DataType.UWORD -> { + val replaceFunc = when { + dt.isSignedByte -> "abs__byte" + dt.isSignedWord -> "abs__word" + dt.isFloat -> "abs__float" + dt.isUnsignedByte || dt.isUnsignedWord -> { return listOf(IAstModification.ReplaceNode(functionCallExpr, functionCallExpr.args[0], parent)) } else -> { @@ -214,10 +214,10 @@ class VarConstantValueTypeAdjuster( val t1 = functionCallExpr.args[0].inferType(program) if(t1.isKnown) { val dt = t1.getOrElse { throw InternalCompilerException("invalid dt") } - val replaceFunc = when(dt) { - DataType.UBYTE -> "sqrt__ubyte" - DataType.UWORD -> "sqrt__uword" - DataType.FLOAT -> "sqrt__float" + val replaceFunc = when { + dt.isUnsignedByte -> "sqrt__ubyte" + dt.isUnsignedWord -> "sqrt__uword" + dt.isFloat -> "sqrt__float" else -> { errors.err("expected unsigned or float numeric argument", functionCallExpr.args[0].position) return noModifications @@ -243,9 +243,9 @@ class VarConstantValueTypeAdjuster( val t1 = argTypes.single() if(t1.isKnown) { val dt = t1.getOrElse { throw InternalCompilerException("invalid dt") } - val replaceFunc = when(dt) { - DataType.UBYTE -> "divmod__ubyte" - DataType.UWORD -> "divmod__uword" + val replaceFunc = when { + dt.isUnsignedByte -> "divmod__ubyte" + dt.isUnsignedWord -> "divmod__uword" else -> { errors.err("expected all ubyte or all uword arguments", functionCallStatement.args[0].position) return noModifications @@ -294,7 +294,7 @@ internal class ConstantIdentifierReplacer( try { val cval = identifier.constValue(program) ?: return noModifications val arrayIdx = identifier.parent as? ArrayIndexedExpression - if(arrayIdx!=null && cval.type in NumericDatatypes) { + if(arrayIdx!=null && cval.type.isNumeric) { // special case when the identifier is used as a pointer var // var = constpointer[x] --> var = @(constvalue+x) [directmemoryread] // constpointer[x] = var -> @(constvalue+x) [directmemorywrite] = var @@ -308,8 +308,8 @@ internal class ConstantIdentifierReplacer( listOf(IAstModification.ReplaceNode(arrayIdx, memread, arrayIdx.parent)) } } - when (cval.type) { - in NumericDatatypesWithBoolean -> { + when { + cval.type.isNumericOrBool -> { if(parent is AddressOf) return noModifications // cannot replace the identifier INSIDE the addr-of here, let's do it later. return listOf( @@ -320,7 +320,7 @@ internal class ConstantIdentifierReplacer( ) ) } - in PassByReferenceDatatypes -> throw InternalCompilerException("pass-by-reference type should not be considered a constant") + cval.type.isPassByRef -> throw InternalCompilerException("pass-by-reference type should not be considered a constant") else -> return noModifications } } catch (x: UndefinedSymbolError) { @@ -361,16 +361,16 @@ internal class ConstantIdentifierReplacer( } } - when(decl.datatype) { - DataType.FLOAT -> { + when { + decl.datatype.isFloat -> { // vardecl: for scalar float vars, promote constant integer initialization values to floats val litval = decl.value as? NumericLiteral - if (litval!=null && litval.type in IntegerDatatypesWithBoolean) { - val newValue = NumericLiteral(DataType.FLOAT, litval.number, litval.position) + if (litval!=null && litval.type.isIntegerOrBool) { + val newValue = NumericLiteral(BaseDataType.FLOAT, litval.number, litval.position) return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) } } - in ArrayDatatypes -> { + decl.datatype.isArray -> { val replacedArrayInitializer = createConstArrayInitializerValue(decl) if(replacedArrayInitializer!=null) return listOf(IAstModification.ReplaceNode(decl.value!!, replacedArrayInitializer, decl)) @@ -390,7 +390,7 @@ internal class ConstantIdentifierReplacer( if(range!=null) { val targetDatatype = assignment.target.inferType(program) if(targetDatatype.isArray) { - val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.ARRAYLITERAL, targetDatatype.getOr(DataType.UNDEFINED), + val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.ARRAYLITERAL, targetDatatype.getOrUndef(), ZeropageWish.DONTCARE, null, "dummy", emptyList(), assignment.value, false, false, 0u, false, Position.DUMMY) val replaceValue = createConstArrayInitializerValue(decl) @@ -424,29 +424,31 @@ internal class ConstantIdentifierReplacer( else if(constRange.first { + val dt = decl.datatype + when { + dt.isUnsignedByteArray || dt.isSignedByteArray || dt.isUnsignedWordArray || dt.isSignedWordArray -> { if(declArraySize!=null && declArraySize!=rangeExpr.size()) errors.err("range expression size (${rangeExpr.size()}) doesn't match declared array size ($declArraySize)", decl.value?.position!!) if(constRange!=null) { - val eltType = rangeExpr.inferType(program).getOr(DataType.UBYTE) - return if(eltType in ByteDatatypes) { + val rangeType = rangeExpr.inferType(program).getOr(DataType.forDt(BaseDataType.UBYTE)) + return if(rangeType.isByte) { ArrayLiteral(InferredTypes.InferredType.known(decl.datatype), - constRange.map { NumericLiteral(eltType, it.toDouble(), decl.value!!.position) }.toTypedArray(), + constRange.map { NumericLiteral(rangeType.base, it.toDouble(), decl.value!!.position) }.toTypedArray(), position = decl.value!!.position) } else { + require(rangeType.sub!=null) ArrayLiteral(InferredTypes.InferredType.known(decl.datatype), - constRange.map { NumericLiteral(eltType, it.toDouble(), decl.value!!.position) }.toTypedArray(), + constRange.map { NumericLiteral(rangeType.sub!!.dt, it.toDouble(), decl.value!!.position) }.toTypedArray(), position = decl.value!!.position) } } } - DataType.ARRAY_F -> { + dt.isFloatArray -> { if(declArraySize!=null && declArraySize!=rangeExpr.size()) errors.err("range expression size (${rangeExpr.size()}) doesn't match declared array size ($declArraySize)", decl.value?.position!!) if(constRange!=null) { - return ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_F), - constRange.map { NumericLiteral(DataType.FLOAT, it.toDouble(), decl.value!!.position) }.toTypedArray(), + return ArrayLiteral(InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.FLOAT)), + constRange.map { NumericLiteral(BaseDataType.FLOAT, it.toDouble(), decl.value!!.position) }.toTypedArray(), position = decl.value!!.position) } } diff --git a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt index 532330256..fe4efc190 100644 --- a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt @@ -30,11 +30,11 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr val subTypecast = typecast.expression as? TypecastExpression if (subTypecast != null) { // remove the sub-typecast if its datatype is larger than the outer typecast - if(subTypecast.type largerThan typecast.type) { + if(subTypecast.type.largerSizeThan(typecast.type)) { mods += IAstModification.ReplaceNode(typecast.expression, subTypecast.expression, typecast) } } else { - if (typecast.expression.inferType(program) istype typecast.type) { + if (typecast.expression.inferType(program) issimpletype typecast.type) { // remove duplicate cast mods += IAstModification.ReplaceNode(typecast, typecast.expression, parent) } @@ -67,11 +67,11 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr val booleanCondition = ifElse.condition as? BinaryExpression if(booleanCondition!=null && booleanCondition.operator=="&") { val rightNum = booleanCondition.right as? NumericLiteral - if (rightNum!=null && rightNum.type==DataType.UWORD) { + if (rightNum!=null && rightNum.type==BaseDataType.UWORD) { if ((rightNum.number.toInt() and 0x00ff) == 0) { // if WORD & $xx00 -> if msb(WORD) & $xx val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), booleanCondition.left.position), mutableListOf(booleanCondition.left), booleanCondition.left.position) - val bytevalue = NumericLiteral(DataType.UBYTE, (rightNum.number.toInt() shr 8).toDouble(), booleanCondition.right.position) + val bytevalue = NumericLiteral(BaseDataType.UBYTE, (rightNum.number.toInt() shr 8).toDouble(), booleanCondition.right.position) return listOf( IAstModification.ReplaceNode(booleanCondition.left, msb, booleanCondition), IAstModification.ReplaceNode(booleanCondition.right, bytevalue, booleanCondition)) @@ -79,7 +79,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr else if ((rightNum.number.toInt() and 0xff00) == 0) { // if WORD & $00ff -> if lsb(WORD) & $ff val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), booleanCondition.left.position), mutableListOf(booleanCondition.left), booleanCondition.left.position) - val bytevalue = NumericLiteral(DataType.UBYTE, rightNum.number, booleanCondition.right.position) + val bytevalue = NumericLiteral(BaseDataType.UBYTE, rightNum.number, booleanCondition.right.position) return listOf( IAstModification.ReplaceNode(booleanCondition.left, lsb, booleanCondition), IAstModification.ReplaceNode(booleanCondition.right, bytevalue, booleanCondition)) @@ -130,12 +130,12 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr )) } - val leftDt = leftIDt.getOr(DataType.UNDEFINED) - val rightDt = rightIDt.getOr(DataType.UNDEFINED) + val leftDt = leftIDt.getOrUndef() + val rightDt = rightIDt.getOrUndef() if (expr.operator == "+" || expr.operator == "-" && leftVal == null && rightVal == null - && leftDt in NumericDatatypes && rightDt in NumericDatatypes) { + && leftDt.isNumeric && rightDt.isNumeric) { val leftBinExpr = expr.left as? BinaryExpression val rightBinExpr = expr.right as? BinaryExpression if (leftBinExpr?.operator == "*") { @@ -145,7 +145,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr val x = expr.right val y = determineY(x, leftBinExpr) if (y != null) { - val yPlus1 = BinaryExpression(y, "+", NumericLiteral(leftDt, 1.0, y.position), y.position) + val yPlus1 = BinaryExpression(y, "+", NumericLiteral(leftDt.base, 1.0, y.position), y.position) val replacement = BinaryExpression(x, "*", yPlus1, x.position) return listOf(IAstModification.ReplaceNode(expr, replacement, parent)) } @@ -155,7 +155,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr val x = expr.right val y = determineY(x, leftBinExpr) if (y != null) { - val yMinus1 = BinaryExpression(y, "-", NumericLiteral(leftDt, 1.0, y.position), y.position) + val yMinus1 = BinaryExpression(y, "-", NumericLiteral(leftDt.base, 1.0, y.position), y.position) val replacement = BinaryExpression(x, "*", yMinus1, x.position) return listOf(IAstModification.ReplaceNode(expr, replacement, parent)) } @@ -176,7 +176,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr } // X <= Y-1 ---> X= Y+1 ---> X>Y - if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { + if(leftDt.isInteger && rightDt.isInteger) { val rightExpr = expr.right as? BinaryExpression if(rightExpr!=null && rightExpr.right.constValue(program)?.number==1.0) { if (expr.operator == "<=" && rightExpr.operator == "-") { @@ -189,24 +189,24 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr } } - if(leftDt!=DataType.FLOAT && expr.operator == ">=" && rightVal?.number == 1.0) { + if(!leftDt.isFloat && expr.operator == ">=" && rightVal?.number == 1.0) { // for integers: x >= 1 --> x > 0 expr.operator = ">" return listOf(IAstModification.ReplaceNode(expr.right, NumericLiteral.optimalInteger(0, expr.right.position), expr)) } // for signed integers: X <= -1 => X<0 , X > -1 => X>=0 - if(leftDt in SignedDatatypes && leftDt!=DataType.FLOAT && rightVal?.number==-1.0) { + if(leftDt.isSigned && !leftDt.isFloat && rightVal?.number==-1.0) { if(expr.operator=="<=") { expr.operator = "<" - return listOf(IAstModification.ReplaceNode(expr.right, NumericLiteral(rightDt, 0.0, expr.right.position), expr)) + return listOf(IAstModification.ReplaceNode(expr.right, NumericLiteral(rightDt.base, 0.0, expr.right.position), expr)) } else if(expr.operator==">") { expr.operator = ">=" - return listOf(IAstModification.ReplaceNode(expr.right, NumericLiteral(rightDt, 0.0, expr.right.position), expr)) + return listOf(IAstModification.ReplaceNode(expr.right, NumericLiteral(rightDt.base, 0.0, expr.right.position), expr)) } } - if (leftDt == DataType.UBYTE || leftDt == DataType.UWORD) { + if (leftDt.isUnsignedByte || leftDt.isUnsignedWord) { if(expr.operator == ">=" && rightVal?.number == 0.0) { // unsigned >= 0 --> true return listOf(IAstModification.ReplaceNode(expr, NumericLiteral.fromBoolean(true, expr.position), parent)) @@ -217,13 +217,13 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr } } - if(leftDt!=DataType.FLOAT && expr.operator == "<" && rightVal?.number == 1.0) { + if(!leftDt.isFloat && expr.operator == "<" && rightVal?.number == 1.0) { // for integers: x < 1 --> x <= 0 expr.operator = "<=" return listOf(IAstModification.ReplaceNode(expr.right, NumericLiteral.optimalInteger(0, expr.right.position), expr)) } - if (leftDt == DataType.UBYTE || leftDt == DataType.UWORD) { + if (leftDt.isUnsignedByte || leftDt.isUnsignedWord) { if(expr.operator == "<" && rightVal?.number == 0.0) { // unsigned < 0 --> false return listOf(IAstModification.ReplaceNode(expr, NumericLiteral.fromBoolean(false, expr.position), parent)) @@ -236,7 +236,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr // optimize boolean constant comparisons if(expr.operator=="==") { - if(rightDt==DataType.BOOL && leftDt==DataType.BOOL) { + if(rightDt.isBool && leftDt.isBool) { val rightConstBool = rightVal?.asBooleanValue if(rightConstBool==true) { return listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) @@ -244,19 +244,19 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr } if (rightVal?.number == 1.0) { if (rightDt != leftDt) { - val right = NumericLiteral(leftDt, rightVal.number, rightVal.position) + val right = NumericLiteral(leftDt.base, rightVal.number, rightVal.position) return listOf(IAstModification.ReplaceNode(expr.right, right, expr)) } } else if (rightVal?.number == 0.0) { if (rightDt != leftDt) { - val right = NumericLiteral(leftDt, rightVal.number, rightVal.position) + val right = NumericLiteral(leftDt.base, rightVal.number, rightVal.position) return listOf(IAstModification.ReplaceNode(expr.right, right, expr)) } } } if (expr.operator=="!=") { - if(rightDt==DataType.BOOL && leftDt==DataType.BOOL) { + if(rightDt.isBool && leftDt.isBool) { val rightConstBool = rightVal?.asBooleanValue if(rightConstBool==false) { listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) @@ -264,13 +264,13 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr } if (rightVal?.number == 1.0) { if(rightDt!=leftDt) { - val right = NumericLiteral(leftDt, rightVal.number, rightVal.position) + val right = NumericLiteral(leftDt.base, rightVal.number, rightVal.position) return listOf(IAstModification.ReplaceNode(expr.right, right, expr)) } } else if (rightVal?.number == 0.0) { if(rightDt!=leftDt) { - val right = NumericLiteral(leftDt, rightVal.number, rightVal.position) + val right = NumericLiteral(leftDt.base, rightVal.number, rightVal.position) return listOf(IAstModification.ReplaceNode(expr.right, right, expr)) } } @@ -322,10 +322,10 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr when { leftVal?.number==0.0 -> expr.right rightVal?.number==0.0 -> expr.left - rightIDt.isBytes && rightVal?.number==255.0 -> NumericLiteral(DataType.UBYTE, 255.0, rightVal.position) - rightIDt.isWords && rightVal?.number==65535.0 -> NumericLiteral(DataType.UWORD, 65535.0, rightVal.position) - leftIDt.isBytes && leftVal?.number==255.0 -> NumericLiteral(DataType.UBYTE, 255.0, leftVal.position) - leftIDt.isWords && leftVal?.number==65535.0 -> NumericLiteral(DataType.UWORD, 65535.0, leftVal.position) + rightIDt.isBytes && rightVal?.number==255.0 -> NumericLiteral(BaseDataType.UBYTE, 255.0, rightVal.position) + rightIDt.isWords && rightVal?.number==65535.0 -> NumericLiteral(BaseDataType.UWORD, 65535.0, rightVal.position) + leftIDt.isBytes && leftVal?.number==255.0 -> NumericLiteral(BaseDataType.UBYTE, 255.0, leftVal.position) + leftIDt.isWords && leftVal?.number==65535.0 -> NumericLiteral(BaseDataType.UWORD, 65535.0, leftVal.position) else -> null } } @@ -361,7 +361,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr else -> null } - if(rightVal!=null && leftDt==DataType.BOOL) { + if(rightVal!=null && leftDt.isBool) { // boolean compare against a number -> just keep the boolean, no compare if(expr.operator=="==" || expr.operator=="!=") { val test = if (expr.operator == "==") rightVal.asBooleanValue else !rightVal.asBooleanValue @@ -384,8 +384,8 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr if ((andNum and 0x00ff) == 0) { // (WORD & $xx00)==y -> (msb(WORD) & $xx)==y val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), bitwise.left.position), mutableListOf(bitwise.left), bitwise.left.position) - val bytevalue = NumericLiteral(DataType.UBYTE, (andNum shr 8).toDouble(), bitwise.right.position) - val rightvalByte = NumericLiteral(DataType.UBYTE, (rightVal.number.toInt() shr 8).toDouble(), rightVal.position) + val bytevalue = NumericLiteral(BaseDataType.UBYTE, (andNum shr 8).toDouble(), bitwise.right.position) + val rightvalByte = NumericLiteral(BaseDataType.UBYTE, (rightVal.number.toInt() shr 8).toDouble(), rightVal.position) return listOf( IAstModification.ReplaceNode(bitwise.left, msb, bitwise), IAstModification.ReplaceNode(bitwise.right, bytevalue, bitwise), @@ -395,8 +395,8 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr else if((andNum and 0xff00) == 0) { // (WORD & $00xx)==y -> (lsb(WORD) & $xx)==y val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), bitwise.left.position), mutableListOf(bitwise.left), bitwise.left.position) - val bytevalue = NumericLiteral(DataType.UBYTE, andNum.toDouble(), bitwise.right.position) - val rightvalByte = NumericLiteral(DataType.UBYTE, (rightVal.number.toInt() and 255).toDouble(), rightVal.position) + val bytevalue = NumericLiteral(BaseDataType.UBYTE, andNum.toDouble(), bitwise.right.position) + val rightvalByte = NumericLiteral(BaseDataType.UBYTE, (rightVal.number.toInt() and 255).toDouble(), rightVal.position) return listOf( IAstModification.ReplaceNode(bitwise.left, lsb, bitwise), IAstModification.ReplaceNode(bitwise.right, bytevalue, bitwise), @@ -480,13 +480,13 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr val arg = functionCallExpr.args[0] if(arg is TypecastExpression) { val valueDt = arg.expression.inferType(program) - if (valueDt istype DataType.UBYTE) { + if (valueDt issimpletype BaseDataType.UBYTE) { // useless lsb() of ubyte value return listOf(IAstModification.ReplaceNode(functionCallExpr, arg.expression, parent)) } - else if (valueDt istype DataType.BYTE) { + else if (valueDt issimpletype BaseDataType.BYTE) { // useless lsb() of byte value, but as lsb() returns unsigned, we have to cast now. - val cast = TypecastExpression(arg.expression, DataType.UBYTE, true, arg.position) + val cast = TypecastExpression(arg.expression, BaseDataType.UBYTE, true, arg.position) return listOf(IAstModification.ReplaceNode(functionCallExpr, cast, parent)) } } else { @@ -497,13 +497,13 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr return listOf(IAstModification.ReplaceNode(functionCallExpr, highReg, parent)) } val argDt = arg.inferType(program) - if (argDt istype DataType.UBYTE) { + if (argDt issimpletype BaseDataType.UBYTE) { // useless lsb() of byte value return listOf(IAstModification.ReplaceNode(functionCallExpr, arg, parent)) } - else if (argDt istype DataType.BYTE) { + else if (argDt issimpletype BaseDataType.BYTE) { // useless lsb() of byte value, but as lsb() returns unsigned, we have to cast now. - val cast = TypecastExpression(arg, DataType.UBYTE, true, arg.position) + val cast = TypecastExpression(arg, BaseDataType.UBYTE, true, arg.position) return listOf(IAstModification.ReplaceNode(functionCallExpr, cast, parent)) } } @@ -514,11 +514,11 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr val arg = functionCallExpr.args[0] if(arg is TypecastExpression) { val valueDt = arg.expression.inferType(program) - if (valueDt istype DataType.BYTE || valueDt istype DataType.UBYTE) { + if (valueDt issimpletype BaseDataType.BYTE || valueDt issimpletype BaseDataType.UBYTE) { // useless msb() of byte value that was typecasted to word, replace with 0 return listOf(IAstModification.ReplaceNode( functionCallExpr, - NumericLiteral(valueDt.getOr(DataType.UBYTE), 0.0, arg.expression.position), + NumericLiteral(valueDt.getOr(DataType.forDt(BaseDataType.UBYTE)).base, 0.0, arg.expression.position), parent)) } } else { @@ -529,11 +529,11 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr return listOf(IAstModification.ReplaceNode(functionCallExpr, highReg, parent)) } val argDt = arg.inferType(program) - if (argDt istype DataType.BYTE || argDt istype DataType.UBYTE) { + if (argDt issimpletype BaseDataType.BYTE || argDt issimpletype BaseDataType.UBYTE) { // useless msb() of byte value, replace with 0 return listOf(IAstModification.ReplaceNode( functionCallExpr, - NumericLiteral(argDt.getOr(DataType.UBYTE), 0.0, arg.position), + NumericLiteral(argDt.getOr(DataType.forDt(BaseDataType.UBYTE)).base, 0.0, arg.position), parent)) } } @@ -542,7 +542,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr if(functionCallExpr.target.nameInSource == listOf("mkword")) { if(functionCallExpr.args[0].constValue(program)?.number==0.0) { // just cast the lsb to uword - val cast = TypecastExpression(functionCallExpr.args[1], DataType.UWORD, true, functionCallExpr.position) + val cast = TypecastExpression(functionCallExpr.args[1], BaseDataType.UWORD, true, functionCallExpr.position) return listOf(IAstModification.ReplaceNode(functionCallExpr, cast, parent)) } } @@ -651,7 +651,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr val idt = expr.inferType(program) if(!idt.isKnown) throw FatalAstException("unknown dt") - return NumericLiteral(idt.getOr(DataType.UNDEFINED), 0.0, expr.position) + return NumericLiteral(idt.getOrUndef().base, 0.0, expr.position) } else if (cv in powersOfTwoFloat) { expr.operator = "&" expr.right = NumericLiteral.optimalInteger(cv!!.toInt()-1, expr.position) @@ -675,7 +675,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr val leftIDt = expr.left.inferType(program) if (!leftIDt.isKnown) return null - val leftDt = leftIDt.getOr(DataType.UNDEFINED) + val leftDt = leftIDt.getOrUndef() when (cv) { 0.0 -> return null // fall through to regular float division to properly deal with division by zero -1.0 -> { @@ -691,36 +691,36 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr } } 256.0 -> { - when(leftDt) { - DataType.UBYTE -> return NumericLiteral(DataType.UBYTE, 0.0, expr.position) - DataType.BYTE -> return null // is either 0 or -1 we cannot tell here - DataType.UWORD, DataType.WORD -> { + when(leftDt.base) { + BaseDataType.UBYTE -> return NumericLiteral(BaseDataType.UBYTE, 0.0, expr.position) + BaseDataType.BYTE -> return null // is either 0 or -1 we cannot tell here + BaseDataType.UWORD, BaseDataType.WORD -> { // just use: msb(value) as type val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position) - return if(leftDt==DataType.WORD) - TypecastExpression(msb, DataType.BYTE, true, expr.position) + return if(leftDt.isSignedWord) + TypecastExpression(msb, BaseDataType.BYTE, true, expr.position) else - TypecastExpression(msb, DataType.UWORD, true, expr.position) + TypecastExpression(msb, BaseDataType.UWORD, true, expr.position) } else -> return null } } in powersOfTwoFloat -> { val numshifts = powersOfTwoFloat.indexOf(cv) - if (leftDt in IntegerDatatypes) { + if (leftDt.isInteger) { // division by a power of two => shift right (signed and unsigned) return BinaryExpression(expr.left, ">>", NumericLiteral.optimalInteger(numshifts, expr.position), expr.position) } } } - if (leftDt == DataType.UBYTE) { + if (leftDt.isUnsignedByte) { if (abs(rightConst.number) >= 256.0) { - return NumericLiteral(DataType.UBYTE, 0.0, expr.position) + return NumericLiteral(BaseDataType.UBYTE, 0.0, expr.position) } - } else if (leftDt == DataType.UWORD) { + } else if (leftDt.isUnsignedWord) { if (abs(rightConst.number) >= 65536.0) { - return NumericLiteral(DataType.UBYTE, 0.0, expr.position) + return NumericLiteral(BaseDataType.UBYTE, 0.0, expr.position) } } } @@ -793,14 +793,14 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr val targetIDt = expr.left.inferType(program) if(!targetIDt.isKnown) throw FatalAstException("unknown dt") - when (val targetDt = targetIDt.getOr(DataType.UNDEFINED)) { - DataType.UBYTE, DataType.BYTE -> { + when (val targetDt = targetIDt.getOrUndef().base) { + BaseDataType.UBYTE, BaseDataType.BYTE -> { if (amount >= 8) { errors.info("shift always results in 0", expr.position) return NumericLiteral(targetDt, 0.0, expr.position) } } - DataType.UWORD -> { + BaseDataType.UWORD -> { if (amount >= 16) { errors.info("shift always results in 0", expr.position) return NumericLiteral(targetDt, 0.0, expr.position) @@ -808,7 +808,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr else if(amount==8) { // shift left by 8 bits is just a byte operation: mkword(lsb(X), 0) val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), expr.position), mutableListOf(expr.left), expr.position) - return FunctionCallExpression(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(lsb, NumericLiteral(DataType.UBYTE, 0.0, expr.position)), expr.position) + return FunctionCallExpression(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(lsb, NumericLiteral(BaseDataType.UBYTE, 0.0, expr.position)), expr.position) } else if (amount > 8) { // same as above but with residual shifts. @@ -817,7 +817,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr return FunctionCallExpression(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(shifted, NumericLiteral.optimalInteger(0, expr.position)), expr.position) } } - DataType.WORD -> { + BaseDataType.WORD -> { if (amount >= 16) { errors.info("shift always results in 0", expr.position) return NumericLiteral(targetDt, 0.0, expr.position) @@ -825,15 +825,15 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr else if(amount==8) { // shift left by 8 bits is just a byte operation: mkword(lsb(X), 0) val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), expr.position), mutableListOf(expr.left), expr.position) - val mkword = FunctionCallExpression(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(lsb, NumericLiteral(DataType.UBYTE, 0.0, expr.position)), expr.position) - return TypecastExpression(mkword, DataType.WORD, true, expr.position) + val mkword = FunctionCallExpression(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(lsb, NumericLiteral(BaseDataType.UBYTE, 0.0, expr.position)), expr.position) + return TypecastExpression(mkword, BaseDataType.WORD, true, expr.position) } else if (amount > 8) { // same as above but with residual shifts. val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), expr.position), mutableListOf(expr.left), expr.position) val shifted = BinaryExpression(lsb, "<<", NumericLiteral.optimalInteger(amount - 8, expr.position), expr.position) val mkword = FunctionCallExpression(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(shifted, NumericLiteral.optimalInteger(0, expr.position)), expr.position) - return TypecastExpression(mkword, DataType.WORD, true, expr.position) + return TypecastExpression(mkword, BaseDataType.WORD, true, expr.position) } } else -> { @@ -853,20 +853,20 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr val idt = expr.left.inferType(program) if(!idt.isKnown) throw FatalAstException("unknown dt") - when (idt.getOr(DataType.UNDEFINED)) { - DataType.UBYTE -> { + when (idt.getOrUndef().base) { + BaseDataType.UBYTE -> { if (amount >= 8) { errors.info("shift always results in 0", expr.position) return NumericLiteral.optimalInteger(0, expr.position) } } - DataType.BYTE -> { + BaseDataType.BYTE -> { if (amount > 8) { expr.right = NumericLiteral.optimalInteger(8, expr.right.position) return null } } - DataType.UWORD -> { + BaseDataType.UWORD -> { if (amount >= 16) { errors.err("useless to shift by more than 15 bits", expr.position) return null @@ -874,15 +874,15 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr else if(amount==8) { // shift right by 8 bits is just a byte operation: msb(X) as uword val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position) - return TypecastExpression(msb, DataType.UWORD, true, expr.position) + return TypecastExpression(msb, BaseDataType.UWORD, true, expr.position) } else if (amount > 8) { // same as above but with residual shifts. val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position) - return TypecastExpression(BinaryExpression(msb, ">>", NumericLiteral.optimalInteger(amount - 8, expr.position), expr.position), DataType.UWORD, true, expr.position) + return TypecastExpression(BinaryExpression(msb, ">>", NumericLiteral.optimalInteger(amount - 8, expr.position), expr.position), BaseDataType.UWORD, true, expr.position) } } - DataType.WORD -> { + BaseDataType.WORD -> { if (amount >= 16) { errors.err("useless to shift by more than 15 bits", expr.position) return null @@ -890,12 +890,12 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr else if(amount == 8) { // shift right by 8 bits is just a byte operation: msb(X) as byte (will get converted to word later) val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position) - return TypecastExpression(msb, DataType.BYTE, true, expr.position) + return TypecastExpression(msb, BaseDataType.BYTE, true, expr.position) } else if(amount > 8) { // same as above but with residual shifts. Take care to do signed shift. val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position) - val signed = TypecastExpression(msb, DataType.BYTE, true, expr.position) + val signed = TypecastExpression(msb, BaseDataType.BYTE, true, expr.position) return BinaryExpression(signed, ">>", NumericLiteral.optimalInteger(amount - 8, expr.position), expr.position) } } diff --git a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt index 25a9229a1..f3d73a0d8 100644 --- a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt @@ -6,8 +6,8 @@ import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification import prog8.code.core.AssociativeOperators +import prog8.code.core.BaseDataType import prog8.code.core.CompilationOptions -import prog8.code.core.DataType import prog8.code.core.IErrorReporter @@ -44,7 +44,7 @@ class StatementOptimizer(private val program: Program, val firstCharEncoded = options.compTarget.encodeString(string.value, string.encoding)[0] val chrout = FunctionCallStatement( IdentifierReference(listOf("txt", "chrout"), pos), - mutableListOf(NumericLiteral(DataType.UBYTE, firstCharEncoded.toDouble(), pos)), + mutableListOf(NumericLiteral(BaseDataType.UBYTE, firstCharEncoded.toDouble(), pos)), functionCallStatement.void, pos ) return listOf(IAstModification.ReplaceNode(functionCallStatement, chrout, parent)) @@ -52,12 +52,12 @@ class StatementOptimizer(private val program: Program, val firstTwoCharsEncoded = options.compTarget.encodeString(string.value.take(2), string.encoding) val chrout1 = FunctionCallStatement( IdentifierReference(listOf("txt", "chrout"), pos), - mutableListOf(NumericLiteral(DataType.UBYTE, firstTwoCharsEncoded[0].toDouble(), pos)), + mutableListOf(NumericLiteral(BaseDataType.UBYTE, firstTwoCharsEncoded[0].toDouble(), pos)), functionCallStatement.void, pos ) val chrout2 = FunctionCallStatement( IdentifierReference(listOf("txt", "chrout"), pos), - mutableListOf(NumericLiteral(DataType.UBYTE, firstTwoCharsEncoded[1].toDouble(), pos)), + mutableListOf(NumericLiteral(BaseDataType.UBYTE, firstTwoCharsEncoded[1].toDouble(), pos)), functionCallStatement.void, pos ) return listOf( @@ -157,13 +157,13 @@ class StatementOptimizer(private val program: Program, } val iterable = (forLoop.iterable as? IdentifierReference)?.targetVarDecl(program) if(iterable!=null) { - if(iterable.datatype==DataType.STR) { + if(iterable.datatype.isString) { val sv = iterable.value as StringLiteral val size = sv.value.length if(size==1) { // loop over string of length 1 -> just assign the single character val character = options.compTarget.encodeString(sv.value, sv.encoding)[0] - val byte = NumericLiteral(DataType.UBYTE, character.toDouble(), iterable.position) + val byte = NumericLiteral(BaseDataType.UBYTE, character.toDouble(), iterable.position) val scope = AnonymousScope(mutableListOf(), forLoop.position) scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, null, false, forLoop.position), byte, AssignmentOrigin.OPTIMIZER, forLoop.position)) scope.statements.addAll(forLoop.body.statements) @@ -366,7 +366,7 @@ class StatementOptimizer(private val program: Program, if (fcall != null && (fcall.target.nameInSource == listOf("lsb"))) { if (fcall.args.single() isSameAs assignment.target) { // optimize word=lsb(word) ==> word &= $00ff - val and255 = BinaryExpression(fcall.args[0], "&", NumericLiteral(DataType.UWORD, 255.0, fcall.position), fcall.position) + val and255 = BinaryExpression(fcall.args[0], "&", NumericLiteral(BaseDataType.UWORD, 255.0, fcall.position), fcall.position) val newAssign = Assignment(assignment.target, and255, AssignmentOrigin.OPTIMIZER, fcall.position) return listOf(IAstModification.ReplaceNode(assignment, newAssign, parent)) } diff --git a/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt b/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt index 0fd5f0a01..150da2152 100644 --- a/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt +++ b/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt @@ -8,7 +8,6 @@ import prog8.ast.expressions.TypecastExpression import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -import prog8.code.core.DataType import prog8.code.core.ICompilationTarget import prog8.code.core.IErrorReporter import prog8.code.core.internedStringsModuleName @@ -291,7 +290,7 @@ class UnusedCodeRemover(private val program: Program, val cvalue1 = assign1.value.constValue(program) if(cvalue1!=null && cvalue1.number==0.0 && assign2.target.isSameAs(assign1.target, program) && assign2.isAugmentable) { val value2 = assign2.value - val zero = defaultZero(value2.inferType(program).getOr(DataType.UNDEFINED), value2.position) + val zero = defaultZero(value2.inferType(program), value2.position) when(value2) { is BinaryExpression -> substituteZeroInBinexpr(value2, zero, assign1, assign2) is PrefixExpression -> substituteZeroInPrefixexpr(value2, zero, assign1, assign2) diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 269724a34..8f804ffa1 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -3,7 +3,9 @@ package prog8 import kotlinx.cli.* import prog8.ast.base.AstException import prog8.code.core.CbmPrgLauncherType -import prog8.code.target.* +import prog8.code.target.CompilationTargets +import prog8.code.target.Cx16Target +import prog8.code.target.getCompilationTargetByName import prog8.code.target.virtual.VirtualMachineDefinition import prog8.compiler.CompilationResult import prog8.compiler.CompilerArguments diff --git a/compiler/src/prog8/compiler/BuiltinFunctions.kt b/compiler/src/prog8/compiler/BuiltinFunctions.kt index 7c7e79db0..3a792b910 100644 --- a/compiler/src/prog8/compiler/BuiltinFunctions.kt +++ b/compiler/src/prog8/compiler/BuiltinFunctions.kt @@ -59,10 +59,13 @@ private fun oneIntArgOutputInt(args: List, position: Position, progr if(args.size!=1) throw SyntaxError("built-in function requires one integer argument", position) val constval = args[0].constValue(program) ?: throw NotConstArgumentException() - val allowedDt = if(signed) IntegerDatatypes else arrayOf(DataType.UBYTE, DataType.UWORD) - if(constval.type !in allowedDt) - throw SyntaxError("built-in function requires one integer argument", position) - + if(signed) { + if(!constval.type.isInteger) + throw SyntaxError("built-in function requires one integer argument", position) + } else { + if(constval.type!=BaseDataType.UBYTE && constval.type!=BaseDataType.UWORD) + throw SyntaxError("built-in function requires one integer argument", position) + } val integer = constval.number.toInt() return NumericLiteral.optimalInteger(function(integer).toInt(), args[0].position) } @@ -71,10 +74,10 @@ private fun oneFloatArgOutputFloat(args: List, position: Position, p if(args.size!=1) throw SyntaxError("built-in function requires one float argument", position) val constval = args[0].constValue(program) ?: throw NotConstArgumentException() - if(constval.type != DataType.FLOAT) + if(constval.type != BaseDataType.FLOAT) throw SyntaxError("built-in function requires one float argument", position) - return NumericLiteral(DataType.FLOAT, function(constval.number), args[0].position) + return NumericLiteral(BaseDataType.FLOAT, function(constval.number), args[0].position) } private fun builtinAbs(args: List, position: Position, program: Program): NumericLiteral { @@ -83,10 +86,8 @@ private fun builtinAbs(args: List, position: Position, program: Prog throw SyntaxError("abs requires one integer argument", position) val constval = args[0].constValue(program) ?: throw NotConstArgumentException() - return when (constval.type) { - in IntegerDatatypes -> NumericLiteral.optimalInteger(abs(constval.number.toInt()), args[0].position) - else -> throw SyntaxError("abs requires one integer argument", position) - } + return if (constval.type.isInteger) NumericLiteral.optimalInteger(abs(constval.number.toInt()), args[0].position) + else throw SyntaxError("abs requires one integer argument", position) } private fun builtinSizeof(args: List, position: Position, program: Program): NumericLiteral { @@ -99,7 +100,7 @@ private fun builtinSizeof(args: List, position: Position, program: P val dt = args[0].inferType(program) if(dt.isKnown) { if(args[0] is NumericLiteral) - return NumericLiteral.optimalInteger(program.memsizer.memorySize(dt.getOr(DataType.UNDEFINED)), position) + return NumericLiteral.optimalInteger(program.memsizer.memorySize(dt.getOrUndef(), null), position) val target = (args[0] as IdentifierReference).targetStatement(program) ?: throw CannotEvaluateException("sizeof", "no target") @@ -107,11 +108,11 @@ private fun builtinSizeof(args: List, position: Position, program: P return when { dt.isArray -> { val length = (target as VarDecl).arraysize?.constIndex() ?: throw CannotEvaluateException("sizeof", "unknown array size") - val elementDt = ArrayToElementTypes.getValue(dt.getOr(DataType.UNDEFINED)) - NumericLiteral.optimalInteger(program.memsizer.memorySize(elementDt) * length, position) + val elementDt = dt.getOrUndef().elementType() + NumericLiteral.optimalInteger(program.memsizer.memorySize(elementDt, length), position) } - dt istype DataType.STR -> throw SyntaxError("sizeof(str) is undefined, did you mean len, or perhaps strings.length?", position) - else -> NumericLiteral(DataType.UBYTE, program.memsizer.memorySize(dt.getOr(DataType.UNDEFINED)).toDouble(), position) + dt.isString -> throw SyntaxError("sizeof(str) is undefined, did you mean len, or perhaps strings.length?", position) + else -> NumericLiteral(BaseDataType.UBYTE, program.memsizer.memorySize(dt.getOrUndef(), null).toDouble(), position) } } else { throw SyntaxError("sizeof invalid argument type", position) @@ -136,18 +137,18 @@ private fun builtinLen(args: List, position: Position, program: Prog val target = (args[0] as IdentifierReference).targetVarDecl(program) ?: throw CannotEvaluateException("len", "no target vardecl") - return when(target.datatype) { - in ArrayDatatypes -> { + return when { + target.datatype.isArray -> { arraySize = target.arraysize?.constIndex() if(arraySize==null) throw CannotEvaluateException("len", "arraysize unknown") NumericLiteral.optimalInteger(arraySize, args[0].position) } - DataType.STR -> { + target.datatype.isString -> { val refLv = target.value as? StringLiteral ?: throw CannotEvaluateException("len", "stringsize unknown") NumericLiteral.optimalInteger(refLv.value.length, args[0].position) } - in NumericDatatypes, DataType.BOOL -> throw SyntaxError("cannot use len on numeric value, did you mean sizeof?", args[0].position) + target.datatype.isNumericOrBool -> throw SyntaxError("cannot use len on numeric value, did you mean sizeof?", args[0].position) else -> throw InternalCompilerException("weird datatype") } } @@ -158,14 +159,14 @@ private fun builtinMkword(args: List, position: Position, program: P val constMsb = args[0].constValue(program) ?: throw NotConstArgumentException() val constLsb = args[1].constValue(program) ?: throw NotConstArgumentException() val result = (constMsb.number.toInt() shl 8) or constLsb.number.toInt() - return NumericLiteral(DataType.UWORD, result.toDouble(), position) + return NumericLiteral(BaseDataType.UWORD, result.toDouble(), position) } private fun builtinSgn(args: List, position: Position, program: Program): NumericLiteral { if (args.size != 1) throw SyntaxError("sgn requires one argument", position) val constval = args[0].constValue(program) ?: throw NotConstArgumentException() - return NumericLiteral(DataType.BYTE, constval.number.sign, position) + return NumericLiteral(BaseDataType.BYTE, constval.number.sign, position) } private fun builtinMinByte(args: List, position: Position, program: Program): NumericLiteral { @@ -174,7 +175,7 @@ private fun builtinMinByte(args: List, position: Position, program: val val1 = args[0].constValue(program) ?: throw NotConstArgumentException() val val2 = args[1].constValue(program) ?: throw NotConstArgumentException() val result = min(val1.number.toInt(), val2.number.toInt()) - return NumericLiteral(DataType.BYTE, result.toDouble(), position) + return NumericLiteral(BaseDataType.BYTE, result.toDouble(), position) } private fun builtinMinUByte(args: List, position: Position, program: Program): NumericLiteral { @@ -183,7 +184,7 @@ private fun builtinMinUByte(args: List, position: Position, program: val val1 = args[0].constValue(program) ?: throw NotConstArgumentException() val val2 = args[1].constValue(program) ?: throw NotConstArgumentException() val result = min(val1.number.toInt(), val2.number.toInt()) - return NumericLiteral(DataType.UBYTE, result.toDouble(), position) + return NumericLiteral(BaseDataType.UBYTE, result.toDouble(), position) } private fun builtinMinWord(args: List, position: Position, program: Program): NumericLiteral { @@ -192,7 +193,7 @@ private fun builtinMinWord(args: List, position: Position, program: val val1 = args[0].constValue(program) ?: throw NotConstArgumentException() val val2 = args[1].constValue(program) ?: throw NotConstArgumentException() val result = min(val1.number.toInt(), val2.number.toInt()) - return NumericLiteral(DataType.WORD, result.toDouble(), position) + return NumericLiteral(BaseDataType.WORD, result.toDouble(), position) } private fun builtinMinUWord(args: List, position: Position, program: Program): NumericLiteral { @@ -201,7 +202,7 @@ private fun builtinMinUWord(args: List, position: Position, program: val val1 = args[0].constValue(program) ?: throw NotConstArgumentException() val val2 = args[1].constValue(program) ?: throw NotConstArgumentException() val result = min(val1.number.toInt(), val2.number.toInt()) - return NumericLiteral(DataType.UWORD, result.toDouble(), position) + return NumericLiteral(BaseDataType.UWORD, result.toDouble(), position) } private fun builtinMaxByte(args: List, position: Position, program: Program): NumericLiteral { @@ -210,7 +211,7 @@ private fun builtinMaxByte(args: List, position: Position, program: val val1 = args[0].constValue(program) ?: throw NotConstArgumentException() val val2 = args[1].constValue(program) ?: throw NotConstArgumentException() val result = max(val1.number.toInt(), val2.number.toInt()) - return NumericLiteral(DataType.BYTE, result.toDouble(), position) + return NumericLiteral(BaseDataType.BYTE, result.toDouble(), position) } private fun builtinMaxUByte(args: List, position: Position, program: Program): NumericLiteral { @@ -219,7 +220,7 @@ private fun builtinMaxUByte(args: List, position: Position, program: val val1 = args[0].constValue(program) ?: throw NotConstArgumentException() val val2 = args[1].constValue(program) ?: throw NotConstArgumentException() val result = max(val1.number.toInt(), val2.number.toInt()) - return NumericLiteral(DataType.UBYTE, result.toDouble(), position) + return NumericLiteral(BaseDataType.UBYTE, result.toDouble(), position) } private fun builtinMaxWord(args: List, position: Position, program: Program): NumericLiteral { @@ -228,7 +229,7 @@ private fun builtinMaxWord(args: List, position: Position, program: val val1 = args[0].constValue(program) ?: throw NotConstArgumentException() val val2 = args[1].constValue(program) ?: throw NotConstArgumentException() val result = max(val1.number.toInt(), val2.number.toInt()) - return NumericLiteral(DataType.WORD, result.toDouble(), position) + return NumericLiteral(BaseDataType.WORD, result.toDouble(), position) } private fun builtinMaxUWord(args: List, position: Position, program: Program): NumericLiteral { @@ -237,7 +238,7 @@ private fun builtinMaxUWord(args: List, position: Position, program: val val1 = args[0].constValue(program) ?: throw NotConstArgumentException() val val2 = args[1].constValue(program) ?: throw NotConstArgumentException() val result = max(val1.number.toInt(), val2.number.toInt()) - return NumericLiteral(DataType.UWORD, result.toDouble(), position) + return NumericLiteral(BaseDataType.UWORD, result.toDouble(), position) } private fun builtinClampUByte(args: List, position: Position, program: Program): NumericLiteral { @@ -247,7 +248,7 @@ private fun builtinClampUByte(args: List, position: Position, progra val minimum = args[1].constValue(program) ?: throw NotConstArgumentException() val maximum = args[2].constValue(program) ?: throw NotConstArgumentException() val result = min(max(value.number, minimum.number), maximum.number) - return NumericLiteral(DataType.UBYTE, result, position) + return NumericLiteral(BaseDataType.UBYTE, result, position) } private fun builtinClampByte(args: List, position: Position, program: Program): NumericLiteral { @@ -257,7 +258,7 @@ private fun builtinClampByte(args: List, position: Position, program val minimum = args[1].constValue(program) ?: throw NotConstArgumentException() val maximum = args[2].constValue(program) ?: throw NotConstArgumentException() val result = min(max(value.number, minimum.number), maximum.number) - return NumericLiteral(DataType.BYTE, result, position) + return NumericLiteral(BaseDataType.BYTE, result, position) } private fun builtinClampUWord(args: List, position: Position, program: Program): NumericLiteral { @@ -267,7 +268,7 @@ private fun builtinClampUWord(args: List, position: Position, progra val minimum = args[1].constValue(program) ?: throw NotConstArgumentException() val maximum = args[2].constValue(program) ?: throw NotConstArgumentException() val result = min(max(value.number, minimum.number), maximum.number) - return NumericLiteral(DataType.UWORD, result, position) + return NumericLiteral(BaseDataType.UWORD, result, position) } private fun builtinClampWord(args: List, position: Position, program: Program): NumericLiteral { @@ -277,6 +278,6 @@ private fun builtinClampWord(args: List, position: Position, program val minimum = args[1].constValue(program) ?: throw NotConstArgumentException() val maximum = args[2].constValue(program) ?: throw NotConstArgumentException() val result = min(max(value.number, minimum.number), maximum.number) - return NumericLiteral(DataType.WORD, result, position) + return NumericLiteral(BaseDataType.WORD, result, position) } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 8aecc05ad..38ef197e9 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -131,13 +131,13 @@ internal class AstChecker(private val program: Program, if(expectedReturnValues.size==1 && returnStmt.value!=null) { val valueDt = returnStmt.value!!.inferType(program) if(valueDt.isKnown) { - if (expectedReturnValues[0] != valueDt.getOr(DataType.UNDEFINED)) { - if(valueDt istype DataType.BOOL && expectedReturnValues[0] == DataType.UBYTE) { + if (expectedReturnValues[0] != valueDt.getOrUndef()) { + if(valueDt.isBool && expectedReturnValues[0].isUnsignedByte) { // if the return value is a bool and the return type is ubyte, allow this. But give a warning. errors.info("return type of the subroutine should probably be bool instead of ubyte", returnStmt.position) - } else if(valueDt.isIterable && expectedReturnValues[0]==DataType.UWORD) { + } else if(valueDt.isIterable && expectedReturnValues[0].isUnsignedWord) { // you can return a string or array when an uword (pointer) is returned - } else if(valueDt istype DataType.UWORD && expectedReturnValues[0]==DataType.STR) { + } else if(valueDt issimpletype BaseDataType.UWORD && expectedReturnValues[0].isString) { // you can return an uword pointer when the return type is a string } else { errors.err("type $valueDt of return value doesn't match subroutine's return type ${expectedReturnValues[0]}",returnStmt.value!!.position) @@ -186,46 +186,49 @@ internal class AstChecker(private val program: Program, } } - val iterableDt = forLoop.iterable.inferType(program).getOr(DataType.BYTE) + val iterableDt = forLoop.iterable.inferType(program).getOr(DataType.forDt(BaseDataType.BYTE)) + + if(iterableDt.isNumeric) TODO("iterable type should not be simple numeric!? "+forLoop.position) // TODO + if(forLoop.iterable is IFunctionCall) { errors.err("can not loop over function call return value", forLoop.position) - } else if(iterableDt !in IterableDatatypes && forLoop.iterable !is RangeExpression) { + } else if(!(iterableDt.isIterable) && forLoop.iterable !is RangeExpression) { errors.err("can only loop over an iterable type", forLoop.position) } else { val loopvar = forLoop.loopVar.targetVarDecl(program) if(loopvar==null || loopvar.type== VarDeclType.CONST) { errors.err("for loop requires a variable to loop with", forLoop.position) } else { - when (loopvar.datatype) { - DataType.UBYTE -> { - if(iterableDt!= DataType.UBYTE && iterableDt!= DataType.ARRAY_UB && iterableDt != DataType.STR) + require(loopvar.datatype.isNumericOrBool) + when (loopvar.datatype.base) { + BaseDataType.UBYTE -> { + if(!iterableDt.isUnsignedByte && !iterableDt.isUnsignedByteArray && !iterableDt.isString) // TODO remove ubyte check? errors.err("ubyte loop variable can only loop over unsigned bytes or strings", forLoop.position) - checkUnsignedLoopDownto0(forLoop.iterable as? RangeExpression) } - DataType.BOOL -> { - if(iterableDt != DataType.ARRAY_BOOL) + BaseDataType.BOOL -> { + if(!iterableDt.isBoolArray) errors.err("bool loop variable can only loop over boolean array", forLoop.position) } - DataType.UWORD -> { - if(iterableDt!= DataType.UBYTE && iterableDt!= DataType.UWORD && iterableDt != DataType.STR && - iterableDt != DataType.ARRAY_UB && iterableDt != DataType.ARRAY_UW && - iterableDt != DataType.ARRAY_UW_SPLIT) + BaseDataType.UWORD -> { + if(!iterableDt.isUnsignedByte && !iterableDt.isUnsignedWord && !iterableDt.isString && // TODO remove byte and word check? + !iterableDt.isUnsignedByteArray && !iterableDt.isUnsignedWordArray && + !iterableDt.isSplitWordArray) errors.err("uword loop variable can only loop over unsigned bytes, words or strings", forLoop.position) checkUnsignedLoopDownto0(forLoop.iterable as? RangeExpression) } - DataType.BYTE -> { - if(iterableDt!= DataType.BYTE && iterableDt!= DataType.ARRAY_B) + BaseDataType.BYTE -> { + if(!iterableDt.isSignedByte && !iterableDt.isSignedByteArray) // TODO remove byte check? errors.err("byte loop variable can only loop over bytes", forLoop.position) } - DataType.WORD -> { - if(iterableDt!= DataType.BYTE && iterableDt!= DataType.WORD && - iterableDt != DataType.ARRAY_B && iterableDt != DataType.ARRAY_UB && - iterableDt != DataType.ARRAY_W && iterableDt != DataType.ARRAY_W_SPLIT) + BaseDataType.WORD -> { + if(!iterableDt.isSignedByte && !iterableDt.isSignedWord && // TODO remove byte and word check? + !iterableDt.isSignedByteArray && !iterableDt.isUnsignedByteArray && + !iterableDt.isSignedWordArray && !iterableDt.isSplitWordArray) errors.err("word loop variable can only loop over bytes or words", forLoop.position) } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { // Looping over float variables is very inefficient because the loopvar is going to // get copied over with new values all the time. We don't support this for now. // Loop with an integer index variable if you really need to... or write different code. @@ -245,7 +248,7 @@ internal class AstChecker(private val program: Program, errors.err("range start value is incompatible with loop variable type", range.position) if(to != null) checkValueTypeAndRange(loopvar.datatype, to) - else if(range.to.inferType(program) isnot loopvar.datatype) + else if(!(range.to.inferType(program) istype loopvar.datatype)) errors.err("range end value is incompatible with loop variable type", range.position) } } @@ -385,7 +388,7 @@ internal class AstChecker(private val program: Program, } val varbank = subroutine.asmAddress?.varbank if(varbank!=null) { - if(varbank.targetVarDecl(program)?.datatype!=DataType.UBYTE) + if(varbank.targetVarDecl(program)?.datatype?.isUnsignedByte!=true) err("bank variable must be ubyte") } if(subroutine.inline && subroutine.asmAddress!=null) @@ -422,31 +425,29 @@ internal class AstChecker(private val program: Program, err("number of return registers is not the isSameAs as number of return values") for(param in subroutine.parameters.zip(subroutine.asmParameterRegisters)) { if(param.second.registerOrPair in arrayOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) { - if (param.first.type != DataType.UBYTE && param.first.type != DataType.BYTE && param.first.type != DataType.BOOL) + if (!param.first.type.isByteOrBool) errors.err("parameter '${param.first.name}' should be (u)byte or bool", param.first.position) } else if(param.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { - if (param.first.type != DataType.UWORD && param.first.type != DataType.WORD - && param.first.type != DataType.STR && param.first.type !in ArrayDatatypes) + if (!param.first.type.isWord && !param.first.type.isString && !param.first.type.isArray) err("parameter '${param.first.name}' should be (u)word (an address) or str") } else if(param.second.statusflag!=null) { - if (param.first.type != DataType.BOOL) + if (!param.first.type.isBool) errors.err("parameter '${param.first.name}' should be of type bool", param.first.position) } } subroutine.returntypes.zip(subroutine.asmReturnvaluesRegisters).forEachIndexed { index, pair -> if(pair.second.registerOrPair in arrayOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) { - if (pair.first != DataType.UBYTE && pair.first != DataType.BYTE && pair.first != DataType.BOOL) + if (!pair.first.isByteOrBool) err("return type #${index + 1} should be (u)byte") } else if(pair.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { - if (pair.first != DataType.UWORD && pair.first != DataType.WORD - && pair.first != DataType.STR && pair.first !in ArrayDatatypes) + if (!pair.first.isWord && !pair.first.isString && !pair.first.isArray) err("return type #${index + 1} should be (u)word/address") } else if(pair.second.statusflag!=null) { - if (pair.first != DataType.BOOL) + if (!pair.first.isBool) err("return type #${index + 1} should be bool") } } @@ -518,7 +519,7 @@ internal class AstChecker(private val program: Program, else { if(!compilerOptions.ignoreFootguns) errors.warn("\uD83D\uDCA3 footgun: reusing R0-R15 as parameters risks overwriting due to clobbering or no callstack", subroutine.position) - if(p.type !in WordDatatypes && p.type !in ByteDatatypesWithBoolean) { + if(!p.type.isWord && !p.type.isByteOrBool) { errors.err("can only use register param when type is boolean, byte or word", p.position) } } @@ -527,7 +528,7 @@ internal class AstChecker(private val program: Program, if(p.name.startsWith('_')) errors.err("identifiers cannot start with an underscore", p.position) - if(p.type in PassByReferenceDatatypes && p.type !in listOf(DataType.STR, DataType.ARRAY_UB)) { + if(p.type.isPassByRef && !p.type.isString && !p.type.isUnsignedByteArray) { errors.err("this pass-by-reference type can't be used as a parameter type. Instead, use an uword to receive the address, or access the variable from the outer scope directly.", p.position) } } @@ -570,7 +571,7 @@ internal class AstChecker(private val program: Program, val targetDt = target.inferType(program) val valueDt = value.inferType(program) if(valueDt.isKnown && !(valueDt isAssignableTo targetDt) && !targetDt.isIterable) { - if(!(valueDt istype DataType.STR && targetDt istype DataType.UWORD)) { + if(!(valueDt issimpletype BaseDataType.STR && targetDt issimpletype BaseDataType.UWORD)) { if(targetDt.isUnknown) { if(target.identifier?.targetStatement(program)!=null) errors.err("target datatype is unknown", target.position) @@ -580,13 +581,13 @@ internal class AstChecker(private val program: Program, } if(value is TypecastExpression) { - if(augmentable && targetDt istype DataType.FLOAT) + if(augmentable && targetDt issimpletype BaseDataType.FLOAT) errors.err("typecasting a float value in-place makes no sense", value.position) } val numvalue = value.constValue(program) if(numvalue!=null && targetDt.isKnown) - checkValueTypeAndRange(targetDt.getOr(DataType.UNDEFINED), numvalue) + checkValueTypeAndRange(targetDt.getOrUndef(), numvalue) } if(assignment.target.multi==null) { @@ -636,7 +637,7 @@ internal class AstChecker(private val program: Program, } fcallTarget.returntypes.zip(targets).withIndex().forEach { (index, p) -> val (returnType, target) = p - val targetDt = target.inferType(program).getOr(DataType.UNDEFINED) + val targetDt = target.inferType(program).getOrUndef() if (!target.void && !(returnType isAssignableTo targetDt)) errors.err("can't assign returnvalue #${index + 1} to corresponding target; $returnType vs $targetDt", target.position) } @@ -685,8 +686,8 @@ internal class AstChecker(private val program: Program, if (assignment.value !is BinaryExpression && assignment.value !is PrefixExpression && assignment.value !is ContainmentCheck && assignment.value !is IfExpression) errors.err("invalid assignment value, maybe forgot '&' (address-of)", assignment.value.position) } else { - checkAssignmentCompatible(assignTarget, targetDatatype.getOr(DataType.UNDEFINED), - sourceDatatype.getOr(DataType.UNDEFINED), assignment.value) + checkAssignmentCompatible(assignTarget, targetDatatype.getOrUndef(), + sourceDatatype.getOrUndef(), assignment.value) } } } @@ -722,10 +723,10 @@ internal class AstChecker(private val program: Program, if(decl.names.size>1) throw InternalCompilerException("vardecls with multiple names should have been converted into individual vardecls") - if(decl.datatype==DataType.LONG && decl.type!=VarDeclType.CONST) + if(decl.datatype.isLong && decl.type!=VarDeclType.CONST) errors.err("cannot use long type for variables; only for constants", decl.position) if(decl.type==VarDeclType.MEMORY) { - if (decl.datatype == DataType.BOOL || decl.datatype == DataType.ARRAY_BOOL) + if (decl.datatype.isBool || decl.datatype.isBoolArray) errors.err("variables mapped in memory should be numeric", decl.position) } @@ -738,12 +739,12 @@ internal class AstChecker(private val program: Program, // CONST can only occur on simple types (byte, word, float) if(decl.type== VarDeclType.CONST) { - if (decl.datatype !in NumericDatatypesWithBoolean) + if (!decl.datatype.isNumericOrBool) err("const can only be used on numeric types or booleans") } // FLOATS enabled? - if(!compilerOptions.floats && decl.datatype.oneOf(DataType.FLOAT, DataType.ARRAY_F) && decl.type!= VarDeclType.MEMORY) + if(!compilerOptions.floats && (decl.datatype.isFloat || decl.datatype.isFloatArray) && decl.type != VarDeclType.MEMORY) err("floating point used, but that is not enabled via options") // ARRAY without size specifier MUST have an iterable initializer value @@ -788,17 +789,18 @@ internal class AstChecker(private val program: Program, val arraysize = decl.arraysize if(arraysize!=null) { val arraySize = arraysize.constIndex() ?: 1 - when(decl.datatype) { - DataType.ARRAY_B, DataType.ARRAY_UB -> + val dt = decl.datatype + when { + dt.isString || dt.isByteArray || dt.isBoolArray -> if(arraySize > 256) err("byte array length must be 1-256") - in SplitWordArrayTypes -> + dt.isSplitWordArray -> if(arraySize > 256) err("split word array length must be 1-256") - DataType.ARRAY_W, DataType.ARRAY_UW -> + dt.isWordArray -> if(arraySize > 128) err("word array length must be 1-128") - DataType.ARRAY_F -> + dt.isFloatArray -> if(arraySize > 51) err("float array length must be 1-51") else -> {} @@ -806,7 +808,7 @@ internal class AstChecker(private val program: Program, } val numvalue = decl.value as? NumericLiteral if(numvalue!=null) { - if (numvalue.type !in IntegerDatatypes || numvalue.number.toInt() < 0 || numvalue.number.toInt() > 65535) { + if (!numvalue.type.isInteger || numvalue.number.toInt() < 0 || numvalue.number.toInt() > 65535) { valueerr("memory address must be valid integer 0..\$ffff") } } else { @@ -818,14 +820,14 @@ internal class AstChecker(private val program: Program, val declValue = decl.value if(declValue!=null && decl.type==VarDeclType.VAR) { val iDt = declValue.inferType(program) - if (iDt isnot decl.datatype) { + if (!(iDt istype decl.datatype)) { if(decl.isArray) { - val eltDt = ArrayToElementTypes.getValue(decl.datatype) - if(iDt isnot eltDt) - valueerr("value has incompatible type ($iDt) for the variable (${decl.datatype})") + val eltDt = decl.datatype.elementType() + if(!(iDt istype eltDt)) + valueerr("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})") } else { - if(!(iDt.isBool && decl.datatype==DataType.UBYTE || iDt.istype(DataType.UBYTE) && decl.datatype==DataType.BOOL)) - valueerr("value has incompatible type ($iDt) for the variable (${decl.datatype})") + if(!(iDt.isBool && decl.datatype.isUnsignedByte || iDt issimpletype BaseDataType.UBYTE && decl.datatype.isBool)) + valueerr("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})") } } } @@ -841,10 +843,10 @@ internal class AstChecker(private val program: Program, val arraysize = decl.arraysize?.constIndex() val numericvalue = decl.value?.constValue(program) if (numericvalue != null && arraysize != null) { - when (numericvalue.type) { - in IntegerDatatypes -> suggestion = "[${numericvalue.number.toInt()}] * $arraysize" - DataType.FLOAT -> suggestion = "[${numericvalue.number}] * $arraysize" - DataType.BOOL -> suggestion = "[${numericvalue.asBooleanValue}] * $arraysize" + when { + numericvalue.type.isInteger -> suggestion = "[${numericvalue.number.toInt()}] * $arraysize" + numericvalue.type == BaseDataType.FLOAT -> suggestion = "[${numericvalue.number}] * $arraysize" + numericvalue.type == BaseDataType.BOOL -> suggestion = "[${numericvalue.asBooleanValue}] * $arraysize" else -> {} } } @@ -860,20 +862,20 @@ internal class AstChecker(private val program: Program, if(length==null) err("array length must be known at compile-time") else { - when (decl.datatype) { - DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B -> { + when { + decl.datatype.isString || decl.datatype.isByteArray || decl.datatype.isBoolArray -> { if (length == 0 || length > 256) err("string and byte array length must be 1-256") } - in SplitWordArrayTypes -> { + decl.datatype.isSplitWordArray -> { if (length == 0 || length > 256) err("split word array length must be 1-256") } - DataType.ARRAY_UW, DataType.ARRAY_W -> { + decl.datatype.isWordArray -> { if (length == 0 || length > 128) err("word array length must be 1-128") } - DataType.ARRAY_F -> { + decl.datatype.isFloatArray -> { if (length == 0 || length > 51) err("float array length must be 1-51") } @@ -886,7 +888,7 @@ internal class AstChecker(private val program: Program, err("@split can't be used on memory mapped arrays") } - if(decl.datatype==DataType.STR) { + if(decl.datatype.isString) { if(decl.value==null) { // complain about uninitialized str, but only if it's a regular variable val parameter = (decl.parent as? Subroutine)?.parameters?.singleOrNull{ it.name==decl.name } @@ -906,7 +908,7 @@ internal class AstChecker(private val program: Program, err("zeropage usage has been disabled by options") if(decl.splitArray) { - if (decl.datatype !in arrayOf(DataType.ARRAY_W, DataType.ARRAY_UW, DataType.ARRAY_W_SPLIT, DataType.ARRAY_UW_SPLIT)) { + if (!decl.datatype.isWordArray) { errors.err("split can only be used on word arrays", decl.position) } } @@ -914,7 +916,7 @@ internal class AstChecker(private val program: Program, if(decl.alignment>0u) { if(decl.alignment !in arrayOf(2u,64u,256u)) err("variable alignment can only be one of 2 (word), 64 or 256 (page)") - if(!decl.isArray && decl.datatype!=DataType.STR) + if(!decl.isArray && !decl.datatype.isString) err("only string and array variables can have an alignment option") else if(decl.type==VarDeclType.MEMORY) err("only normal variables can have an alignment option") @@ -927,7 +929,7 @@ internal class AstChecker(private val program: Program, if (decl.dirty) { - if(decl.datatype==DataType.STR) + if(decl.datatype.isString) errors.err("string variables cannot be @dirty", decl.position) else { if(decl.value==null) { @@ -1081,11 +1083,11 @@ internal class AstChecker(private val program: Program, override fun visit(array: ArrayLiteral) { if(array.type.isKnown) { - if (!compilerOptions.floats && array.type.oneOf(DataType.FLOAT, DataType.ARRAY_F)) { + if (!compilerOptions.floats && (array.type issimpletype BaseDataType.FLOAT || array.type.isFloatArray)) { errors.err("floating point used, but that is not enabled via options", array.position) } val arrayspec = ArrayIndex.forArray(array) - checkValueTypeAndRangeArray(array.type.getOr(DataType.UNDEFINED), arrayspec, array) + checkValueTypeAndRangeArray(array.type.getOrUndef(), arrayspec, array) } if(array.parent is VarDecl) { @@ -1118,7 +1120,7 @@ internal class AstChecker(private val program: Program, } override fun visit(string: StringLiteral) { - checkValueTypeAndRangeString(DataType.STR, string) + checkValueTypeAndRangeString(DataType.forDt(BaseDataType.STR), string) try { // just *try* if it can be encoded, don't actually do it val bytes = compilerOptions.compTarget.encodeString(string.value, string.encoding) @@ -1141,24 +1143,24 @@ internal class AstChecker(private val program: Program, } checkLongType(expr) - val dt = expr.expression.inferType(program).getOr(DataType.UNDEFINED) - if(dt==DataType.UNDEFINED) + val dt = expr.expression.inferType(program).getOrUndef() + if(dt.isUndefined) return // any error should be reported elsewhere when (expr.operator) { "-" -> { - if (dt != DataType.BYTE && dt != DataType.WORD && dt != DataType.FLOAT) { + if (!(dt.isSigned && dt.isNumeric)) { errors.err("can only take negative of a signed number type", expr.position) } } "~" -> { - if(dt !in IntegerDatatypes) + if(!dt.isInteger) errors.err("can only use bitwise invert on integer types", expr.position) - else if(dt==DataType.BOOL) + else if(dt.isBool) errors.err("bitwise invert is for integer types, use 'not' on booleans", expr.position) } "not" -> { - if(dt!=DataType.BOOL) { + if(!dt.isBool) { errors.err("logical not is for booleans", expr.position) } } @@ -1212,11 +1214,11 @@ internal class AstChecker(private val program: Program, return // hopefully this error will be detected elsewhere } - val leftDt = leftIDt.getOr(DataType.UNDEFINED) - val rightDt = rightIDt.getOr(DataType.UNDEFINED) + val leftDt = leftIDt.getOrUndef() + val rightDt = rightIDt.getOrUndef() if(expr.operator=="+" || expr.operator=="-") { - if(leftDt == DataType.STR || rightDt == DataType.STR || leftDt in ArrayDatatypes || rightDt in ArrayDatatypes) { + if(leftDt.isString || rightDt.isString || leftDt.isArray || rightDt.isArray) { errors.err("missing & (address-of) on the operand", expr.position) return } @@ -1229,13 +1231,13 @@ internal class AstChecker(private val program: Program, if(divisor==0.0) errors.err("division by zero", expr.right.position) if(expr.operator=="%") { - if ((rightDt != DataType.UBYTE && rightDt != DataType.UWORD) || (leftDt!= DataType.UBYTE && leftDt!= DataType.UWORD)) + if ((!rightDt.isUnsignedByte && !rightDt.isUnsignedWord) || (!leftDt.isUnsignedByte && !leftDt.isUnsignedWord)) errors.err("remainder can only be used on unsigned integer operands", expr.right.position) } } "in" -> throw FatalAstException("in expression should have been replaced by containmentcheck") "<<", ">>" -> { - if(rightDt in WordDatatypes) { + if(rightDt.isWord) { val shift = expr.right.constValue(program)?.number?.toInt() if(shift==null || shift > 255) { errors.err("shift by a word value not supported, max is a byte", expr.position) @@ -1244,22 +1246,22 @@ internal class AstChecker(private val program: Program, } } - if(leftDt !in NumericDatatypes && leftDt != DataType.STR && leftDt != DataType.BOOL) + if(!leftDt.isNumeric && !leftDt.isString && !leftDt.isBool) errors.err("left operand is not numeric or str", expr.left.position) - if(rightDt!in NumericDatatypes && rightDt != DataType.STR && rightDt != DataType.BOOL) + if(!rightDt.isNumeric && !rightDt.isString && !rightDt.isBool) errors.err("right operand is not numeric or str", expr.right.position) if(leftDt!=rightDt) { - if(leftDt==DataType.STR && rightDt in IntegerDatatypes && expr.operator=="*") { + if(leftDt.isString && rightDt.isInteger && expr.operator=="*") { // exception allowed: str * constvalue if(expr.right.constValue(program)==null) errors.err("can only use string repeat with a constant number value", expr.left.position) - } else if(leftDt==DataType.BOOL && rightDt in ByteDatatypes || leftDt in ByteDatatypes && rightDt==DataType.BOOL) { + } else if(leftDt.isBool && rightDt.isByte || leftDt.isByte && rightDt.isBool) { // expression with one side BOOL other side (U)BYTE is allowed; bool==byte - } else if((expr.operator == "<<" || expr.operator == ">>") && (leftDt in WordDatatypes && rightDt in ByteDatatypes)) { + } else if((expr.operator == "<<" || expr.operator == ">>") && (leftDt.isWord && rightDt.isByte)) { // exception allowed: shifting a word by a byte - } else if((expr.operator in BitwiseOperators) && (leftDt in IntegerDatatypes && rightDt in IntegerDatatypes)) { + } else if((expr.operator in BitwiseOperators) && (leftDt.isInteger && rightDt.isInteger)) { // exception allowed: bitwise operations with any integers - } else if((leftDt==DataType.UWORD && rightDt==DataType.STR) || (leftDt==DataType.STR && rightDt==DataType.UWORD)) { + } else if((leftDt.isUnsignedWord && rightDt.isString) || (leftDt.isString && rightDt.isUnsignedWord)) { // exception allowed: comparing uword (pointer) with string } else { errors.err("left and right operands aren't the same type: $leftDt vs $rightDt", expr.position) @@ -1267,31 +1269,31 @@ internal class AstChecker(private val program: Program, } if(expr.operator !in ComparisonOperators) { - if (leftDt == DataType.STR && rightDt == DataType.STR || leftDt in ArrayDatatypes && rightDt in ArrayDatatypes) { + if (leftDt.isString && rightDt.isString || leftDt.isArray && rightDt.isArray) { // str+str and str*number have already been const evaluated before we get here. errors.err("no computational or logical expressions with strings or arrays are possible", expr.position) } } else { - if(expr.left is TypecastExpression && expr.right is NumericLiteral && !expr.right.inferType(program).istype(DataType.FLOAT)) { - val origLeftDt = (expr.left as TypecastExpression).expression.inferType(program).getOr(DataType.UNDEFINED) - if(rightDt.largerThan(origLeftDt) && !(expr.right as NumericLiteral).cast(origLeftDt, true).isValid) + if(expr.left is TypecastExpression && expr.right is NumericLiteral && !(expr.right.inferType(program) issimpletype BaseDataType.FLOAT)) { + val origLeftDt = (expr.left as TypecastExpression).expression.inferType(program).getOrUndef() + if(rightDt.largerSizeThan(origLeftDt) && !(expr.right as NumericLiteral).cast(origLeftDt.base, true).isValid) errors.err("operands are not the same type", expr.right.position) } - if(expr.right is TypecastExpression && expr.left is NumericLiteral && !expr.left.inferType(program).istype(DataType.FLOAT)) { - val origRightDt = (expr.right as TypecastExpression).expression.inferType(program).getOr(DataType.UNDEFINED) - if(leftDt.largerThan(origRightDt) && !(expr.left as NumericLiteral).cast(origRightDt, true).isValid) + if(expr.right is TypecastExpression && expr.left is NumericLiteral && !(expr.left.inferType(program) issimpletype BaseDataType.FLOAT)) { + val origRightDt = (expr.right as TypecastExpression).expression.inferType(program).getOrUndef() + if(leftDt.largerSizeThan(origRightDt) && !(expr.left as NumericLiteral).cast(origRightDt.base, true).isValid) errors.err("operands are not the same type", expr.right.position) } } - if(leftDt==DataType.BOOL || rightDt==DataType.BOOL || - (expr.left as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true || - (expr.right as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true) { + if(leftDt.isBool || rightDt.isBool || + (expr.left as? TypecastExpression)?.expression?.inferType(program)?.isBool==true || + (expr.right as? TypecastExpression)?.expression?.inferType(program)?.isBool==true) { if(expr.operator in setOf("<", "<=", ">", ">=")) { errors.err("can't use boolean operand with this comparison operator", expr.position) } // for now, don't enforce bool type with only logical operators... -// if(expr.operator in InvalidOperatorsForBoolean && (leftDt==DataType.BOOL || (expr.left as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true)) { +// if(expr.operator in InvalidOperatorsForBoolean && (leftDt.isBool || (expr.left as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true)) { // errors.err("can't use boolean operand with this operator ${expr.operator}", expr.left.position) // } if(expr.operator == "==" || expr.operator == "!=") { @@ -1301,19 +1303,19 @@ internal class AstChecker(private val program: Program, errors.warn("expression is always false", expr.position) } } - if((expr.operator == "/" || expr.operator == "%") && ( rightDt==DataType.BOOL || (expr.right as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true)) { + if((expr.operator == "/" || expr.operator == "%") && ( rightDt.isBool || (expr.right as? TypecastExpression)?.expression?.inferType(program)?.isBool==true)) { errors.err("can't use boolean operand with this operator ${expr.operator}", expr.right.position) } } if(expr.operator in LogicalOperators) { - if (leftDt != DataType.BOOL || rightDt != DataType.BOOL) { + if (!leftDt.isBool || !rightDt.isBool) { errors.err("logical operator requires boolean operands", expr.right.position) } } else { - if (leftDt == DataType.BOOL || rightDt == DataType.BOOL) { + if (leftDt.isBool || rightDt.isBool) { if(expr.operator!="==" && expr.operator!="!=") errors.err("operator requires numeric operands", expr.right.position) } @@ -1322,7 +1324,7 @@ internal class AstChecker(private val program: Program, override fun visit(typecast: TypecastExpression) { checkLongType(typecast) - if(typecast.type in IterableDatatypes) + if(typecast.type.isIterable) errors.err("cannot type cast to string or array type", typecast.position) if(!typecast.expression.inferType(program).isKnown) @@ -1349,14 +1351,14 @@ internal class AstChecker(private val program: Program, if(stepLv==null) { err("range step must be a constant integer") return - } else if (stepLv.type !in IntegerDatatypes || stepLv.number.toInt() == 0) { + } else if (!stepLv.type.isInteger || stepLv.number.toInt() == 0) { err("range step must be an integer != 0") return } val step = stepLv.number.toInt() if(from!=null && to != null) { when { - from.type in IntegerDatatypes && to.type in IntegerDatatypes -> { + from.type.isInteger && to.type.isInteger -> { val fromValue = from.number.toInt() val toValue = to.number.toInt() if(fromValue== toValue) @@ -1384,7 +1386,7 @@ internal class AstChecker(private val program: Program, // warn about sgn(unsigned) this is likely a mistake if(functionCallExpr.target.nameInSource.last()=="sgn") { val sgnArgType = functionCallExpr.args.first().inferType(program) - if(sgnArgType istype DataType.UBYTE || sgnArgType istype DataType.UWORD) + if(sgnArgType issimpletype BaseDataType.UBYTE || sgnArgType issimpletype BaseDataType.UWORD) errors.warn("sgn() of unsigned type is always 0 or 1, this is perhaps not what was intended", functionCallExpr.args.first().position) } @@ -1442,7 +1444,7 @@ internal class AstChecker(private val program: Program, if(funcName[0] == "sort") { // sort is not supported on float arrays val idref = functionCallStatement.args.singleOrNull() as? IdentifierReference - if(idref!=null && idref.inferType(program) istype DataType.ARRAY_F) { + if(idref!=null && idref.inferType(program).isFloatArray) { errors.err("sorting a floating point array is not supported", functionCallStatement.args.first().position) } } @@ -1554,11 +1556,11 @@ internal class AstChecker(private val program: Program, checkLongType(arrayIndexedExpression) val target = arrayIndexedExpression.arrayvar.targetStatement(program) if(target is VarDecl) { - if(target.datatype !in IterableDatatypes && target.datatype!=DataType.UWORD) + if(!target.datatype.isIterable && !target.datatype.isUnsignedWord) errors.err("indexing requires an iterable or address uword variable", arrayIndexedExpression.position) val indexVariable = arrayIndexedExpression.indexer.indexExpr as? IdentifierReference if(indexVariable!=null) { - if(indexVariable.targetVarDecl(program)?.datatype in SignedDatatypes) { + if(indexVariable.targetVarDecl(program)?.datatype?.isSigned==true) { errors.err("variable array indexing can't be performed with signed variables", indexVariable.position) return } @@ -1568,7 +1570,7 @@ internal class AstChecker(private val program: Program, if(arraysize!=null) { if(index!=null && (index<0 || index>=arraysize)) errors.err("index out of bounds", arrayIndexedExpression.indexer.position) - } else if(target.datatype == DataType.STR) { + } else if(target.datatype.isString) { if(target.value is StringLiteral) { // check string lengths for non-memory mapped strings val stringLen = (target.value as StringLiteral).value.length @@ -1583,7 +1585,7 @@ internal class AstChecker(private val program: Program, // check index value 0..255 val dtxNum = arrayIndexedExpression.indexer.indexExpr.inferType(program) - if(dtxNum.isKnown && dtxNum isnot DataType.UBYTE && dtxNum isnot DataType.BYTE) + if(dtxNum.isKnown && !(dtxNum issimpletype BaseDataType.UBYTE) && !(dtxNum issimpletype BaseDataType.BYTE)) errors.err("array indexing is limited to byte size 0..255", arrayIndexedExpression.position) super.visit(arrayIndexedExpression) @@ -1624,10 +1626,10 @@ internal class AstChecker(private val program: Program, for((constvalue, pos) in constvalues) { when { constvalue == null -> errors.err("choice value must be a constant", pos) - constvalue.type !in IntegerDatatypesWithBoolean -> errors.err("choice value must be a byte or word", pos) - conditionType isnot constvalue.type -> { + !constvalue.type.isIntegerOrBool -> errors.err("choice value must be a byte or word", pos) + !(conditionType issimpletype constvalue.type) -> { if(conditionType.isKnown) { - if(conditionType.istype(DataType.BOOL)) { + if(conditionType.isBool) { if(constvalue.number!=0.0 && constvalue.number!=1.0) errors.err("choice value datatype differs from condition value", pos) } else { @@ -1650,11 +1652,11 @@ internal class AstChecker(private val program: Program, if (iterableDt.isIterable) { if (containment.iterable !is RangeExpression) { - val iterableEltDt = ArrayToElementTypes.getValue(iterableDt.getOr(DataType.UNDEFINED)) + val iterableEltDt = iterableDt.getOrUndef().elementType() val invalidDt = if (elementDt.isBytes) { - iterableEltDt !in ByteDatatypes + !iterableEltDt.isByte } else if (elementDt.isWords) { - iterableEltDt !in WordDatatypes + !iterableEltDt.isWord } else { false } @@ -1669,12 +1671,12 @@ internal class AstChecker(private val program: Program, } override fun visit(memread: DirectMemoryRead) { - if(!memread.addressExpression.inferType(program).istype(DataType.UWORD)) { + if(!(memread.addressExpression.inferType(program) issimpletype BaseDataType.UWORD)) { errors.err("address for memory access isn't uword", memread.position) } val tc = memread.addressExpression as? TypecastExpression if(tc!=null && tc.implicit) { - if(!tc.expression.inferType(program).istype(DataType.UWORD)) { + if(!(tc.expression.inferType(program) issimpletype BaseDataType.UWORD)) { errors.err("address for memory access isn't uword", memread.position) } } @@ -1682,12 +1684,12 @@ internal class AstChecker(private val program: Program, } override fun visit(memwrite: DirectMemoryWrite) { - if(!memwrite.addressExpression.inferType(program).istype(DataType.UWORD)) { + if(!(memwrite.addressExpression.inferType(program) issimpletype BaseDataType.UWORD)) { errors.err("address for memory access isn't uword", memwrite.position) } val tc = memwrite.addressExpression as? TypecastExpression if(tc!=null && tc.implicit) { - if(!tc.expression.inferType(program).istype(DataType.UWORD)) { + if(!(tc.expression.inferType(program) issimpletype BaseDataType.UWORD)) { errors.err("address for memory access isn't uword", memwrite.position) } } @@ -1700,7 +1702,7 @@ internal class AstChecker(private val program: Program, } private fun checkLongType(expression: Expression) { - if(expression.inferType(program).istype(DataType.LONG)) { + if(expression.inferType(program) issimpletype BaseDataType.LONG) { if((expression.parent as? VarDecl)?.type!=VarDeclType.CONST) { if (expression.parent !is RepeatLoop) { if (errors.noErrorForLine(expression.position)) @@ -1711,7 +1713,7 @@ internal class AstChecker(private val program: Program, } private fun checkValueTypeAndRangeString(targetDt: DataType, value: StringLiteral) : Boolean { - return if (targetDt == DataType.STR) { + return if (targetDt.isString) { when { value.value.length > 255 -> { errors.err("string length must be 0-255", value.position) @@ -1740,9 +1742,9 @@ internal class AstChecker(private val program: Program, if(value.type.isUnknown) return false - when (targetDt) { - DataType.STR -> return err("string value expected") - DataType.ARRAY_BOOL -> { + when { + targetDt.isString -> return err("string value expected") + targetDt.isBoolArray -> { // value may be either a single byte, or a byte arraysize (of all constant values)\ if(value.type istype targetDt) { if(!checkArrayValues(value, targetDt)) @@ -1761,7 +1763,7 @@ internal class AstChecker(private val program: Program, } return err("invalid boolean array initialization value ${value.type}, expected $targetDt") } - DataType.ARRAY_UB, DataType.ARRAY_B -> { + targetDt.isByteArray -> { // value may be either a single byte, or a byte arraysize (of all constant values), or a range if(value.type istype targetDt) { if(!checkArrayValues(value, targetDt)) @@ -1780,14 +1782,14 @@ internal class AstChecker(private val program: Program, } return err("invalid byte array initialization value ${value.type}, expected $targetDt") } - DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_W_SPLIT, DataType.ARRAY_UW_SPLIT-> { + targetDt.isWordArray -> { // value may be either a single word, or a word arraysize, or a range if(value.type istype targetDt) { if(!checkArrayValues(value, targetDt)) return false val arraySpecSize = arrayspec.constIndex() val arraySize = value.value.size - val maxLength = if(targetDt in SplitWordArrayTypes) 256 else 128 + val maxLength = if(targetDt.isSplitWordArray) 256 else 128 if(arraySpecSize!=null && arraySpecSize>0) { if(arraySpecSize>maxLength) return err("array length must be 1-$maxLength") @@ -1800,7 +1802,7 @@ internal class AstChecker(private val program: Program, } return err("invalid word array initialization value ${value.type}, expected $targetDt") } - DataType.ARRAY_F -> { + targetDt.isFloatArray -> { // value may be either a single float, or a float arraysize if(value.type istype targetDt) { if(!checkArrayValues(value, targetDt)) @@ -1833,57 +1835,57 @@ internal class AstChecker(private val program: Program, errors.err(msg, value.position) return false } - when (targetDt) { - DataType.FLOAT -> { + + when { + targetDt.isFloat -> { val number=value.number if (number > compilerOptions.compTarget.machine.FLOAT_MAX_POSITIVE || number < compilerOptions.compTarget.machine.FLOAT_MAX_NEGATIVE) return err("value '$number' out of range") } - DataType.UBYTE -> { - if(value.type==DataType.FLOAT) + targetDt.isUnsignedByte -> { + if(value.type==BaseDataType.FLOAT) err("unsigned byte value expected instead of float; possible loss of precision") val number=value.number if (number < 0 || number > 255) return err("value '$number' out of range for unsigned byte") } - DataType.BYTE -> { - if(value.type==DataType.FLOAT) + targetDt.isSignedByte -> { + if(value.type==BaseDataType.FLOAT) err("byte value expected instead of float; possible loss of precision") val number=value.number if (number < -128 || number > 127) return err("value '$number' out of range for byte") } - DataType.UWORD -> { - if(value.type==DataType.FLOAT) + targetDt.isUnsignedWord -> { + if(value.type==BaseDataType.FLOAT) err("unsigned word value expected instead of float; possible loss of precision") val number=value.number if (number < 0 || number > 65535) return err("value '$number' out of range for unsigned word") } - DataType.WORD -> { - if(value.type==DataType.FLOAT) + targetDt.isSignedWord -> { + if(value.type==BaseDataType.FLOAT) err("word value expected instead of float; possible loss of precision") val number=value.number if (number < -32768 || number > 32767) return err("value '$number' out of range for word") } - DataType.LONG -> { - if(value.type==DataType.FLOAT) + targetDt.isLong -> { + if(value.type==BaseDataType.FLOAT) err("integer value expected instead of float; possible loss of precision") val number=value.number if (number < -2147483647 || number > 2147483647) return err("value '$number' out of range for long") } - DataType.BOOL -> { - if (value.type!=DataType.BOOL) { - err("type of value ${value.type} doesn't match target $targetDt") + targetDt.isBool -> { + if (value.type!=BaseDataType.BOOL) { + err("type of value ${value.type.toString().lowercase()} doesn't match target $targetDt") } } - in ArrayDatatypes -> { - val eltDt = ArrayToElementTypes.getValue(targetDt) - return checkValueTypeAndRange(eltDt, value) + targetDt.isArray -> { + return checkValueTypeAndRange(targetDt.elementType(), value) } - else -> return err("type of value ${value.type} doesn't match target $targetDt") + else -> return err("type of value ${value.type.toString().lowercase()} doesn't match target $targetDt") } return true } @@ -1906,23 +1908,23 @@ internal class AstChecker(private val program: Program, } } val correct: Boolean - when (targetDt) { - DataType.ARRAY_UB -> { + when { + targetDt.isUnsignedByteArray -> { correct = array.all { it in 0..255 } } - DataType.ARRAY_B -> { + targetDt.isSignedByteArray -> { correct = array.all { it in -128..127 } } - DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> { + targetDt.isUnsignedWordArray || targetDt.isSplitUnsignedWordArray -> { correct = array.all { (it in 0..65535) } } - DataType.ARRAY_W, DataType.ARRAY_W_SPLIT -> { + targetDt.isSignedWordArray || targetDt.isSplitSignedWordArray -> { correct = array.all { it in -32768..32767 } } - DataType.ARRAY_BOOL -> { + targetDt.isBoolArray -> { correct = array.all { it==0 || it==1 } } - DataType.ARRAY_F -> correct = true + targetDt.isFloatArray -> correct = true else -> throw FatalAstException("invalid type $targetDt") } if (!correct) @@ -1936,7 +1938,7 @@ internal class AstChecker(private val program: Program, sourceValue: Expression) : Boolean { val position = sourceValue.position - if (targetDatatype in ArrayDatatypes) { + if (targetDatatype.isArray) { if(sourceValue.inferType(program).isArray) errors.err("cannot assign arrays directly. Maybe use sys.memcopy instead.", target.position) else @@ -1951,51 +1953,51 @@ internal class AstChecker(private val program: Program, errors.err("can't assign a range value to something else", position) return false } - if(sourceDatatype==DataType.UNDEFINED) { + if(sourceDatatype.isUndefined) { errors.err("assignment right hand side doesn't result in a value", position) return false } - val result = when(targetDatatype) { - DataType.BOOL -> sourceDatatype==DataType.BOOL - DataType.BYTE -> sourceDatatype == DataType.BYTE - DataType.UBYTE -> sourceDatatype == DataType.UBYTE - DataType.WORD -> sourceDatatype in setOf(DataType.BYTE, DataType.UBYTE, DataType.WORD) - DataType.UWORD -> sourceDatatype == DataType.UBYTE || sourceDatatype == DataType.UWORD - DataType.LONG -> sourceDatatype in IntegerDatatypes - DataType.FLOAT -> sourceDatatype in NumericDatatypes - DataType.STR -> sourceDatatype == DataType.STR + val result = when { + targetDatatype.isBool -> sourceDatatype.isBool + targetDatatype.isSignedByte -> sourceDatatype.isSignedByte + targetDatatype.isUnsignedByte -> sourceDatatype.isUnsignedByte + targetDatatype.isSignedWord -> sourceDatatype.isSignedWord || sourceDatatype.isByte + targetDatatype.isUnsignedWord -> sourceDatatype.isUnsignedWord || sourceDatatype.isUnsignedByte + targetDatatype.isLong -> sourceDatatype.isLong + targetDatatype.isFloat -> sourceDatatype.isNumeric + targetDatatype.isString -> sourceDatatype.isString else -> false } if(result) return true - if((sourceDatatype== DataType.UWORD || sourceDatatype== DataType.WORD) && (targetDatatype== DataType.UBYTE || targetDatatype== DataType.BYTE)) { + if(sourceDatatype.isWord && targetDatatype.isByte) { errors.err("cannot assign word to byte, use msb() or lsb()?", position) } - else if(sourceDatatype in IterableDatatypes && targetDatatype in ByteDatatypes) { + else if(sourceDatatype.isIterable && targetDatatype.isByte) { errors.err("cannot assign string or array to a byte", position) } - else if(sourceDatatype== DataType.FLOAT && targetDatatype in IntegerDatatypes) - errors.err("cannot assign float to ${targetDatatype.name.lowercase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position) + else if(sourceDatatype.isFloat&& targetDatatype.isInteger) + errors.err("cannot assign float to ${targetDatatype}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position) else if((sourceValue as? BinaryExpression)?.operator in BitwiseOperators && targetDatatype.equalsSize(sourceDatatype)) { // this is allowed: bitwise operation between different types as long as they're the same size. } - else if(targetDatatype==DataType.UWORD && sourceDatatype in PassByReferenceDatatypes) { + else if(targetDatatype.isUnsignedWord && sourceDatatype.isPassByRef) { // this is allowed: a pass-by-reference datatype into an uword (pointer value). } - else if(sourceDatatype in ArrayDatatypes && targetDatatype in ArrayDatatypes) { + else if(sourceDatatype.isArray && targetDatatype.isArray) { // this is allowed (assigning array to array) } - else if(sourceDatatype==DataType.BOOL && targetDatatype!=DataType.BOOL) { + else if(sourceDatatype.isBool && !targetDatatype.isBool) { errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position) } - else if(targetDatatype==DataType.BOOL && sourceDatatype!=DataType.BOOL) { + else if(targetDatatype.isBool && !sourceDatatype.isBool) { errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position) } - else if(targetDatatype==DataType.STR) { - if(sourceDatatype==DataType.UWORD) + else if(targetDatatype.isString) { + if(sourceDatatype.isUnsignedWord) errors.err("can't assign UWORD to STR. If the source is a string and you actually want to overwrite the target string, use an explicit strings.copy(src,tgt) instead.", position) else errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position) diff --git a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt index 9de3110f4..ccf03e53f 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt @@ -63,7 +63,7 @@ internal fun Program.charLiteralsToUByteLiterals(target: ICompilationTarget, err val encoded = target.encodeString(char.value.toString(), char.encoding) listOf(IAstModification.ReplaceNode( char, - NumericLiteral(DataType.UBYTE, encoded[0].toDouble(), char.position), + NumericLiteral(BaseDataType.UBYTE, encoded[0].toDouble(), char.position), parent )) } catch (x: CharConversionException) { @@ -208,7 +208,7 @@ internal fun IdentifierReference.checkFunctionOrLabelExists(program: Program, st is Label, is Subroutine, is BuiltinFunctionPlaceholder -> return targetStatement is VarDecl -> { if(statement is Jump) { - if (targetStatement.datatype == DataType.UWORD) + if (targetStatement.datatype.isUnsignedWord) return targetStatement else errors.err("wrong address variable datatype, expected uword", this.position) diff --git a/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt index d86ce4511..477d034a1 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt @@ -7,7 +7,10 @@ import prog8.ast.expressions.FunctionCallExpression import prog8.ast.expressions.StringLiteral import prog8.ast.statements.* import prog8.ast.walk.IAstVisitor -import prog8.code.core.* +import prog8.code.core.BuiltinFunctions +import prog8.code.core.ICompilationTarget +import prog8.code.core.IErrorReporter +import prog8.code.core.Position import prog8.code.target.VMTarget /** @@ -209,7 +212,7 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter, } } is VarDecl -> { - if(target.type!=VarDeclType.VAR || target.datatype!=DataType.UWORD) + if(target.type!=VarDeclType.VAR || !target.datatype.isUnsignedWord) errors.err("wrong address variable datatype, expected uword", call.target.position) } is Alias -> {} diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index 2e399deba..1a338b05e 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -138,7 +138,7 @@ class AstPreprocessor(val program: Program, } } else { // handle declaration of a single variable - if(decl.value!=null && (decl.datatype in NumericDatatypes || decl.datatype==DataType.BOOL)) { + if(decl.value!=null && decl.datatype.isNumericOrBool) { val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, null, false, decl.position) val assign = Assignment(target, decl.value!!, AssignmentOrigin.VARINIT, decl.position) replacements.add(IAstModification.ReplaceNode(decl, assign, scope)) @@ -185,7 +185,7 @@ class AstPreprocessor(val program: Program, return makeSplitArray(decl) } - if(decl.datatype==DataType.ARRAY_W || decl.datatype==DataType.ARRAY_UW) { + if(decl.datatype.isWordArray) { if ("splitarrays" in decl.definingBlock.options()) return makeSplitArray(decl) if ("splitarrays" in decl.definingModule.options()) @@ -196,14 +196,10 @@ class AstPreprocessor(val program: Program, } private fun shouldSplitArray(decl: VarDecl): Boolean = - options.splitWordArrays && (decl.datatype==DataType.ARRAY_W || decl.datatype==DataType.ARRAY_UW) && !decl.definingBlock.isInLibrary + options.splitWordArrays && (decl.datatype.isWordArray && !decl.datatype.isSplitWordArray) && !decl.definingBlock.isInLibrary private fun makeSplitArray(decl: VarDecl): Iterable { - val splitDt = when(decl.datatype) { - DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> DataType.ARRAY_UW_SPLIT - DataType.ARRAY_W,DataType.ARRAY_W_SPLIT -> DataType.ARRAY_W_SPLIT - else -> throw FatalAstException("invalid dt") - } + val splitDt = DataType.arrayFor(decl.datatype.sub!!.dt, true) val newDecl = VarDecl( decl.type, decl.origin, splitDt, decl.zeropage, decl.arraysize, decl.name, emptyList(), decl.value?.copy(), decl.sharedWithAsm, true, decl.alignment, false, decl.position @@ -276,7 +272,7 @@ class AstPreprocessor(val program: Program, if(targetStatement!=null) { if(targetStatement is Subroutine) { for(arg in call.args.zip(targetStatement.parameters)) { - if(arg.first.inferType(program).isBytes && arg.second.type==DataType.STR) { + if(arg.first.inferType(program).isBytes && arg.second.type.isString) { errors.err("cannot use byte value for string parameter", arg.first.position) } } diff --git a/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt b/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt index b3994c138..8369edc71 100644 --- a/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt +++ b/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt @@ -26,7 +26,7 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co } override fun after(decl: VarDecl, parent: Node): Iterable { - if (decl.type == VarDeclType.VAR && decl.value != null && (decl.datatype in NumericDatatypes || decl.datatype==DataType.BOOL)) { + if (decl.type == VarDeclType.VAR && decl.value != null && decl.datatype.isNumericOrBool) { throw InternalCompilerException("vardecls with initial numerical value, should have been rewritten as plain vardecl + assignment $decl") } @@ -158,11 +158,11 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co } } - if(rightNum!=null && rightNum.type in IntegerDatatypes && rightNum.number!=0.0) { + if(rightNum!=null && rightNum.type.isInteger && rightNum.number!=0.0) { when(expr.operator) { ">" -> { // X>N -> X>=N+1, easier to do in 6502 - val maximum = if(rightNum.type in ByteDatatypes) 255 else 65535 + val maximum = if(rightNum.type.isByte) 255 else 65535 if(rightNum.number=", NumericLiteral(rightNum.type, numPlusOne.toDouble(), rightNum.position), expr.position) @@ -171,7 +171,7 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co } "<=" -> { // X<=N -> Xubyte, word<->uword or even redundant casts (sourcetype = target type). // the special typecast of a reference type (str, array) to an UWORD will be changed into address-of, // UNLESS it's a str parameter in the containing subroutine - then we remove the typecast altogether - val sourceDt = typecast.expression.inferType(program).getOr(DataType.UNDEFINED) - if (typecast.type in ByteDatatypes && sourceDt in ByteDatatypes - || typecast.type in WordDatatypes && sourceDt in WordDatatypes - ) { + val sourceDt = typecast.expression.inferType(program).getOrUndef() + if (typecast.type.isByte && sourceDt.isByte || typecast.type.isWord && sourceDt.isWord) { if(typecast.parent !is Expression) { return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent)) } } - if(typecast.type==sourceDt) + if(typecast.type==sourceDt.base) return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent)) - if(sourceDt in PassByReferenceDatatypes) { - if(typecast.type== DataType.UWORD) { + if(sourceDt.isPassByRef) { + if(typecast.type == BaseDataType.UWORD) { val identifier = typecast.expression as? IdentifierReference if(identifier!=null) { return if(identifier.isSubroutineParameter(program)) { @@ -74,20 +75,20 @@ internal class BeforeAsmTypecastCleaner(val program: Program, // if the datatype of the arguments of cmp() are different, cast the byte one to word. val arg1 = fcs.args[0] val arg2 = fcs.args[1] - val dt1 = arg1.inferType(program).getOr(DataType.UNDEFINED) - val dt2 = arg2.inferType(program).getOr(DataType.UNDEFINED) - if(dt1==DataType.BOOL && dt2==DataType.BOOL) + val dt1 = arg1.inferType(program).getOrUndef() + val dt2 = arg2.inferType(program).getOrUndef() + if(dt1.isBool && dt2.isBool) return noModifications - else if(dt1 in ByteDatatypes) { - if(dt2 in ByteDatatypes) + else if(dt1.isByte) { + if(dt2.isByte) return noModifications - val (replaced, cast) = arg1.typecastTo(if(dt1== DataType.UBYTE) DataType.UWORD else DataType.WORD, dt1, true) + val (replaced, cast) = arg1.typecastTo(if(dt1.isUnsignedByte) BaseDataType.UWORD else BaseDataType.WORD, dt1, true) if(replaced) return listOf(IAstModification.ReplaceNode(arg1, cast, fcs)) } else { - if(dt2 in WordDatatypes) + if(dt2.isWord) return noModifications - val (replaced, cast) = arg2.typecastTo(if(dt2== DataType.UBYTE) DataType.UWORD else DataType.WORD, dt2, true) + val (replaced, cast) = arg2.typecastTo(if(dt2.isUnsignedByte) BaseDataType.UWORD else BaseDataType.WORD, dt2, true) if(replaced) return listOf(IAstModification.ReplaceNode(arg2, cast, fcs)) } @@ -100,12 +101,12 @@ internal class BeforeAsmTypecastCleaner(val program: Program, val shifts = expr.right.constValue(program) if(shifts!=null) { val dt = expr.left.inferType(program) - if(dt.istype(DataType.UBYTE) && shifts.number>=8.0) + if(dt issimpletype BaseDataType.UBYTE && shifts.number>=8.0) errors.info("shift always results in 0", expr.position) - if(dt.istype(DataType.UWORD) && shifts.number>=16.0) + if(dt issimpletype BaseDataType.UWORD && shifts.number>=16.0) errors.info("shift always results in 0", expr.position) - if(shifts.number<=255.0 && shifts.type in WordDatatypes) { - val byteVal = NumericLiteral(DataType.UBYTE, shifts.number, shifts.position) + if(shifts.number<=255.0 && shifts.type.isWord) { + val byteVal = NumericLiteral(BaseDataType.UBYTE, shifts.number, shifts.position) return listOf(IAstModification.ReplaceNode(expr.right, byteVal, expr)) } } diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index 395db57cb..923068c2c 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -5,7 +5,10 @@ import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -import prog8.code.core.* +import prog8.code.core.BaseDataType +import prog8.code.core.ComparisonOperators +import prog8.code.core.IErrorReporter +import prog8.code.core.Position internal class CodeDesugarer(val program: Program, private val errors: IErrorReporter) : AstWalker() { @@ -203,8 +206,8 @@ _after: // "array indexing is limited to byte size 0..255" error for pointervariables. val indexExpr = arrayIndexedExpression.indexer.indexExpr val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl(program) - if(arrayVar!=null && arrayVar.datatype==DataType.UWORD) { - val wordIndex = TypecastExpression(indexExpr, DataType.UWORD, true, indexExpr.position) + if(arrayVar!=null && arrayVar.datatype.isUnsignedWord) { + val wordIndex = TypecastExpression(indexExpr, BaseDataType.UWORD, true, indexExpr.position) val address = BinaryExpression(arrayIndexedExpression.arrayvar.copy(), "+", wordIndex, arrayIndexedExpression.position) return if(parent is AssignTarget) { // assignment to array @@ -222,10 +225,10 @@ _after: override fun after(expr: BinaryExpression, parent: Node): Iterable { fun isStringComparison(leftDt: InferredTypes.InferredType, rightDt: InferredTypes.InferredType): Boolean = - if(leftDt istype DataType.STR && rightDt istype DataType.STR) + if(leftDt issimpletype BaseDataType.STR && rightDt issimpletype BaseDataType.STR) true else - leftDt istype DataType.UWORD && rightDt istype DataType.STR || leftDt istype DataType.STR && rightDt istype DataType.UWORD + leftDt issimpletype BaseDataType.UWORD && rightDt issimpletype BaseDataType.STR || leftDt issimpletype BaseDataType.STR && rightDt issimpletype BaseDataType.UWORD if(expr.operator=="in") { val containment = ContainmentCheck(expr.left, expr.right, expr.position) diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index be020edab..a749ff24e 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -291,7 +291,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr val singleName = srcCall.target.nameInSource.singleOrNull() if(singleName!=null && singleName in BuiltinFunctions) { // it is a builtin function. Create a special Ast node for that. - val type = builtinFunctionReturnType(singleName).getOr(DataType.UNDEFINED) + val type = builtinFunctionReturnType(singleName).getOrUndef() val noSideFx = BuiltinFunctions.getValue(singleName).pure val call = PtBuiltinFunctionCall(singleName, true, noSideFx, type, srcCall.position) for (arg in srcCall.args) @@ -324,7 +324,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr val (target, _) = srcCall.target.targetNameAndType(program) val iType = srcCall.inferType(program) - val call = PtFunctionCall(target, iType.isUnknown && srcCall.parent !is Assignment, iType.getOrElse { DataType.UNDEFINED }, srcCall.position) + val call = PtFunctionCall(target, iType.isUnknown && srcCall.parent !is Assignment, iType.getOrElse { DataType.forDt(BaseDataType.UNDEFINED) }, srcCall.position) for (arg in srcCall.args) call.add(transformExpression(arg)) return call @@ -375,8 +375,8 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr val endLabel = program.makeLabel("cend") val scopedElseLabel = (srcIf.definingScope.scopedName + elseLabel).joinToString(".") val scopedEndLabel = (srcIf.definingScope.scopedName + endLabel).joinToString(".") - val elseLbl = PtIdentifier(scopedElseLabel, DataType.UNDEFINED, srcIf.position) - val endLbl = PtIdentifier(scopedEndLabel, DataType.UNDEFINED, srcIf.position) + val elseLbl = PtIdentifier(scopedElseLabel, DataType.forDt(BaseDataType.UNDEFINED), srcIf.position) + val endLbl = PtIdentifier(scopedEndLabel, DataType.forDt(BaseDataType.UNDEFINED), srcIf.position) ifScope.add(PtJump(elseLbl, null, srcIf.position)) val elseScope = PtNodeGroup() branch.add(ifScope) @@ -534,8 +534,8 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr private fun transformSub(srcSub: Subroutine): PtSub { val (vardecls, statements) = srcSub.statements.partition { it is VarDecl } var returntype = srcSub.returntypes.singleOrNull() - if(returntype==DataType.STR) - returntype=DataType.UWORD // if a sub returns 'str', replace with uword. Intermediate AST and I.R. don't contain 'str' datatype anymore. + if(returntype?.isString==true) + returntype=DataType.forDt(BaseDataType.UWORD) // if a sub returns 'str', replace with uword. Intermediate AST and I.R. don't contain 'str' datatype anymore. // do not bother about the 'inline' hint of the source subroutine. val sub = PtSub(srcSub.name, @@ -607,7 +607,8 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr } private fun transform(srcArr: ArrayIndexedExpression): PtArrayIndexer { - if(srcArr.arrayvar.targetVarDecl(program)!!.datatype !in ArrayDatatypes + DataType.STR) + val dt = srcArr.arrayvar.targetVarDecl(program)!!.datatype + if(!dt.isArray && !dt.isString) throw FatalAstException("array indexing can only be used on array or string variables ${srcArr.position}") val eltType = srcArr.inferType(program).getOrElse { throw FatalAstException("unknown dt") } val array = PtArrayIndexer(eltType, srcArr.position) @@ -638,29 +639,29 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr fun desugar(range: RangeExpression): PtExpression { require(range.from.inferType(program)==range.to.inferType(program)) - val expr = PtBinaryExpression("and", DataType.BOOL, srcCheck.position) + val expr = PtBinaryExpression("and", DataType.forDt(BaseDataType.BOOL), srcCheck.position) val x1 = transformExpression(srcCheck.element) val x2 = transformExpression(srcCheck.element) val eltDt = srcCheck.element.inferType(program) if(eltDt.isInteger) { - val low = PtBinaryExpression("<=", DataType.BOOL, srcCheck.position) + val low = PtBinaryExpression("<=", DataType.forDt(BaseDataType.BOOL), srcCheck.position) low.add(transformExpression(range.from)) low.add(x1) expr.add(low) - val high = PtBinaryExpression("<=", DataType.BOOL, srcCheck.position) + val high = PtBinaryExpression("<=", DataType.forDt(BaseDataType.BOOL), srcCheck.position) high.add(x2) high.add(transformExpression(range.to)) expr.add(high) } else { - val low = PtBinaryExpression("<=", DataType.BOOL, srcCheck.position) - val lowFloat = PtTypeCast(DataType.FLOAT, range.from.position) + val low = PtBinaryExpression("<=", DataType.forDt(BaseDataType.BOOL), srcCheck.position) + val lowFloat = PtTypeCast(BaseDataType.FLOAT, range.from.position) lowFloat.add(transformExpression(range.from)) low.add(lowFloat) low.add(x1) expr.add(low) - val high = PtBinaryExpression("<=", DataType.BOOL, srcCheck.position) + val high = PtBinaryExpression("<=", DataType.forDt(BaseDataType.BOOL), srcCheck.position) high.add(x2) - val highFLoat = PtTypeCast(DataType.FLOAT, range.to.position) + val highFLoat = PtTypeCast(BaseDataType.FLOAT, range.to.position) highFLoat.add(transformExpression(range.to)) high.add(highFLoat) expr.add(high) @@ -681,7 +682,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr val constElt = srcCheck.element.constValue(program)?.number val step = range.step.constValue(program)?.number if(constElt!=null && constRange!=null) { - return PtNumber(DataType.UBYTE, if(constRange.first<=constElt && constElt<=constRange.last) 1.0 else 0.0, srcCheck.position) + return PtNumber(BaseDataType.UBYTE, if(constRange.first<=constElt && constElt<=constRange.last) 1.0 else 0.0, srcCheck.position) } else if(step==1.0) { // x in low to high --> low <=x and x <= high @@ -694,7 +695,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr return desugar(range) } else { errors.err("cannot use step size different than 1 or -1 in a non constant range containment check", srcCheck.position) - return PtNumber(DataType.BYTE, 0.0, Position.DUMMY) + return PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY) } } else -> throw FatalAstException("iterable in containmentcheck must always be an identifier (referencing string or array) or a range expression $srcCheck") @@ -714,7 +715,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr } private fun transform(number: NumericLiteral): PtExpression { - return if(number.type==DataType.BOOL) + return if(number.type==BaseDataType.BOOL) PtBool(number.asBooleanValue, number.position) else PtNumber(number.type, number.number, number.position) diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt index cae964bf4..ab63910c1 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt @@ -43,7 +43,7 @@ private fun setDeferMasks(program: PtProgram, errors: IErrorReporter): Map>, program: PtPro fun invokedeferbefore(node: PtNode) { val idx = node.parent.children.indexOf(node) - val invokedefer = PtFunctionCall(node.definingSub()!!.scopedName+"."+invokeDefersRoutineName, true, DataType.UNDEFINED, node.position) + val invokedefer = PtFunctionCall(node.definingSub()!!.scopedName+"."+invokeDefersRoutineName, true, DataType.forDt(BaseDataType.UNDEFINED), node.position) node.parent.add(idx, invokedefer) } @@ -154,7 +154,7 @@ private fun integrateDefers(subdefers: Map>, program: PtPro newRet.add(popCall) val group = PtNodeGroup() group.add(pushCall) - group.add(PtFunctionCall(ret.definingSub()!!.scopedName+"."+invokeDefersRoutineName, true, DataType.UNDEFINED, ret.position)) + group.add(PtFunctionCall(ret.definingSub()!!.scopedName+"."+invokeDefersRoutineName, true,DataType.forDt(BaseDataType.UNDEFINED), ret.position)) group.add(newRet) group.parent = ret.parent val idx = ret.parent.children.indexOf(ret) @@ -168,7 +168,7 @@ private fun integrateDefers(subdefers: Map>, program: PtPro val idx = sub.children.indexOfLast { it !is PtDefer } val ret = PtReturn(sub.position) sub.add(idx+1, ret) - val invokedefer = PtFunctionCall(sub.scopedName+"."+invokeDefersRoutineName, true, DataType.UNDEFINED, sub.position) + val invokedefer = PtFunctionCall(sub.scopedName+"."+invokeDefersRoutineName, true, DataType.forDt(BaseDataType.UNDEFINED), sub.position) sub.add(idx+1, invokedefer) } } @@ -181,14 +181,14 @@ private fun integrateDefers(subdefers: Map>, program: PtPro for((idx, defer) in defers.reversed().withIndex()) { val shift = PtAugmentedAssign(">>=", Position.DUMMY) shift.add(PtAssignTarget(false, sub.position).also { - it.add(PtIdentifier(sub.scopedName+"."+maskVarName, DataType.UBYTE, sub.position)) + it.add(PtIdentifier(sub.scopedName+"."+maskVarName, DataType.forDt(BaseDataType.UBYTE), sub.position)) }) - shift.add(PtNumber(DataType.UBYTE, 1.0, sub.position)) + shift.add(PtNumber(BaseDataType.UBYTE, 1.0, sub.position)) defersRoutine.add(shift) val skiplabel = "prog8_defer_skip_${idx+1}" val branchcc = PtConditionalBranch(BranchCondition.CC, Position.DUMMY) branchcc.add(PtNodeGroup().also { - it.add(PtJump(PtIdentifier(defersRoutine.scopedName+"."+skiplabel, DataType.UNDEFINED, Position.DUMMY), null, Position.DUMMY)) + it.add(PtJump(PtIdentifier(defersRoutine.scopedName+"."+skiplabel, DataType.forDt(BaseDataType.UBYTE), Position.DUMMY), null, Position.DUMMY)) }) branchcc.add(PtNodeGroup()) defersRoutine.add(branchcc) diff --git a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt index 6f07a587c..16b84b8b9 100644 --- a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt +++ b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt @@ -4,7 +4,6 @@ import prog8.ast.IFunctionCall import prog8.ast.IStatementContainer import prog8.ast.Node import prog8.ast.Program -import prog8.ast.base.FatalAstException import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.AstWalker @@ -41,7 +40,7 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro if(vardecl!=null) { // adjust the datatype of the array (to an educated guess from the vardecl type) val arrayDt = array.type - if(arrayDt isnot vardecl.datatype) { + if(!(arrayDt istype vardecl.datatype)) { val cast = array.cast(vardecl.datatype) if(cast!=null && cast !== array) return listOf(IAstModification.ReplaceNode(vardecl.value!!, cast, vardecl)) @@ -50,10 +49,10 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro val arrayDt = array.guessDatatype(program) if(arrayDt.isUnknown) return noModifications - val elementDt = ArrayToElementTypes.getValue(arrayDt.getOr(DataType.UNDEFINED)) - val maxSize = when(elementDt) { - in ByteDatatypesWithBoolean -> PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_BYTE - in WordDatatypes -> PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_WORD + val elementDt = arrayDt.getOrUndef().elementType() + val maxSize = when { + elementDt.isByteOrBool -> PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_BYTE + elementDt.isWord -> PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_WORD else -> 0 } if(parent is ContainmentCheck && array.value.size <= maxSize) { @@ -65,9 +64,9 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro val parentAssign = parent as? Assignment val targetDt = parentAssign?.target?.inferType(program) ?: arrayDt // turn the array literal it into an identifier reference - val litval2 = array.cast(targetDt.getOr(DataType.UNDEFINED)) + val litval2 = array.cast(targetDt.getOrUndef()) if (litval2 != null) { - val vardecl2 = VarDecl.createAuto(litval2, targetDt.getOr(DataType.UNDEFINED) in SplitWordArrayTypes) + val vardecl2 = VarDecl.createAuto(litval2, targetDt.getOrUndef().isSplitWordArray) val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position) return listOf( IAstModification.ReplaceNode(array, identifier, parent), @@ -107,7 +106,7 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro // note: the desugaring of a multi-variable vardecl has to be done here // and not in CodeDesugarer, that one is too late (identifiers can't be found otherwise) - if(decl.datatype !in NumericDatatypesWithBoolean) + if(!decl.datatype.isNumericOrBool) errors.err("can only multi declare numeric and boolean variables", decl.position) if(decl.alignment != 0u) { errors.err("only single variable declarations can have alignment", decl.position) @@ -172,11 +171,7 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro } private fun makeNormalArrayFromSplit(variable: VarDecl): VarDecl { - val normalDt = when(variable.datatype) { - DataType.ARRAY_UW_SPLIT -> DataType.ARRAY_UW - DataType.ARRAY_W_SPLIT -> DataType.ARRAY_W - else -> throw FatalAstException("invalid dt") - } + val normalDt = DataType.arrayFor(variable.datatype.sub!!.dt, false) return VarDecl( variable.type, variable.origin, normalDt, variable.zeropage, variable.arraysize, variable.name, emptyList(), variable.value?.copy(), variable.sharedWithAsm, false, variable.alignment, variable.dirty, variable.position diff --git a/compiler/src/prog8/compiler/astprocessing/NotExpressionAndIfComparisonExprChanger.kt b/compiler/src/prog8/compiler/astprocessing/NotExpressionAndIfComparisonExprChanger.kt index 942f8ea6d..9adae4521 100644 --- a/compiler/src/prog8/compiler/astprocessing/NotExpressionAndIfComparisonExprChanger.kt +++ b/compiler/src/prog8/compiler/astprocessing/NotExpressionAndIfComparisonExprChanger.kt @@ -6,7 +6,10 @@ import prog8.ast.expressions.* import prog8.ast.statements.IfElse import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -import prog8.code.core.* +import prog8.code.core.ICompilationTarget +import prog8.code.core.IErrorReporter +import prog8.code.core.invertedComparisonOperator +import prog8.code.core.isIntegerOrBool internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val errors: IErrorReporter, val compTarget: ICompilationTarget) : AstWalker() { @@ -15,7 +18,7 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val val left = expr.left as? BinaryExpression if (left != null) { val rightValue = expr.right.constValue(program) - if (rightValue?.number == 0.0 && rightValue.type in IntegerDatatypesWithBoolean) { + if (rightValue?.number == 0.0 && rightValue.type.isIntegerOrBool) { if (left.operator == "==" && expr.operator == "==") { // (x==something)==0 --> x!=something left.operator = "!=" @@ -58,14 +61,14 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val val rightC = expr.right as? BinaryExpression if(expr.operator=="and" && leftC!=null && rightC!=null && leftC.operator=="==" && rightC.operator=="==") { if (leftC.right.constValue(program)?.number == 0.0 && rightC.right.constValue(program)?.number == 0.0) { - val leftDt = leftC.left.inferType(program).getOr(DataType.UNDEFINED) - val rightDt = rightC.left.inferType(program).getOr(DataType.UNDEFINED) - if(leftDt==rightDt && leftDt in IntegerDatatypes) { + val leftDt = leftC.left.inferType(program).getOrUndef() + val rightDt = rightC.left.inferType(program).getOrUndef() + if(leftDt==rightDt && leftDt.isInteger) { if (rightC.left.isSimple) { // x==0 and y==0 -> (x | y)==0 // the 'or' case cannot be easily optimized with a binary and like this! val inner = BinaryExpression(leftC.left, "|", rightC.left, expr.position) - val compare = BinaryExpression(inner, "==", NumericLiteral(leftDt, 0.0, expr.position), expr.position) + val compare = BinaryExpression(inner, "==", NumericLiteral(leftDt.base, 0.0, expr.position), expr.position) return listOf(IAstModification.ReplaceNode(expr, compare, parent)) } } @@ -147,9 +150,10 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val // not(~x) -> x!=0 if((expr.expression as? PrefixExpression)?.operator=="~") { val x = (expr.expression as PrefixExpression).expression - val dt = x.inferType(program).getOr(DataType.UNDEFINED) - if(dt != DataType.UNDEFINED) { - val notZero = BinaryExpression(x, "!=", NumericLiteral(dt, 0.0, expr.position), expr.position) + val dt = x.inferType(program).getOrUndef() + if(!dt.isUndefined) { + require(dt.isNumeric) + val notZero = BinaryExpression(x, "!=", NumericLiteral(dt.base, 0.0, expr.position), expr.position) return listOf(IAstModification.ReplaceNode(expr, notZero, parent)) } } diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index ece22eca1..0782d36fb 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -5,7 +5,10 @@ import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -import prog8.code.core.* +import prog8.code.core.AssociativeOperators +import prog8.code.core.BaseDataType +import prog8.code.core.DataType +import prog8.code.core.IErrorReporter internal class StatementReorderer( val program: Program, @@ -46,7 +49,7 @@ internal class StatementReorderer( if(decl.dirty && decl.value!=null) errors.err("dirty variable can't have initialization value", decl.position) - if (decl.datatype in NumericDatatypes || decl.datatype==DataType.BOOL) { + if (decl.datatype.isNumericOrBool) { if(decl !in declsProcessedWithInitAssignment) { declsProcessedWithInitAssignment.add(decl) if (decl.value == null) { @@ -191,15 +194,15 @@ internal class StatementReorderer( } // change 'str' and 'ubyte[]' parameters into 'uword' (just treat it as an address) - val stringParams = subroutine.parameters.filter { it.type==DataType.STR || it.type==DataType.ARRAY_UB } + val stringParams = subroutine.parameters.filter { it.type.isString || it.type.isUnsignedByteArray } val parameterChanges = stringParams.map { - val uwordParam = SubroutineParameter(it.name, DataType.UWORD, it.zp, it.registerOrPair, it.position) + val uwordParam = SubroutineParameter(it.name, DataType.forDt(BaseDataType.UWORD), it.zp, it.registerOrPair, it.position) IAstModification.ReplaceNode(it, uwordParam, subroutine) } // change 'str' and 'ubyte[]' return types into 'uword' (just treat it as an address) subroutine.returntypes.withIndex().forEach { (index, type) -> - if(type==DataType.STR || type==DataType.ARRAY_UB) - subroutine.returntypes[index] = DataType.UWORD + if(type.isString || type.isUnsignedByteArray) + subroutine.returntypes[index] = DataType.forDt(BaseDataType.UWORD) } val varsChanges = mutableListOf() @@ -212,7 +215,7 @@ internal class StatementReorderer( .filterIsInstance() .filter { it.origin==VarDeclOrigin.SUBROUTINEPARAM && it.name in stringParamsByNames } .map { - val newvar = VarDecl(it.type, it.origin, DataType.UWORD, + val newvar = VarDecl(it.type, it.origin, DataType.forDt(BaseDataType.UWORD), it.zeropage, null, it.name, @@ -269,7 +272,7 @@ internal class StatementReorderer( } if(!assignment.isAugmentable) { - if (valueType istype DataType.STR && targetType istype DataType.STR) { + if (valueType issimpletype BaseDataType.STR && targetType issimpletype BaseDataType.STR) { // replace string assignment by a call to stringcopy return copyStringValue(assignment) } @@ -321,8 +324,8 @@ internal class StatementReorderer( } else { if (sourceVar.arraysize!!.constIndex() != targetVar.arraysize!!.constIndex()) errors.err("array size mismatch (expecting ${targetVar.arraysize!!.constIndex()}, got ${sourceVar.arraysize!!.constIndex()})", assign.value.position) - val sourceEltDt = ArrayToElementTypes.getValue(sourceVar.datatype) - val targetEltDt = ArrayToElementTypes.getValue(targetVar.datatype) + val sourceEltDt = sourceVar.datatype.elementType() + val targetEltDt = targetVar.datatype.elementType() if (!sourceEltDt.equalsSize(targetEltDt)) { errors.err("element size mismatch", assign.position) } diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index 7160b5288..77da78fce 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -22,13 +22,13 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val declValue = decl.value if(decl.type== VarDeclType.VAR && declValue!=null) { val valueDt = declValue.inferType(program) - if(valueDt isnot decl.datatype) { + if(!(valueDt istype decl.datatype)) { if(valueDt.isInteger && decl.isArray) { - if(decl.datatype == DataType.ARRAY_BOOL) { + if(decl.datatype.isBoolArray) { val integer = declValue.constValue(program)?.number if(integer!=null) { - val num = NumericLiteral(DataType.BOOL, if(integer==0.0) 0.0 else 1.0, declValue.position) + val num = NumericLiteral(BaseDataType.BOOL, if(integer==0.0) 0.0 else 1.0, declValue.position) num.parent = decl decl.value = num } @@ -42,7 +42,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val return noModifications val modifications = mutableListOf() - addTypecastOrCastedValueModification(modifications, declValue, decl.datatype, decl) + addTypecastOrCastedValueModification(modifications, declValue, decl.datatype.base, decl) return modifications } } @@ -62,10 +62,10 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val leftConst = expr.left.constValue(program) if(leftConst!=null) { val leftConstAsWord = - if(leftDt.istype(DataType.UBYTE)) - NumericLiteral(DataType.UWORD, leftConst.number, leftConst.position) + if(leftDt issimpletype BaseDataType.UBYTE) + NumericLiteral(BaseDataType.UWORD, leftConst.number, leftConst.position) else - NumericLiteral(DataType.WORD, leftConst.number, leftConst.position) + NumericLiteral(BaseDataType.WORD, leftConst.number, leftConst.position) val modifications = mutableListOf() if (parent is Assignment) { if (parent.target.inferType(program).isWords) { @@ -73,7 +73,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val // if(rightDt.isBytes) // modifications += IAstModification.ReplaceNode(expr.right, TypecastExpression(expr.right, leftConstAsWord.type, true, expr.right.position), expr) } - } else if (parent is TypecastExpression && parent.type == DataType.UWORD && parent.parent is Assignment) { + } else if (parent is TypecastExpression && parent.type == BaseDataType.UWORD && parent.parent is Assignment) { val assign = parent.parent as Assignment if (assign.target.inferType(program).isWords) { modifications += IAstModification.ReplaceNode(expr.left, leftConstAsWord, expr) @@ -93,47 +93,47 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val value = if(rightDt.isBytes) 256+leftCv.number else 65536+leftCv.number return listOf(IAstModification.ReplaceNode( expr.left, - NumericLiteral(rightDt.getOr(DataType.UNDEFINED), value, expr.left.position), + NumericLiteral(rightDt.getOrUndef().base, value, expr.left.position), expr)) } if(rightCv!=null && rightCv.number<0) { val value = if(leftDt.isBytes) 256+rightCv.number else 65536+rightCv.number return listOf(IAstModification.ReplaceNode( expr.right, - NumericLiteral(leftDt.getOr(DataType.UNDEFINED), value, expr.right.position), + NumericLiteral(leftDt.getOrUndef().base, value, expr.right.position), expr)) } - if(leftDt istype DataType.BYTE && rightDt.oneOf(DataType.UBYTE, DataType.UWORD)) { + if(leftDt issimpletype BaseDataType.BYTE && (rightDt issimpletype BaseDataType.UBYTE || rightDt issimpletype BaseDataType.UWORD)) { // cast left to unsigned - val cast = TypecastExpression(expr.left, rightDt.getOr(DataType.UNDEFINED), true, expr.left.position) + val cast = TypecastExpression(expr.left, rightDt.getOrUndef().base, true, expr.left.position) return listOf(IAstModification.ReplaceNode(expr.left, cast, expr)) } - if(leftDt istype DataType.WORD && rightDt.oneOf(DataType.UBYTE, DataType.UWORD)) { + if(leftDt issimpletype BaseDataType.WORD && (rightDt issimpletype BaseDataType.UBYTE || rightDt issimpletype BaseDataType.UWORD)) { // cast left to unsigned word. Cast right to unsigned word if it is ubyte val mods = mutableListOf() - val cast = TypecastExpression(expr.left, DataType.UWORD, true, expr.left.position) + val cast = TypecastExpression(expr.left, BaseDataType.UWORD, true, expr.left.position) mods += IAstModification.ReplaceNode(expr.left, cast, expr) - if(rightDt istype DataType.UBYTE) { + if(rightDt issimpletype BaseDataType.UBYTE) { mods += IAstModification.ReplaceNode(expr.right, - TypecastExpression(expr.right, DataType.UWORD, true, expr.right.position), + TypecastExpression(expr.right, BaseDataType.UWORD, true, expr.right.position), expr) } return mods } - if(rightDt istype DataType.BYTE && leftDt.oneOf(DataType.UBYTE, DataType.UWORD)) { + if(rightDt issimpletype BaseDataType.BYTE && (leftDt issimpletype BaseDataType.UBYTE || leftDt issimpletype BaseDataType.UWORD)) { // cast right to unsigned - val cast = TypecastExpression(expr.right, leftDt.getOr(DataType.UNDEFINED), true, expr.right.position) + val cast = TypecastExpression(expr.right, leftDt.getOrUndef().base, true, expr.right.position) return listOf(IAstModification.ReplaceNode(expr.right, cast, expr)) } - if(rightDt istype DataType.WORD && leftDt.oneOf(DataType.UBYTE, DataType.UWORD)) { + if(rightDt issimpletype BaseDataType.WORD && (leftDt issimpletype BaseDataType.UBYTE || leftDt issimpletype BaseDataType.UWORD)) { // cast right to unsigned word. Cast left to unsigned word if it is ubyte val mods = mutableListOf() - val cast = TypecastExpression(expr.right, DataType.UWORD, true, expr.right.position) + val cast = TypecastExpression(expr.right, BaseDataType.UWORD, true, expr.right.position) mods += IAstModification.ReplaceNode(expr.right, cast, expr) - if(leftDt istype DataType.UBYTE) { + if(leftDt issimpletype BaseDataType.UBYTE) { mods += IAstModification.ReplaceNode(expr.left, - TypecastExpression(expr.left, DataType.UWORD, true, expr.left.position), + TypecastExpression(expr.left, BaseDataType.UWORD, true, expr.left.position), expr) } return mods @@ -143,16 +143,16 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val if((expr.operator!="<<" && expr.operator!=">>") || !leftDt.isWords || !rightDt.isBytes) { // determine common datatype and add typecast as required to make left and right equal types - val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt.getOr(DataType.UNDEFINED), rightDt.getOr(DataType.UNDEFINED), expr.left, expr.right) + val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt.getOrUndef(), rightDt.getOrUndef(), expr.left, expr.right) if(toFix!=null) { - if(commonDt==DataType.BOOL) { + if(commonDt.isBool) { // don't automatically cast to bool errors.err("left and right operands aren't the same type: $leftDt vs $rightDt", expr.position) } else { val modifications = mutableListOf() when { - toFix===expr.left -> addTypecastOrCastedValueModification(modifications, expr.left, commonDt, expr) - toFix===expr.right -> addTypecastOrCastedValueModification(modifications, expr.right, commonDt, expr) + toFix===expr.left -> addTypecastOrCastedValueModification(modifications, expr.left, commonDt.base, expr) + toFix===expr.right -> addTypecastOrCastedValueModification(modifications, expr.right, commonDt.base, expr) else -> throw FatalAstException("confused binary expression side") } return modifications @@ -170,19 +170,19 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val valueItype = assignment.value.inferType(program) val targetItype = assignment.target.inferType(program) if(targetItype.isKnown && valueItype.isKnown) { - val targettype = targetItype.getOr(DataType.UNDEFINED) - val valuetype = valueItype.getOr(DataType.UNDEFINED) + val targettype = targetItype.getOrUndef() + val valuetype = valueItype.getOrUndef() if (valuetype != targettype) { if (valuetype isAssignableTo targettype) { - if(valuetype in IterableDatatypes && targettype==DataType.UWORD) + if(valuetype.isIterable && targettype.isUnsignedWord) // special case, don't typecast STR/arrays to UWORD, we support those assignments "directly" return noModifications val modifications = mutableListOf() - addTypecastOrCastedValueModification(modifications, assignment.value, targettype, assignment) + addTypecastOrCastedValueModification(modifications, assignment.value, targettype.base, assignment) return modifications } else { fun castLiteral(cvalue2: NumericLiteral): List { - val cast = cvalue2.cast(targettype, true) + val cast = cvalue2.cast(targettype.base, true) return if(cast.isValid) listOf(IAstModification.ReplaceNode(assignment.value, cast.valueOrZero(), assignment)) else @@ -211,7 +211,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val modifications = mutableListOf() val params = when(val sub = call.target.targetStatement(program)) { is BuiltinFunctionPlaceholder -> BuiltinFunctions.getValue(sub.name).parameters.toList() - is Subroutine -> sub.parameters.map { FParam(it.name, it.type) } + is Subroutine -> sub.parameters.map { FParam(it.name, it.type.base) } else -> emptyList() } @@ -219,17 +219,17 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val targetDt = it.first.possibleDatatypes.first() val argIdt = it.second.inferType(program) if (argIdt.isKnown) { - val argDt = argIdt.getOr(DataType.UNDEFINED) - if (argDt !in it.first.possibleDatatypes) { + val argDt = argIdt.getOrUndef() + if (argDt.base !in it.first.possibleDatatypes) { val identifier = it.second as? IdentifierReference val number = it.second as? NumericLiteral if(number!=null) { addTypecastOrCastedValueModification(modifications, it.second, targetDt, call as Node) - } else if(identifier!=null && targetDt==DataType.UWORD && argDt in PassByReferenceDatatypes) { + } else if(identifier!=null && targetDt==BaseDataType.UWORD && argDt.isPassByRef) { if(!identifier.isSubroutineParameter(program)) { // We allow STR/ARRAY values for UWORD parameters. // If it's an array (not STR), take the address. - if(argDt != DataType.STR) { + if(!argDt.isString) { modifications += IAstModification.ReplaceNode( identifier, AddressOf(identifier, null, it.second.position), @@ -237,16 +237,16 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val ) } } - } else if(targetDt==DataType.BOOL) { - addTypecastOrCastedValueModification(modifications, it.second, DataType.BOOL, call as Node) - } else if(argDt isAssignableTo targetDt) { - if(argDt!=DataType.STR || targetDt!=DataType.UWORD) + } else if(targetDt==BaseDataType.BOOL) { + addTypecastOrCastedValueModification(modifications, it.second, BaseDataType.BOOL, call as Node) + } else if(argDt isAssignableTo DataType.forDt(targetDt)) { + if(!argDt.isString || targetDt!=BaseDataType.UWORD) addTypecastOrCastedValueModification(modifications, it.second, targetDt, call as Node) } } } else { val identifier = it.second as? IdentifierReference - if(identifier!=null && targetDt==DataType.UWORD) { + if(identifier!=null && targetDt==BaseDataType.UWORD) { // take the address of the identifier modifications += IAstModification.ReplaceNode( identifier, @@ -261,7 +261,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val override fun after(typecast: TypecastExpression, parent: Node): Iterable { // warn about any implicit type casts to Float, because that may not be intended - if(typecast.implicit && typecast.type.oneOf(DataType.FLOAT, DataType.ARRAY_F)) { + if(typecast.implicit && typecast.type==BaseDataType.FLOAT) { if(options.floats) errors.info("integer implicitly converted to float. Suggestion: use float literals, add an explicit cast, or revert to integer arithmetic", typecast.position) else @@ -275,12 +275,12 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val // make sure the memory address is an uword val modifications = mutableListOf() val dt = memread.addressExpression.inferType(program) - if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) { - val castedValue = (memread.addressExpression as? NumericLiteral)?.cast(DataType.UWORD, true)?.valueOrZero() + if(dt.isKnown && !dt.getOr(DataType.forDt(BaseDataType.UWORD)).isUnsignedWord) { + val castedValue = (memread.addressExpression as? NumericLiteral)?.cast(BaseDataType.UWORD, true)?.valueOrZero() if(castedValue!=null) modifications += IAstModification.ReplaceNode(memread.addressExpression, castedValue, memread) else - addTypecastOrCastedValueModification(modifications, memread.addressExpression, DataType.UWORD, memread) + addTypecastOrCastedValueModification(modifications, memread.addressExpression, BaseDataType.UWORD, memread) } return modifications } @@ -289,12 +289,12 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val // make sure the memory address is an uword val modifications = mutableListOf() val dt = memwrite.addressExpression.inferType(program) - if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) { - val castedValue = (memwrite.addressExpression as? NumericLiteral)?.cast(DataType.UWORD, true)?.valueOrZero() + if(dt.isKnown && !dt.getOr(DataType.forDt(BaseDataType.UWORD)).isUnsignedWord) { + val castedValue = (memwrite.addressExpression as? NumericLiteral)?.cast(BaseDataType.UWORD, true)?.valueOrZero() if(castedValue!=null) modifications += IAstModification.ReplaceNode(memwrite.addressExpression, castedValue, memwrite) else - addTypecastOrCastedValueModification(modifications, memwrite.addressExpression, DataType.UWORD, memwrite) + addTypecastOrCastedValueModification(modifications, memwrite.addressExpression, BaseDataType.UWORD, memwrite) } return modifications } @@ -308,9 +308,9 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val if(subroutine.returntypes.size==1) { val subReturnType = subroutine.returntypes.first() val returnDt = returnValue.inferType(program) - if(returnDt isnot subReturnType && returnValue is NumericLiteral) { + if(!(returnDt istype subReturnType) && returnValue is NumericLiteral) { // see if we might change the returnvalue into the expected type - val castedValue = returnValue.convertTypeKeepValue(subReturnType) + val castedValue = returnValue.convertTypeKeepValue(subReturnType.base) if(castedValue.isValid) { return listOf(IAstModification.ReplaceNode(returnValue, castedValue.valueOrZero(), returnStmt)) } @@ -318,12 +318,12 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val if (returnDt istype subReturnType or returnDt.isNotAssignableTo(subReturnType)) return noModifications if (returnValue is NumericLiteral) { - val cast = returnValue.cast(subReturnType, true) + val cast = returnValue.cast(subReturnType.base, true) if(cast.isValid) returnStmt.value = cast.valueOrZero() } else { val modifications = mutableListOf() - addTypecastOrCastedValueModification(modifications, returnValue, subReturnType, returnStmt) + addTypecastOrCastedValueModification(modifications, returnValue, subReturnType.base, returnStmt) return modifications } } @@ -338,7 +338,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val values?.toTypedArray()?.withIndex()?.forEach { (index, value) -> val valueDt = value.inferType(program) if(valueDt.isKnown && valueDt!=conditionDt) { - val castedValue = value.typecastTo(conditionDt.getOr(DataType.UNDEFINED), valueDt.getOr(DataType.UNDEFINED), true) + val castedValue = value.typecastTo(conditionDt.getOrUndef().base, valueDt.getOrUndef(), true) if(castedValue.first) { castedValue.second.linkParents(whenChoice) values[index] = castedValue.second @@ -350,8 +350,8 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val } override fun after(range: RangeExpression, parent: Node): Iterable { - val fromDt = range.from.inferType(program).getOr(DataType.UNDEFINED) - val toDt = range.to.inferType(program).getOr(DataType.UNDEFINED) + val fromDt = range.from.inferType(program).getOrUndef() + val toDt = range.to.inferType(program).getOrUndef() val fromConst = range.from.constValue(program) val toConst = range.to.constValue(program) val varDt = if (parent is ContainmentCheck) @@ -360,7 +360,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val parent.loopVarDt(program) else InferredTypes.InferredType.unknown() - return adjustRangeDts(range, fromConst, fromDt, toConst, toDt, varDt.getOr(DataType.UNDEFINED), parent) + return adjustRangeDts(range, fromConst, fromDt, toConst, toDt, varDt.getOrUndef(), parent) } override fun after(array: ArrayLiteral, parent: Node): Iterable { @@ -371,7 +371,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val if (elt is IdentifierReference) { val eltType = elt.inferType(program) val tgt = elt.targetStatement(program) - if(eltType.isPassByReference || tgt is Subroutine || tgt is Label || tgt is Block) { + if(eltType.isIterable || tgt is Subroutine || tgt is Label || tgt is Block) { val addressof = AddressOf(elt, null, elt.position) addressof.linkParents(array) array.value[index] = addressof @@ -387,14 +387,14 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val falseDt = ifExpr.falsevalue.inferType(program) if (trueDt != falseDt) { val (commonDt, toFix) = BinaryExpression.commonDatatype( - trueDt.getOr(DataType.UNDEFINED), - falseDt.getOr(DataType.UNDEFINED), + trueDt.getOrUndef(), + falseDt.getOrUndef(), ifExpr.truevalue, ifExpr.falsevalue ) if (toFix != null) { val modifications = mutableListOf() - addTypecastOrCastedValueModification(modifications, toFix, commonDt, ifExpr) + addTypecastOrCastedValueModification(modifications, toFix, commonDt.base, ifExpr) return modifications } } @@ -411,7 +411,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val parent: Node ): List { - if(varDt!=DataType.UNDEFINED) { + if(!varDt.isUndefined) { if(fromDt==varDt && toDt==varDt) { return noModifications } else if(fromDt==toDt && fromDt.isAssignableTo(varDt)) { @@ -421,9 +421,9 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val if(fromConst!=null) { val smaller = NumericLiteral.optimalInteger(fromConst.number.toInt(), fromConst.position) - if(fromDt.largerThan(smaller.type)) { + if(fromDt.base.largerSizeThan(smaller.type)) { val toType = range.to.inferType(program) - if(toType isnot smaller.type) { + if(!(toType issimpletype smaller.type)) { if(toConst!=null) { // can we make the to value into the same smaller type? val smallerTo = NumericLiteral.optimalInteger(toConst.number.toInt(), toConst.position) @@ -440,9 +440,9 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val } if(toConst!=null) { val smaller = NumericLiteral.optimalInteger(toConst.number.toInt(), toConst.position) - if(toDt.largerThan(smaller.type)) { + if(toDt.base.largerSizeThan(smaller.type)) { val fromType = range.from.inferType(program) - if(fromType isnot smaller.type) { + if(!(fromType issimpletype smaller.type)) { if(fromConst!=null) { // can we make the from value into the same smaller type? val smallerFrom = NumericLiteral.optimalInteger(fromConst.number.toInt(), fromConst.position) @@ -461,7 +461,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val modifications = mutableListOf() val (commonDt, toChange) = BinaryExpression.commonDatatype(fromDt, toDt, range.from, range.to) if(toChange!=null) - addTypecastOrCastedValueModification(modifications, toChange, commonDt, range) + addTypecastOrCastedValueModification(modifications, toChange, commonDt.base, range) return modifications } @@ -470,8 +470,8 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val constIdx = arrayIndexedExpression.indexer.constIndex() if(constIdx!=null) { val smaller = NumericLiteral.optimalInteger(constIdx, arrayIndexedExpression.indexer.position) - val idxDt = arrayIndexedExpression.indexer.indexExpr.inferType(program).getOr(DataType.UNDEFINED) - if(idxDt.largerThan(smaller.type)) { + val idxDt = arrayIndexedExpression.indexer.indexExpr.inferType(program).getOrUndef() + if(idxDt.base.largerSizeThan(smaller.type)) { val newIdx = ArrayIndex(smaller, smaller.position) val newIndexer = ArrayIndexedExpression(arrayIndexedExpression.arrayvar, newIdx, arrayIndexedExpression.position) return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, newIndexer, parent)) @@ -483,16 +483,15 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val private fun addTypecastOrCastedValueModification( modifications: MutableList, expressionToCast: Expression, - requiredType: DataType, + requiredType: BaseDataType, parent: Node ) { - val sourceDt = expressionToCast.inferType(program).getOr(DataType.UNDEFINED) - if(sourceDt == requiredType) + val sourceDt = expressionToCast.inferType(program).getOrUndef() + if(sourceDt.base == requiredType) return - if(requiredType==DataType.BOOL) { + if(requiredType == BaseDataType.BOOL) return - } - if(expressionToCast is NumericLiteral && expressionToCast.type!=DataType.FLOAT) { // refuse to automatically truncate floats + if(expressionToCast is NumericLiteral && expressionToCast.type!=BaseDataType.FLOAT) { // refuse to automatically truncate floats val castedValue = expressionToCast.cast(requiredType, true) if (castedValue.isValid) { val signOriginal = sign(expressionToCast.number) diff --git a/compiler/src/prog8/compiler/astprocessing/Utility.kt b/compiler/src/prog8/compiler/astprocessing/Utility.kt index 31ce47048..b984caa29 100644 --- a/compiler/src/prog8/compiler/astprocessing/Utility.kt +++ b/compiler/src/prog8/compiler/astprocessing/Utility.kt @@ -4,39 +4,40 @@ import prog8.ast.base.FatalAstException import prog8.code.ast.PtExpression import prog8.code.ast.PtFunctionCall import prog8.code.ast.PtTypeCast +import prog8.code.core.BaseDataType import prog8.code.core.DataType -import prog8.code.core.PassByReferenceDatatypes internal fun makePushPopFunctionCalls(value: PtExpression): Pair { - var popTypecast: DataType? = null - var pushTypecast: DataType? = null + var popTypecast: BaseDataType? = null + var pushTypecast: BaseDataType? = null var pushWord = false var pushFloat = false - when(value.type) { - DataType.BOOL -> { - pushTypecast = DataType.UBYTE - popTypecast = DataType.BOOL + when { + value.type.isBool -> { + pushTypecast = BaseDataType.UBYTE + popTypecast = BaseDataType.BOOL } - DataType.BYTE -> { - pushTypecast = DataType.UBYTE - popTypecast = DataType.BYTE + value.type.isSignedByte -> { + pushTypecast = BaseDataType.UBYTE + popTypecast = BaseDataType.BYTE } - DataType.WORD -> { + value.type.isSignedWord -> { pushWord = true - pushTypecast = DataType.UWORD - popTypecast = DataType.WORD + pushTypecast = BaseDataType.UWORD + popTypecast = BaseDataType.WORD } - DataType.UBYTE -> {} - DataType.UWORD, in PassByReferenceDatatypes -> pushWord = true - DataType.FLOAT -> pushFloat = true + value.type.isUnsignedByte -> {} + value.type.isUnsignedWord -> pushWord = true + value.type.isPassByRef -> pushWord = true + value.type.isFloat -> pushFloat = true else -> throw FatalAstException("unsupported return value type ${value.type} with defer") } val pushFunc = if(pushFloat) "floats.push" else if(pushWord) "sys.pushw" else "sys.push" val popFunc = if(pushFloat) "floats.pop" else if(pushWord) "sys.popw" else "sys.pop" - val pushCall = PtFunctionCall(pushFunc, true, DataType.UNDEFINED, value.position) + val pushCall = PtFunctionCall(pushFunc, true, DataType.forDt(BaseDataType.UNDEFINED), value.position) if(pushTypecast!=null) { val typecast = PtTypeCast(pushTypecast, value.position).also { it.add(value) @@ -47,7 +48,8 @@ internal fun makePushPopFunctionCalls(value: PtExpression): Pair { if(decl.isArray) { errors.err("value has incompatible type ($valueType) for the variable (${decl.datatype})", decl.value!!.position) } else { - if (valueDt.largerThan(decl.datatype)) { + if (valueDt.largerSizeThan(decl.datatype)) { val constValue = decl.value?.constValue(program) if (constValue != null) errors.err("value '$constValue' out of range for ${decl.datatype}", constValue.position) @@ -51,13 +51,13 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, } VarDeclType.CONST -> { // change the vardecl type itself as well, but only if new type is smaller - if(valueDt.largerThan(decl.datatype)) { + if(valueDt.largerSizeThan(decl.datatype)) { val constValue = decl.value!!.constValue(program)!! errors.err("value '${constValue.number}' out of range for ${decl.datatype}", constValue.position) } else { // don't make it signed if it was unsigned and vice versa - if(valueDt in SignedDatatypes && decl.datatype !in SignedDatatypes || - valueDt !in SignedDatatypes && decl.datatype in SignedDatatypes) { + if(valueDt.isSigned && decl.datatype.isUnsigned || + valueDt.isUnsigned && decl.datatype.isSigned) { val constValue = decl.value!!.constValue(program)!! errors.err("value '${constValue.number}' out of range for ${decl.datatype}", constValue.position) } else { @@ -105,12 +105,12 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, } val sourceDt = typecast.expression.inferType(program) - if(sourceDt istype typecast.type) + if(sourceDt issimpletype typecast.type) return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent)) if(parent is Assignment) { - val targetDt = parent.target.inferType(program).getOr(DataType.UNDEFINED) - if(targetDt!=DataType.UNDEFINED && sourceDt istype targetDt) { + val targetDt = parent.target.inferType(program).getOrUndef() + if(!targetDt.isUndefined && sourceDt istype targetDt) { // we can get rid of this typecast because the type is already the target type return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent)) } @@ -160,7 +160,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, // ^ X --> 0 (X is word or byte) val valueDt = expr.expression.inferType(program) if(valueDt.isBytes || valueDt.isWords) { - val zero = NumericLiteral(DataType.UBYTE, 0.0, expr.expression.position) + val zero = NumericLiteral(BaseDataType.UBYTE, 0.0, expr.expression.position) return listOf(IAstModification.ReplaceNode(expr, zero, parent)) } } @@ -204,17 +204,17 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, if(isMultiComparisonRecurse(leftBinExpr1)) { val elementIType = needle.inferType(program) if(elementIType.isUnknown) return noModifications - val elementType = elementIType.getOrElse { DataType.UNDEFINED } - if(values.size==2 || values.size==3 && (elementType==DataType.UBYTE || elementType==DataType.UWORD)) { + val elementType = elementIType.getOrUndef() + if(values.size==2 || values.size==3 && (elementType.isUnsignedByte || elementType.isUnsignedWord)) { val numbers = values.map{it.number}.toSet() if(numbers == setOf(0.0, 1.0)) { // we can replace unsigned x==0 or x==1 with x<2 - val compare = BinaryExpression(needle, "<", NumericLiteral(elementType, 2.0, expr.position), expr.position) + val compare = BinaryExpression(needle, "<", NumericLiteral(elementType.base, 2.0, expr.position), expr.position) return listOf(IAstModification.ReplaceNode(expr, compare, parent)) } if(numbers == setOf(0.0, 1.0, 2.0)) { // we can replace unsigned x==0 or x==1 or x==2 with x<3 - val compare = BinaryExpression(needle, "<", NumericLiteral(elementType, 3.0, expr.position), expr.position) + val compare = BinaryExpression(needle, "<", NumericLiteral(elementType.base, 3.0, expr.position), expr.position) return listOf(IAstModification.ReplaceNode(expr, compare, parent)) } } @@ -223,7 +223,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, // replace x==1 or x==2 or x==3 with a containment check x in [1,2,3] val valueCopies = values.sortedBy { it.number }.map { it.copy() } - val arrayType = ElementToArrayTypes.getValue(elementType) + val arrayType = DataType.arrayFor(elementType.base) val valuesArray = ArrayLiteral(InferredTypes.InferredType.known(arrayType), valueCopies.toTypedArray(), expr.position) val containment = ContainmentCheck(needle, valuesArray, expr.position) return listOf(IAstModification.ReplaceNode(expr, containment, parent)) @@ -265,7 +265,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, fun replaceWithFalse(): Iterable { errors.warn("condition is always false", containment.position) - return listOf(IAstModification.ReplaceNode(containment, NumericLiteral(DataType.UBYTE, 0.0, containment.position), parent)) + return listOf(IAstModification.ReplaceNode(containment, NumericLiteral(BaseDataType.UBYTE, 0.0, containment.position), parent)) } fun checkArray(array: Array): Iterable { @@ -301,7 +301,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, return replaceWithFalse() if(stringVal.value.length==1) { val string = program.encoding.encodeString(stringVal.value, stringVal.encoding) - return replaceWithEquals(NumericLiteral(DataType.UBYTE, string[0].toDouble(), stringVal.position)) + return replaceWithEquals(NumericLiteral(BaseDataType.UBYTE, string[0].toDouble(), stringVal.position)) } return noModifications } @@ -370,7 +370,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, if(name==listOf("msw")) { val valueDt = functionCallExpr.args[0].inferType(program) if(valueDt.isWords || valueDt.isBytes) { - val zero = NumericLiteral(DataType.UWORD, 0.0, functionCallExpr.position) + val zero = NumericLiteral(BaseDataType.UWORD, 0.0, functionCallExpr.position) return listOf(IAstModification.ReplaceNode(functionCallExpr, zero, parent)) } } else if(name==listOf("lsw")) { @@ -378,7 +378,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, if(valueDt.isWords) return listOf(IAstModification.ReplaceNode(functionCallExpr, functionCallExpr.args[0], parent)) if(valueDt.isBytes) { - val cast = TypecastExpression(functionCallExpr.args[0], DataType.UWORD, true, functionCallExpr.position) + val cast = TypecastExpression(functionCallExpr.args[0], BaseDataType.UWORD, true, functionCallExpr.position) return listOf(IAstModification.ReplaceNode(functionCallExpr, cast, parent)) } } diff --git a/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt b/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt index 295fc6eab..4e6a1c33e 100644 --- a/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt +++ b/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt @@ -76,10 +76,10 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila return true // there are some exceptions that are considered compatible, such as STR <> UWORD - if(argDt==DataType.STR && paramDt==DataType.UWORD || - argDt==DataType.UWORD && paramDt==DataType.STR || - argDt==DataType.UWORD && paramDt==DataType.ARRAY_UB || - argDt==DataType.STR && paramDt==DataType.ARRAY_UB) + if(argDt.isString && paramDt.isUnsignedWord || + argDt.isUnsignedWord && paramDt.isString || + argDt.isUnsignedWord && paramDt.isUnsignedByteArray || + argDt.isString && paramDt.isUnsignedByteArray) return true return false @@ -95,7 +95,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila else null } - val argtypes = argITypes.map { it.getOr(DataType.UNDEFINED) } + val argtypes = argITypes.map { it.getOrUndef() } val target = call.target.targetStatement(program) if (target is Subroutine) { val consideredParamTypes: List = target.parameters.map { it.type } @@ -132,7 +132,12 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila if(argtypes.size != consideredParamTypes.size) return Pair("invalid number of arguments", call.position) argtypes.zip(consideredParamTypes).forEachIndexed { index, pair -> - val anyCompatible = pair.second.any { argTypeCompatible(pair.first, it) } + val anyCompatible = pair.second.any { + if(it.isArray) + pair.first.isArray + else + argTypeCompatible(pair.first, DataType.forDt(it)) + } if (!anyCompatible) { val actual = pair.first return if(pair.second.size==1) { diff --git a/compiler/test/TestBuiltinFunctions.kt b/compiler/test/TestBuiltinFunctions.kt index e55eb9fc8..e15acd6ea 100644 --- a/compiler/test/TestBuiltinFunctions.kt +++ b/compiler/test/TestBuiltinFunctions.kt @@ -1,15 +1,16 @@ package prog8tests.compiler import io.kotest.core.spec.style.FunSpec +import io.kotest.inspectors.shouldForAll import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import prog8.ast.expressions.NumericLiteral import prog8.ast.statements.Assignment import prog8.ast.statements.FunctionCallStatement +import prog8.code.core.BaseDataType import prog8.code.core.BuiltinFunctions -import prog8.code.core.DataType -import prog8.code.core.NumericDatatypes import prog8.code.core.RegisterOrPair +import prog8.code.core.isNumeric import prog8.code.target.Cx16Target import prog8tests.helpers.compileText @@ -19,16 +20,16 @@ class TestBuiltinFunctions: FunSpec({ val func = BuiltinFunctions.getValue("sgn") func.parameters.size shouldBe 1 func.parameters[0].name shouldBe "value" - func.parameters[0].possibleDatatypes shouldBe NumericDatatypes + func.parameters[0].possibleDatatypes. shouldForAll { it.isNumeric } func.pure shouldBe true - func.returnType shouldBe DataType.BYTE + func.returnType shouldBe BaseDataType.BYTE - val conv = func.callConvention(listOf(DataType.UBYTE)) + val conv = func.callConvention(listOf(BaseDataType.UBYTE)) conv.params.size shouldBe 1 - conv.params[0].dt shouldBe DataType.UBYTE + conv.params[0].dt shouldBe BaseDataType.UBYTE conv.params[0].reg shouldBe RegisterOrPair.A conv.params[0].variable shouldBe false - conv.returns.dt shouldBe DataType.BYTE + conv.returns.dt shouldBe BaseDataType.BYTE conv.returns.reg shouldBe RegisterOrPair.A } @@ -38,7 +39,7 @@ class TestBuiltinFunctions: FunSpec({ func.pure shouldBe false func.returnType shouldBe null - val conv = func.callConvention(listOf(DataType.UWORD, DataType.UWORD)) + val conv = func.callConvention(listOf(BaseDataType.UWORD, BaseDataType.UWORD)) conv.params.size shouldBe 2 conv.returns.dt shouldBe null conv.returns.reg shouldBe null @@ -48,9 +49,9 @@ class TestBuiltinFunctions: FunSpec({ val func = BuiltinFunctions.getValue("poke") func.parameters.size shouldBe 2 func.parameters[0].name shouldBe "address" - func.parameters[0].possibleDatatypes shouldBe arrayOf(DataType.UWORD) + func.parameters[0].possibleDatatypes shouldBe arrayOf(BaseDataType.UWORD) func.parameters[1].name shouldBe "value" - func.parameters[1].possibleDatatypes shouldBe arrayOf(DataType.UBYTE) + func.parameters[1].possibleDatatypes shouldBe arrayOf(BaseDataType.UBYTE) func.pure shouldBe false func.returnType shouldBe null } diff --git a/compiler/test/TestCompilerOnCharLit.kt b/compiler/test/TestCompilerOnCharLit.kt index a3cb37922..cd99d3c68 100644 --- a/compiler/test/TestCompilerOnCharLit.kt +++ b/compiler/test/TestCompilerOnCharLit.kt @@ -14,6 +14,7 @@ import prog8.ast.statements.Assignment import prog8.ast.statements.AssignmentOrigin import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDeclType +import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.Encoding import prog8.code.target.Cx16Target @@ -53,7 +54,7 @@ class TestCompilerOnCharLit: FunSpec({ funCall.args[0] shouldBe instanceOf() } val arg = funCall.args[0] as NumericLiteral - arg.type shouldBe DataType.UBYTE + arg.type shouldBe BaseDataType.UBYTE arg.number shouldBe platform.encodeString("\n", Encoding.PETSCII)[0].toDouble() } @@ -77,7 +78,7 @@ class TestCompilerOnCharLit: FunSpec({ val arg = funCall.args[0] as IdentifierReference val decl = arg.targetVarDecl(program)!! decl.type shouldBe VarDeclType.VAR - decl.datatype shouldBe DataType.UBYTE + decl.datatype shouldBe DataType.forDt(BaseDataType.UBYTE) withClue("initializer value should have been moved to separate assignment"){ decl.value shouldBe null @@ -88,7 +89,7 @@ class TestCompilerOnCharLit: FunSpec({ assignInitialValue.value shouldBe instanceOf() } val initializerValue = assignInitialValue.value as NumericLiteral - initializerValue.type shouldBe DataType.UBYTE + initializerValue.type shouldBe BaseDataType.UBYTE initializerValue.number shouldBe platform.encodeString("\n", Encoding.PETSCII)[0].toDouble() } @@ -113,7 +114,7 @@ class TestCompilerOnCharLit: FunSpec({ is IdentifierReference -> { val decl = arg.targetVarDecl(program)!! decl.type shouldBe VarDeclType.CONST - decl.datatype shouldBe DataType.UBYTE + decl.datatype shouldBe DataType.forDt(BaseDataType.UBYTE) (decl.value as NumericLiteral).number shouldBe platform.encodeString("\n", Encoding.PETSCII)[0] } is NumericLiteral -> { diff --git a/compiler/test/TestCompilerOnRanges.kt b/compiler/test/TestCompilerOnRanges.kt index a976c79ef..515d9d85c 100644 --- a/compiler/test/TestCompilerOnRanges.kt +++ b/compiler/test/TestCompilerOnRanges.kt @@ -13,6 +13,7 @@ import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.RangeExpression import prog8.ast.statements.ForLoop import prog8.ast.statements.VarDecl +import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.Encoding import prog8.code.core.Position @@ -35,8 +36,7 @@ class TestCompilerOnRanges: FunSpec({ val result = compileText(platform, false, """ main { sub start() { - ubyte[] cs = sc:'a' to 'z' ; values are computed at compile time - cs[0] = 23 ; keep optimizer from removing it + ubyte[] @shared cs = sc:'a' to sc:'z' ; values are computed at compile time } } """)!! @@ -49,7 +49,7 @@ class TestCompilerOnRanges: FunSpec({ .value // Array .map { (it as NumericLiteral).number.toInt() } val expectedStart = platform.encodeString("a", Encoding.SCREENCODES)[0].toInt() - val expectedEnd = platform.encodeString("z", Encoding.PETSCII)[0].toInt() + val expectedEnd = platform.encodeString("z", Encoding.SCREENCODES)[0].toInt() val expectedStr = "$expectedStart .. $expectedEnd" val actualStr = "${rhsValues.first()} .. ${rhsValues.last()}" @@ -67,8 +67,7 @@ class TestCompilerOnRanges: FunSpec({ %import floats main { sub start() { - float[] cs = 'a' to 'z' ; values are computed at compile time - cs[0] = 23 ; keep optimizer from removing it + float[] @shared cs = 'a' to 'z' ; values are computed at compile time } } """)!! @@ -117,8 +116,7 @@ class TestCompilerOnRanges: FunSpec({ $optEnableFloats main { sub start() { - float[$sizeInDecl] cs = 1 to 42 ; values are computed at compile time - cs[0] = 23 ; keep optimizer from removing it + float[$sizeInDecl] @shared cs = 1 to 42 ; values are computed at compile time } } """) @@ -227,7 +225,7 @@ class TestCompilerOnRanges: FunSpec({ .map { it.iterable } .filterIsInstance()[0] - iterable.inferType(program).getOr(DataType.UNDEFINED) shouldBe DataType.STR + iterable.inferType(program).getOrUndef() shouldBe DataType.forDt(BaseDataType.STR) } test("testRangeExprNumericSize") { @@ -266,7 +264,7 @@ class TestCompilerOnRanges: FunSpec({ (array as ArrayLiteral).value.size shouldBe 26 val forloop = (statements.dropLast(1).last() as ForLoop) forloop.iterable shouldBe instanceOf() - (forloop.iterable as RangeExpression).step shouldBe NumericLiteral(DataType.BYTE, -2.0, Position.DUMMY) + (forloop.iterable as RangeExpression).step shouldBe NumericLiteral(BaseDataType.BYTE, -2.0, Position.DUMMY) } test("range with start/end variables should be ok") { @@ -285,7 +283,7 @@ class TestCompilerOnRanges: FunSpec({ val statements = result.compilerAst.entrypoint.statements val forloop = (statements.dropLast(1).last() as ForLoop) forloop.iterable shouldBe instanceOf() - (forloop.iterable as RangeExpression).step shouldBe NumericLiteral(DataType.BYTE, -2.0, Position.DUMMY) + (forloop.iterable as RangeExpression).step shouldBe NumericLiteral(BaseDataType.BYTE, -2.0, Position.DUMMY) } diff --git a/compiler/test/TestGoldenRam.kt b/compiler/test/TestGoldenRam.kt index 3918ac642..3c275c46a 100644 --- a/compiler/test/TestGoldenRam.kt +++ b/compiler/test/TestGoldenRam.kt @@ -27,7 +27,7 @@ class TestGoldenRam: FunSpec({ test("empty golden ram allocations") { val errors = ErrorReporterForTests() val golden = GoldenRam(options, UIntRange.EMPTY) - val result = golden.allocate("test", DataType.UBYTE, null, null, errors) + val result = golden.allocate("test", DataType.forDt(BaseDataType.UBYTE), null, null, errors) result.expectError { "should not be able to allocate anything" } } @@ -35,28 +35,28 @@ class TestGoldenRam: FunSpec({ val errors = ErrorReporterForTests() val golden = GoldenRam(options, 0x400u until 0x800u) - var result = golden.allocate("test", DataType.UBYTE, null, null, errors) + var result = golden.allocate("test", DataType.forDt(BaseDataType.UBYTE), null, null, errors) var alloc = result.getOrThrow() alloc.size shouldBe 1 alloc.address shouldBe 0x400u - result = golden.allocate("test", DataType.STR, 100, null, errors) + result = golden.allocate("test", DataType.forDt(BaseDataType.STR), 100, null, errors) alloc = result.getOrThrow() alloc.size shouldBe 100 alloc.address shouldBe 0x401u repeat(461) { - result = golden.allocate("test", DataType.UWORD, null, null, errors) + result = golden.allocate("test", DataType.forDt(BaseDataType.UWORD), null, null, errors) alloc = result.getOrThrow() alloc.size shouldBe 2 } - result = golden.allocate("test", DataType.UWORD, null, null, errors) + result = golden.allocate("test", DataType.forDt(BaseDataType.UWORD), null, null, errors) result.expectError { "just 1 more byte available" } - result = golden.allocate("test", DataType.UBYTE, null, null, errors) + result = golden.allocate("test", DataType.forDt(BaseDataType.UBYTE), null, null, errors) alloc = result.getOrThrow() alloc.size shouldBe 1 alloc.address shouldBe golden.region.last - result = golden.allocate("test", DataType.UBYTE, null, null, errors) + result = golden.allocate("test", DataType.forDt(BaseDataType.UBYTE), null, null, errors) result.expectError { "nothing more available" } } diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index 619faa1fd..1c25e3d8e 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -12,10 +12,7 @@ import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.PrefixExpression import prog8.ast.statements.* -import prog8.code.core.DataType -import prog8.code.core.Position -import prog8.code.core.SourceCode -import prog8.code.core.ZeropageWish +import prog8.code.core.* import prog8.code.target.* import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyMemsizer @@ -114,7 +111,7 @@ class TestMemory: FunSpec({ } fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget { - val decl = VarDecl(vartype, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY) + val decl = VarDecl(vartype, VarDeclOrigin.USERCODE, DataType.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY) val memexpr = IdentifierReference(listOf("address"), Position.DUMMY) val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) @@ -152,7 +149,7 @@ class TestMemory: FunSpec({ } test("regular variable not in mapped IO ram on C64") { - val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, 0u, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, 0u, false, Position.DUMMY) val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) @@ -164,7 +161,7 @@ class TestMemory: FunSpec({ test("memory mapped variable not in mapped IO ram on C64") { val address = 0x1000u - val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.forDt(BaseDataType.UBYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY) val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) @@ -176,7 +173,7 @@ class TestMemory: FunSpec({ test("memory mapped variable in mapped IO ram on C64") { val address = 0xd020u - val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.forDt(BaseDataType.UBYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY) val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) @@ -187,7 +184,7 @@ class TestMemory: FunSpec({ } test("array not in mapped IO ram") { - val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, 0u, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, 0u, false, Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) @@ -200,7 +197,7 @@ class TestMemory: FunSpec({ test("memory mapped array not in mapped IO ram") { val address = 0x1000u - val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) @@ -213,7 +210,7 @@ class TestMemory: FunSpec({ test("memory mapped array in mapped IO ram") { val address = 0xd800u - val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY) + val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) @@ -249,31 +246,43 @@ class TestMemory: FunSpec({ context("memsizer") { withData(VMTarget(), AtariTarget(), C64Target(), PETTarget(), AtariTarget(), C128Target()) { target -> - shouldThrow { - target.memorySize(DataType.UNDEFINED) - } - shouldThrow { - target.memorySize(DataType.LONG) - } - target.memorySize(DataType.BOOL) shouldBe 1 - target.memorySize(DataType.BYTE) shouldBe 1 - target.memorySize(DataType.WORD) shouldBe 2 - target.memorySize(DataType.FLOAT) shouldBe target.machine.FLOAT_MEM_SIZE - target.memorySize(DataType.STR) shouldBe 2 - target.memorySize(DataType.ARRAY_UB) shouldBe 2 - target.memorySize(DataType.ARRAY_UW) shouldBe 2 - target.memorySize(DataType.ARRAY_F) shouldBe 2 - shouldThrow { - target.memorySize(DataType.UBYTE, 10) + target.memorySize(SubType.forDt(BaseDataType.UNDEFINED)) } - target.memorySize(DataType.UWORD, 10) shouldBe 10 // uword is pointer to array of bytes - target.memorySize(DataType.ARRAY_B, 10) shouldBe 10 - target.memorySize(DataType.ARRAY_UB, 10) shouldBe 10 - target.memorySize(DataType.ARRAY_F, 10) shouldBe 10*target.machine.FLOAT_MEM_SIZE - target.memorySize(DataType.ARRAY_UW, 10) shouldBe 20 - target.memorySize(DataType.ARRAY_W_SPLIT, 10) shouldBe 20 - target.memorySize(DataType.ARRAY_UW_SPLIT, 10) shouldBe 20 + shouldThrow { + target.memorySize(SubType.forDt(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(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.arrayFor(BaseDataType.BOOL), 10) shouldBe 10 + target.memorySize(DataType.arrayFor(BaseDataType.BYTE), 10) shouldBe 10 + target.memorySize(DataType.arrayFor(BaseDataType.WORD), 10) shouldBe 20 + target.memorySize(DataType.arrayFor(BaseDataType.WORD), 10) shouldBe 20 + target.memorySize(DataType.arrayFor(BaseDataType.FLOAT), 10) shouldBe 10*target.machine.FLOAT_MEM_SIZE + target.memorySize(DataType.arrayFor(BaseDataType.WORD, true), 10) shouldBe 20 + target.memorySize(DataType.arrayFor(BaseDataType.UWORD, true), 10) shouldBe 20 + + target.memorySize(DataType.forDt(BaseDataType.BOOL), 10) shouldBe 10 + target.memorySize(DataType.forDt(BaseDataType.UWORD), 10) shouldBe 20 + target.memorySize(DataType.forDt(BaseDataType.FLOAT), 10) shouldBe 10*target.machine.FLOAT_MEM_SIZE } } }) diff --git a/compiler/test/TestNumbers.kt b/compiler/test/TestNumbers.kt index 598be7e3e..59c6e81c6 100644 --- a/compiler/test/TestNumbers.kt +++ b/compiler/test/TestNumbers.kt @@ -215,10 +215,10 @@ class TestNumbers: FunSpec({ compileText(C64Target(), false, src, writeAssembly = false, errors=errors) shouldBe null errors.errors.size shouldBe 6 errors.errors[0] shouldContain "out of range" - errors.errors[1] shouldContain "WORD doesn't match" + errors.errors[1] shouldContain "word doesn't match" errors.errors[2] shouldContain "out of range" - errors.errors[3] shouldContain "BYTE doesn't match" + errors.errors[3] shouldContain "byte doesn't match" errors.errors[4] shouldContain "out of range" - errors.errors[5] shouldContain "BYTE doesn't match" + errors.errors[5] shouldContain "byte doesn't match" } }) diff --git a/compiler/test/TestNumericLiteral.kt b/compiler/test/TestNumericLiteral.kt index 9c7ac30d3..6c9200832 100644 --- a/compiler/test/TestNumericLiteral.kt +++ b/compiler/test/TestNumericLiteral.kt @@ -11,6 +11,7 @@ import prog8.ast.expressions.InferredTypes import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.StringLiteral import prog8.ast.statements.AnonymousScope +import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.Encoding import prog8.code.core.Position @@ -25,7 +26,7 @@ class TestNumericLiteral: FunSpec({ val dummyPos = Position("test", 0, 0, 0) test("testIdentity") { - val v = NumericLiteral(DataType.UWORD, 12345.0, dummyPos) + val v = NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos) (v==v) shouldBe true (v != v) shouldBe false (v <= v) shouldBe true @@ -33,65 +34,65 @@ class TestNumericLiteral: FunSpec({ (v < v ) shouldBe false (v > v ) shouldBe false - sameValueAndType(NumericLiteral(DataType.UWORD, 12345.0, dummyPos), NumericLiteral(DataType.UWORD, 12345.0, dummyPos)) shouldBe true + sameValueAndType(NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos), NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos)) shouldBe true } test("test truncating") { shouldThrow { - NumericLiteral(DataType.BYTE, -2.345, dummyPos) + NumericLiteral(BaseDataType.BYTE, -2.345, dummyPos) }.message shouldContain "refused truncating" shouldThrow { - NumericLiteral(DataType.BYTE, -2.6, dummyPos) + NumericLiteral(BaseDataType.BYTE, -2.6, dummyPos) }.message shouldContain "refused truncating" shouldThrow { - NumericLiteral(DataType.UWORD, 2222.345, dummyPos) + NumericLiteral(BaseDataType.UWORD, 2222.345, dummyPos) }.message shouldContain "refused truncating" - NumericLiteral(DataType.UBYTE, 2.0, dummyPos).number shouldBe 2.0 - NumericLiteral(DataType.BYTE, -2.0, dummyPos).number shouldBe -2.0 - NumericLiteral(DataType.UWORD, 2222.0, dummyPos).number shouldBe 2222.0 - NumericLiteral(DataType.FLOAT, 123.456, dummyPos) + NumericLiteral(BaseDataType.UBYTE, 2.0, dummyPos).number shouldBe 2.0 + NumericLiteral(BaseDataType.BYTE, -2.0, dummyPos).number shouldBe -2.0 + NumericLiteral(BaseDataType.UWORD, 2222.0, dummyPos).number shouldBe 2222.0 + NumericLiteral(BaseDataType.FLOAT, 123.456, dummyPos) } test("testEqualsAndNotEquals") { - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) == NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) == NumericLiteral(DataType.UWORD, 100.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) == NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UWORD, 254.0, dummyPos) == NumericLiteral(DataType.UBYTE, 254.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UWORD, 12345.0, dummyPos) == NumericLiteral(DataType.UWORD, 12345.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UWORD, 12345.0, dummyPos) == NumericLiteral(DataType.FLOAT, 12345.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) == NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.FLOAT, 22239.0, dummyPos) == NumericLiteral(DataType.UWORD, 22239.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.FLOAT, 9.99, dummyPos) == NumericLiteral(DataType.FLOAT, 9.99, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) == NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) == NumericLiteral(BaseDataType.UWORD, 100.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) == NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos) == NumericLiteral(BaseDataType.UBYTE, 254.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos) == NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos) == NumericLiteral(BaseDataType.FLOAT, 12345.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos) == NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.FLOAT, 22239.0, dummyPos) == NumericLiteral(BaseDataType.UWORD, 22239.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.FLOAT, 9.99, dummyPos) == NumericLiteral(BaseDataType.FLOAT, 9.99, dummyPos)) shouldBe true - sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe true - sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.UWORD, 100.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.UWORD, 254.0, dummyPos), NumericLiteral(DataType.UBYTE, 254.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.UWORD, 12345.0, dummyPos), NumericLiteral(DataType.UWORD, 12345.0, dummyPos)) shouldBe true - sameValueAndType(NumericLiteral(DataType.UWORD, 12345.0, dummyPos), NumericLiteral(DataType.FLOAT, 12345.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.FLOAT, 100.0, dummyPos), NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.FLOAT, 22239.0, dummyPos), NumericLiteral(DataType.UWORD, 22239.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.FLOAT, 9.99, dummyPos), NumericLiteral(DataType.FLOAT, 9.99, dummyPos)) shouldBe true + sameValueAndType(NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos), NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe true + sameValueAndType(NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos), NumericLiteral(BaseDataType.UWORD, 100.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos), NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos), NumericLiteral(BaseDataType.UBYTE, 254.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos), NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos)) shouldBe true + sameValueAndType(NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos), NumericLiteral(BaseDataType.FLOAT, 12345.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos), NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.FLOAT, 22239.0, dummyPos), NumericLiteral(BaseDataType.UWORD, 22239.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.FLOAT, 9.99, dummyPos), NumericLiteral(BaseDataType.FLOAT, 9.99, dummyPos)) shouldBe true - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) != NumericLiteral(DataType.UBYTE, 101.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) != NumericLiteral(DataType.UWORD, 101.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) != NumericLiteral(DataType.FLOAT, 101.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UWORD, 245.0, dummyPos) != NumericLiteral(DataType.UBYTE, 246.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UWORD, 12345.0, dummyPos) != NumericLiteral(DataType.UWORD, 12346.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UWORD, 12345.0, dummyPos) != NumericLiteral(DataType.FLOAT, 12346.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.FLOAT, 9.99, dummyPos) != NumericLiteral(DataType.UBYTE, 9.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.FLOAT, 9.99, dummyPos) != NumericLiteral(DataType.UWORD, 9.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.FLOAT, 9.99, dummyPos) != NumericLiteral(DataType.FLOAT, 9.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) != NumericLiteral(BaseDataType.UBYTE, 101.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) != NumericLiteral(BaseDataType.UWORD, 101.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) != NumericLiteral(BaseDataType.FLOAT, 101.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UWORD, 245.0, dummyPos) != NumericLiteral(BaseDataType.UBYTE, 246.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos) != NumericLiteral(BaseDataType.UWORD, 12346.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos) != NumericLiteral(BaseDataType.FLOAT, 12346.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.FLOAT, 9.99, dummyPos) != NumericLiteral(BaseDataType.UBYTE, 9.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.FLOAT, 9.99, dummyPos) != NumericLiteral(BaseDataType.UWORD, 9.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.FLOAT, 9.99, dummyPos) != NumericLiteral(BaseDataType.FLOAT, 9.0, dummyPos)) shouldBe true - sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.UBYTE, 101.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.UWORD, 101.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.UBYTE, 100.0, dummyPos), NumericLiteral(DataType.FLOAT, 101.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.UWORD, 245.0, dummyPos), NumericLiteral(DataType.UBYTE, 246.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.UWORD, 12345.0, dummyPos), NumericLiteral(DataType.UWORD, 12346.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.UWORD, 12345.0, dummyPos), NumericLiteral(DataType.FLOAT, 12346.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.FLOAT, 9.99, dummyPos), NumericLiteral(DataType.UBYTE, 9.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.FLOAT, 9.99, dummyPos), NumericLiteral(DataType.UWORD, 9.0, dummyPos)) shouldBe false - sameValueAndType(NumericLiteral(DataType.FLOAT, 9.99, dummyPos), NumericLiteral(DataType.FLOAT, 9.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos), NumericLiteral(BaseDataType.UBYTE, 101.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos), NumericLiteral(BaseDataType.UWORD, 101.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos), NumericLiteral(BaseDataType.FLOAT, 101.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.UWORD, 245.0, dummyPos), NumericLiteral(BaseDataType.UBYTE, 246.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos), NumericLiteral(BaseDataType.UWORD, 12346.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.UWORD, 12345.0, dummyPos), NumericLiteral(BaseDataType.FLOAT, 12346.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.FLOAT, 9.99, dummyPos), NumericLiteral(BaseDataType.UBYTE, 9.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.FLOAT, 9.99, dummyPos), NumericLiteral(BaseDataType.UWORD, 9.0, dummyPos)) shouldBe false + sameValueAndType(NumericLiteral(BaseDataType.FLOAT, 9.99, dummyPos), NumericLiteral(BaseDataType.FLOAT, 9.0, dummyPos)) shouldBe false } @@ -103,146 +104,146 @@ class TestNumericLiteral: FunSpec({ (StringLiteral.create("hello", Encoding.SCREENCODES, dummyPos) != StringLiteral.create("bye", Encoding.SCREENCODES, dummyPos)) shouldBe true (StringLiteral.create("hello", Encoding.SCREENCODES, dummyPos) != StringLiteral.create("hello", Encoding.PETSCII, dummyPos)) shouldBe true - val lvOne = NumericLiteral(DataType.UBYTE, 1.0, dummyPos) - val lvTwo = NumericLiteral(DataType.UBYTE, 2.0, dummyPos) - val lvThree = NumericLiteral(DataType.UBYTE, 3.0, dummyPos) - val lvOneR = NumericLiteral(DataType.UBYTE, 1.0, dummyPos) - val lvTwoR = NumericLiteral(DataType.UBYTE, 2.0, dummyPos) - val lvThreeR = NumericLiteral(DataType.UBYTE, 3.0, dummyPos) - val lvFour= NumericLiteral(DataType.UBYTE, 4.0, dummyPos) - val lv1 = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), arrayOf(lvOne, lvTwo, lvThree), dummyPos) - val lv2 = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), arrayOf(lvOneR, lvTwoR, lvThreeR), dummyPos) - val lv3 = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), arrayOf(lvOneR, lvTwoR, lvFour), dummyPos) + val lvOne = NumericLiteral(BaseDataType.UBYTE, 1.0, dummyPos) + val lvTwo = NumericLiteral(BaseDataType.UBYTE, 2.0, dummyPos) + val lvThree = NumericLiteral(BaseDataType.UBYTE, 3.0, dummyPos) + val lvOneR = NumericLiteral(BaseDataType.UBYTE, 1.0, dummyPos) + val lvTwoR = NumericLiteral(BaseDataType.UBYTE, 2.0, dummyPos) + val lvThreeR = NumericLiteral(BaseDataType.UBYTE, 3.0, dummyPos) + val lvFour= NumericLiteral(BaseDataType.UBYTE, 4.0, dummyPos) + val lv1 = ArrayLiteral(InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.UBYTE)), arrayOf(lvOne, lvTwo, lvThree), dummyPos) + val lv2 = ArrayLiteral(InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.UBYTE)), arrayOf(lvOneR, lvTwoR, lvThreeR), dummyPos) + val lv3 = ArrayLiteral(InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.UBYTE)), arrayOf(lvOneR, lvTwoR, lvFour), dummyPos) lv1 shouldBe lv2 lv1 shouldNotBe lv3 } test("testGreaterThan") { - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) > NumericLiteral(DataType.UBYTE, 99.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UWORD, 254.0, dummyPos) > NumericLiteral(DataType.UWORD, 253.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) > NumericLiteral(DataType.FLOAT, 99.9, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) > NumericLiteral(BaseDataType.UBYTE, 99.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos) > NumericLiteral(BaseDataType.UWORD, 253.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos) > NumericLiteral(BaseDataType.FLOAT, 99.9, dummyPos)) shouldBe true - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) >= NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UWORD, 254.0, dummyPos) >= NumericLiteral(DataType.UWORD, 254.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) >= NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) >= NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos) >= NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos) >= NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) > NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe false - (NumericLiteral(DataType.UWORD, 254.0, dummyPos) > NumericLiteral(DataType.UWORD, 254.0, dummyPos)) shouldBe false - (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) > NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) > NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos) > NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos) > NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe false - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) >= NumericLiteral(DataType.UBYTE, 101.0, dummyPos)) shouldBe false - (NumericLiteral(DataType.UWORD, 254.0, dummyPos) >= NumericLiteral(DataType.UWORD, 255.0, dummyPos)) shouldBe false - (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) >= NumericLiteral(DataType.FLOAT, 100.1, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) >= NumericLiteral(BaseDataType.UBYTE, 101.0, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos) >= NumericLiteral(BaseDataType.UWORD, 255.0, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos) >= NumericLiteral(BaseDataType.FLOAT, 100.1, dummyPos)) shouldBe false } test("testLessThan") { - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) < NumericLiteral(DataType.UBYTE, 101.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UWORD, 254.0, dummyPos) < NumericLiteral(DataType.UWORD, 255.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) < NumericLiteral(DataType.FLOAT, 100.1, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) < NumericLiteral(BaseDataType.UBYTE, 101.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos) < NumericLiteral(BaseDataType.UWORD, 255.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos) < NumericLiteral(BaseDataType.FLOAT, 100.1, dummyPos)) shouldBe true - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) <= NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UWORD, 254.0, dummyPos) <= NumericLiteral(DataType.UWORD, 254.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) <= NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) <= NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos) <= NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos)) shouldBe true + (NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos) <= NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe true - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) < NumericLiteral(DataType.UBYTE, 100.0, dummyPos)) shouldBe false - (NumericLiteral(DataType.UWORD, 254.0, dummyPos) < NumericLiteral(DataType.UWORD, 254.0, dummyPos)) shouldBe false - (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) < NumericLiteral(DataType.FLOAT, 100.0, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) < NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos) < NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos) < NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe false - (NumericLiteral(DataType.UBYTE, 100.0, dummyPos) <= NumericLiteral(DataType.UBYTE, 99.0, dummyPos)) shouldBe false - (NumericLiteral(DataType.UWORD, 254.0, dummyPos) <= NumericLiteral(DataType.UWORD, 253.0, dummyPos)) shouldBe false - (NumericLiteral(DataType.FLOAT, 100.0, dummyPos) <= NumericLiteral(DataType.FLOAT, 99.9, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.UBYTE, 100.0, dummyPos) <= NumericLiteral(BaseDataType.UBYTE, 99.0, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.UWORD, 254.0, dummyPos) <= NumericLiteral(BaseDataType.UWORD, 253.0, dummyPos)) shouldBe false + (NumericLiteral(BaseDataType.FLOAT, 100.0, dummyPos) <= NumericLiteral(BaseDataType.FLOAT, 99.9, dummyPos)) shouldBe false } test("optimalInteger") { - NumericLiteral.optimalInteger(10, Position.DUMMY).type shouldBe DataType.UBYTE + NumericLiteral.optimalInteger(10, Position.DUMMY).type shouldBe BaseDataType.UBYTE NumericLiteral.optimalInteger(10, Position.DUMMY).number shouldBe 10.0 - NumericLiteral.optimalInteger(-10, Position.DUMMY).type shouldBe DataType.BYTE + NumericLiteral.optimalInteger(-10, Position.DUMMY).type shouldBe BaseDataType.BYTE NumericLiteral.optimalInteger(-10, Position.DUMMY).number shouldBe -10.0 - NumericLiteral.optimalInteger(1000, Position.DUMMY).type shouldBe DataType.UWORD + NumericLiteral.optimalInteger(1000, Position.DUMMY).type shouldBe BaseDataType.UWORD NumericLiteral.optimalInteger(-1000, Position.DUMMY).number shouldBe -1000.0 - NumericLiteral.optimalInteger(1000u, Position.DUMMY).type shouldBe DataType.UWORD + NumericLiteral.optimalInteger(1000u, Position.DUMMY).type shouldBe BaseDataType.UWORD NumericLiteral.optimalInteger(1000u, Position.DUMMY).number shouldBe 1000.0 - NumericLiteral.optimalInteger(DataType.UBYTE, DataType.UWORD, 1, Position.DUMMY).type shouldBe DataType.UWORD - NumericLiteral.optimalInteger(DataType.UWORD, DataType.UBYTE, 1, Position.DUMMY).type shouldBe DataType.UWORD - NumericLiteral.optimalInteger(DataType.UWORD, null, 1, Position.DUMMY).type shouldBe DataType.UWORD - NumericLiteral.optimalInteger(DataType.UBYTE, DataType.UBYTE, -1, Position.DUMMY).type shouldBe DataType.BYTE - NumericLiteral.optimalInteger(DataType.UBYTE, null, -1, Position.DUMMY).type shouldBe DataType.BYTE - NumericLiteral.optimalInteger(DataType.UWORD, DataType.UWORD, -1, Position.DUMMY).type shouldBe DataType.WORD - NumericLiteral.optimalInteger(DataType.UWORD, null, -1, Position.DUMMY).type shouldBe DataType.WORD + NumericLiteral.optimalInteger(BaseDataType.UBYTE, BaseDataType.UWORD, 1, Position.DUMMY).type shouldBe BaseDataType.UWORD + NumericLiteral.optimalInteger(BaseDataType.UWORD, BaseDataType.UBYTE, 1, Position.DUMMY).type shouldBe BaseDataType.UWORD + NumericLiteral.optimalInteger(BaseDataType.UWORD, null, 1, Position.DUMMY).type shouldBe BaseDataType.UWORD + NumericLiteral.optimalInteger(BaseDataType.UBYTE, BaseDataType.UBYTE, -1, Position.DUMMY).type shouldBe BaseDataType.BYTE + NumericLiteral.optimalInteger(BaseDataType.UBYTE, null, -1, Position.DUMMY).type shouldBe BaseDataType.BYTE + NumericLiteral.optimalInteger(BaseDataType.UWORD, BaseDataType.UWORD, -1, Position.DUMMY).type shouldBe BaseDataType.WORD + NumericLiteral.optimalInteger(BaseDataType.UWORD, null, -1, Position.DUMMY).type shouldBe BaseDataType.WORD } test("optimalNumeric") { - NumericLiteral.optimalNumeric(10, Position.DUMMY).type shouldBe DataType.UBYTE + NumericLiteral.optimalNumeric(10, Position.DUMMY).type shouldBe BaseDataType.UBYTE NumericLiteral.optimalNumeric(10, Position.DUMMY).number shouldBe 10.0 - NumericLiteral.optimalNumeric(-10, Position.DUMMY).type shouldBe DataType.BYTE + NumericLiteral.optimalNumeric(-10, Position.DUMMY).type shouldBe BaseDataType.BYTE NumericLiteral.optimalNumeric(-10, Position.DUMMY).number shouldBe -10.0 - NumericLiteral.optimalNumeric(1000, Position.DUMMY).type shouldBe DataType.UWORD + NumericLiteral.optimalNumeric(1000, Position.DUMMY).type shouldBe BaseDataType.UWORD NumericLiteral.optimalNumeric(1000, Position.DUMMY).number shouldBe 1000.0 - NumericLiteral.optimalNumeric(-1000, Position.DUMMY).type shouldBe DataType.WORD + NumericLiteral.optimalNumeric(-1000, Position.DUMMY).type shouldBe BaseDataType.WORD NumericLiteral.optimalNumeric(-1000, Position.DUMMY).number shouldBe -1000.0 - NumericLiteral.optimalNumeric(1.123, Position.DUMMY).type shouldBe DataType.FLOAT + NumericLiteral.optimalNumeric(1.123, Position.DUMMY).type shouldBe BaseDataType.FLOAT NumericLiteral.optimalNumeric(1.123, Position.DUMMY).number shouldBe 1.123 - NumericLiteral.optimalNumeric(1.0, Position.DUMMY).type shouldBe DataType.UBYTE + NumericLiteral.optimalNumeric(1.0, Position.DUMMY).type shouldBe BaseDataType.UBYTE NumericLiteral.optimalNumeric(1.0, Position.DUMMY).number shouldBe 1.0 - NumericLiteral.optimalNumeric(-1.0, Position.DUMMY).type shouldBe DataType.BYTE + NumericLiteral.optimalNumeric(-1.0, Position.DUMMY).type shouldBe BaseDataType.BYTE NumericLiteral.optimalNumeric(-1.0, Position.DUMMY).number shouldBe -1.0 - NumericLiteral.optimalNumeric(1234.0, Position.DUMMY).type shouldBe DataType.UWORD + NumericLiteral.optimalNumeric(1234.0, Position.DUMMY).type shouldBe BaseDataType.UWORD NumericLiteral.optimalNumeric(1234.0, Position.DUMMY).number shouldBe 1234.0 - NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).type shouldBe DataType.WORD + NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).type shouldBe BaseDataType.WORD NumericLiteral.optimalNumeric(-1234.0, Position.DUMMY).number shouldBe -1234.0 - NumericLiteral.optimalNumeric(DataType.UBYTE, DataType.UWORD, 1.0, Position.DUMMY).type shouldBe DataType.UWORD - NumericLiteral.optimalNumeric(DataType.UWORD, DataType.UBYTE, 1.0, Position.DUMMY).type shouldBe DataType.UWORD - NumericLiteral.optimalNumeric(DataType.UWORD, null, 1.0, Position.DUMMY).type shouldBe DataType.UWORD - NumericLiteral.optimalNumeric(DataType.UBYTE, DataType.UBYTE, -1.0, Position.DUMMY).type shouldBe DataType.BYTE - NumericLiteral.optimalNumeric(DataType.UBYTE, null, -1.0, Position.DUMMY).type shouldBe DataType.BYTE - NumericLiteral.optimalNumeric(DataType.UWORD, DataType.UWORD, -1.0, Position.DUMMY).type shouldBe DataType.WORD - NumericLiteral.optimalNumeric(DataType.UWORD, null, -1.0, Position.DUMMY).type shouldBe DataType.WORD + NumericLiteral.optimalNumeric(BaseDataType.UBYTE, BaseDataType.UWORD, 1.0, Position.DUMMY).type shouldBe BaseDataType.UWORD + NumericLiteral.optimalNumeric(BaseDataType.UWORD, BaseDataType.UBYTE, 1.0, Position.DUMMY).type shouldBe BaseDataType.UWORD + NumericLiteral.optimalNumeric(BaseDataType.UWORD, null, 1.0, Position.DUMMY).type shouldBe BaseDataType.UWORD + NumericLiteral.optimalNumeric(BaseDataType.UBYTE, BaseDataType.UBYTE, -1.0, Position.DUMMY).type shouldBe BaseDataType.BYTE + NumericLiteral.optimalNumeric(BaseDataType.UBYTE, null, -1.0, Position.DUMMY).type shouldBe BaseDataType.BYTE + NumericLiteral.optimalNumeric(BaseDataType.UWORD, BaseDataType.UWORD, -1.0, Position.DUMMY).type shouldBe BaseDataType.WORD + NumericLiteral.optimalNumeric(BaseDataType.UWORD, null, -1.0, Position.DUMMY).type shouldBe BaseDataType.WORD - NumericLiteral.optimalNumeric(DataType.UBYTE, DataType.UWORD, 1.234, Position.DUMMY).type shouldBe DataType.FLOAT - NumericLiteral.optimalNumeric(DataType.UWORD, DataType.UBYTE, 1.234, Position.DUMMY).type shouldBe DataType.FLOAT - NumericLiteral.optimalNumeric(DataType.UWORD, null, 1.234, Position.DUMMY).type shouldBe DataType.FLOAT - NumericLiteral.optimalNumeric(DataType.UBYTE, DataType.UBYTE, -1.234, Position.DUMMY).type shouldBe DataType.FLOAT - NumericLiteral.optimalNumeric(DataType.UBYTE, null, -1.234, Position.DUMMY).type shouldBe DataType.FLOAT - NumericLiteral.optimalNumeric(DataType.UWORD, DataType.UWORD, -1.234, Position.DUMMY).type shouldBe DataType.FLOAT - NumericLiteral.optimalNumeric(DataType.UWORD, null, -1.234, Position.DUMMY).type shouldBe DataType.FLOAT + NumericLiteral.optimalNumeric(BaseDataType.UBYTE, BaseDataType.UWORD, 1.234, Position.DUMMY).type shouldBe BaseDataType.FLOAT + NumericLiteral.optimalNumeric(BaseDataType.UWORD, BaseDataType.UBYTE, 1.234, Position.DUMMY).type shouldBe BaseDataType.FLOAT + NumericLiteral.optimalNumeric(BaseDataType.UWORD, null, 1.234, Position.DUMMY).type shouldBe BaseDataType.FLOAT + NumericLiteral.optimalNumeric(BaseDataType.UBYTE, BaseDataType.UBYTE, -1.234, Position.DUMMY).type shouldBe BaseDataType.FLOAT + NumericLiteral.optimalNumeric(BaseDataType.UBYTE, null, -1.234, Position.DUMMY).type shouldBe BaseDataType.FLOAT + NumericLiteral.optimalNumeric(BaseDataType.UWORD, BaseDataType.UWORD, -1.234, Position.DUMMY).type shouldBe BaseDataType.FLOAT + NumericLiteral.optimalNumeric(BaseDataType.UWORD, null, -1.234, Position.DUMMY).type shouldBe BaseDataType.FLOAT } test("cast can change value") { - fun num(dt: DataType, num: Double): NumericLiteral { + fun num(dt: BaseDataType, num: Double): NumericLiteral { val n = NumericLiteral(dt, num, Position.DUMMY) n.linkParents(AnonymousScope(mutableListOf(), Position.DUMMY)) return n } - val cast1 = num(DataType.UBYTE, 200.0).cast(DataType.BYTE, false) + val cast1 = num(BaseDataType.UBYTE, 200.0).cast(BaseDataType.BYTE, false) cast1.isValid shouldBe true cast1.valueOrZero().number shouldBe -56.0 - val cast2 = num(DataType.BYTE, -50.0).cast(DataType.UBYTE, false) + val cast2 = num(BaseDataType.BYTE, -50.0).cast(BaseDataType.UBYTE, false) cast2.isValid shouldBe true cast2.valueOrZero().number shouldBe 206.0 - val cast3 = num(DataType.UWORD, 55555.0).cast(DataType.WORD, false) + val cast3 = num(BaseDataType.UWORD, 55555.0).cast(BaseDataType.WORD, false) cast3.isValid shouldBe true cast3.valueOrZero().number shouldBe -9981.0 - val cast4 = num(DataType.WORD, -3333.0).cast(DataType.UWORD, false) + val cast4 = num(BaseDataType.WORD, -3333.0).cast(BaseDataType.UWORD, false) cast4.isValid shouldBe true cast4.valueOrZero().number shouldBe 62203.0 } test("convert cannot change value") { - fun num(dt: DataType, num: Double): NumericLiteral { + fun num(dt: BaseDataType, num: Double): NumericLiteral { val n = NumericLiteral(dt, num, Position.DUMMY) n.linkParents(AnonymousScope(mutableListOf(), Position.DUMMY)) return n } - num(DataType.UBYTE, 200.0).convertTypeKeepValue(DataType.BYTE).isValid shouldBe false - num(DataType.BYTE, -50.0).convertTypeKeepValue(DataType.UBYTE).isValid shouldBe false - num(DataType.UWORD, 55555.0).convertTypeKeepValue(DataType.WORD).isValid shouldBe false - num(DataType.WORD, -3333.0).convertTypeKeepValue(DataType.UWORD).isValid shouldBe false + num(BaseDataType.UBYTE, 200.0).convertTypeKeepValue(BaseDataType.BYTE).isValid shouldBe false + num(BaseDataType.BYTE, -50.0).convertTypeKeepValue(BaseDataType.UBYTE).isValid shouldBe false + num(BaseDataType.UWORD, 55555.0).convertTypeKeepValue(BaseDataType.WORD).isValid shouldBe false + num(BaseDataType.WORD, -3333.0).convertTypeKeepValue(BaseDataType.UWORD).isValid shouldBe false - num(DataType.UBYTE, 42.0).convertTypeKeepValue(DataType.BYTE).isValid shouldBe true - num(DataType.BYTE, 42.0).convertTypeKeepValue(DataType.UBYTE).isValid shouldBe true - num(DataType.UWORD, 12345.0).convertTypeKeepValue(DataType.WORD).isValid shouldBe true - num(DataType.WORD, 12345.0).convertTypeKeepValue(DataType.UWORD).isValid shouldBe true + num(BaseDataType.UBYTE, 42.0).convertTypeKeepValue(BaseDataType.BYTE).isValid shouldBe true + num(BaseDataType.BYTE, 42.0).convertTypeKeepValue(BaseDataType.UBYTE).isValid shouldBe true + num(BaseDataType.UWORD, 12345.0).convertTypeKeepValue(BaseDataType.WORD).isValid shouldBe true + num(BaseDataType.WORD, 12345.0).convertTypeKeepValue(BaseDataType.UWORD).isValid shouldBe true } }) diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index b2166123e..976ffa84a 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -15,6 +15,7 @@ import prog8.ast.statements.* import prog8.code.ast.PtAssignTarget import prog8.code.ast.PtAssignment import prog8.code.ast.PtFunctionCall +import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.Position import prog8.code.target.C64Target @@ -115,8 +116,8 @@ other { } test("generated constvalue from typecast inherits proper parent linkage") { - val number = NumericLiteral(DataType.UBYTE, 11.0, Position.DUMMY) - val tc = TypecastExpression(number, DataType.BYTE, false, Position.DUMMY) + val number = NumericLiteral(BaseDataType.UBYTE, 11.0, Position.DUMMY) + val tc = TypecastExpression(number, BaseDataType.BYTE, false, Position.DUMMY) val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) tc.linkParents(ParentSentinel) tc.parent shouldNotBe null @@ -125,12 +126,12 @@ other { val constvalue = tc.constValue(program)!! constvalue shouldBe instanceOf() constvalue.number shouldBe 11.0 - constvalue.type shouldBe DataType.BYTE + constvalue.type shouldBe BaseDataType.BYTE constvalue.parent shouldBeSameInstanceAs tc.parent } test("generated constvalue from prefixexpr inherits proper parent linkage") { - val number = NumericLiteral(DataType.UBYTE, 11.0, Position.DUMMY) + val number = NumericLiteral(BaseDataType.UBYTE, 11.0, Position.DUMMY) val pfx = PrefixExpression("-", number, Position.DUMMY) val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) pfx.linkParents(ParentSentinel) @@ -140,7 +141,7 @@ other { val constvalue = pfx.constValue(program)!! constvalue shouldBe instanceOf() constvalue.number shouldBe -11.0 - constvalue.type shouldBe DataType.BYTE + constvalue.type shouldBe BaseDataType.BYTE constvalue.parent shouldBeSameInstanceAs pfx.parent } @@ -360,19 +361,19 @@ main { val z6init = statements[11] as Assignment z1decl.name shouldBe "z1" - z1init.value shouldBe NumericLiteral(DataType.UBYTE, 10.0, Position.DUMMY) + z1init.value shouldBe NumericLiteral(BaseDataType.UBYTE, 10.0, Position.DUMMY) z2decl.name shouldBe "z2" - z2init.value shouldBe NumericLiteral(DataType.UBYTE, 255.0, Position.DUMMY) + z2init.value shouldBe NumericLiteral(BaseDataType.UBYTE, 255.0, Position.DUMMY) z3decl.name shouldBe "z3" - z3init.value shouldBe NumericLiteral(DataType.BOOL, 1.0, Position.DUMMY) + z3init.value shouldBe NumericLiteral(BaseDataType.BOOL, 1.0, Position.DUMMY) z4decl.name shouldBe "z4" - z4init.value shouldBe NumericLiteral(DataType.UWORD, 0.0, Position.DUMMY) + z4init.value shouldBe NumericLiteral(BaseDataType.UWORD, 0.0, Position.DUMMY) z5decl.name shouldBe "z5" (z5init.value as BinaryExpression).operator shouldBe "+" - (z5init.value as BinaryExpression).right shouldBe NumericLiteral(DataType.UBYTE, 5.0, Position.DUMMY) + (z5init.value as BinaryExpression).right shouldBe NumericLiteral(BaseDataType.UBYTE, 5.0, Position.DUMMY) z6decl.name shouldBe "z6" (z6init.value as BinaryExpression).operator shouldBe "-" - (z6init.value as BinaryExpression).right shouldBe NumericLiteral(DataType.UBYTE, 5.0, Position.DUMMY) + (z6init.value as BinaryExpression).right shouldBe NumericLiteral(BaseDataType.UBYTE, 5.0, Position.DUMMY) } test("force_output option should work with optimizing memwrite assignment") { @@ -537,13 +538,13 @@ main { stmts.filterIsInstance().size shouldBe 5 val assignXX1 = stmts[1] as Assignment assignXX1.target.identifier!!.nameInSource shouldBe listOf("xx") - assignXX1.value shouldBe NumericLiteral(DataType.UWORD, 20.0, Position.DUMMY) + assignXX1.value shouldBe NumericLiteral(BaseDataType.UWORD, 20.0, Position.DUMMY) val assignXX2 = stmts.last() as Assignment assignXX2.target.identifier!!.nameInSource shouldBe listOf("xx") val xxValue = assignXX2.value as BinaryExpression xxValue.operator shouldBe "+" (xxValue.left as? IdentifierReference)?.nameInSource shouldBe listOf("xx") - xxValue.right shouldBe NumericLiteral(DataType.UWORD, 10.0, Position.DUMMY) + xxValue.right shouldBe NumericLiteral(BaseDataType.UWORD, 10.0, Position.DUMMY) } test("multi-comparison with many values replaced by containment check on heap variable") { @@ -581,7 +582,7 @@ main { arrayDecl.isArray shouldBe true arrayDecl.arraysize?.constIndex() shouldBe 6 val arrayValue = arrayDecl.value as ArrayLiteral - arrayValue.type shouldBe InferredTypes.InferredType.known(DataType.ARRAY_UB) + arrayValue.type shouldBe InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.UBYTE)) arrayValue.value shouldBe listOf( NumericLiteral.optimalInteger(1, Position.DUMMY), NumericLiteral.optimalInteger(2, Position.DUMMY), @@ -968,25 +969,25 @@ main { st.size shouldBe 17 val answerValue = (st[3] as Assignment).value - answerValue shouldBe NumericLiteral(DataType.UWORD, 0.0, Position.DUMMY) + answerValue shouldBe NumericLiteral(BaseDataType.UWORD, 0.0, Position.DUMMY) val funcarg1 = (st[4] as FunctionCallStatement).args.single() - funcarg1 shouldBe NumericLiteral(DataType.UWORD, 0.0, Position.DUMMY) + funcarg1 shouldBe NumericLiteral(BaseDataType.UWORD, 0.0, Position.DUMMY) val answer2Value = (st[8] as Assignment).value - answer2Value shouldBe NumericLiteral(DataType.UWORD, 8.0, Position.DUMMY) + answer2Value shouldBe NumericLiteral(BaseDataType.UWORD, 8.0, Position.DUMMY) val funcarg2 = (st[9] as FunctionCallStatement).args.single() - funcarg2 shouldBe NumericLiteral(DataType.UWORD, 8.0, Position.DUMMY) + funcarg2 shouldBe NumericLiteral(BaseDataType.UWORD, 8.0, Position.DUMMY) val answer3ValueTc = (st[15] as Assignment).value as TypecastExpression - answer3ValueTc.type shouldBe DataType.UWORD + answer3ValueTc.type shouldBe BaseDataType.UWORD val answer3Value = answer3ValueTc.expression as FunctionCallExpression answer3Value.target.nameInSource shouldBe listOf("msb") answer3Value.args.single() shouldBe instanceOf() val funcarg3tc = (st[16] as FunctionCallStatement).args.single() as TypecastExpression - funcarg3tc.type shouldBe DataType.UWORD + funcarg3tc.type shouldBe BaseDataType.UWORD val funcarg3 = funcarg3tc.expression as FunctionCallExpression funcarg3.target.nameInSource shouldBe listOf("msb") funcarg3.args.single() shouldBe instanceOf() diff --git a/compiler/test/TestPtNumber.kt b/compiler/test/TestPtNumber.kt index 58d692fd3..3c640fc5d 100644 --- a/compiler/test/TestPtNumber.kt +++ b/compiler/test/TestPtNumber.kt @@ -8,6 +8,7 @@ import io.kotest.matchers.string.shouldContain import prog8.code.ast.PtArray import prog8.code.ast.PtNumber import prog8.code.ast.PtString +import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.Encoding import prog8.code.core.Position @@ -22,7 +23,7 @@ class TestPtNumber: FunSpec({ val dummyPos = Position("test", 0, 0, 0) test("testIdentity") { - val v = PtNumber(DataType.UWORD, 12345.0, dummyPos) + val v = PtNumber(BaseDataType.UWORD, 12345.0, dummyPos) (v==v) shouldBe true (v != v) shouldBe false (v <= v) shouldBe true @@ -30,65 +31,65 @@ class TestPtNumber: FunSpec({ (v < v ) shouldBe false (v > v ) shouldBe false - sameValueAndType(PtNumber(DataType.UWORD, 12345.0, dummyPos), PtNumber(DataType.UWORD, 12345.0, dummyPos)) shouldBe true + sameValueAndType(PtNumber(BaseDataType.UWORD, 12345.0, dummyPos), PtNumber(BaseDataType.UWORD, 12345.0, dummyPos)) shouldBe true } test("test truncating") { shouldThrow { - PtNumber(DataType.BYTE, -2.345, dummyPos) + PtNumber(BaseDataType.BYTE, -2.345, dummyPos) }.message shouldContain "refused truncating" shouldThrow { - PtNumber(DataType.BYTE, -2.6, dummyPos) + PtNumber(BaseDataType.BYTE, -2.6, dummyPos) }.message shouldContain "refused truncating" shouldThrow { - PtNumber(DataType.UWORD, 2222.345, dummyPos) + PtNumber(BaseDataType.UWORD, 2222.345, dummyPos) }.message shouldContain "refused truncating" - PtNumber(DataType.UBYTE, 2.0, dummyPos).number shouldBe 2.0 - PtNumber(DataType.BYTE, -2.0, dummyPos).number shouldBe -2.0 - PtNumber(DataType.UWORD, 2222.0, dummyPos).number shouldBe 2222.0 - PtNumber(DataType.FLOAT, 123.456, dummyPos) + PtNumber(BaseDataType.UBYTE, 2.0, dummyPos).number shouldBe 2.0 + PtNumber(BaseDataType.BYTE, -2.0, dummyPos).number shouldBe -2.0 + PtNumber(BaseDataType.UWORD, 2222.0, dummyPos).number shouldBe 2222.0 + PtNumber(BaseDataType.FLOAT, 123.456, dummyPos) } test("testEqualsAndNotEquals") { - (PtNumber(DataType.UBYTE, 100.0, dummyPos) == PtNumber(DataType.UBYTE, 100.0, dummyPos)) shouldBe true - (PtNumber(DataType.UBYTE, 100.0, dummyPos) == PtNumber(DataType.UWORD, 100.0, dummyPos)) shouldBe true - (PtNumber(DataType.UBYTE, 100.0, dummyPos) == PtNumber(DataType.FLOAT, 100.0, dummyPos)) shouldBe true - (PtNumber(DataType.UWORD, 254.0, dummyPos) == PtNumber(DataType.UBYTE, 254.0, dummyPos)) shouldBe true - (PtNumber(DataType.UWORD, 12345.0, dummyPos) == PtNumber(DataType.UWORD, 12345.0, dummyPos)) shouldBe true - (PtNumber(DataType.UWORD, 12345.0, dummyPos) == PtNumber(DataType.FLOAT, 12345.0, dummyPos)) shouldBe true - (PtNumber(DataType.FLOAT, 100.0, dummyPos) == PtNumber(DataType.UBYTE, 100.0, dummyPos)) shouldBe true - (PtNumber(DataType.FLOAT, 22239.0, dummyPos) == PtNumber(DataType.UWORD, 22239.0, dummyPos)) shouldBe true - (PtNumber(DataType.FLOAT, 9.99, dummyPos) == PtNumber(DataType.FLOAT, 9.99, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) == PtNumber(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) == PtNumber(BaseDataType.UWORD, 100.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) == PtNumber(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UWORD, 254.0, dummyPos) == PtNumber(BaseDataType.UBYTE, 254.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UWORD, 12345.0, dummyPos) == PtNumber(BaseDataType.UWORD, 12345.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UWORD, 12345.0, dummyPos) == PtNumber(BaseDataType.FLOAT, 12345.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.FLOAT, 100.0, dummyPos) == PtNumber(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.FLOAT, 22239.0, dummyPos) == PtNumber(BaseDataType.UWORD, 22239.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.FLOAT, 9.99, dummyPos) == PtNumber(BaseDataType.FLOAT, 9.99, dummyPos)) shouldBe true - sameValueAndType(PtNumber(DataType.UBYTE, 100.0, dummyPos), PtNumber(DataType.UBYTE, 100.0, dummyPos)) shouldBe true - sameValueAndType(PtNumber(DataType.UBYTE, 100.0, dummyPos), PtNumber(DataType.UWORD, 100.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.UBYTE, 100.0, dummyPos), PtNumber(DataType.FLOAT, 100.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.UWORD, 254.0, dummyPos), PtNumber(DataType.UBYTE, 254.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.UWORD, 12345.0, dummyPos), PtNumber(DataType.UWORD, 12345.0, dummyPos)) shouldBe true - sameValueAndType(PtNumber(DataType.UWORD, 12345.0, dummyPos), PtNumber(DataType.FLOAT, 12345.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.FLOAT, 100.0, dummyPos), PtNumber(DataType.UBYTE, 100.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.FLOAT, 22239.0, dummyPos), PtNumber(DataType.UWORD, 22239.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.FLOAT, 9.99, dummyPos), PtNumber(DataType.FLOAT, 9.99, dummyPos)) shouldBe true + sameValueAndType(PtNumber(BaseDataType.UBYTE, 100.0, dummyPos), PtNumber(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe true + sameValueAndType(PtNumber(BaseDataType.UBYTE, 100.0, dummyPos), PtNumber(BaseDataType.UWORD, 100.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.UBYTE, 100.0, dummyPos), PtNumber(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.UWORD, 254.0, dummyPos), PtNumber(BaseDataType.UBYTE, 254.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.UWORD, 12345.0, dummyPos), PtNumber(BaseDataType.UWORD, 12345.0, dummyPos)) shouldBe true + sameValueAndType(PtNumber(BaseDataType.UWORD, 12345.0, dummyPos), PtNumber(BaseDataType.FLOAT, 12345.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.FLOAT, 100.0, dummyPos), PtNumber(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.FLOAT, 22239.0, dummyPos), PtNumber(BaseDataType.UWORD, 22239.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.FLOAT, 9.99, dummyPos), PtNumber(BaseDataType.FLOAT, 9.99, dummyPos)) shouldBe true - (PtNumber(DataType.UBYTE, 100.0, dummyPos) != PtNumber(DataType.UBYTE, 101.0, dummyPos)) shouldBe true - (PtNumber(DataType.UBYTE, 100.0, dummyPos) != PtNumber(DataType.UWORD, 101.0, dummyPos)) shouldBe true - (PtNumber(DataType.UBYTE, 100.0, dummyPos) != PtNumber(DataType.FLOAT, 101.0, dummyPos)) shouldBe true - (PtNumber(DataType.UWORD, 245.0, dummyPos) != PtNumber(DataType.UBYTE, 246.0, dummyPos)) shouldBe true - (PtNumber(DataType.UWORD, 12345.0, dummyPos) != PtNumber(DataType.UWORD, 12346.0, dummyPos)) shouldBe true - (PtNumber(DataType.UWORD, 12345.0, dummyPos) != PtNumber(DataType.FLOAT, 12346.0, dummyPos)) shouldBe true - (PtNumber(DataType.FLOAT, 9.99, dummyPos) != PtNumber(DataType.UBYTE, 9.0, dummyPos)) shouldBe true - (PtNumber(DataType.FLOAT, 9.99, dummyPos) != PtNumber(DataType.UWORD, 9.0, dummyPos)) shouldBe true - (PtNumber(DataType.FLOAT, 9.99, dummyPos) != PtNumber(DataType.FLOAT, 9.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) != PtNumber(BaseDataType.UBYTE, 101.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) != PtNumber(BaseDataType.UWORD, 101.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) != PtNumber(BaseDataType.FLOAT, 101.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UWORD, 245.0, dummyPos) != PtNumber(BaseDataType.UBYTE, 246.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UWORD, 12345.0, dummyPos) != PtNumber(BaseDataType.UWORD, 12346.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UWORD, 12345.0, dummyPos) != PtNumber(BaseDataType.FLOAT, 12346.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.FLOAT, 9.99, dummyPos) != PtNumber(BaseDataType.UBYTE, 9.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.FLOAT, 9.99, dummyPos) != PtNumber(BaseDataType.UWORD, 9.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.FLOAT, 9.99, dummyPos) != PtNumber(BaseDataType.FLOAT, 9.0, dummyPos)) shouldBe true - sameValueAndType(PtNumber(DataType.UBYTE, 100.0, dummyPos), PtNumber(DataType.UBYTE, 101.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.UBYTE, 100.0, dummyPos), PtNumber(DataType.UWORD, 101.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.UBYTE, 100.0, dummyPos), PtNumber(DataType.FLOAT, 101.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.UWORD, 245.0, dummyPos), PtNumber(DataType.UBYTE, 246.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.UWORD, 12345.0, dummyPos), PtNumber(DataType.UWORD, 12346.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.UWORD, 12345.0, dummyPos), PtNumber(DataType.FLOAT, 12346.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.FLOAT, 9.99, dummyPos), PtNumber(DataType.UBYTE, 9.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.FLOAT, 9.99, dummyPos), PtNumber(DataType.UWORD, 9.0, dummyPos)) shouldBe false - sameValueAndType(PtNumber(DataType.FLOAT, 9.99, dummyPos), PtNumber(DataType.FLOAT, 9.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.UBYTE, 100.0, dummyPos), PtNumber(BaseDataType.UBYTE, 101.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.UBYTE, 100.0, dummyPos), PtNumber(BaseDataType.UWORD, 101.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.UBYTE, 100.0, dummyPos), PtNumber(BaseDataType.FLOAT, 101.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.UWORD, 245.0, dummyPos), PtNumber(BaseDataType.UBYTE, 246.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.UWORD, 12345.0, dummyPos), PtNumber(BaseDataType.UWORD, 12346.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.UWORD, 12345.0, dummyPos), PtNumber(BaseDataType.FLOAT, 12346.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.FLOAT, 9.99, dummyPos), PtNumber(BaseDataType.UBYTE, 9.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.FLOAT, 9.99, dummyPos), PtNumber(BaseDataType.UWORD, 9.0, dummyPos)) shouldBe false + sameValueAndType(PtNumber(BaseDataType.FLOAT, 9.99, dummyPos), PtNumber(BaseDataType.FLOAT, 9.0, dummyPos)) shouldBe false } @@ -100,57 +101,57 @@ class TestPtNumber: FunSpec({ (PtString("hello", Encoding.SCREENCODES, dummyPos) != PtString("bye", Encoding.SCREENCODES, dummyPos)) shouldBe true (PtString("hello", Encoding.SCREENCODES, dummyPos) != PtString("hello", Encoding.PETSCII, dummyPos)) shouldBe true - val lvOne = PtNumber(DataType.UBYTE, 1.0, dummyPos) - val lvTwo = PtNumber(DataType.UBYTE, 2.0, dummyPos) - val lvThree = PtNumber(DataType.UBYTE, 3.0, dummyPos) - val lvOneR = PtNumber(DataType.UBYTE, 1.0, dummyPos) - val lvTwoR = PtNumber(DataType.UBYTE, 2.0, dummyPos) - val lvThreeR = PtNumber(DataType.UBYTE, 3.0, dummyPos) - val lvFour= PtNumber(DataType.UBYTE, 4.0, dummyPos) - val lv1 = PtArray(DataType.ARRAY_UB, dummyPos) + val lvOne = PtNumber(BaseDataType.UBYTE, 1.0, dummyPos) + val lvTwo = PtNumber(BaseDataType.UBYTE, 2.0, dummyPos) + val lvThree = PtNumber(BaseDataType.UBYTE, 3.0, dummyPos) + val lvOneR = PtNumber(BaseDataType.UBYTE, 1.0, dummyPos) + val lvTwoR = PtNumber(BaseDataType.UBYTE, 2.0, dummyPos) + val lvThreeR = PtNumber(BaseDataType.UBYTE, 3.0, dummyPos) + val lvFour= PtNumber(BaseDataType.UBYTE, 4.0, dummyPos) + val lv1 = PtArray(DataType.arrayFor(BaseDataType.UBYTE), dummyPos) arrayOf(lvOne, lvTwo, lvThree).forEach { lv1.add(it) } - val lv2 = PtArray(DataType.ARRAY_UB, dummyPos) + val lv2 = PtArray(DataType.arrayFor(BaseDataType.UBYTE), dummyPos) arrayOf(lvOneR, lvTwoR, lvThreeR).forEach { lv2.add(it) } - val lv3 = PtArray(DataType.ARRAY_UB, dummyPos) + val lv3 = PtArray(DataType.arrayFor(BaseDataType.UBYTE), dummyPos) arrayOf(lvOneR, lvTwoR, lvFour).forEach { lv3.add(it) } lv1 shouldBe lv2 lv1 shouldNotBe lv3 } test("testGreaterThan") { - (PtNumber(DataType.UBYTE, 100.0, dummyPos) > PtNumber(DataType.UBYTE, 99.0, dummyPos)) shouldBe true - (PtNumber(DataType.UWORD, 254.0, dummyPos) > PtNumber(DataType.UWORD, 253.0, dummyPos)) shouldBe true - (PtNumber(DataType.FLOAT, 100.0, dummyPos) > PtNumber(DataType.FLOAT, 99.9, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) > PtNumber(BaseDataType.UBYTE, 99.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UWORD, 254.0, dummyPos) > PtNumber(BaseDataType.UWORD, 253.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.FLOAT, 100.0, dummyPos) > PtNumber(BaseDataType.FLOAT, 99.9, dummyPos)) shouldBe true - (PtNumber(DataType.UBYTE, 100.0, dummyPos) >= PtNumber(DataType.UBYTE, 100.0, dummyPos)) shouldBe true - (PtNumber(DataType.UWORD, 254.0, dummyPos) >= PtNumber(DataType.UWORD, 254.0, dummyPos)) shouldBe true - (PtNumber(DataType.FLOAT, 100.0, dummyPos) >= PtNumber(DataType.FLOAT, 100.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) >= PtNumber(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UWORD, 254.0, dummyPos) >= PtNumber(BaseDataType.UWORD, 254.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.FLOAT, 100.0, dummyPos) >= PtNumber(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe true - (PtNumber(DataType.UBYTE, 100.0, dummyPos) > PtNumber(DataType.UBYTE, 100.0, dummyPos)) shouldBe false - (PtNumber(DataType.UWORD, 254.0, dummyPos) > PtNumber(DataType.UWORD, 254.0, dummyPos)) shouldBe false - (PtNumber(DataType.FLOAT, 100.0, dummyPos) > PtNumber(DataType.FLOAT, 100.0, dummyPos)) shouldBe false + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) > PtNumber(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe false + (PtNumber(BaseDataType.UWORD, 254.0, dummyPos) > PtNumber(BaseDataType.UWORD, 254.0, dummyPos)) shouldBe false + (PtNumber(BaseDataType.FLOAT, 100.0, dummyPos) > PtNumber(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe false - (PtNumber(DataType.UBYTE, 100.0, dummyPos) >= PtNumber(DataType.UBYTE, 101.0, dummyPos)) shouldBe false - (PtNumber(DataType.UWORD, 254.0, dummyPos) >= PtNumber(DataType.UWORD, 255.0, dummyPos)) shouldBe false - (PtNumber(DataType.FLOAT, 100.0, dummyPos) >= PtNumber(DataType.FLOAT, 100.1, dummyPos)) shouldBe false + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) >= PtNumber(BaseDataType.UBYTE, 101.0, dummyPos)) shouldBe false + (PtNumber(BaseDataType.UWORD, 254.0, dummyPos) >= PtNumber(BaseDataType.UWORD, 255.0, dummyPos)) shouldBe false + (PtNumber(BaseDataType.FLOAT, 100.0, dummyPos) >= PtNumber(BaseDataType.FLOAT, 100.1, dummyPos)) shouldBe false } test("testLessThan") { - (PtNumber(DataType.UBYTE, 100.0, dummyPos) < PtNumber(DataType.UBYTE, 101.0, dummyPos)) shouldBe true - (PtNumber(DataType.UWORD, 254.0, dummyPos) < PtNumber(DataType.UWORD, 255.0, dummyPos)) shouldBe true - (PtNumber(DataType.FLOAT, 100.0, dummyPos) < PtNumber(DataType.FLOAT, 100.1, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) < PtNumber(BaseDataType.UBYTE, 101.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UWORD, 254.0, dummyPos) < PtNumber(BaseDataType.UWORD, 255.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.FLOAT, 100.0, dummyPos) < PtNumber(BaseDataType.FLOAT, 100.1, dummyPos)) shouldBe true - (PtNumber(DataType.UBYTE, 100.0, dummyPos) <= PtNumber(DataType.UBYTE, 100.0, dummyPos)) shouldBe true - (PtNumber(DataType.UWORD, 254.0, dummyPos) <= PtNumber(DataType.UWORD, 254.0, dummyPos)) shouldBe true - (PtNumber(DataType.FLOAT, 100.0, dummyPos) <= PtNumber(DataType.FLOAT, 100.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) <= PtNumber(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.UWORD, 254.0, dummyPos) <= PtNumber(BaseDataType.UWORD, 254.0, dummyPos)) shouldBe true + (PtNumber(BaseDataType.FLOAT, 100.0, dummyPos) <= PtNumber(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe true - (PtNumber(DataType.UBYTE, 100.0, dummyPos) < PtNumber(DataType.UBYTE, 100.0, dummyPos)) shouldBe false - (PtNumber(DataType.UWORD, 254.0, dummyPos) < PtNumber(DataType.UWORD, 254.0, dummyPos)) shouldBe false - (PtNumber(DataType.FLOAT, 100.0, dummyPos) < PtNumber(DataType.FLOAT, 100.0, dummyPos)) shouldBe false + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) < PtNumber(BaseDataType.UBYTE, 100.0, dummyPos)) shouldBe false + (PtNumber(BaseDataType.UWORD, 254.0, dummyPos) < PtNumber(BaseDataType.UWORD, 254.0, dummyPos)) shouldBe false + (PtNumber(BaseDataType.FLOAT, 100.0, dummyPos) < PtNumber(BaseDataType.FLOAT, 100.0, dummyPos)) shouldBe false - (PtNumber(DataType.UBYTE, 100.0, dummyPos) <= PtNumber(DataType.UBYTE, 99.0, dummyPos)) shouldBe false - (PtNumber(DataType.UWORD, 254.0, dummyPos) <= PtNumber(DataType.UWORD, 253.0, dummyPos)) shouldBe false - (PtNumber(DataType.FLOAT, 100.0, dummyPos) <= PtNumber(DataType.FLOAT, 99.9, dummyPos)) shouldBe false + (PtNumber(BaseDataType.UBYTE, 100.0, dummyPos) <= PtNumber(BaseDataType.UBYTE, 99.0, dummyPos)) shouldBe false + (PtNumber(BaseDataType.UWORD, 254.0, dummyPos) <= PtNumber(BaseDataType.UWORD, 253.0, dummyPos)) shouldBe false + (PtNumber(BaseDataType.FLOAT, 100.0, dummyPos) <= PtNumber(BaseDataType.FLOAT, 99.9, dummyPos)) shouldBe false } }) diff --git a/compiler/test/TestSubroutines.kt b/compiler/test/TestSubroutines.kt index ba63570dc..f3d2d06b1 100644 --- a/compiler/test/TestSubroutines.kt +++ b/compiler/test/TestSubroutines.kt @@ -8,6 +8,7 @@ import io.kotest.matchers.types.instanceOf import prog8.ast.IFunctionCall import prog8.ast.expressions.IdentifierReference import prog8.ast.statements.* +import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.target.C64Target import prog8.compiler.astprocessing.hasRtsInAsm @@ -31,7 +32,7 @@ class TestSubroutines: FunSpec({ val errors = ErrorReporterForTests() compileText(C64Target(), false, text, writeAssembly = true, errors=errors) shouldBe null errors.errors.size shouldBe 1 - errors.errors[0] shouldContain "type mismatch, was: STR expected: UBYTE" + errors.errors[0] shouldContain "type mismatch, was: str expected: ubyte" } test("stringParameter") { @@ -65,12 +66,12 @@ class TestSubroutines: FunSpec({ asmfunc.statements.isEmpty() shouldBe true func.isAsmSubroutine shouldBe false withClue("str param for subroutines should be changed into UWORD") { - asmfunc.parameters.single().type shouldBe DataType.UWORD - func.parameters.single().type shouldBe DataType.UWORD + asmfunc.parameters.single().type shouldBe DataType.forDt(BaseDataType.UWORD) + func.parameters.single().type shouldBe DataType.forDt(BaseDataType.UWORD) func.statements.size shouldBe 4 val paramvar = func.statements[0] as VarDecl paramvar.name shouldBe "thing" - paramvar.datatype shouldBe DataType.UWORD + paramvar.datatype shouldBe DataType.forDt(BaseDataType.UWORD) } val assign = func.statements[2] as Assignment assign.target.identifier!!.nameInSource shouldBe listOf("t2") @@ -126,8 +127,8 @@ class TestSubroutines: FunSpec({ asmfunc.hasRtsInAsm(false) shouldBe true func.isAsmSubroutine shouldBe false withClue("str param should have been changed to uword") { - asmfunc.parameters.single().type shouldBe DataType.UWORD - func.parameters.single().type shouldBe DataType.UWORD + asmfunc.parameters.single().type shouldBe DataType.forDt(BaseDataType.UWORD) + func.parameters.single().type shouldBe DataType.forDt(BaseDataType.UWORD) } func.statements.size shouldBe 5 @@ -135,7 +136,7 @@ class TestSubroutines: FunSpec({ val paramvar = func.statements[0] as VarDecl paramvar.name shouldBe "thing" withClue("pre-asmgen should have changed str to uword type") { - paramvar.datatype shouldBe DataType.UWORD + paramvar.datatype shouldBe DataType.forDt(BaseDataType.UWORD) } val assign = func.statements[2] as Assignment assign.target.identifier!!.nameInSource shouldBe listOf("t2") @@ -181,8 +182,8 @@ class TestSubroutines: FunSpec({ val asmfunc = mainBlock.statements.filterIsInstance().single { it.name=="asmfunc"} val func = mainBlock.statements.filterIsInstance().single { it.name=="func"} withClue("ubyte array param should have been replaced by UWORD pointer") { - asmfunc.parameters.single().type shouldBe DataType.UWORD - func.parameters.single().type shouldBe DataType.UWORD + asmfunc.parameters.single().type shouldBe DataType.forDt(BaseDataType.UWORD) + func.parameters.single().type shouldBe DataType.forDt(BaseDataType.UWORD) } } diff --git a/compiler/test/TestSymbolTable.kt b/compiler/test/TestSymbolTable.kt index c882c9ffa..f63482d2c 100644 --- a/compiler/test/TestSymbolTable.kt +++ b/compiler/test/TestSymbolTable.kt @@ -7,10 +7,7 @@ import io.kotest.matchers.shouldNotBe import io.kotest.matchers.types.shouldBeSameInstanceAs import prog8.code.* import prog8.code.ast.* -import prog8.code.core.DataType -import prog8.code.core.Position -import prog8.code.core.SourceCode -import prog8.code.core.ZeropageWish +import prog8.code.core.* import prog8tests.helpers.DummyMemsizer import prog8tests.helpers.DummyStringEncoder @@ -40,9 +37,9 @@ class TestSymbolTable: FunSpec({ st.lookupUnscoped("undefined") shouldBe null st.lookup("undefined") shouldBe null st.lookup("undefined.undefined") shouldBe null - var default = st.lookupUnscopedOrElse("undefined") { StNode("default", StNodeType.LABEL, PtIdentifier("default", DataType.BYTE, Position.DUMMY)) } + var default = st.lookupUnscopedOrElse("undefined") { StNode("default", StNodeType.LABEL, PtIdentifier("default", DataType.forDt(BaseDataType.BYTE), Position.DUMMY)) } default.name shouldBe "default" - default = st.lookupUnscopedOrElse("undefined") { StNode("default", StNodeType.LABEL, PtIdentifier("default", DataType.BYTE, Position.DUMMY)) } + default = st.lookupUnscopedOrElse("undefined") { StNode("default", StNodeType.LABEL, PtIdentifier("default", DataType.forDt(BaseDataType.BYTE), Position.DUMMY)) } default.name shouldBe "default" val msbFunc = st.lookupUnscopedOrElse("msb") { fail("msb must be found") } @@ -64,7 +61,7 @@ class TestSymbolTable: FunSpec({ val v1 = sub1.lookupUnscopedOrElse("v1") { fail("v1 must be found") } as StStaticVariable v1.type shouldBe StNodeType.STATICVAR v1.name shouldBe "v1" - v1.dt shouldBe DataType.BYTE + v1.dt shouldBe DataType.forDt(BaseDataType.BYTE) val blockc = sub1.lookupUnscopedOrElse("blockc") { fail("blockc") } as StConstant blockc.type shouldBe StNodeType.CONSTANT @@ -84,15 +81,15 @@ class TestSymbolTable: FunSpec({ } test("static vars") { - val node = PtIdentifier("dummy", DataType.UBYTE, Position.DUMMY) - val stVar1 = StStaticVariable("initialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0, node) + val node = PtIdentifier("dummy", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) + val stVar1 = StStaticVariable("initialized", DataType.forDt(BaseDataType.UBYTE), null, null, null, ZeropageWish.DONTCARE, 0, node) stVar1.setOnetimeInitNumeric(99.0) - val stVar2 = StStaticVariable("uninitialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0, node) + val stVar2 = StStaticVariable("uninitialized", DataType.forDt(BaseDataType.UBYTE), null, null, null, ZeropageWish.DONTCARE, 0, node) val arrayInitNonzero = listOf(StArrayElement(1.1, null, null), StArrayElement(2.2, null, null), StArrayElement(3.3, null, null)) val arrayInitAllzero = listOf(StArrayElement(0.0, null, null), StArrayElement(0.0, null, null), StArrayElement(0.0, null, null)) - val stVar3 = StStaticVariable("initialized", DataType.ARRAY_UW, null, arrayInitNonzero, 3, ZeropageWish.DONTCARE, 0, node) - val stVar4 = StStaticVariable("initialized", DataType.ARRAY_UW, null, arrayInitAllzero, 3, ZeropageWish.DONTCARE, 0, node) - val stVar5 = StStaticVariable("uninitialized", DataType.ARRAY_UW, null, null, 3, ZeropageWish.DONTCARE, 0, node) + val stVar3 = StStaticVariable("initialized", DataType.arrayFor(BaseDataType.UWORD), null, arrayInitNonzero, 3, ZeropageWish.DONTCARE, 0, node) + val stVar4 = StStaticVariable("initialized", DataType.arrayFor(BaseDataType.UWORD), null, arrayInitAllzero, 3, ZeropageWish.DONTCARE, 0, node) + val stVar5 = StStaticVariable("uninitialized", DataType.arrayFor(BaseDataType.UWORD), null, null, 3, ZeropageWish.DONTCARE, 0, node) stVar1.uninitialized shouldBe false stVar1.length shouldBe null @@ -113,15 +110,15 @@ private fun makeSt(): SymbolTable { // first build the AST val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder) val astBlock1 = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY) - val astConstant1 = PtConstant("c1", DataType.UWORD, 12345.0, Position.DUMMY) - val astConstant2 = PtConstant("blockc", DataType.UWORD, 999.0, Position.DUMMY) + val astConstant1 = PtConstant("c1", DataType.forDt(BaseDataType.UWORD), 12345.0, Position.DUMMY) + val astConstant2 = PtConstant("blockc", DataType.forDt(BaseDataType.UWORD), 999.0, Position.DUMMY) astBlock1.add(astConstant1) astBlock1.add(astConstant2) val astSub1 = PtSub("sub1", emptyList(), null, Position.DUMMY) val astSub2 = PtSub("sub2", emptyList(), null, Position.DUMMY) val astSub1v1 = PtVariable( "v1", - DataType.BYTE, + DataType.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, 0u, null, @@ -130,7 +127,7 @@ private fun makeSt(): SymbolTable { ) val astSub1v2 = PtVariable( "v2", - DataType.BYTE, + DataType.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, 0u, null, @@ -139,7 +136,7 @@ private fun makeSt(): SymbolTable { ) val astSub1v3 = PtVariable( "v3", - DataType.FLOAT, + DataType.forDt(BaseDataType.FLOAT), ZeropageWish.DONTCARE, 0u, null, @@ -148,7 +145,7 @@ private fun makeSt(): SymbolTable { ) val astSub1v4 = PtVariable( "slab1", - DataType.UWORD, + DataType.forDt(BaseDataType.UWORD), ZeropageWish.DONTCARE, 0u, null, @@ -157,7 +154,7 @@ private fun makeSt(): SymbolTable { ) val astSub2v1 = PtVariable( "v1", - DataType.BYTE, + DataType.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, 0u, null, @@ -166,7 +163,7 @@ private fun makeSt(): SymbolTable { ) val astSub2v2 = PtVariable( "v2", - DataType.BYTE, + DataType.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, 0u, null, @@ -181,7 +178,7 @@ private fun makeSt(): SymbolTable { astSub2.add(astSub2v2) astBlock1.add(astSub1) astBlock1.add(astSub2) - val astBfunc = PtIdentifier("msb", DataType.UBYTE, Position.DUMMY) + val astBfunc = PtIdentifier("msb", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) astBlock1.add(astBfunc) val astBlock2 = PtBlock("block2", false, SourceCode.Generated("block2"), PtBlock.Options(), Position.DUMMY) val astSub21 = PtSub("sub1", emptyList(), null, Position.DUMMY) @@ -202,14 +199,14 @@ private fun makeSt(): SymbolTable { val sub12 = StNode("sub2", StNodeType.SUBROUTINE, astSub2) block1.add(sub11) block1.add(sub12) - block1.add(StConstant("c1", DataType.UWORD, 12345.0, astConstant1)) - block1.add(StConstant("blockc", DataType.UWORD, 999.0, astConstant2)) - sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0, astSub1v1)) - sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0, astSub1v2)) - sub11.add(StMemVar("v3", DataType.FLOAT, 12345u, null, astSub1v3)) + block1.add(StConstant("c1", BaseDataType.UWORD, 12345.0, astConstant1)) + block1.add(StConstant("blockc", BaseDataType.UWORD, 999.0, astConstant2)) + sub11.add(StStaticVariable("v1", DataType.forDt(BaseDataType.BYTE), null, null, null, ZeropageWish.DONTCARE, 0, astSub1v1)) + sub11.add(StStaticVariable("v2", DataType.forDt(BaseDataType.BYTE), null, null, null, ZeropageWish.DONTCARE, 0, astSub1v2)) + sub11.add(StMemVar("v3", DataType.forDt(BaseDataType.FLOAT), 12345u, null, astSub1v3)) sub11.add(StMemorySlab("slab1", 200u, 64u, astSub1v4)) - sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0, astSub2v1)) - sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0, astSub2v2)) + sub12.add(StStaticVariable("v1", DataType.forDt(BaseDataType.BYTE), null, null, null, ZeropageWish.DONTCARE, 0, astSub2v1)) + sub12.add(StStaticVariable("v2", DataType.forDt(BaseDataType.BYTE), null, null, null, ZeropageWish.DONTCARE, 0, astSub2v2)) val block2 = StNode("block2", StNodeType.BLOCK, astBlock2) val sub21 = StNode("sub1", StNodeType.SUBROUTINE, astSub21) val sub22 = StNode("sub2", StNodeType.SUBROUTINE, astSub22) diff --git a/compiler/test/TestTypecasts.kt b/compiler/test/TestTypecasts.kt index d75b006ce..823e1c281 100644 --- a/compiler/test/TestTypecasts.kt +++ b/compiler/test/TestTypecasts.kt @@ -13,6 +13,7 @@ import prog8.ast.statements.Assignment import prog8.ast.statements.IfElse import prog8.code.ast.PtAsmSub import prog8.code.ast.PtSub +import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.Position import prog8.code.target.C64Target @@ -36,7 +37,7 @@ class TestTypecasts: FunSpec({ val result = compileText(C64Target(), false, text, writeAssembly = false, errors=errors) result shouldBe null errors.errors.size shouldBe 1 - errors.errors[0] shouldContain "type mismatch" + errors.errors[0] shouldContain "type mismatch, was: float expected one of: [UWORD, WORD, LONG]" } test("not casting bool operands to logical operators") { @@ -125,9 +126,9 @@ main { right2.operator shouldBe "!=" right3.operator shouldBe "!=" right2.left shouldBe instanceOf() - right2.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY) + right2.right shouldBe NumericLiteral(BaseDataType.UBYTE, 0.0, Position.DUMMY) right3.left shouldBe instanceOf() - right3.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY) + right3.right shouldBe NumericLiteral(BaseDataType.UBYTE, 0.0, Position.DUMMY) assignValue4.right shouldBe instanceOf() assignValue5.right shouldBe instanceOf() } @@ -155,11 +156,11 @@ main { val stmts = result.compilerAst.entrypoint.statements stmts.size shouldBe 7 val fcall1 = ((stmts[4] as Assignment).value as IFunctionCall) - fcall1.args[0] shouldBe NumericLiteral(DataType.BOOL, 1.0, Position.DUMMY) - fcall1.args[1] shouldBe NumericLiteral(DataType.BOOL, 0.0, Position.DUMMY) + fcall1.args[0] shouldBe NumericLiteral(BaseDataType.BOOL, 1.0, Position.DUMMY) + fcall1.args[1] shouldBe NumericLiteral(BaseDataType.BOOL, 0.0, Position.DUMMY) val fcall2 = ((stmts[5] as Assignment).value as IFunctionCall) - fcall2.args[0] shouldBe NumericLiteral(DataType.BOOL, 0.0, Position.DUMMY) - fcall2.args[1] shouldBe NumericLiteral(DataType.BOOL, 1.0, Position.DUMMY) + fcall2.args[0] shouldBe NumericLiteral(BaseDataType.BOOL, 0.0, Position.DUMMY) + fcall2.args[1] shouldBe NumericLiteral(BaseDataType.BOOL, 1.0, Position.DUMMY) val ifCond = (stmts[6] as IfElse).condition as BinaryExpression ifCond.operator shouldBe "and" // no asm writing so logical expressions haven't been replaced with bitwise equivalents yet (ifCond.left as IdentifierReference).nameInSource shouldBe listOf("boolvalue1") @@ -223,11 +224,11 @@ main { stmts.size shouldBe 4 val assign1tc = (stmts[2] as Assignment).value as TypecastExpression val assign2tc = (stmts[3] as Assignment).value as TypecastExpression - assign1tc.type shouldBe DataType.WORD - assign2tc.type shouldBe DataType.WORD + assign1tc.type shouldBe BaseDataType.WORD + assign2tc.type shouldBe BaseDataType.WORD assign2tc.expression shouldBe instanceOf() val assign1subtc = (assign1tc.expression as TypecastExpression) - assign1subtc.type shouldBe DataType.BYTE + assign1subtc.type shouldBe BaseDataType.BYTE assign1subtc.expression shouldBe instanceOf() } @@ -689,8 +690,8 @@ main { errors.errors.size shouldBe 4 errors.errors[0] shouldContain("argument 1 type mismatch") errors.errors[1] shouldContain("argument 1 type mismatch") - errors.errors[2] shouldContain("type of value BOOL doesn't match target") - errors.errors[3] shouldContain("type of value BOOL doesn't match target") + errors.errors[2] shouldContain("type of value bool doesn't match target") + errors.errors[3] shouldContain("type of value bool doesn't match target") } test("bool function parameters correct typing") { @@ -721,7 +722,7 @@ main { errors.errors[2] shouldContain("type mismatch") errors.errors[3] shouldContain("type mismatch") errors.errors[4] shouldContain("type mismatch") - errors.errors[5] shouldContain("type of value BOOL doesn't match target") + errors.errors[5] shouldContain("type of value bool doesn't match target") } test("no implicit bool-to-int cast") { @@ -742,7 +743,7 @@ main { compileText(C64Target(), false, src, writeAssembly = false, errors = errors) shouldBe null errors.errors.size shouldBe 2 errors.errors[0] shouldContain(":5:14: argument 1 type mismatch") - errors.errors[1] shouldContain(":6:20: type of value BOOL doesn't match target") + errors.errors[1] shouldContain(":6:20: type of value bool doesn't match target") } test("no implicit int-to-bool cast") { @@ -772,8 +773,8 @@ main { errors.errors.size shouldBe 4 errors.errors[0] shouldContain(":4:15: no implicit cast") errors.errors[1] shouldContain(":5:15: no implicit cast") - errors.errors[2] shouldContain(":8:28: type of value UBYTE doesn't match target") - errors.errors[3] shouldContain(":9:28: type of value UWORD doesn't match target") + errors.errors[2] shouldContain(":8:28: type of value ubyte doesn't match target") + errors.errors[3] shouldContain(":9:28: type of value uword doesn't match target") } test("str replaced with uword in subroutine params and return types") { @@ -801,11 +802,11 @@ main { val result = compileText(VMTarget(), true, src, writeAssembly = true)!! val main = result.codegenAst!!.allBlocks().first() val derp = main.children.single { it is PtSub && it.name=="main.derp"} as PtSub - derp.returntype shouldBe DataType.UWORD - derp.parameters.single().type shouldBe DataType.UWORD + derp.returntype shouldBe DataType.forDt(BaseDataType.UWORD) + derp.parameters.single().type shouldBe DataType.forDt(BaseDataType.UWORD) val mult3 = main.children.single { it is PtAsmSub && it.name=="main.mult3"} as PtAsmSub - mult3.parameters.single().second.type shouldBe DataType.UWORD - mult3.returns.single().second shouldBe DataType.UWORD + mult3.parameters.single().second.type shouldBe DataType.forDt(BaseDataType.UWORD) + mult3.returns.single().second shouldBe DataType.forDt(BaseDataType.UWORD) } test("return 0 for str converted to uword") { @@ -884,8 +885,8 @@ main { val errors = ErrorReporterForTests() compileText(C64Target(), false, src, writeAssembly = false, errors = errors) shouldBe null errors.errors.size shouldBe 2 - errors.errors[0] shouldContain "17:16: type UBYTE of return value doesn't match subroutine's return type BYTE" - errors.errors[1] shouldContain "20:16: type UWORD of return value doesn't match subroutine's return type WORD" + errors.errors[0] shouldContain "17:16: type ubyte of return value doesn't match subroutine's return type byte" + errors.errors[1] shouldContain "20:16: type uword of return value doesn't match subroutine's return type word" } test("if-expression adjusts different value types to common type") { @@ -901,10 +902,10 @@ main { val st = program.entrypoint.statements st.size shouldBe 1 val assign = st[0] as Assignment - assign.target.inferType(program).getOr(DataType.UNDEFINED) shouldBe DataType.BYTE + assign.target.inferType(program).getOrUndef().base shouldBe BaseDataType.BYTE val ifexpr = assign.value as IfExpression - ifexpr.truevalue.inferType(program).getOr(DataType.UNDEFINED) shouldBe DataType.BYTE - ifexpr.falsevalue.inferType(program).getOr(DataType.UNDEFINED) shouldBe DataType.BYTE + ifexpr.truevalue.inferType(program).getOrUndef().base shouldBe BaseDataType.BYTE + ifexpr.falsevalue.inferType(program).getOrUndef().base shouldBe BaseDataType.BYTE ifexpr.truevalue shouldBe instanceOf() ifexpr.falsevalue shouldBe instanceOf() } @@ -928,29 +929,29 @@ main { val v1 = (st[2] as Assignment).value as BinaryExpression v1.operator shouldBe "+" (v1.left as IdentifierReference).nameInSource shouldBe listOf("cx16","r0") - (v1.right as NumericLiteral).type shouldBe DataType.UWORD + (v1.right as NumericLiteral).type shouldBe BaseDataType.UWORD (v1.right as NumericLiteral).number shouldBe 39 val v2 = (st[3] as Assignment).value as BinaryExpression v2.operator shouldBe "+" (v2.left as IdentifierReference).nameInSource shouldBe listOf("cx16","r0") - (v2.right as NumericLiteral).type shouldBe DataType.UWORD + (v2.right as NumericLiteral).type shouldBe BaseDataType.UWORD (v2.right as NumericLiteral).number shouldBe 399 val v3 = (st[4] as Assignment).value as TypecastExpression - v3.type shouldBe DataType.UWORD + v3.type shouldBe BaseDataType.UWORD val v3e = v3.expression as BinaryExpression v3e.operator shouldBe "*" (v3e.left as IdentifierReference).nameInSource shouldBe listOf("cx16","r0L") - (v3e.right as NumericLiteral).type shouldBe DataType.UBYTE + (v3e.right as NumericLiteral).type shouldBe BaseDataType.UBYTE (v3e.right as NumericLiteral).number shouldBe 5 val v4 = (st[5] as Assignment).value as BinaryExpression v4.operator shouldBe "*" val v4t = v4.left as TypecastExpression - v4t.type shouldBe DataType.UWORD + v4t.type shouldBe BaseDataType.UWORD (v4t.expression as IdentifierReference).nameInSource shouldBe listOf("cx16","r0L") - (v4.right as NumericLiteral).type shouldBe DataType.UWORD + (v4.right as NumericLiteral).type shouldBe BaseDataType.UWORD (v4.right as NumericLiteral).number shouldBe 5 } }) diff --git a/compiler/test/TestZeropage.kt b/compiler/test/TestZeropage.kt index 63136d405..4a8987604 100644 --- a/compiler/test/TestZeropage.kt +++ b/compiler/test/TestZeropage.kt @@ -74,26 +74,26 @@ class TestC64Zeropage: FunSpec({ compTarget = c64target, loadAddress = 999u, memtopAddress = 0xffffu )) - var result = zp.allocate("", DataType.UBYTE, null, null, errors) + var result = zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors) result.onFailure { fail(it.toString()) } - result = zp.allocate("", DataType.UBYTE, null, null, errors) + result = zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors) result.onFailure { fail(it.toString()) } - result = zp.allocate("varname", DataType.UBYTE, null, null, errors) + result = zp.allocate("varname", DataType.forDt(BaseDataType.UBYTE), null, null, errors) result.onFailure { fail(it.toString()) } - shouldThrow { zp.allocate("varname", DataType.UBYTE,null, null, errors) } - result = zp.allocate("varname2", DataType.UBYTE, null, null, errors) + shouldThrow { zp.allocate("varname", DataType.forDt(BaseDataType.UBYTE),null, null, errors) } + result = zp.allocate("varname2", DataType.forDt(BaseDataType.UBYTE), null, null, errors) result.onFailure { fail(it.toString()) } } test("testZpFloatEnable") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu)) - var result = zp.allocate("", DataType.FLOAT, null, null, errors) + var result = zp.allocate("", DataType.forDt(BaseDataType.FLOAT), null, null, errors) result.expectError { "should be allocation error due to disabled floats" } val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu)) - result = zp2.allocate("", DataType.FLOAT, null, null, errors) + result = zp2.allocate("", DataType.forDt(BaseDataType.FLOAT), null, null, errors) result.expectError { "should be allocation error due to disabled ZP use" } val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu)) - zp3.allocate("", DataType.FLOAT, null, null, errors) + zp3.allocate("", DataType.forDt(BaseDataType.FLOAT), null, null, errors) } test("testZpModesWithFloats") { @@ -115,7 +115,7 @@ class TestC64Zeropage: FunSpec({ val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu)) println(zp.free) zp.availableBytes() shouldBe 0 - val result = zp.allocate("", DataType.BYTE, null, null, errors) + val result = zp.allocate("", DataType.forDt(BaseDataType.BYTE), null, null, errors) result.expectError { "expected error due to disabled ZP use" } } @@ -128,9 +128,9 @@ class TestC64Zeropage: FunSpec({ zp3.availableBytes() shouldBe 96 val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u, 0xffffu)) zp4.availableBytes() shouldBe 207 - zp4.allocate("test", DataType.UBYTE, null, null, errors) + zp4.allocate("test", DataType.forDt(BaseDataType.UBYTE), null, null, errors) zp4.availableBytes() shouldBe 206 - zp4.allocate("test2", DataType.UBYTE, null, null, errors) + zp4.allocate("test2", DataType.forDt(BaseDataType.UBYTE), null, null, errors) zp4.availableBytes() shouldBe 205 } @@ -169,19 +169,19 @@ class TestC64Zeropage: FunSpec({ zp.hasByteAvailable() shouldBe true zp.hasWordAvailable() shouldBe true - var result = zp.allocate("", DataType.FLOAT, null, null, errors) + var result = zp.allocate("", DataType.forDt(BaseDataType.FLOAT), null, null, errors) result.expectError { "expect allocation error: in regular zp there aren't 5 sequential bytes free" } for (i in 0 until zp.availableBytes()) { - val alloc = zp.allocate("", DataType.UBYTE, null, null, errors) + val alloc = zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors) alloc.getOrElse { throw it } } zp.availableBytes() shouldBe 0 zp.hasByteAvailable() shouldBe false zp.hasWordAvailable() shouldBe false - result = zp.allocate("", DataType.UBYTE, null, null, errors) + result = zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors) result.expectError { "expected allocation error" } - result = zp.allocate("", DataType.UWORD, null, null, errors) + result = zp.allocate("", DataType.forDt(BaseDataType.UWORD), null, null, errors) result.expectError { "expected allocation error" } } @@ -190,47 +190,47 @@ class TestC64Zeropage: FunSpec({ zp.availableBytes() shouldBe 207 zp.hasByteAvailable() shouldBe true zp.hasWordAvailable() shouldBe true - var result = zp.allocate("", DataType.UWORD, null, null, errors) + var result = zp.allocate("", DataType.forDt(BaseDataType.UWORD), null, null, errors) val loc = result.getOrElse { throw it } .address loc shouldBeGreaterThan 3u loc shouldNotBeIn zp.free val num = zp.availableBytes() / 2 for(i in 0..num-3) { - zp.allocate("", DataType.UWORD, null, null, errors) + zp.allocate("", DataType.forDt(BaseDataType.UWORD), null, null, errors) } zp.availableBytes() shouldBe 5 // can't allocate because no more sequential bytes, only fragmented - result = zp.allocate("", DataType.UWORD, null, null, errors) + result = zp.allocate("", DataType.forDt(BaseDataType.UWORD), null, null, errors) result.expectError { "should give allocation error" } for(i in 0..4) { - zp.allocate("", DataType.UBYTE, null, null, errors) + zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors) } zp.availableBytes() shouldBe 0 zp.hasByteAvailable() shouldBe false zp.hasWordAvailable() shouldBe false - result = zp.allocate("", DataType.UBYTE, null, null, errors) + result = zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors) result.expectError { "should give allocation error" } } test("testEfficientAllocation") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u, 0xffffu)) zp.availableBytes() shouldBe 17 - zp.allocate("", DataType.WORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x04u - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x06u - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0au - zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9bu - zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9eu - zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xb0u - zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xbeu - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0eu - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x92u - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x96u - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0xa6u - zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0xf9u + zp.allocate("", DataType.forDt(BaseDataType.WORD), null, null, errors).getOrElse{throw it}.address shouldBe 0x04u + zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x06u + zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x0au + zp.allocate("", DataType.forDt(BaseDataType.UWORD), null, null, errors).getOrElse{throw it}.address shouldBe 0x9bu + zp.allocate("", DataType.forDt(BaseDataType.UWORD), null, null, errors).getOrElse{throw it}.address shouldBe 0x9eu + zp.allocate("", DataType.forDt(BaseDataType.UWORD), null, null, errors).getOrElse{throw it}.address shouldBe 0xb0u + zp.allocate("", DataType.forDt(BaseDataType.UWORD), null, null, errors).getOrElse{throw it}.address shouldBe 0xbeu + zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x0eu + zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x92u + zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x96u + zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0xa6u + zp.allocate("", DataType.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0xf9u zp.availableBytes() shouldBe 0 } @@ -261,9 +261,9 @@ class TestCx16Zeropage: FunSpec({ zp2.availableBytes() shouldBe 175 val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u, 0xffffu)) zp3.availableBytes() shouldBe 216 - zp3.allocate("test", DataType.UBYTE, null, null, errors) + zp3.allocate("test", DataType.forDt(BaseDataType.UBYTE), null, null, errors) zp3.availableBytes() shouldBe 215 - zp3.allocate("test2", DataType.UBYTE, null, null, errors) + zp3.allocate("test2", DataType.forDt(BaseDataType.UBYTE), null, null, errors) zp3.availableBytes() shouldBe 214 } diff --git a/compiler/test/ast/TestAstChecks.kt b/compiler/test/ast/TestAstChecks.kt index 279d821fd..7ce236954 100644 --- a/compiler/test/ast/TestAstChecks.kt +++ b/compiler/test/ast/TestAstChecks.kt @@ -121,7 +121,7 @@ class TestAstChecks: FunSpec({ main { sub start() { &ubyte a = 10000 - uword z = 500 + uword @shared z = 500 a[4] = (z % 3) as ubyte } } diff --git a/compiler/test/ast/TestConst.kt b/compiler/test/ast/TestConst.kt index c378814aa..df73797ee 100644 --- a/compiler/test/ast/TestConst.kt +++ b/compiler/test/ast/TestConst.kt @@ -13,7 +13,7 @@ import prog8.ast.statements.Assignment import prog8.ast.statements.Return import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDeclType -import prog8.code.core.DataType +import prog8.code.core.BaseDataType import prog8.code.core.Position import prog8.code.target.C64Target import prog8.code.target.Cx16Target @@ -55,23 +55,23 @@ class TestConst: FunSpec({ val addR0value = (stmts[4] as Assignment).value val binexpr0 = addR0value as BinaryExpression binexpr0.operator shouldBe "+" - binexpr0.right shouldBe NumericLiteral(DataType.UWORD, 10000.0, Position.DUMMY) + binexpr0.right shouldBe NumericLiteral(BaseDataType.UWORD, 10000.0, Position.DUMMY) val addR2value = (stmts[5] as Assignment).value val binexpr2 = addR2value as BinaryExpression binexpr2.operator shouldBe "+" - binexpr2.right shouldBe NumericLiteral(DataType.UWORD, 10000.0, Position.DUMMY) + binexpr2.right shouldBe NumericLiteral(BaseDataType.UWORD, 10000.0, Position.DUMMY) val addR4value = (stmts[6] as Assignment).value val binexpr4 = addR4value as BinaryExpression binexpr4.operator shouldBe "+" - binexpr4.right shouldBe NumericLiteral(DataType.UWORD, 22.0, Position.DUMMY) + binexpr4.right shouldBe NumericLiteral(BaseDataType.UWORD, 22.0, Position.DUMMY) val subR5value = (stmts[7] as Assignment).value val binexpr5 = subR5value as BinaryExpression binexpr5.operator shouldBe "-" - binexpr5.right shouldBe NumericLiteral(DataType.WORD, 1899.0, Position.DUMMY) + binexpr5.right shouldBe NumericLiteral(BaseDataType.WORD, 1899.0, Position.DUMMY) val subR7value = (stmts[8] as Assignment).value val binexpr7 = subR7value as BinaryExpression binexpr7.operator shouldBe "+" - binexpr7.right shouldBe NumericLiteral(DataType.WORD, 99.0, Position.DUMMY) + binexpr7.right shouldBe NumericLiteral(BaseDataType.WORD, 99.0, Position.DUMMY) } test("const folding multiple scenarios * and / (floats)") { @@ -112,24 +112,24 @@ class TestConst: FunSpec({ val mulR0Value = (stmts[3] as Assignment).value val binexpr0 = mulR0Value as BinaryExpression binexpr0.operator shouldBe "*" - binexpr0.right shouldBe NumericLiteral(DataType.FLOAT, 180.0, Position.DUMMY) + binexpr0.right shouldBe NumericLiteral(BaseDataType.FLOAT, 180.0, Position.DUMMY) val mulR1Value = (stmts[5] as Assignment).value val binexpr1 = mulR1Value as BinaryExpression binexpr1.operator shouldBe "*" - binexpr1.right shouldBe NumericLiteral(DataType.FLOAT, 180.0, Position.DUMMY) + binexpr1.right shouldBe NumericLiteral(BaseDataType.FLOAT, 180.0, Position.DUMMY) val divR2Value = (stmts[7] as Assignment).value val binexpr2 = divR2Value as BinaryExpression binexpr2.operator shouldBe "/" - binexpr2.right shouldBe NumericLiteral(DataType.FLOAT, 90.0, Position.DUMMY) + binexpr2.right shouldBe NumericLiteral(BaseDataType.FLOAT, 90.0, Position.DUMMY) val mulR3Value = (stmts[9] as Assignment).value val binexpr3 = mulR3Value as BinaryExpression binexpr3.operator shouldBe "*" - binexpr3.right shouldBe NumericLiteral(DataType.FLOAT, 5.0, Position.DUMMY) + binexpr3.right shouldBe NumericLiteral(BaseDataType.FLOAT, 5.0, Position.DUMMY) binexpr3.left shouldBe instanceOf() val mulR4Value = (stmts[11] as Assignment).value val binexpr4 = mulR4Value as BinaryExpression binexpr4.operator shouldBe "*" - binexpr4.right shouldBe NumericLiteral(DataType.FLOAT, 18.0, Position.DUMMY) + binexpr4.right shouldBe NumericLiteral(BaseDataType.FLOAT, 18.0, Position.DUMMY) binexpr4.left shouldBe instanceOf() } @@ -160,24 +160,24 @@ class TestConst: FunSpec({ val mulR0Value = (stmts[2] as Assignment).value val binexpr0 = mulR0Value as BinaryExpression binexpr0.operator shouldBe "*" - binexpr0.right shouldBe NumericLiteral(DataType.WORD, 180.0, Position.DUMMY) + binexpr0.right shouldBe NumericLiteral(BaseDataType.WORD, 180.0, Position.DUMMY) val mulR1Value = (stmts[3] as Assignment).value val binexpr1 = mulR1Value as BinaryExpression binexpr1.operator shouldBe "*" - binexpr1.right shouldBe NumericLiteral(DataType.WORD, 180.0, Position.DUMMY) + binexpr1.right shouldBe NumericLiteral(BaseDataType.WORD, 180.0, Position.DUMMY) val divR2Value = (stmts[4] as Assignment).value val binexpr2 = divR2Value as BinaryExpression binexpr2.operator shouldBe "/" - binexpr2.right shouldBe NumericLiteral(DataType.WORD, 90.0, Position.DUMMY) + binexpr2.right shouldBe NumericLiteral(BaseDataType.WORD, 90.0, Position.DUMMY) val mulR3Value = (stmts[5] as Assignment).value val binexpr3 = mulR3Value as BinaryExpression binexpr3.operator shouldBe "*" - binexpr3.right shouldBe NumericLiteral(DataType.WORD, 10.0, Position.DUMMY) + binexpr3.right shouldBe NumericLiteral(BaseDataType.WORD, 10.0, Position.DUMMY) binexpr3.left shouldBe instanceOf() val mulR4Value = (stmts[6] as Assignment).value val binexpr4 = mulR4Value as BinaryExpression binexpr4.operator shouldBe "/" - binexpr4.right shouldBe NumericLiteral(DataType.WORD, 5.0, Position.DUMMY) + binexpr4.right shouldBe NumericLiteral(BaseDataType.WORD, 5.0, Position.DUMMY) binexpr4.left shouldBe instanceOf() } @@ -211,13 +211,13 @@ class TestConst: FunSpec({ declX2.value shouldBe null declY1.value shouldBe null declY2.value shouldBe null - (initX1.value as NumericLiteral).type shouldBe DataType.BYTE + (initX1.value as NumericLiteral).type shouldBe BaseDataType.BYTE (initX1.value as NumericLiteral).number shouldBe 11.0 - (initX2.value as NumericLiteral).type shouldBe DataType.BYTE + (initX2.value as NumericLiteral).type shouldBe BaseDataType.BYTE (initX2.value as NumericLiteral).number shouldBe 11.0 - (initY1.value as NumericLiteral).type shouldBe DataType.UBYTE + (initY1.value as NumericLiteral).type shouldBe BaseDataType.UBYTE (initY1.value as NumericLiteral).number shouldBe 11.0 - (initY2.value as NumericLiteral).type shouldBe DataType.UBYTE + (initY2.value as NumericLiteral).type shouldBe BaseDataType.UBYTE (initY2.value as NumericLiteral).number shouldBe 11.0 } diff --git a/compiler/test/ast/TestIntermediateAst.kt b/compiler/test/ast/TestIntermediateAst.kt index 2d7711e8d..ea1766f1d 100644 --- a/compiler/test/ast/TestIntermediateAst.kt +++ b/compiler/test/ast/TestIntermediateAst.kt @@ -4,36 +4,37 @@ import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import prog8.code.ast.PtBinaryExpression import prog8.code.ast.PtNumber +import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.Position class TestIntermediateAst: FunSpec({ test("isSame on binaryExpressions") { - val expr1 = PtBinaryExpression("/", DataType.UBYTE, Position.DUMMY) - expr1.add(PtNumber(DataType.UBYTE, 1.0, Position.DUMMY)) - expr1.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY)) - val expr2 = PtBinaryExpression("/", DataType.UBYTE, Position.DUMMY) - expr2.add(PtNumber(DataType.UBYTE, 1.0, Position.DUMMY)) - expr2.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY)) + val expr1 = PtBinaryExpression("/", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) + expr1.add(PtNumber(BaseDataType.UBYTE, 1.0, Position.DUMMY)) + expr1.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY)) + val expr2 = PtBinaryExpression("/", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) + expr2.add(PtNumber(BaseDataType.UBYTE, 1.0, Position.DUMMY)) + expr2.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY)) (expr1 isSameAs expr2) shouldBe true - val expr3 = PtBinaryExpression("/", DataType.UBYTE, Position.DUMMY) - expr3.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY)) - expr3.add(PtNumber(DataType.UBYTE, 1.0, Position.DUMMY)) + val expr3 = PtBinaryExpression("/", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) + expr3.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY)) + expr3.add(PtNumber(BaseDataType.UBYTE, 1.0, Position.DUMMY)) (expr1 isSameAs expr3) shouldBe false } test("isSame on binaryExpressions with associative operators") { - val expr1 = PtBinaryExpression("+", DataType.UBYTE, Position.DUMMY) - expr1.add(PtNumber(DataType.UBYTE, 1.0, Position.DUMMY)) - expr1.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY)) - val expr2 = PtBinaryExpression("+", DataType.UBYTE, Position.DUMMY) - expr2.add(PtNumber(DataType.UBYTE, 1.0, Position.DUMMY)) - expr2.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY)) + val expr1 = PtBinaryExpression("+", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) + expr1.add(PtNumber(BaseDataType.UBYTE, 1.0, Position.DUMMY)) + expr1.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY)) + val expr2 = PtBinaryExpression("+", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) + expr2.add(PtNumber(BaseDataType.UBYTE, 1.0, Position.DUMMY)) + expr2.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY)) (expr1 isSameAs expr2) shouldBe true - val expr3 = PtBinaryExpression("+", DataType.UBYTE, Position.DUMMY) - expr3.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY)) - expr3.add(PtNumber(DataType.UBYTE, 1.0, Position.DUMMY)) + val expr3 = PtBinaryExpression("+", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) + expr3.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY)) + expr3.add(PtNumber(BaseDataType.UBYTE, 1.0, Position.DUMMY)) (expr1 isSameAs expr3) shouldBe true } }) \ No newline at end of file diff --git a/compiler/test/ast/TestProg8Parser.kt b/compiler/test/ast/TestProg8Parser.kt index cd591774b..98801de0b 100644 --- a/compiler/test/ast/TestProg8Parser.kt +++ b/compiler/test/ast/TestProg8Parser.kt @@ -623,8 +623,8 @@ class TestProg8Parser: FunSpec( { } test("testLiteralValueComparisons") { - val ten = NumericLiteral(DataType.UWORD, 10.0, Position.DUMMY) - val nine = NumericLiteral(DataType.UBYTE, 9.0, Position.DUMMY) + val ten = NumericLiteral(BaseDataType.UWORD, 10.0, Position.DUMMY) + val nine = NumericLiteral(BaseDataType.UBYTE, 9.0, Position.DUMMY) ten shouldBe ten nine shouldNotBe ten (ten != ten) shouldBe false @@ -754,9 +754,9 @@ class TestProg8Parser: FunSpec( { val expr = bb2.value as BinaryExpression println(expr) expr.operator shouldBe "or" - expr.left.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UBYTE - expr.right.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UWORD - expr.inferType(program).getOrElse { fail("dt") } shouldBe DataType.BOOL + expr.left.inferType(program).getOrElse { fail("dt") } shouldBe DataType.forDt(BaseDataType.UBYTE) + expr.right.inferType(program).getOrElse { fail("dt") } shouldBe DataType.forDt(BaseDataType.UWORD) + expr.inferType(program).getOrElse { fail("dt") } shouldBe DataType.forDt(BaseDataType.BOOL) } test("inferred type for typecasted expressions with logical operators") { @@ -779,16 +779,16 @@ class TestProg8Parser: FunSpec( { val zz = (stmts[3] as VarDecl).value as BinaryExpression val bb2 = (stmts[4] as VarDecl).value as BinaryExpression val zz2 = (stmts[5] as VarDecl).value as BinaryExpression - qq.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UWORD - zz.inferType(program).getOrElse { fail("dt") } shouldBe DataType.BOOL - bb2.inferType(program).getOrElse { fail("dt") } shouldBe DataType.BOOL + qq.inferType(program).getOrElse { fail("dt") } shouldBe DataType.forDt(BaseDataType.UWORD) + zz.inferType(program).getOrElse { fail("dt") } shouldBe DataType.forDt(BaseDataType.BOOL) + bb2.inferType(program).getOrElse { fail("dt") } shouldBe DataType.forDt(BaseDataType.BOOL) zz2.operator shouldBe "or" val left = zz2.left as TypecastExpression val right = zz2.right as PrefixExpression - left.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UWORD - right.inferType(program).getOrElse { fail("dt") } shouldBe DataType.BOOL - zz2.inferType(program).getOrElse { fail("dt") } shouldBe DataType.BOOL + left.inferType(program).getOrElse { fail("dt") } shouldBe DataType.forDt(BaseDataType.UWORD) + right.inferType(program).getOrElse { fail("dt") } shouldBe DataType.forDt(BaseDataType.BOOL) + zz2.inferType(program).getOrElse { fail("dt") } shouldBe DataType.forDt(BaseDataType.BOOL) } test("type cast from byte to ubyte as desired target type") { @@ -803,7 +803,7 @@ class TestProg8Parser: FunSpec( { val stmts = (module.statements.single() as Block).statements stmts.size shouldBe 2 val ubexpr = (stmts[1] as VarDecl).value as TypecastExpression - ubexpr.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UBYTE + ubexpr.inferType(program).getOrElse { fail("dt") } shouldBe DataType.forDt(BaseDataType.UBYTE) } test("assignment isAugmented correctness") { @@ -871,12 +871,12 @@ class TestProg8Parser: FunSpec( { } string.value[2].code shouldBe 65 val zero = start.statements[2] as Assignment - zero.value shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY) + zero.value shouldBe NumericLiteral(BaseDataType.UBYTE, 0.0, Position.DUMMY) val ff = start.statements[4] as Assignment - ff.value shouldBe NumericLiteral(DataType.UBYTE, 255.0, Position.DUMMY) + ff.value shouldBe NumericLiteral(BaseDataType.UBYTE, 255.0, Position.DUMMY) val letter = start.statements[6] as Assignment val encodedletter = PetsciiEncoding.encodePetscii("A", true).getOrElse { fail("petscii error") }.single() - letter.value shouldBe NumericLiteral(DataType.UBYTE, encodedletter.toDouble(), Position.DUMMY) + letter.value shouldBe NumericLiteral(BaseDataType.UBYTE, encodedletter.toDouble(), Position.DUMMY) } test("`in` containment checks") { diff --git a/compiler/test/ast/TestSubroutines.kt b/compiler/test/ast/TestSubroutines.kt index b2a36836d..d2b8e1719 100644 --- a/compiler/test/ast/TestSubroutines.kt +++ b/compiler/test/ast/TestSubroutines.kt @@ -8,6 +8,7 @@ import prog8.ast.statements.Block import prog8.ast.statements.Subroutine import prog8.code.ast.PtAssignTarget import prog8.code.ast.PtAssignment +import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.SourceCode import prog8.code.target.C64Target @@ -37,10 +38,10 @@ class TestSubroutines: FunSpec({ val asmfunc = mainBlock.statements.filterIsInstance().single { it.name=="asmfunc"} val func = mainBlock.statements.filterIsInstance().single { it.name=="func"} asmfunc.isAsmSubroutine shouldBe true - asmfunc.parameters.single().type shouldBe DataType.STR + asmfunc.parameters.single().type shouldBe DataType.forDt(BaseDataType.STR) asmfunc.statements.isEmpty() shouldBe true func.isAsmSubroutine shouldBe false - func.parameters.single().type shouldBe DataType.STR + func.parameters.single().type shouldBe DataType.forDt(BaseDataType.STR) func.statements.isEmpty() shouldBe true } @@ -62,10 +63,10 @@ class TestSubroutines: FunSpec({ val asmfunc = mainBlock.statements.filterIsInstance().single { it.name=="asmfunc"} val func = mainBlock.statements.filterIsInstance().single { it.name=="func"} asmfunc.isAsmSubroutine shouldBe true - asmfunc.parameters.single().type shouldBe DataType.ARRAY_UB + asmfunc.parameters.single().type shouldBe DataType.arrayFor(BaseDataType.UBYTE) asmfunc.statements.isEmpty() shouldBe true func.isAsmSubroutine shouldBe false - func.parameters.single().type shouldBe DataType.ARRAY_UB + func.parameters.single().type shouldBe DataType.arrayFor(BaseDataType.UBYTE) func.statements.isEmpty() shouldBe true } diff --git a/compiler/test/ast/TestVariousCompilerAst.kt b/compiler/test/ast/TestVariousCompilerAst.kt index 8bfb9305e..b4f8843c5 100644 --- a/compiler/test/ast/TestVariousCompilerAst.kt +++ b/compiler/test/ast/TestVariousCompilerAst.kt @@ -1,5 +1,6 @@ package prog8tests.ast +import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.comparables.shouldBeGreaterThan import io.kotest.matchers.shouldBe @@ -11,8 +12,10 @@ import prog8.ast.IFunctionCall import prog8.ast.expressions.* import prog8.ast.statements.* 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 @@ -557,10 +560,10 @@ main { val assign2expr = (stmts[5] as Assignment).value as BinaryExpression assign1expr.operator shouldBe "<<" val leftval1 = assign1expr.left.constValue(result.compilerAst)!! - leftval1.type shouldBe DataType.UWORD + leftval1.type shouldBe BaseDataType.UWORD leftval1.number shouldBe 1.0 val leftval2 = assign2expr.left.constValue(result.compilerAst)!! - leftval2.type shouldBe DataType.UWORD + leftval2.type shouldBe BaseDataType.UWORD leftval2.number shouldBe 1.0 } @@ -834,13 +837,13 @@ main { val result = compileText(VMTarget(), optimize=true, src, writeAssembly=false)!! val st = result.compilerAst.entrypoint.statements st.size shouldBe 8 - val assignUbb = ((st[5] as Assignment).value as TypecastExpression) - assignUbb.type shouldBe DataType.UBYTE - assignUbb.expression shouldBe instanceOf() + val assignUbbVal = ((st[5] as Assignment).value as TypecastExpression) + assignUbbVal.type shouldBe BaseDataType.UBYTE + assignUbbVal.expression shouldBe instanceOf() val assignVaddr = (st[7] as Assignment).value as FunctionCallExpression assignVaddr.target.nameInSource shouldBe listOf("mkword") val tc = assignVaddr.args[0] as TypecastExpression - tc.type shouldBe DataType.UBYTE + tc.type shouldBe BaseDataType.UBYTE tc.expression shouldBe instanceOf() } @@ -869,6 +872,88 @@ 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 + DataType.forDt(BaseDataType.UWORD).isWord shouldBe true + DataType.forDt(BaseDataType.BYTE).isByte shouldBe true + DataType.forDt(BaseDataType.UBYTE).isByte shouldBe true + + shouldThrow { + DataType.arrayFor(BaseDataType.ARRAY) + } + shouldThrow { + DataType.arrayFor(BaseDataType.LONG) + } + shouldThrow { + DataType.arrayFor(BaseDataType.UNDEFINED) + } + shouldThrow { + DataType.arrayFor(BaseDataType.UBYTE, 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 false + DataType.arrayFor(BaseDataType.UWORD, true).isArray shouldBe true + DataType.arrayFor(BaseDataType.UWORD, true).isSplitWordArray shouldBe true + } + + test("array of strings becomes array of uword pointers") { + val src=""" + main { + sub start() { + str variable = "name1" + str[2] @shared names = [ variable, "name2" ] + } + }""" + + val result = compileText(C64Target(), false, src, writeAssembly = true) + result shouldNotBe null + + val st1 = result!!.compilerAst.entrypoint.statements + st1.size shouldBe 3 + st1[0] shouldBe instanceOf() + st1[1] shouldBe instanceOf() + (st1[0] as VarDecl).name shouldBe "variable" + (st1[1] as VarDecl).name shouldBe "names" + val array1 = (st1[1] as VarDecl).value as ArrayLiteral + array1.type.isArray shouldBe true + array1.type.getOrUndef() shouldBe DataType.arrayFor(BaseDataType.UWORD, false) + + val ast2 = result.codegenAst!! + val st2 = ast2.entrypoint()!!.children + st2.size shouldBe 3 + (st2[0] as PtVariable).name shouldBe "p8v_variable" + (st2[1] as PtVariable).name shouldBe "p8v_names" + val array2 = (st2[1] as PtVariable).value as PtArray + array2.type shouldBe DataType.arrayFor(BaseDataType.UWORD, false) + } + test("defer syntactic sugaring") { val src=""" main { diff --git a/compiler/test/codegeneration/TestArrayThings.kt b/compiler/test/codegeneration/TestArrayThings.kt index a09cde735..f945ea433 100644 --- a/compiler/test/codegeneration/TestArrayThings.kt +++ b/compiler/test/codegeneration/TestArrayThings.kt @@ -400,5 +400,24 @@ label: errors.errors[0] shouldContain "contains non-constant" errors.errors[1] shouldContain "contains non-constant" } + + test("memsizing in codegen of array return values") { + val src=""" +main { + sub start() { + cx16.r1 = give_array1() + cx16.r2 = give_array2() + } + + sub give_array1() -> uword { + return [1,2,3,4] + } + sub give_array2() -> uword { + return [1000,2000,3000,4000] + } +}""" + compileText(VMTarget(), false, src, writeAssembly = true) shouldNotBe null + compileText(C64Target(), false, src, writeAssembly = true) shouldNotBe null + } }) diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index 8879f85ba..4848d5437 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -46,8 +46,8 @@ class TestAsmGenSymbols: StringSpec({ } */ - val varInSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "localvar", emptyList(), NumericLiteral.optimalInteger(1234, Position.DUMMY), false, false, 0u, false, Position.DUMMY) - val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", emptyList(), null, false, false, 0u, false, Position.DUMMY) + val varInSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.forDt(BaseDataType.UWORD), ZeropageWish.DONTCARE, null, "localvar", emptyList(), NumericLiteral.optimalInteger(1234, Position.DUMMY), false, false, 0u, false, Position.DUMMY) + val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.forDt(BaseDataType.UWORD), ZeropageWish.DONTCARE, null, "tgt", emptyList(), null, false, false, 0u, false, Position.DUMMY) val labelInSub = Label("locallabel", Position.DUMMY) val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, null, false, Position.DUMMY) @@ -63,7 +63,7 @@ class TestAsmGenSymbols: StringSpec({ val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8) val subroutine = Subroutine("start", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY) val labelInBlock = Label("label_outside", Position.DUMMY) - val varInBlock = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", emptyList(),null, false, false, 0u, false, Position.DUMMY) + val varInBlock = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.forDt(BaseDataType.UWORD), ZeropageWish.DONTCARE, null, "var_outside", emptyList(),null, false, false, 0u, false, Position.DUMMY) val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY) val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test")) @@ -149,8 +149,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 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_REG", DataType.UBYTE, Position.DUMMY) - val id2 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_W2", DataType.UWORD, Position.DUMMY) + val id1 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_REG", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY) + val id2 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD), Position.DUMMY) id1.parent = PtProgram("test", DummyMemsizer, DummyStringEncoder) id2.parent = PtProgram("test", DummyMemsizer, DummyStringEncoder) asmgen.asmSymbolName(id1) shouldBe "P8ZP_SCRATCH_REG" diff --git a/compiler/test/codegeneration/TestVariousCodeGen.kt b/compiler/test/codegeneration/TestVariousCodeGen.kt index c94ba33c6..777515285 100644 --- a/compiler/test/codegeneration/TestVariousCodeGen.kt +++ b/compiler/test/codegeneration/TestVariousCodeGen.kt @@ -13,6 +13,7 @@ import prog8.code.ast.PtFunctionCall import prog8.code.ast.PtIfElse import prog8.code.ast.PtPrefix import prog8.code.ast.PtVariable +import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.target.* import prog8tests.helpers.ErrorReporterForTests @@ -77,7 +78,7 @@ main { val seed = start.children[0] as PtVariable seed.name shouldBe "p8v_seed" seed.value shouldBe null - seed.type shouldBe DataType.ARRAY_UW + seed.type shouldBe DataType.arrayFor(BaseDataType.UWORD) val assign = start.children[1] as PtAssignment assign.target.identifier!!.name shouldBe "cx16.r0" assign.value shouldBe instanceOf() diff --git a/compiler/test/helpers/Dummies.kt b/compiler/test/helpers/Dummies.kt index 87a2f6fc3..0ece1def8 100644 --- a/compiler/test/helpers/Dummies.kt +++ b/compiler/test/helpers/Dummies.kt @@ -21,16 +21,25 @@ internal object DummyFunctions : IBuiltinFunctions { } internal object DummyMemsizer : IMemSizer { - override fun memorySize(dt: DataType) = when(dt) { - in ByteDatatypesWithBoolean -> 1 - DataType.FLOAT -> 5 - else -> 2 + override fun memorySize(dt: DataType, numElements: Int?): Int { + if(dt.isArray || dt.isSplitWordArray) { + require(numElements!=null) + return when(dt.sub?.dt) { + BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements + BaseDataType.UWORD, BaseDataType.WORD -> numElements*2 + BaseDataType.FLOAT -> numElements*5 + else -> throw IllegalArgumentException("invalid sub type") + } + } + return when { + dt.isByteOrBool -> 1 * (numElements ?: 1) + dt.isFloat -> 5 * (numElements ?: 1) + else -> 2 * (numElements ?: 1) + } } - override fun memorySize(arrayDt: DataType, numElements: Int) = when(arrayDt) { - DataType.ARRAY_UW -> numElements*2 - DataType.ARRAY_W -> numElements*2 - DataType.ARRAY_F -> numElements*5 - else -> numElements + + override fun memorySize(dt: SubType): Int { + return memorySize(DataType.forDt(dt.dt), null) } } @@ -69,11 +78,11 @@ internal object DummyCompilationTarget : ICompilationTarget { throw NotImplementedError("dummy") } - override fun memorySize(dt: DataType): Int { + override fun memorySize(dt: DataType, numElements: Int?): Int { throw NotImplementedError("dummy") } - override fun memorySize(arrayDt: DataType, numElements: Int): Int { + override fun memorySize(dt: SubType): Int { throw NotImplementedError("dummy") } } diff --git a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt index d8abc5a48..43cf3475f 100644 --- a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt +++ b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt @@ -116,28 +116,6 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: output("\n") } - private fun datatypeString(dt: DataType): String { - return when (dt) { - DataType.BOOL -> "bool" - DataType.UBYTE -> "ubyte" - DataType.BYTE -> "byte" - DataType.UWORD -> "uword" - DataType.WORD -> "word" - DataType.LONG -> "long" - DataType.FLOAT -> "float" - DataType.STR -> "str" - DataType.ARRAY_UB -> "ubyte[" - DataType.ARRAY_B -> "byte[" - DataType.ARRAY_UW -> "uword[" - DataType.ARRAY_W -> "word[" - DataType.ARRAY_F -> "float[" - DataType.ARRAY_BOOL -> "bool[" - DataType.ARRAY_UW_SPLIT -> "@split uword[" - DataType.ARRAY_W_SPLIT -> "@split word[" - DataType.UNDEFINED -> throw IllegalArgumentException("wrong dt") - } - } - override fun visit(decl: VarDecl) { if(decl.origin==VarDeclOrigin.SUBROUTINEPARAM) return @@ -148,7 +126,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: VarDeclType.MEMORY -> output("&") } - output(datatypeString(decl.datatype)) + output(decl.datatype.sourceString()) if(decl.arraysize!=null) { decl.arraysize!!.indexExpr.accept(this) } @@ -201,7 +179,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: param.second.statusflag!=null -> param.second.statusflag.toString() else -> "?????" } - output("${datatypeString(param.first.type)} ${param.first.name} @$reg") + output("${param.first.type.sourceString()} ${param.first.name} @$reg") if(param.first!==subroutine.parameters.last()) output(", ") } @@ -210,7 +188,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: output("sub ${subroutine.name} (") for(param in subroutine.parameters) { val reg = if(param.registerOrPair!=null) " @${param.registerOrPair}" else "" - output("${datatypeString(param.type)} ${param.name}$reg") + output("${param.type} ${param.name}$reg") if(param!==subroutine.parameters.last()) output(", ") } @@ -229,7 +207,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: if(subroutine.returntypes.any()) { if(subroutine.asmReturnvaluesRegisters.isNotEmpty()) { val rts = subroutine.returntypes.zip(subroutine.asmReturnvaluesRegisters).joinToString(", ") { - val dtstr = datatypeString(it.first) + val dtstr = it.first.sourceString() if(it.second.registerOrPair!=null) "$dtstr @${it.second.registerOrPair}" else @@ -237,7 +215,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: } output("-> $rts ") } else { - val rts = subroutine.returntypes.joinToString(", ") { datatypeString(it) } + val rts = subroutine.returntypes.joinToString(", ") { it.sourceString() } output("-> $rts ") } } @@ -325,8 +303,8 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: override fun visit(numLiteral: NumericLiteral) { when (numLiteral.type) { - DataType.BOOL -> output(if(numLiteral.number==0.0) "false" else "true") - DataType.FLOAT -> output(numLiteral.number.toString()) + BaseDataType.BOOL -> output(if(numLiteral.number==0.0) "false" else "true") + BaseDataType.FLOAT -> output(numLiteral.number.toString()) else -> output(numLiteral.number.toInt().toString()) } } @@ -472,7 +450,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: override fun visit(typecast: TypecastExpression) { output("(") typecast.expression.accept(this) - output(" as ${datatypeString(typecast.type)}) ") + output(" as ${DataType.forDt(typecast.type).sourceString()}) ") } override fun visit(memread: DirectMemoryRead) { diff --git a/compilerAst/src/prog8/ast/AstToplevel.kt b/compilerAst/src/prog8/ast/AstToplevel.kt index 13d251ea5..107d1fad1 100644 --- a/compilerAst/src/prog8/ast/AstToplevel.kt +++ b/compilerAst/src/prog8/ast/AstToplevel.kt @@ -3,14 +3,12 @@ package prog8.ast import prog8.ast.base.FatalAstException import prog8.ast.expressions.Expression import prog8.ast.expressions.IdentifierReference +import prog8.ast.expressions.InferredTypes import prog8.ast.expressions.NumericLiteral import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstVisitor -import prog8.code.core.DataType -import prog8.code.core.Encoding -import prog8.code.core.Position -import prog8.code.core.SourceCode +import prog8.code.core.* object ParentSentinel : Node { @@ -376,12 +374,16 @@ internal object BuiltinFunctionScopePlaceholder : INameScope { } -fun defaultZero(dt: DataType, position: Position) = when(dt) { - DataType.BOOL -> NumericLiteral(DataType.BOOL, 0.0, position) - DataType.UBYTE -> NumericLiteral(DataType.UBYTE, 0.0, position) - DataType.BYTE -> NumericLiteral(DataType.BYTE, 0.0, position) - DataType.UWORD, DataType.STR -> NumericLiteral(DataType.UWORD, 0.0, position) - DataType.WORD -> NumericLiteral(DataType.WORD, 0.0, position) - DataType.FLOAT -> NumericLiteral(DataType.FLOAT, 0.0, position) +fun defaultZero(dt: BaseDataType, position: Position) = when(dt) { + BaseDataType.BOOL -> NumericLiteral(BaseDataType.BOOL, 0.0, position) + BaseDataType.UBYTE -> NumericLiteral(BaseDataType.UBYTE, 0.0, position) + BaseDataType.BYTE -> NumericLiteral(BaseDataType.BYTE, 0.0, position) + BaseDataType.UWORD, BaseDataType.STR -> NumericLiteral(BaseDataType.UWORD, 0.0, position) + BaseDataType.WORD -> NumericLiteral(BaseDataType.WORD, 0.0, position) + BaseDataType.FLOAT -> NumericLiteral(BaseDataType.FLOAT, 0.0, position) 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/Program.kt b/compilerAst/src/prog8/ast/Program.kt index 83db3db4d..2360719b8 100644 --- a/compilerAst/src/prog8/ast/Program.kt +++ b/compilerAst/src/prog8/ast/Program.kt @@ -87,7 +87,7 @@ class Program(val name: String, fun addNewInternedStringvar(string: StringLiteral): Pair, VarDecl> { val varName = "string_${internedStringsBlock.statements.size}" val decl = VarDecl( - VarDeclType.VAR, VarDeclOrigin.STRINGLITERAL, DataType.STR, ZeropageWish.NOT_IN_ZEROPAGE, null, varName, emptyList(), string, + VarDeclType.VAR, VarDeclOrigin.STRINGLITERAL, DataType.forDt(BaseDataType.STR), ZeropageWish.NOT_IN_ZEROPAGE, null, varName, emptyList(), string, sharedWithAsm = false, splitArray = false, alignment = 0u, dirty = false, position = string.position ) internedStringsBlock.statements.add(decl) diff --git a/compilerAst/src/prog8/ast/SymbolDumper.kt b/compilerAst/src/prog8/ast/SymbolDumper.kt index 0370c2abe..0111da6af 100644 --- a/compilerAst/src/prog8/ast/SymbolDumper.kt +++ b/compilerAst/src/prog8/ast/SymbolDumper.kt @@ -70,28 +70,6 @@ private class SymbolDumper(val skipLibraries: Boolean): IAstVisitor { } } - private fun datatypeString(dt: DataType): String { - return when (dt) { - DataType.BOOL -> "bool" - DataType.UBYTE -> "ubyte" - DataType.BYTE -> "byte" - DataType.UWORD -> "uword" - DataType.WORD -> "word" - DataType.LONG -> "long" - DataType.FLOAT -> "float" - DataType.STR -> "str" - DataType.ARRAY_UB -> "ubyte[" - DataType.ARRAY_B -> "byte[" - DataType.ARRAY_UW -> "uword[" - DataType.ARRAY_W -> "word[" - DataType.ARRAY_F -> "float[" - DataType.ARRAY_BOOL -> "bool[" - DataType.ARRAY_UW_SPLIT -> "@split uword[" - DataType.ARRAY_W_SPLIT -> "@split word[" - DataType.UNDEFINED -> throw IllegalArgumentException("wrong dt") - } - } - override fun visit(decl: VarDecl) { if(decl.origin==VarDeclOrigin.SUBROUTINEPARAM) return @@ -102,7 +80,7 @@ private class SymbolDumper(val skipLibraries: Boolean): IAstVisitor { VarDeclType.MEMORY -> output("&") } - output(datatypeString(decl.datatype)) + output(decl.datatype.sourceString()) if(decl.arraysize!=null) { decl.arraysize!!.indexExpr.accept(this) } @@ -134,7 +112,7 @@ private class SymbolDumper(val skipLibraries: Boolean): IAstVisitor { param.second.statusflag!=null -> param.second.statusflag.toString() else -> "?????" } - output("${datatypeString(param.first.type)} ${param.first.name} @$reg") + output("${param.first.type.sourceString()} ${param.first.name} @$reg") if(param.first!==subroutine.parameters.last()) output(", ") } @@ -142,7 +120,7 @@ private class SymbolDumper(val skipLibraries: Boolean): IAstVisitor { else { output("${subroutine.name} (") for(param in subroutine.parameters) { - output("${datatypeString(param.type)} ${param.name}") + output("${param.type.sourceString()} ${param.name}") if(param!==subroutine.parameters.last()) output(", ") } @@ -161,7 +139,7 @@ private class SymbolDumper(val skipLibraries: Boolean): IAstVisitor { if(subroutine.returntypes.any()) { if(subroutine.asmReturnvaluesRegisters.isNotEmpty()) { val rts = subroutine.returntypes.zip(subroutine.asmReturnvaluesRegisters).joinToString(", ") { - val dtstr = datatypeString(it.first) + val dtstr = it.first.sourceString() if(it.second.registerOrPair!=null) "$dtstr @${it.second.registerOrPair}" else @@ -169,7 +147,7 @@ private class SymbolDumper(val skipLibraries: Boolean): IAstVisitor { } output("-> $rts ") } else { - val rts = subroutine.returntypes.joinToString(", ") { datatypeString(it) } + val rts = subroutine.returntypes.joinToString(", ") { it.sourceString() } output("-> $rts ") } } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 2b72e13b1..039af3501 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -15,7 +15,7 @@ import kotlin.io.path.isRegularFile /***************** Antlr Extension methods to create AST ****************/ -private data class NumericLiteralNode(val number: Double, val datatype: DataType) +private data class NumericLiteralNode(val number: Double, val datatype: BaseDataType) private fun ParserRuleContext.toPosition() : Position { @@ -229,18 +229,20 @@ private fun Asmsub_returnsContext.toAst(): List else -> throw SyntaxError("invalid register or status flag", toPosition()) } } + // asmsubs currently only return a base datatype + val returnBaseDt = it.datatype().toAst() AsmSubroutineReturn( - it.datatype().toAst(), + DataType.forDt(returnBaseDt), registerorpair, statusregister) } -private fun Asmsub_paramsContext.toAst(): List - = asmsub_param().map { +private fun Asmsub_paramsContext.toAst(): List = asmsub_param().map { val vardecl = it.vardecl() - var datatype = vardecl.datatype()?.toAst() ?: DataType.UNDEFINED + val baseDt = vardecl.datatype()?.toAst() ?: BaseDataType.UNDEFINED + var datatype = DataType.forDt(baseDt) if(vardecl.ARRAYSIG()!=null || vardecl.arrayindex()!=null) - datatype = ElementToArrayTypes.getValue(datatype) + datatype = datatype.elementToArray() val (registerorpair, statusregister) = parseParamRegister(it.register, it.toPosition()) val identifiers = vardecl.identifier() if(identifiers.size>1) @@ -316,7 +318,7 @@ private fun SubroutineContext.toAst() : Subroutine { return Subroutine( identifier().text, sub_params()?.toAst()?.toMutableList() ?: mutableListOf(), - if (returntype == null) mutableListOf() else mutableListOf(returntype), + if (returntype == null) mutableListOf() else mutableListOf(DataType.forDt(returntype)), emptyList(), emptyList(), emptySet(), @@ -337,9 +339,10 @@ private fun Sub_paramsContext.toAst(): List = if(options.DIRTY().isNotEmpty()) throw SyntaxError("cannot use @dirty on parameters", it.toPosition()) val zp = getZpOption(options) - var datatype = decl.datatype()?.toAst() ?: DataType.UNDEFINED + var baseDt = decl.datatype()?.toAst() ?: BaseDataType.UNDEFINED + var datatype = DataType.forDt(baseDt) if(decl.ARRAYSIG()!=null || decl.arrayindex()!=null) - datatype = ElementToArrayTypes.getValue(datatype) + datatype = datatype.elementToArray() val identifiers = decl.identifier() if(identifiers.size>1) @@ -421,11 +424,11 @@ private fun AugassignmentContext.toAst(): Assignment { return Assignment(assign_target().toAst(), expression, AssignmentOrigin.USERCODE, toPosition()) } -private fun DatatypeContext.toAst(): DataType { +private fun DatatypeContext.toAst(): BaseDataType { return try { - DataType.valueOf(text.uppercase()) + BaseDataType.valueOf(text.uppercase()) } catch (_: IllegalArgumentException) { - DataType.UNDEFINED + BaseDataType.UNDEFINED } } @@ -446,7 +449,7 @@ private fun IntegerliteralContext.toAst(): NumericLiteralNode { fun makeLiteral(literalTextWithGrouping: String, radix: Int): NumericLiteralNode { val literalText = literalTextWithGrouping.replace("_", "") val integer: Int - var datatype = DataType.UBYTE + var datatype = BaseDataType.UBYTE when (radix) { 10 -> { integer = try { @@ -455,19 +458,19 @@ private fun IntegerliteralContext.toAst(): NumericLiteralNode { throw SyntaxError("invalid decimal literal ${x.message}", toPosition()) } datatype = when(integer) { - in 0..255 -> DataType.UBYTE - in -128..127 -> DataType.BYTE - in 0..65535 -> DataType.UWORD - in -32768..32767 -> DataType.WORD - in -2147483647..2147483647 -> DataType.LONG - else -> DataType.FLOAT + in 0..255 -> BaseDataType.UBYTE + in -128..127 -> BaseDataType.BYTE + in 0..65535 -> BaseDataType.UWORD + in -32768..32767 -> BaseDataType.WORD + in -2147483647..2147483647 -> BaseDataType.LONG + else -> BaseDataType.FLOAT } } 2 -> { if(literalText.length>16) - datatype = DataType.LONG + datatype = BaseDataType.LONG else if(literalText.length>8) - datatype = DataType.UWORD + datatype = BaseDataType.UWORD try { integer = literalText.toInt(2) } catch(x: NumberFormatException) { @@ -476,9 +479,9 @@ private fun IntegerliteralContext.toAst(): NumericLiteralNode { } 16 -> { if(literalText.length>4) - datatype = DataType.LONG + datatype = BaseDataType.LONG else if(literalText.length>2) - datatype = DataType.UWORD + datatype = BaseDataType.UWORD try { integer = literalText.toInt(16) } catch(x: NumberFormatException) { @@ -511,15 +514,15 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi val intLit = litval.integerliteral()?.toAst() when { intLit!=null -> when(intLit.datatype) { - DataType.UBYTE -> NumericLiteral(DataType.UBYTE, intLit.number, litval.toPosition()) - DataType.BYTE -> NumericLiteral(DataType.BYTE, intLit.number, litval.toPosition()) - DataType.UWORD -> NumericLiteral(DataType.UWORD, intLit.number, litval.toPosition()) - DataType.WORD -> NumericLiteral(DataType.WORD, intLit.number, litval.toPosition()) - DataType.LONG -> NumericLiteral(DataType.LONG, intLit.number, litval.toPosition()) - DataType.FLOAT -> NumericLiteral(DataType.FLOAT, intLit.number, litval.toPosition()) + BaseDataType.UBYTE -> NumericLiteral(BaseDataType.UBYTE, intLit.number, litval.toPosition()) + BaseDataType.BYTE -> NumericLiteral(BaseDataType.BYTE, intLit.number, litval.toPosition()) + BaseDataType.UWORD -> NumericLiteral(BaseDataType.UWORD, intLit.number, litval.toPosition()) + BaseDataType.WORD -> NumericLiteral(BaseDataType.WORD, intLit.number, litval.toPosition()) + BaseDataType.LONG -> NumericLiteral(BaseDataType.LONG, intLit.number, litval.toPosition()) + BaseDataType.FLOAT -> NumericLiteral(BaseDataType.FLOAT, intLit.number, litval.toPosition()) else -> throw FatalAstException("invalid datatype for numeric literal") } - litval.floatliteral()!=null -> NumericLiteral(DataType.FLOAT, litval.floatliteral().toAst(), litval.toPosition()) + litval.floatliteral()!=null -> NumericLiteral(BaseDataType.FLOAT, litval.floatliteral().toAst(), litval.toPosition()) litval.stringliteral()!=null -> litval.stringliteral().toAst() litval.charliteral()!=null -> litval.charliteral().toAst() litval.arrayliteral()!=null -> { @@ -569,8 +572,11 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi if(childCount==3 && children[0].text=="(" && children[2].text==")") return expression(0).toAst(insideParentheses=true) // expression within ( ) - if(typecast()!=null) - return TypecastExpression(expression(0).toAst(), typecast().datatype().toAst(), false, toPosition()) + if(typecast()!=null) { + // typecast is always to a base datatype + val baseDt = typecast().datatype().toAst() + return TypecastExpression(expression(0).toAst(), baseDt, false, toPosition()) + } if(directmemory()!=null) return DirectMemoryRead(directmemory().expression().toAst(), toPosition()) @@ -760,27 +766,18 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl val alignpage = options.ALIGNPAGE().isNotEmpty() if(alignpage && alignword) throw SyntaxError("choose a single alignment option", toPosition()) - val origDt = datatype()?.toAst() ?: DataType.UNDEFINED + val baseDt = datatype()?.toAst() ?: BaseDataType.UNDEFINED + val origDt = DataType.forDt(baseDt) val dt = if(isArray) { - val arrayDt = ElementToArrayTypes.getValue(origDt) - if(split) { - when(arrayDt) { - DataType.ARRAY_UW -> DataType.ARRAY_UW_SPLIT - DataType.ARRAY_W -> DataType.ARRAY_W_SPLIT - else -> arrayDt // type error will be generated later in the ast check - } - } else arrayDt + if(split && origDt.isWord) + origDt.elementToArray(split) + else + origDt.elementToArray(false) // type error will be generated later in the ast check } else origDt - val datatype = if(!split) dt else when(dt) { - DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> DataType.ARRAY_UW_SPLIT - DataType.ARRAY_W,DataType.ARRAY_W_SPLIT -> DataType.ARRAY_W_SPLIT - else -> dt - } - return VarDecl( type, VarDeclOrigin.USERCODE, - datatype, + dt, zp, arrayindex()?.toAst(), name, diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 43e46e9fb..beeeefb56 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -11,7 +11,7 @@ import prog8.ast.walk.IAstVisitor import prog8.code.core.* import prog8.code.target.encodings.JapaneseCharacterConverter import java.io.CharConversionException -import java.util.Objects +import java.util.* import kotlin.math.abs import kotlin.math.floor import kotlin.math.truncate @@ -68,9 +68,9 @@ sealed class Expression: Node { } } - fun typecastTo(targetDt: DataType, sourceDt: DataType, implicit: Boolean=false): Pair { - require(sourceDt!=DataType.UNDEFINED && targetDt!=DataType.UNDEFINED) - if(sourceDt==targetDt) + fun typecastTo(targetDt: BaseDataType, sourceDt: DataType, implicit: Boolean=false): Pair { + require(!sourceDt.isUndefined && targetDt!=BaseDataType.UNDEFINED) + if(sourceDt.base==targetDt && sourceDt.sub==null) return Pair(false, this) if(this is TypecastExpression) { this.type = targetDt @@ -101,16 +101,16 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid val constval = expression.constValue(program) ?: return null val converted = when(operator) { "+" -> constval - "-" -> when (constval.type) { - in IntegerDatatypes -> NumericLiteral.optimalInteger(-constval.number.toInt(), constval.position) - DataType.FLOAT -> NumericLiteral(DataType.FLOAT, -constval.number, constval.position) + "-" -> when { + constval.type.isInteger -> NumericLiteral.optimalInteger(-constval.number.toInt(), constval.position) + constval.type == BaseDataType.FLOAT -> NumericLiteral(BaseDataType.FLOAT, -constval.number, constval.position) else -> throw ExpressionError("can only take negative of int or float", constval.position) } - "~" -> when (constval.type) { - DataType.BYTE -> NumericLiteral(DataType.BYTE, constval.number.toInt().inv().toDouble(), constval.position) - DataType.UBYTE -> NumericLiteral(DataType.UBYTE, (constval.number.toInt().inv() and 255).toDouble(), constval.position) - DataType.WORD -> NumericLiteral(DataType.WORD, constval.number.toInt().inv().toDouble(), constval.position) - DataType.UWORD -> NumericLiteral(DataType.UWORD, (constval.number.toInt().inv() and 65535).toDouble(), constval.position) + "~" -> when { + constval.type == BaseDataType.BYTE -> NumericLiteral(BaseDataType.BYTE, constval.number.toInt().inv().toDouble(), constval.position) + constval.type == BaseDataType.UBYTE -> NumericLiteral(BaseDataType.UBYTE, (constval.number.toInt().inv() and 255).toDouble(), constval.position) + constval.type == BaseDataType.WORD -> NumericLiteral(BaseDataType.WORD, constval.number.toInt().inv().toDouble(), constval.position) + constval.type == BaseDataType.UWORD -> NumericLiteral(BaseDataType.UWORD, (constval.number.toInt().inv() and 65535).toDouble(), constval.position) else -> throw ExpressionError("can only take bitwise inversion of int", constval.position) } "not" -> NumericLiteral.fromBoolean(constval.number==0.0, constval.position) @@ -127,15 +127,15 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid val inferred = expression.inferType(program) return when(operator) { "+" -> inferred - "not" -> InferredTypes.knownFor(DataType.BOOL) + "not" -> InferredTypes.knownFor(BaseDataType.BOOL) "~" -> { - if(inferred.isBytes) InferredTypes.knownFor(DataType.UBYTE) - else if(inferred.isWords) InferredTypes.knownFor(DataType.UWORD) + if(inferred.isBytes) InferredTypes.knownFor(BaseDataType.UBYTE) + else if(inferred.isWords) InferredTypes.knownFor(BaseDataType.UWORD) else InferredTypes.InferredType.unknown() } "-" -> { - if(inferred.isBytes) InferredTypes.knownFor(DataType.BYTE) - else if(inferred.isWords) InferredTypes.knownFor(DataType.WORD) + if(inferred.isBytes) InferredTypes.knownFor(BaseDataType.BYTE) + else if(inferred.isWords) InferredTypes.knownFor(BaseDataType.WORD) else inferred } else -> throw FatalAstException("weird prefix expression operator") @@ -199,18 +199,18 @@ class BinaryExpression( try { val dt = InferredTypes.knownFor( commonDatatype( - leftDt.getOr(DataType.BYTE), - rightDt.getOr(DataType.BYTE), + leftDt.getOr(DataType.forDt(BaseDataType.BYTE)), + rightDt.getOr(DataType.forDt(BaseDataType.BYTE)), null, null ).first ) if(operator=="*") { // if both operands are the same, X*X is always positive. if(left isSameAs right) { - if(dt.istype(DataType.BYTE)) - InferredTypes.knownFor(DataType.UBYTE) - else if(dt.istype(DataType.WORD)) - InferredTypes.knownFor(DataType.UWORD) + if(dt istype DataType.forDt(BaseDataType.BYTE)) + InferredTypes.knownFor(BaseDataType.UBYTE) + else if(dt istype DataType.forDt(BaseDataType.WORD)) + InferredTypes.knownFor(BaseDataType.UWORD) else dt } else @@ -222,16 +222,16 @@ class BinaryExpression( } } } - "&", "|", "^" -> when(leftDt.getOr(DataType.UNDEFINED)) { - DataType.BYTE -> InferredTypes.knownFor(DataType.UBYTE) - DataType.WORD -> InferredTypes.knownFor(DataType.UWORD) - DataType.BOOL -> InferredTypes.knownFor(DataType.UBYTE) + "&", "|", "^" -> when(leftDt.getOrUndef()) { + DataType.forDt(BaseDataType.BYTE) -> InferredTypes.knownFor(BaseDataType.UBYTE) + DataType.forDt(BaseDataType.WORD) -> InferredTypes.knownFor(BaseDataType.UWORD) + DataType.forDt(BaseDataType.BOOL) -> InferredTypes.knownFor(BaseDataType.UBYTE) else -> leftDt } "and", "or", "xor", "not", "in", "not in", "<", ">", "<=", ">=", - "==", "!=" -> InferredTypes.knownFor(DataType.BOOL) + "==", "!=" -> InferredTypes.knownFor(BaseDataType.BOOL) "<<", ">>" -> leftDt else -> throw FatalAstException("resulting datatype check for invalid operator $operator") } @@ -250,71 +250,71 @@ class BinaryExpression( // if left or right is a numeric literal, and its value fits in the type of the other operand, use the other's operand type // EXCEPTION: if the numeric value is a word and the other operand is a byte type (to allow v * $0008 for example) if (left is NumericLiteral) { - if(!(leftDt in WordDatatypes && rightDt in ByteDatatypes)) { - val optimal = NumericLiteral.optimalNumeric(rightDt, null, left.number, left.position) - if (optimal.type != leftDt && optimal.type isAssignableTo rightDt) { - return optimal.type to left + if(!(leftDt.isWord && rightDt.isByte)) { + val optimal = NumericLiteral.optimalNumeric(rightDt.base, null, left.number, left.position) + if (optimal.type != leftDt.base && DataType.forDt(optimal.type) isAssignableTo rightDt) { + return DataType.forDt(optimal.type) to left } } } if (right is NumericLiteral) { - if(!(rightDt in WordDatatypes && leftDt in ByteDatatypes)) { - val optimal = NumericLiteral.optimalNumeric(leftDt, null, right.number, right.position) - if (optimal.type != rightDt && optimal.type isAssignableTo leftDt) { - return optimal.type to right + if(!(rightDt.isWord && leftDt.isByte)) { + val optimal = NumericLiteral.optimalNumeric(leftDt.base, null, right.number, right.position) + if (optimal.type != rightDt.base && DataType.forDt(optimal.type) isAssignableTo leftDt) { + return DataType.forDt(optimal.type) to right } } } - return when (leftDt) { - DataType.BOOL -> { - return if(rightDt==DataType.BOOL) - Pair(DataType.BOOL, null) + return when (leftDt.base) { + BaseDataType.BOOL -> { + return if(rightDt.isBool) + Pair(DataType.forDt(BaseDataType.BOOL), null) else - Pair(DataType.BOOL, right) + Pair(DataType.forDt(BaseDataType.BOOL), right) } - DataType.UBYTE -> { - when (rightDt) { - DataType.UBYTE -> Pair(DataType.UBYTE, null) - DataType.BYTE -> Pair(DataType.BYTE, left) - DataType.UWORD -> Pair(DataType.UWORD, left) - DataType.WORD -> Pair(DataType.WORD, left) - DataType.FLOAT -> Pair(DataType.FLOAT, left) + BaseDataType.UBYTE -> { + when (rightDt.base) { + BaseDataType.UBYTE -> Pair(DataType.forDt(BaseDataType.UBYTE), null) + BaseDataType.BYTE -> Pair(DataType.forDt(BaseDataType.BYTE), left) + BaseDataType.UWORD -> Pair(DataType.forDt(BaseDataType.UWORD), left) + BaseDataType.WORD -> Pair(DataType.forDt(BaseDataType.WORD), left) + BaseDataType.FLOAT -> Pair(DataType.forDt(BaseDataType.FLOAT), left) else -> Pair(leftDt, null) // non-numeric datatype } } - DataType.BYTE -> { - when (rightDt) { - DataType.UBYTE -> Pair(DataType.BYTE, right) - DataType.BYTE -> Pair(DataType.BYTE, null) - DataType.UWORD -> Pair(DataType.WORD, left) - DataType.WORD -> Pair(DataType.WORD, left) - DataType.FLOAT -> Pair(DataType.FLOAT, left) + BaseDataType.BYTE -> { + when (rightDt.base) { + BaseDataType.UBYTE -> Pair(DataType.forDt(BaseDataType.BYTE), right) + BaseDataType.BYTE -> Pair(DataType.forDt(BaseDataType.BYTE), null) + BaseDataType.UWORD -> Pair(DataType.forDt(BaseDataType.WORD), left) + BaseDataType.WORD -> Pair(DataType.forDt(BaseDataType.WORD), left) + BaseDataType.FLOAT -> Pair(DataType.forDt(BaseDataType.FLOAT), left) else -> Pair(leftDt, null) // non-numeric datatype } } - DataType.UWORD -> { - when (rightDt) { - DataType.UBYTE -> Pair(DataType.UWORD, right) - DataType.BYTE -> Pair(DataType.WORD, right) - DataType.UWORD -> Pair(DataType.UWORD, null) - DataType.WORD -> Pair(DataType.WORD, left) - DataType.FLOAT -> Pair(DataType.FLOAT, left) + BaseDataType.UWORD -> { + when (rightDt.base) { + BaseDataType.UBYTE -> Pair(DataType.forDt(BaseDataType.UWORD), right) + BaseDataType.BYTE -> Pair(DataType.forDt(BaseDataType.WORD), right) + BaseDataType.UWORD -> Pair(DataType.forDt(BaseDataType.UWORD), null) + BaseDataType.WORD -> Pair(DataType.forDt(BaseDataType.WORD), left) + BaseDataType.FLOAT -> Pair(DataType.forDt(BaseDataType.FLOAT), left) else -> Pair(leftDt, null) // non-numeric datatype } } - DataType.WORD -> { - when (rightDt) { - DataType.UBYTE -> Pair(DataType.WORD, right) - DataType.BYTE -> Pair(DataType.WORD, right) - DataType.UWORD -> Pair(DataType.WORD, right) - DataType.WORD -> Pair(DataType.WORD, null) - DataType.FLOAT -> Pair(DataType.FLOAT, left) + BaseDataType.WORD -> { + when (rightDt.base) { + BaseDataType.UBYTE -> Pair(DataType.forDt(BaseDataType.WORD), right) + BaseDataType.BYTE -> Pair(DataType.forDt(BaseDataType.WORD), right) + BaseDataType.UWORD -> Pair(DataType.forDt(BaseDataType.WORD), right) + BaseDataType.WORD -> Pair(DataType.forDt(BaseDataType.WORD), null) + BaseDataType.FLOAT -> Pair(DataType.forDt(BaseDataType.FLOAT), left) else -> Pair(leftDt, null) // non-numeric datatype } } - DataType.FLOAT -> { - Pair(DataType.FLOAT, right) + BaseDataType.FLOAT -> { + Pair(DataType.forDt(BaseDataType.FLOAT), right) } else -> Pair(leftDt, null) // non-numeric datatype } @@ -351,9 +351,9 @@ class ArrayIndexedExpression(var arrayvar: IdentifierReference, override fun inferType(program: Program): InferredTypes.InferredType { val target = arrayvar.targetStatement(program) if (target is VarDecl) { - return when (target.datatype) { - DataType.STR, DataType.UWORD -> InferredTypes.knownFor(DataType.UBYTE) - in ArrayDatatypes -> InferredTypes.knownFor(ArrayToElementTypes.getValue(target.datatype)) + return when { + target.datatype.isString || target.datatype.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE) + target.datatype.isArray -> InferredTypes.knownFor(target.datatype.elementType()) else -> InferredTypes.knownFor(target.datatype) } } @@ -367,7 +367,7 @@ class ArrayIndexedExpression(var arrayvar: IdentifierReference, override fun copy() = ArrayIndexedExpression(arrayvar.copy(), indexer.copy(), position) } -class TypecastExpression(var expression: Expression, var type: DataType, val implicit: Boolean, override val position: Position) : Expression() { +class TypecastExpression(var expression: Expression, var type: BaseDataType, val implicit: Boolean, override val position: Position) : Expression() { override lateinit var parent: Node override fun linkParents(parent: Node) { @@ -376,7 +376,7 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp } init { - if(type==DataType.BOOL) require(!implicit) {"no implicit cast to boolean allowed"} + if(type==BaseDataType.BOOL) require(!implicit) {"no implicit cast to boolean allowed"} } override val isSimple = expression.isSimple @@ -447,15 +447,15 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI if (arrayIndex != null) { val index = arrayIndex?.constIndex() if (index != null) { - address += when (targetVar.datatype) { - DataType.UWORD -> index - in ArrayDatatypes -> program.memsizer.memorySize(targetVar.datatype, index) + address += when { + target.datatype.isUnsignedWord -> index + target.datatype.isArray -> program.memsizer.memorySize(targetVar.datatype, index) else -> throw FatalAstException("need array or uword ptr") } } else return null } - return NumericLiteral(DataType.UWORD, address, position) + return NumericLiteral(BaseDataType.UWORD, address, position) } } } @@ -464,12 +464,12 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI val constAddress = targetAsmAddress.address.constValue(program) if(constAddress==null) return null - return NumericLiteral(DataType.UWORD, constAddress.number, position) + return NumericLiteral(BaseDataType.UWORD, constAddress.number, position) } return null } override fun referencesIdentifier(nameInSource: List) = identifier.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true - override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UWORD) + override fun inferType(program: Program) = InferredTypes.knownFor(BaseDataType.UWORD) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) } @@ -495,7 +495,7 @@ class DirectMemoryRead(var addressExpression: Expression, override val position: override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun referencesIdentifier(nameInSource: List) = addressExpression.referencesIdentifier(nameInSource) - override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UBYTE) + override fun inferType(program: Program) = InferredTypes.knownFor(BaseDataType.UBYTE) override fun constValue(program: Program): NumericLiteral? = null override fun toString(): String { @@ -503,12 +503,12 @@ class DirectMemoryRead(var addressExpression: Expression, override val position: } } -class NumericLiteral(val type: DataType, // only numerical types allowed +class NumericLiteral(val type: BaseDataType, // only numerical types allowed + bool (there is no separate BooleanLiteral node) numbervalue: Double, // can be byte, word or float depending on the type override val position: Position) : Expression() { override lateinit var parent: Node val number: Double by lazy { - if(type==DataType.FLOAT) + if(type==BaseDataType.FLOAT) numbervalue else { val trunc = truncate(numbervalue) @@ -520,13 +520,13 @@ class NumericLiteral(val type: DataType, // only numerical types allowed init { when(type) { - DataType.UBYTE -> require(numbervalue in 0.0..255.0) - DataType.BYTE -> require(numbervalue in -128.0..127.0) - DataType.UWORD -> require(numbervalue in 0.0..65535.0) - DataType.WORD -> require(numbervalue in -32768.0..32767.0) - DataType.LONG -> require(numbervalue in -2147483647.0..2147483647.0) - DataType.BOOL -> require(numbervalue==0.0 || numbervalue==1.0) - else -> {} + BaseDataType.UBYTE -> require(numbervalue in 0.0..255.0) + BaseDataType.BYTE -> require(numbervalue in -128.0..127.0) + BaseDataType.UWORD -> require(numbervalue in 0.0..65535.0) + BaseDataType.WORD -> require(numbervalue in -32768.0..32767.0) + BaseDataType.LONG -> require(numbervalue in -2147483647.0..2147483647.0) + BaseDataType.BOOL -> require(numbervalue==0.0 || numbervalue==1.0) + else -> require(type.isNumericOrBool) { "numeric literal type should be numeric or bool: $type" } } } @@ -535,27 +535,27 @@ class NumericLiteral(val type: DataType, // only numerical types allowed companion object { fun fromBoolean(bool: Boolean, position: Position) = - NumericLiteral(DataType.BOOL, if(bool) 1.0 else 0.0, position) + NumericLiteral(BaseDataType.BOOL, if(bool) 1.0 else 0.0, position) - fun optimalNumeric(origType1: DataType, origType2: DataType?, value: Number, position: Position) : NumericLiteral = + fun optimalNumeric(origType1: BaseDataType, origType2: BaseDataType?, value: Number, position: Position) : NumericLiteral = fromOptimal(optimalNumeric(value, position), origType1, origType2, position) - fun optimalInteger(origType1: DataType, origType2: DataType?, value: Int, position: Position): NumericLiteral = + fun optimalInteger(origType1: BaseDataType, origType2: BaseDataType?, value: Int, position: Position): NumericLiteral = fromOptimal(optimalInteger(value, position), origType1, origType2, position) fun optimalNumeric(value: Number, position: Position): NumericLiteral { val digits = floor(value.toDouble()) - value.toDouble() return if(value is Double && digits!=0.0) { - NumericLiteral(DataType.FLOAT, value, position) + NumericLiteral(BaseDataType.FLOAT, value, position) } else { val dvalue = value.toDouble() when (value.toInt()) { - in 0..255 -> NumericLiteral(DataType.UBYTE, dvalue, position) - in -128..127 -> NumericLiteral(DataType.BYTE, dvalue, position) - in 0..65535 -> NumericLiteral(DataType.UWORD, dvalue, position) - in -32768..32767 -> NumericLiteral(DataType.WORD, dvalue, position) - in -2147483647..2147483647 -> NumericLiteral(DataType.LONG, dvalue, position) - else -> NumericLiteral(DataType.FLOAT, dvalue, position) + in 0..255 -> NumericLiteral(BaseDataType.UBYTE, dvalue, position) + in -128..127 -> NumericLiteral(BaseDataType.BYTE, dvalue, position) + in 0..65535 -> NumericLiteral(BaseDataType.UWORD, dvalue, position) + in -32768..32767 -> NumericLiteral(BaseDataType.WORD, dvalue, position) + in -2147483647..2147483647 -> NumericLiteral(BaseDataType.LONG, dvalue, position) + else -> NumericLiteral(BaseDataType.FLOAT, dvalue, position) } } } @@ -563,32 +563,32 @@ class NumericLiteral(val type: DataType, // only numerical types allowed fun optimalInteger(value: Int, position: Position): NumericLiteral { val dvalue = value.toDouble() return when (value) { - in 0..255 -> NumericLiteral(DataType.UBYTE, dvalue, position) - in -128..127 -> NumericLiteral(DataType.BYTE, dvalue, position) - in 0..65535 -> NumericLiteral(DataType.UWORD, dvalue, position) - in -32768..32767 -> NumericLiteral(DataType.WORD, dvalue, position) - in -2147483647..2147483647 -> NumericLiteral(DataType.LONG, dvalue, position) + in 0..255 -> NumericLiteral(BaseDataType.UBYTE, dvalue, position) + in -128..127 -> NumericLiteral(BaseDataType.BYTE, dvalue, position) + in 0..65535 -> NumericLiteral(BaseDataType.UWORD, dvalue, position) + in -32768..32767 -> NumericLiteral(BaseDataType.WORD, dvalue, position) + in -2147483647..2147483647 -> NumericLiteral(BaseDataType.LONG, dvalue, position) else -> throw FatalAstException("integer overflow: $dvalue") } } fun optimalInteger(value: UInt, position: Position): NumericLiteral { return when (value) { - in 0u..255u -> NumericLiteral(DataType.UBYTE, value.toDouble(), position) - in 0u..65535u -> NumericLiteral(DataType.UWORD, value.toDouble(), position) - in 0u..2147483647u -> NumericLiteral(DataType.LONG, value.toDouble(), position) + in 0u..255u -> NumericLiteral(BaseDataType.UBYTE, value.toDouble(), position) + in 0u..65535u -> NumericLiteral(BaseDataType.UWORD, value.toDouble(), position) + in 0u..2147483647u -> NumericLiteral(BaseDataType.LONG, value.toDouble(), position) else -> throw FatalAstException("unsigned integer overflow: $value") } } - private fun fromOptimal(optimal: NumericLiteral, origType1: DataType, origType2: DataType?, position: Position): NumericLiteral { - var largestOrig = if(origType2==null) origType1 else if(origType1.largerThan(origType2)) origType1 else origType2 - return if(largestOrig.largerThan(optimal.type)) { - if(optimal.number<0 && largestOrig !in SignedDatatypes) { - when(largestOrig){ - DataType.BOOL -> {} - DataType.UBYTE -> largestOrig = DataType.BYTE - DataType.UWORD -> largestOrig = DataType.WORD + private fun fromOptimal(optimal: NumericLiteral, origType1: BaseDataType, origType2: BaseDataType?, position: Position): NumericLiteral { + var largestOrig = if(origType2==null) origType1 else if(origType1.largerSizeThan(origType2)) origType1 else origType2 + return if(largestOrig.largerSizeThan(optimal.type)) { + if(optimal.number<0 && !largestOrig.isSigned) { + when(largestOrig) { + BaseDataType.BOOL -> {} + BaseDataType.UBYTE -> largestOrig = BaseDataType.BYTE + BaseDataType.UWORD -> largestOrig = BaseDataType.WORD else -> throw FatalAstException("invalid dt") } } @@ -622,14 +622,24 @@ class NumericLiteral(val type: DataType, // only numerical types allowed override fun toString(): String = "NumericLiteral(${type.name}:$number)" - override fun inferType(program: Program) = InferredTypes.knownFor(type) + override fun inferType(program: Program): InferredTypes.InferredType = when(type) { + BaseDataType.UBYTE -> InferredTypes.knownFor(BaseDataType.UBYTE) + BaseDataType.BYTE -> InferredTypes.knownFor(BaseDataType.BYTE) + BaseDataType.UWORD -> InferredTypes.knownFor(BaseDataType.UWORD) + BaseDataType.WORD -> InferredTypes.knownFor(BaseDataType.WORD) + BaseDataType.LONG -> InferredTypes.knownFor(BaseDataType.LONG) + BaseDataType.FLOAT -> InferredTypes.knownFor(BaseDataType.FLOAT) + BaseDataType.BOOL -> InferredTypes.knownFor(BaseDataType.BOOL) + BaseDataType.STR -> InferredTypes.knownFor(BaseDataType.STR) + else -> throw IllegalArgumentException("invalid type for numeric literal: $type") + } override fun hashCode(): Int = Objects.hash(type, number) override fun equals(other: Any?): Boolean { return if(other==null || other !is NumericLiteral) false - else if(type!=DataType.BOOL && other.type!=DataType.BOOL) + else if(type!=BaseDataType.BOOL && other.type!=BaseDataType.BOOL) number==other.number else type==other.type && number==other.number @@ -638,31 +648,31 @@ class NumericLiteral(val type: DataType, // only numerical types allowed operator fun compareTo(other: NumericLiteral): Int = number.compareTo(other.number) class ValueAfterCast(val isValid: Boolean, val whyFailed: String?, private val value: NumericLiteral?) { - fun valueOrZero() = if(isValid) value!! else NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY) + fun valueOrZero() = if(isValid) value!! else NumericLiteral(BaseDataType.UBYTE, 0.0, Position.DUMMY) fun linkParent(parent: Node) { value?.linkParents(parent) } } - fun cast(targettype: DataType, implicit: Boolean): ValueAfterCast { + fun cast(targettype: BaseDataType, implicit: Boolean): ValueAfterCast { val result = internalCast(targettype, implicit) result.linkParent(this.parent) return result } - private fun internalCast(targettype: DataType, implicit: Boolean): ValueAfterCast { + private fun internalCast(targettype: BaseDataType, implicit: Boolean): ValueAfterCast { // NOTE: this MAY convert a value into another when switching from singed to unsigned!!! if(type==targettype) return ValueAfterCast(true, null, this) - if (implicit && targettype in IntegerDatatypes && type==DataType.BOOL) + if (implicit && targettype.isInteger && type== BaseDataType.BOOL) return ValueAfterCast(false, "no implicit cast from boolean to integer allowed", this) - if(targettype == DataType.BOOL) { + if(targettype == BaseDataType.BOOL) { return if(implicit) ValueAfterCast(false, "no implicit cast to boolean allowed", this) - else if(type in NumericDatatypes) + else if(type.isNumeric) ValueAfterCast(true, null, fromBoolean(number!=0.0, position)) else ValueAfterCast(false, "no cast available from $type to BOOL", null) @@ -670,101 +680,101 @@ class NumericLiteral(val type: DataType, // only numerical types allowed when(type) { - DataType.UBYTE -> { - if(targettype==DataType.BYTE && (number in 0.0..127.0 || !implicit)) + BaseDataType.UBYTE -> { + if(targettype==BaseDataType.BYTE && (number in 0.0..127.0 || !implicit)) return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toByte().toDouble(), position)) - if(targettype==DataType.WORD || targettype==DataType.UWORD) + if(targettype==BaseDataType.WORD || targettype==BaseDataType.UWORD) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.FLOAT) + if(targettype==BaseDataType.FLOAT) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.LONG) + if(targettype==BaseDataType.LONG) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } - DataType.BYTE -> { - if(targettype==DataType.UBYTE) { + BaseDataType.BYTE -> { + if(targettype==BaseDataType.UBYTE) { if(number in -128.0..0.0 && !implicit) return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUByte().toDouble(), position)) else if(number in 0.0..255.0) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } - if(targettype==DataType.UWORD) { + if(targettype==BaseDataType.UWORD) { if(number in -32768.0..0.0 && !implicit) return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUShort().toDouble(), position)) else if(number in 0.0..65535.0) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } - if(targettype==DataType.WORD) + if(targettype==BaseDataType.WORD) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.FLOAT) + if(targettype==BaseDataType.FLOAT) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.LONG) + if(targettype==BaseDataType.LONG) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } - DataType.UWORD -> { - if(targettype==DataType.BYTE && number <= 127) + BaseDataType.UWORD -> { + if(targettype==BaseDataType.BYTE && number <= 127) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.UBYTE && number <= 255) + if(targettype==BaseDataType.UBYTE && number <= 255) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.WORD && (number <= 32767 || !implicit)) + if(targettype==BaseDataType.WORD && (number <= 32767 || !implicit)) return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toShort().toDouble(), position)) - if(targettype==DataType.FLOAT) + if(targettype==BaseDataType.FLOAT) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.LONG) + if(targettype==BaseDataType.LONG) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } - DataType.WORD -> { - if(targettype==DataType.BYTE && number >= -128 && number <=127) + BaseDataType.WORD -> { + if(targettype==BaseDataType.BYTE && number >= -128 && number <=127) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.UBYTE) { + if(targettype==BaseDataType.UBYTE) { if(number in -128.0..0.0 && !implicit) return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUByte().toDouble(), position)) else if(number in 0.0..255.0) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } - if(targettype==DataType.UWORD) { + if(targettype==BaseDataType.UWORD) { if(number in -32768.0 .. 0.0 && !implicit) return ValueAfterCast(true, null, NumericLiteral(targettype, number.toInt().toUShort().toDouble(), position)) else if(number in 0.0..65535.0) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } - if(targettype==DataType.FLOAT) + if(targettype==BaseDataType.FLOAT) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.LONG) + if(targettype==BaseDataType.LONG) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } - DataType.FLOAT -> { + BaseDataType.FLOAT -> { try { - if (targettype == DataType.BYTE && number >= -128 && number <= 127) + if (targettype == BaseDataType.BYTE && number >= -128 && number <= 127) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if (targettype == DataType.UBYTE && number >= 0 && number <= 255) + if (targettype == BaseDataType.UBYTE && number >= 0 && number <= 255) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if (targettype == DataType.WORD && number >= -32768 && number <= 32767) + if (targettype == BaseDataType.WORD && number >= -32768 && number <= 32767) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if (targettype == DataType.UWORD && number >= 0 && number <= 65535) + if (targettype == BaseDataType.UWORD && number >= 0 && number <= 65535) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.LONG && number >=0 && number <= 2147483647) + if(targettype==BaseDataType.LONG && number >=0 && number <= 2147483647) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } catch (x: ExpressionError) { return ValueAfterCast(false, x.message,null) } } - DataType.BOOL -> { + BaseDataType.BOOL -> { if(implicit) return ValueAfterCast(false, "no implicit cast from boolean to integer allowed", null) - else if(targettype in IntegerDatatypes) + else if(targettype.isInteger) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } - DataType.LONG -> { + BaseDataType.LONG -> { try { - if (targettype == DataType.BYTE && number >= -128 && number <= 127) + if (targettype == BaseDataType.BYTE && number >= -128 && number <= 127) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if (targettype == DataType.UBYTE && number >= 0 && number <= 255) + if (targettype == BaseDataType.UBYTE && number >= 0 && number <= 255) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if (targettype == DataType.WORD && number >= -32768 && number <= 32767) + if (targettype == BaseDataType.WORD && number >= -32768 && number <= 32767) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if (targettype == DataType.UWORD && number >= 0 && number <= 65535) + if (targettype == BaseDataType.UWORD && number >= 0 && number <= 65535) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) - if(targettype==DataType.FLOAT) + if(targettype==BaseDataType.FLOAT) return ValueAfterCast(true, null, NumericLiteral(targettype, number, position)) } catch (x: ExpressionError) { return ValueAfterCast(false, x.message, null) @@ -777,44 +787,44 @@ class NumericLiteral(val type: DataType, // only numerical types allowed return ValueAfterCast(false, "no cast available from $type to $targettype number=$number", null) } - fun convertTypeKeepValue(targetDt: DataType): ValueAfterCast { + fun convertTypeKeepValue(targetDt: BaseDataType): ValueAfterCast { if(type==targetDt) return ValueAfterCast(true, null, this) when(type) { - DataType.UBYTE -> { + BaseDataType.UBYTE -> { when(targetDt) { - DataType.BYTE -> if(number<=127.0) return cast(targetDt, false) - DataType.UWORD, DataType.WORD, DataType.LONG, DataType.FLOAT -> return cast(targetDt, false) + BaseDataType.BYTE -> if(number<=127.0) return cast(targetDt, false) + BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT -> return cast(targetDt, false) else -> {} } } - DataType.BYTE -> { + BaseDataType.BYTE -> { when(targetDt) { - DataType.UBYTE, DataType.UWORD -> if(number>=0.0) return cast(targetDt, false) - DataType.WORD, DataType.LONG, DataType.FLOAT -> return cast(targetDt, false) + BaseDataType.UBYTE, BaseDataType.UWORD -> if(number>=0.0) return cast(targetDt, false) + BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT -> return cast(targetDt, false) else -> {} } } - DataType.UWORD -> { + BaseDataType.UWORD -> { when(targetDt) { - DataType.UBYTE -> if(number<=255.0) return cast(targetDt, false) - DataType.BYTE -> if(number<=127.0) return cast(targetDt, false) - DataType.WORD -> if(number<=32767.0) return cast(targetDt, false) - DataType.LONG, DataType.FLOAT -> return cast(targetDt, false) + BaseDataType.UBYTE -> if(number<=255.0) return cast(targetDt, false) + BaseDataType.BYTE -> if(number<=127.0) return cast(targetDt, false) + BaseDataType.WORD -> if(number<=32767.0) return cast(targetDt, false) + BaseDataType.LONG, BaseDataType.FLOAT -> return cast(targetDt, false) else -> {} } } - DataType.WORD -> { + BaseDataType.WORD -> { when(targetDt) { - DataType.UBYTE -> if(number in 0.0..255.0) return cast(targetDt, false) - DataType.BYTE -> if(number in -128.0..127.0) return cast(targetDt, false) - DataType.UWORD -> if(number in 0.0..32767.0) return cast(targetDt, false) - DataType.LONG, DataType.FLOAT -> return cast(targetDt, false) + BaseDataType.UBYTE -> if(number in 0.0..255.0) return cast(targetDt, false) + BaseDataType.BYTE -> if(number in -128.0..127.0) return cast(targetDt, false) + BaseDataType.UWORD -> if(number in 0.0..32767.0) return cast(targetDt, false) + BaseDataType.LONG, BaseDataType.FLOAT -> return cast(targetDt, false) else -> {} } } - DataType.LONG, DataType.FLOAT -> return cast(targetDt, false) + BaseDataType.LONG, BaseDataType.FLOAT -> return cast(targetDt, false) else -> {} } return ValueAfterCast(false, "no type conversion possible from $type to $targetDt", null) @@ -859,13 +869,13 @@ class CharLiteral private constructor(val value: Char, override fun referencesIdentifier(nameInSource: List) = false override fun constValue(program: Program): NumericLiteral { val bytevalue = program.encoding.encodeString(value.toString(), encoding).single() - return NumericLiteral(DataType.UBYTE, bytevalue.toDouble(), position) + return NumericLiteral(BaseDataType.UBYTE, bytevalue.toDouble(), position) } override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun toString(): String = "'${value.escape()}'" - override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UBYTE) + override fun inferType(program: Program) = InferredTypes.knownFor(BaseDataType.UBYTE) operator fun compareTo(other: CharLiteral): Int = value.compareTo(other.value) override fun hashCode(): Int = Objects.hash(value, encoding) override fun equals(other: Any?): Boolean { @@ -909,7 +919,7 @@ class StringLiteral private constructor(val value: String, override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun toString(): String = "'${value.escape()}'" - override fun inferType(program: Program) = InferredTypes.knownFor(DataType.STR) + override fun inferType(program: Program) = InferredTypes.knownFor(BaseDataType.STR) operator fun compareTo(other: StringLiteral): Int = value.compareTo(other.value) override fun hashCode(): Int = Objects.hash(value, encoding) override fun equals(other: Any?): Boolean { @@ -962,10 +972,10 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because if(forloop != null) { val loopvarDt = forloop.loopVarDt(program) if(loopvarDt.isKnown) { - return if(!loopvarDt.isArrayElement) + return if(!loopvarDt.isNumericOrBool) InferredTypes.InferredType.unknown() else - InferredTypes.InferredType.known(ElementToArrayTypes.getValue(loopvarDt.getOr(DataType.UNDEFINED))) + InferredTypes.InferredType.known(loopvarDt.getOrUndef().elementToArray()) } } @@ -974,25 +984,21 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because val datatypesInArray = value.map { it.inferType(program) } if(datatypesInArray.any{ it.isUnknown }) return InferredTypes.InferredType.unknown() - val dts = datatypesInArray.map { it.getOr(DataType.UNDEFINED) } + val dts = datatypesInArray.map { it.getOrUndef() } return when { - DataType.FLOAT in dts -> InferredTypes.InferredType.known(DataType.ARRAY_F) - DataType.STR in dts -> InferredTypes.InferredType.known(DataType.ARRAY_UW) - DataType.WORD in dts -> InferredTypes.InferredType.known(DataType.ARRAY_W) - DataType.UWORD in dts -> InferredTypes.InferredType.known(DataType.ARRAY_UW) - DataType.BYTE in dts -> InferredTypes.InferredType.known(DataType.ARRAY_B) - DataType.BOOL in dts -> { - if(dts.all { it==DataType.BOOL}) - InferredTypes.InferredType.known(DataType.ARRAY_BOOL) + dts.any { it.isFloat } -> InferredTypes.InferredType.known(DataType.forDt(BaseDataType.FLOAT).elementToArray()) + dts.any { it.isString } -> InferredTypes.InferredType.known(DataType.forDt(BaseDataType.UWORD).elementToArray()) + dts.any { it.isSignedWord } -> InferredTypes.InferredType.known(DataType.forDt(BaseDataType.WORD).elementToArray()) + dts.any { it.isUnsignedWord } -> InferredTypes.InferredType.known(DataType.forDt(BaseDataType.UWORD).elementToArray()) + dts.any { it.isSignedByte } -> InferredTypes.InferredType.known(DataType.forDt(BaseDataType.BYTE).elementToArray()) + dts.any { it.isBool } -> { + if(dts.all { it.isBool}) + InferredTypes.InferredType.known(DataType.forDt(BaseDataType.BOOL).elementToArray()) else InferredTypes.InferredType.unknown() } - DataType.UBYTE in dts -> InferredTypes.InferredType.known(DataType.ARRAY_UB) - DataType.ARRAY_UW in dts || - DataType.ARRAY_W in dts || - DataType.ARRAY_UB in dts || - DataType.ARRAY_B in dts || - DataType.ARRAY_F in dts -> InferredTypes.InferredType.known(DataType.ARRAY_UW) + dts.any { it.isUnsignedByte } -> InferredTypes.InferredType.known(DataType.forDt(BaseDataType.UBYTE).elementToArray()) + dts.any { it.isArray } -> InferredTypes.InferredType.known(DataType.forDt(BaseDataType.UWORD).elementToArray()) else -> InferredTypes.InferredType.unknown() } } @@ -1000,8 +1006,8 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because fun cast(targettype: DataType): ArrayLiteral? { if(type istype targettype) return this - if(targettype in ArrayDatatypes) { - val elementType = ArrayToElementTypes.getValue(targettype) + if(targettype.isArray) { + val elementType = targettype.elementType() // if all values are numeric literals, just do the cast. // if not: @@ -1010,16 +1016,17 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because // otherwise: return null (cast cannot be done) if(value.all { it is NumericLiteral }) { - val castArray = if(elementType==DataType.BOOL) { + val castArray = if(elementType.isBool) { value.map { - if((it as NumericLiteral).type==DataType.BOOL) + if((it as NumericLiteral).type==BaseDataType.BOOL) it else return null // abort } } else { + require(elementType.isNumericOrBool) value.map { - val cast = (it as NumericLiteral).cast(elementType, true) + val cast = (it as NumericLiteral).cast(elementType.base, true) if(cast.isValid) cast.valueOrZero() else @@ -1028,13 +1035,13 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because } return ArrayLiteral(InferredTypes.InferredType.known(targettype), castArray.toTypedArray(), position = position) } - else if(elementType in WordDatatypes && value.all { it is NumericLiteral || it is AddressOf || it is IdentifierReference}) { + else if(elementType.isWord && value.all { it is NumericLiteral || it is AddressOf || it is IdentifierReference}) { val castArray = value.map { when(it) { is AddressOf -> it is IdentifierReference -> it is NumericLiteral -> { - val numcast = it.cast(elementType, true) + val numcast = it.cast(elementType.base, true) if(numcast.isValid) numcast.valueOrZero() else @@ -1089,18 +1096,18 @@ class RangeExpression(var from: Expression, val toDt=to.inferType(program) return when { !fromDt.isKnown || !toDt.isKnown -> InferredTypes.unknown() - fromDt istype DataType.UBYTE && toDt istype DataType.UBYTE -> InferredTypes.knownFor(DataType.ARRAY_UB) - fromDt istype DataType.UWORD && toDt istype DataType.UWORD -> InferredTypes.knownFor(DataType.ARRAY_UW) - fromDt istype DataType.STR && toDt istype DataType.STR -> InferredTypes.knownFor(DataType.STR) - fromDt istype DataType.WORD || toDt istype DataType.WORD -> InferredTypes.knownFor(DataType.ARRAY_W) - fromDt istype DataType.BYTE || toDt istype DataType.BYTE -> InferredTypes.knownFor(DataType.ARRAY_B) + fromDt istype DataType.forDt(BaseDataType.UBYTE) && toDt istype DataType.forDt(BaseDataType.UBYTE) -> InferredTypes.knownFor(DataType.forDt(BaseDataType.UBYTE).elementToArray()) + fromDt istype DataType.forDt(BaseDataType.UWORD) && toDt istype DataType.forDt(BaseDataType.UWORD) -> InferredTypes.knownFor(DataType.forDt(BaseDataType.UWORD).elementToArray()) + fromDt istype DataType.forDt(BaseDataType.STR) && toDt istype DataType.forDt(BaseDataType.STR) -> InferredTypes.knownFor(BaseDataType.STR) + fromDt istype DataType.forDt(BaseDataType.WORD) || toDt istype DataType.forDt(BaseDataType.WORD) -> InferredTypes.knownFor(DataType.forDt(BaseDataType.WORD).elementToArray()) + fromDt istype DataType.forDt(BaseDataType.BYTE) || toDt istype DataType.forDt(BaseDataType.BYTE) -> InferredTypes.knownFor(DataType.forDt(BaseDataType.BYTE).elementToArray()) else -> { - val fdt = fromDt.getOr(DataType.UNDEFINED) - val tdt = toDt.getOr(DataType.UNDEFINED) - if(fdt largerThan tdt) - InferredTypes.knownFor(ElementToArrayTypes.getValue(fdt)) + val fdt = fromDt.getOrUndef() + val tdt = toDt.getOrUndef() + if(fdt.largerSizeThan(tdt)) + InferredTypes.knownFor(fdt.elementToArray()) else - InferredTypes.knownFor(ElementToArrayTypes.getValue(tdt)) + InferredTypes.knownFor(tdt.elementToArray()) } } } @@ -1167,7 +1174,7 @@ data class IdentifierReference(val nameInSource: List, override val posi ".${target.name}" else target.scopedName.joinToString(".") - val type = inferType(program).getOr(DataType.UNDEFINED) + val type = inferType(program).getOrUndef() return Pair(targetname, type) } @@ -1200,10 +1207,10 @@ data class IdentifierReference(val nameInSource: List, override val posi // the value of a variable can (temporarily) be a different type as the vardecl itself. // don't return the value if the types don't match yet! val value = vardecl.value?.constValue(program) - if(value==null || value.type==vardecl.datatype) + if(value==null || value.type==vardecl.datatype.base) return value val optimal = NumericLiteral.optimalNumeric(value.number, value.position) - if(optimal.type==vardecl.datatype) + if(optimal.type==vardecl.datatype.base) return optimal return null } @@ -1220,7 +1227,7 @@ data class IdentifierReference(val nameInSource: List, override val posi override fun inferType(program: Program): InferredTypes.InferredType { return when (val targetStmt = targetStatement(program)) { is VarDecl -> { - if(targetStmt.datatype==DataType.UNDEFINED) + if(targetStmt.datatype.isUndefined) InferredTypes.unknown() else InferredTypes.knownFor(targetStmt.datatype) @@ -1276,7 +1283,7 @@ class FunctionCallExpression(override var target: IdentifierReference, val resultValue: NumericLiteral? = program.builtinFunctions.constValue(target.nameInSource[0], args, position) if(withDatatypeCheck) { val resultDt = this.inferType(program) - if(resultValue==null || resultDt istype resultValue.type) + if(resultValue==null || resultDt istype DataType.forDt(resultValue.type)) return resultValue throw FatalAstException("evaluated const expression result value doesn't match expected datatype $resultDt, pos=$position") } else { @@ -1338,7 +1345,7 @@ class ContainmentCheck(var element: Expression, return NumericLiteral.fromBoolean(exists, position) } is StringLiteral -> { - if(elementConst.type in ByteDatatypes) { + if(elementConst.type.isByte) { val stringval = iterable as StringLiteral val exists = program.encoding.encodeString(stringval.value, stringval.encoding).contains(elementConst.number.toInt().toUByte() ) return NumericLiteral.fromBoolean(exists, position) @@ -1368,7 +1375,7 @@ class ContainmentCheck(var element: Expression, override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun referencesIdentifier(nameInSource: List): Boolean = element.referencesIdentifier(nameInSource) || iterable.referencesIdentifier(nameInSource) - override fun inferType(program: Program) = InferredTypes.knownFor(DataType.BOOL) + override fun inferType(program: Program) = InferredTypes.knownFor(BaseDataType.BOOL) override fun replaceChildNode(node: Node, replacement: Node) { if(replacement !is Expression) @@ -1435,5 +1442,5 @@ fun invertCondition(cond: Expression, program: Program): Expression { return if(cond.inferType(program).isBool) PrefixExpression("not", cond, cond.position) else - BinaryExpression(cond, "==", NumericLiteral(DataType.UBYTE, 0.0, cond.position), cond.position) + BinaryExpression(cond, "==", NumericLiteral(BaseDataType.UBYTE, 0.0, cond.position), cond.position) } diff --git a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt index 25dba4a26..59bc6710d 100644 --- a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt +++ b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt @@ -1,7 +1,8 @@ package prog8.ast.expressions -import prog8.code.core.* -import java.util.Objects +import prog8.code.core.BaseDataType +import prog8.code.core.DataType +import java.util.* object InferredTypes { @@ -10,18 +11,23 @@ object InferredTypes { require(!(datatype!=null && (isUnknown || isVoid))) { "invalid combination of args" } } - val isKnown = datatype!=null && datatype!=DataType.UNDEFINED + val isKnown get() = datatype!=null && !datatype!!.isUndefined fun getOr(default: DataType) = if(isUnknown || isVoid) default else datatype!! + fun getOrUndef() = if(isUnknown || isVoid) DataType.forDt(BaseDataType.UNDEFINED) else datatype!! fun getOrElse(transform: (InferredType) -> DataType): DataType = if(isUnknown || isVoid) transform(this) else datatype!! - infix fun istype(type: DataType): Boolean = if(isUnknown || isVoid) false else this.datatype==type // strict equality if known - infix fun isnot(type: DataType): Boolean = if(isUnknown || isVoid) true else this.datatype!=type - fun oneOf(vararg types: DataType) = if(isUnknown || isVoid) false else this.datatype in types + infix fun istype(type: DataType): Boolean = if(isUnknown || isVoid) false else this.datatype==type // strict equality if known + infix fun issimpletype(type: BaseDataType): Boolean = if (isUnknown || isVoid) + false + else if(type==BaseDataType.STR && this.datatype?.base==BaseDataType.STR) + true + else (this.datatype?.base == type && this.datatype?.sub == null) // strict equality if known companion object { fun unknown() = InferredType(isUnknown = true, isVoid = false, datatype = null) fun void() = InferredType(isUnknown = false, isVoid = true, datatype = null) fun known(type: DataType) = InferredType(isUnknown = false, isVoid = false, datatype = type) + fun known(basicdt: BaseDataType) = InferredType(isUnknown = false, isVoid = false, datatype = DataType.forDt(basicdt)) } override fun equals(other: Any?): Boolean { @@ -47,41 +53,46 @@ object InferredTypes { infix fun isNotAssignableTo(targetDt: InferredType): Boolean = !this.isAssignableTo(targetDt) infix fun isNotAssignableTo(targetDt: DataType): Boolean = !this.isAssignableTo(targetDt) - val isBool = datatype == DataType.BOOL - val isBytes = datatype in ByteDatatypes - val isWords = datatype in WordDatatypes - val isInteger = datatype in IntegerDatatypes - val isNumeric = datatype in NumericDatatypes - val isArray = datatype in ArrayDatatypes - val isString = datatype in StringlyDatatypes - val isIterable = datatype in IterableDatatypes - val isPassByReference = datatype in PassByReferenceDatatypes - val isPassByValue = datatype in PassByValueDatatypes - val isArrayElement = datatype in ElementToArrayTypes + val isBool = datatype?.isBool==true + val isBytes = datatype?.isByte==true + val isWords = datatype?.isWord==true + val isInteger = datatype?.isInteger==true + val isNumeric = datatype?.isNumeric==true + val isNumericOrBool = datatype?.isNumericOrBool==true + val isArray = datatype?.isArray==true + val isFloatArray = datatype?.isFloatArray==true + val isByteArray = datatype?.isByteArray==true + val isString = datatype?.isString==true + val isStringLy = datatype?.isStringly==true + val isIterable = datatype?.isIterable==true } private val unknownInstance = InferredType.unknown() private val voidInstance = InferredType.void() - private val knownInstances = mapOf( - DataType.UBYTE to InferredType.known(DataType.UBYTE), - DataType.BYTE to InferredType.known(DataType.BYTE), - DataType.UWORD to InferredType.known(DataType.UWORD), - DataType.WORD to InferredType.known(DataType.WORD), - DataType.LONG to InferredType.known(DataType.LONG), - DataType.FLOAT to InferredType.known(DataType.FLOAT), - DataType.BOOL to InferredType.known(DataType.BOOL), - DataType.STR to InferredType.known(DataType.STR), - DataType.ARRAY_UB to InferredType.known(DataType.ARRAY_UB), - DataType.ARRAY_B to InferredType.known(DataType.ARRAY_B), - DataType.ARRAY_UW to InferredType.known(DataType.ARRAY_UW), - DataType.ARRAY_UW_SPLIT to InferredType.known(DataType.ARRAY_UW_SPLIT), - DataType.ARRAY_W to InferredType.known(DataType.ARRAY_W), - DataType.ARRAY_W_SPLIT to InferredType.known(DataType.ARRAY_W_SPLIT), - DataType.ARRAY_F to InferredType.known(DataType.ARRAY_F), - DataType.ARRAY_BOOL to InferredType.known(DataType.ARRAY_BOOL) - ) fun void() = voidInstance fun unknown() = unknownInstance - fun knownFor(type: DataType) = knownInstances.getValue(type) + fun knownFor(baseDt: BaseDataType): InferredType = InferredType.known(baseDt) + fun knownFor(type: DataType): InferredType = when { + type.isUnsignedByte -> InferredType.known(BaseDataType.UBYTE) + type.isSignedByte -> InferredType.known(BaseDataType.BYTE) + type.isUnsignedWord -> InferredType.known(BaseDataType.UWORD) + type.isSignedWord -> InferredType.known(BaseDataType.WORD) + type.isBool -> InferredType.known(BaseDataType.BOOL) + type.isFloat -> InferredType.known(BaseDataType.FLOAT) + type.isString -> InferredType.known(BaseDataType.STR) + type.isLong -> InferredType.known(BaseDataType.LONG) + type.isSplitWordArray -> { + when(type.sub?.dt) { + 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)) + else -> throw IllegalArgumentException("invalid sub type") + } + } + type.isArray -> { + InferredType.known(DataType.arrayFor(type.sub!!.dt)) + } + else -> throw IllegalArgumentException("invalid type") + } } diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 2f54a7e41..7f0eec495 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -258,7 +258,7 @@ class VarDecl(val type: VarDeclType, private var autoHeapValueSequenceNumber = 0 fun fromParameter(param: SubroutineParameter): VarDecl { - val dt = if(param.type in ArrayDatatypes) DataType.UWORD else param.type + val dt = if(param.type.isArray) DataType.forDt(BaseDataType.UWORD) else param.type return VarDecl(VarDeclType.VAR, VarDeclOrigin.SUBROUTINEPARAM, dt, param.zp, null, param.name, emptyList(), null, sharedWithAsm = false, splitArray = false, @@ -278,12 +278,12 @@ class VarDecl(val type: VarDeclType, } init { - if(datatype in SplitWordArrayTypes) + if(datatype.isSplitWordArray) require(splitArray) } val isArray: Boolean - get() = datatype in ArrayDatatypes + get() = datatype.isArray override fun linkParents(parent: Node) { this.parent = parent @@ -304,8 +304,8 @@ class VarDecl(val type: VarDeclType, fun zeroElementValue(): NumericLiteral { if(allowInitializeWithZero) { - return if(datatype in ArrayDatatypes) defaultZero(ArrayToElementTypes.getValue(datatype), position) - else defaultZero(datatype, position) + return if(datatype.isArray) defaultZero(datatype.sub!!, position) + else defaultZero(datatype.base, position) } else throw IllegalArgumentException("attempt to get zero value for vardecl that shouldn't get it") @@ -557,7 +557,7 @@ data class AssignTarget(var identifier: IdentifierReference?, } if (memoryAddress != null) - return InferredTypes.knownFor(DataType.UBYTE) + return InferredTypes.knownFor(BaseDataType.UBYTE) // a multi-target has no 1 particular type return InferredTypes.unknown() diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index 683decab5..148953bae 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -199,20 +199,20 @@ class IRFileReader { if('.' !in name) throw IRParseException("unscoped varname: $name") val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null - val dt: DataType = parseDatatype(type, arraysize!=null) + val dt = parseDatatype(type, arraysize!=null) val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish) val align = if(alignment.isBlank()) 0u else alignment.toUInt() var initNumeric: Double? = null var initArray: StArray? = null - when(dt) { - in NumericDatatypesWithBoolean -> initNumeric = parseIRValue(value) - DataType.ARRAY_BOOL -> { + when { + dt.isNumericOrBool -> initNumeric = parseIRValue(value) + dt.isBoolArray -> { initArray = value.split(',').map { val boolean = parseIRValue(it) != 0.0 StArrayElement(null, null, boolean) } } - in ArrayDatatypes -> { + dt.isArray -> { initArray = value.split(',').map { if (it.startsWith('@')) StArrayElement(null, it.drop(1), null) @@ -220,7 +220,7 @@ class IRFileReader { StArrayElement(parseIRValue(it), null, null) } } - DataType.STR -> throw IRParseException("STR should have been converted to byte array") + dt.isString -> throw IRParseException("STR should have been converted to byte array") else -> throw IRParseException("weird dt") } val dummyNode = PtVariable(name, dt, zp, align, null, null, Position.DUMMY) @@ -255,7 +255,7 @@ class IRFileReader { val match = mappedPattern.matchEntire(line) ?: throw IRParseException("invalid MEMORYMAPPEDVARIABLES $line") val (type, arrayspec, name, address) = match.destructured val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null - val dt: DataType = parseDatatype(type, arraysize!=null) + val dt = parseDatatype(type, arraysize!=null) val dummyNode = PtVariable( name, dt, @@ -289,7 +289,7 @@ class IRFileReader { val (name, size, align) = match.destructured val dummyNode = PtVariable( name, - DataType.ARRAY_UB, + DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.NOT_IN_ZEROPAGE, 0u, null, @@ -514,24 +514,24 @@ class IRFileReader { private fun parseDatatype(type: String, isArray: Boolean): DataType { if(isArray) { return when(type) { - "bool" -> DataType.ARRAY_BOOL - "byte" -> DataType.ARRAY_B - "ubyte", "str" -> DataType.ARRAY_UB - "word" -> DataType.ARRAY_W - "uword" -> DataType.ARRAY_UW - "float" -> DataType.ARRAY_F - "uword_split" -> DataType.ARRAY_UW_SPLIT - "word_split" -> DataType.ARRAY_W_SPLIT + "bool" -> DataType.arrayFor(BaseDataType.BOOL) + "byte" -> DataType.arrayFor(BaseDataType.BYTE) + "ubyte", "str" -> DataType.arrayFor(BaseDataType.UBYTE) + "word" -> DataType.arrayFor(BaseDataType.WORD) + "uword" -> DataType.arrayFor(BaseDataType.UWORD) + "float" -> DataType.arrayFor(BaseDataType.FLOAT) + "uword_split" -> DataType.arrayFor(BaseDataType.UWORD, true) + "word_split" -> DataType.arrayFor(BaseDataType.WORD, true) else -> throw IRParseException("invalid dt $type") } } else { return when(type) { - "bool" -> DataType.BOOL - "byte" -> DataType.BYTE - "ubyte" -> DataType.UBYTE - "word" -> DataType.WORD - "uword" -> DataType.UWORD - "float" -> DataType.FLOAT + "bool" -> DataType.forDt(BaseDataType.BOOL) + "byte" -> DataType.forDt(BaseDataType.BYTE) + "ubyte" -> DataType.forDt(BaseDataType.UBYTE) + "word" -> DataType.forDt(BaseDataType.WORD) + "uword" -> DataType.forDt(BaseDataType.UWORD) + "float" -> DataType.forDt(BaseDataType.FLOAT) // note: 'str' should not occur anymore in IR. Should be 'uword' else -> throw IRParseException("invalid dt $type") } diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index 4ca5fad0c..515c3f801 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -1,6 +1,9 @@ package prog8.intermediate -import prog8.code.core.* +import prog8.code.core.InternalCompilerException +import prog8.code.core.Position +import prog8.code.core.SourceLineCache +import prog8.code.core.toHex import java.nio.file.Path import javax.xml.stream.XMLOutputFactory import javax.xml.stream.XMLStreamWriter @@ -202,7 +205,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { private fun writeVariables() { fun writeNoInitVar(variable: IRStStaticVariable) { - if(variable.dt in SplitWordArrayTypes) { + if(variable.dt.isSplitWordArray) { // split into 2 ubyte arrays lsb+msb xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb zp=${variable.zpwish} align=${variable.align}\n") xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb zp=${variable.zpwish} align=${variable.align}\n") @@ -212,7 +215,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { } fun writeVarWithInit(variable: IRStStaticVariable) { - if(variable.dt in SplitWordArrayTypes) { + if(variable.dt.isSplitWordArray) { val lsbValue: String val msbValue: String if(variable.onetimeInitializationArrayValue==null) { @@ -235,22 +238,23 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb=$lsbValue zp=${variable.zpwish} align=${variable.align}\n") xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb=$msbValue zp=${variable.zpwish} align=${variable.align}\n") } else { - val value: String = when(variable.dt) { - DataType.BOOL -> variable.onetimeInitializationNumericValue?.toInt()?.toString() ?: "" - DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString() - in NumericDatatypes -> variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "" - DataType.STR -> { + val dt = variable.dt + val value: String = when { + dt.isBool -> variable.onetimeInitializationNumericValue?.toInt()?.toString() ?: "" + dt.isFloat -> (variable.onetimeInitializationNumericValue ?: "").toString() + dt.isNumeric -> variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "" + dt.isString -> { val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue.second) + listOf(0u) encoded.joinToString(",") { it.toInt().toString() } } - DataType.ARRAY_F -> { + dt.isFloatArray -> { if(variable.onetimeInitializationArrayValue!=null) { variable.onetimeInitializationArrayValue.joinToString(",") { it.number!!.toString() } } else { "" // array will be zero'd out at program start } } - in ArrayDatatypes -> { + dt.isArray -> { if(variable.onetimeInitializationArrayValue!==null) { variable.onetimeInitializationArrayValue.joinToString(",") { if(it.bool==true) diff --git a/intermediate/src/prog8/intermediate/IRProgram.kt b/intermediate/src/prog8/intermediate/IRProgram.kt index 607d7c48e..866958a1a 100644 --- a/intermediate/src/prog8/intermediate/IRProgram.kt +++ b/intermediate/src/prog8/intermediate/IRProgram.kt @@ -214,8 +214,8 @@ class IRProgram(val name: String, if(instr.labelSymbol!=null && instr.opcode in OpcodesThatBranch) { if(instr.opcode==Opcode.JUMPI) { when(val pointervar = st.lookup(instr.labelSymbol)!!) { - is IRStStaticVariable -> require(pointervar.dt==DataType.UWORD) - is IRStMemVar -> require(pointervar.dt==DataType.UWORD) + is IRStStaticVariable -> require(pointervar.dt.isUnsignedWord) + is IRStMemVar -> require(pointervar.dt.isUnsignedWord) else -> throw AssemblyError("weird pointervar type") } } @@ -411,8 +411,8 @@ class IRSubroutine( require(!label.startsWith("main.main.")) {"subroutine name invalid main prefix: $label"} // params and return value should not be str - require(parameters.all{ it.dt in NumericDatatypes || it.dt==DataType.BOOL }) {"non-numeric/non-bool parameter"} - require(returnType==null || returnType in NumericDatatypes || returnType==DataType.BOOL) {"non-numeric/non-bool returntype $returnType"} + require(parameters.all{ it.dt.isNumericOrBool }) {"non-numeric/non-bool parameter"} + require(returnType==null || returnType.isNumericOrBool) {"non-numeric/non-bool returntype $returnType"} } operator fun plusAssign(chunk: IRCodeChunkBase) { diff --git a/intermediate/src/prog8/intermediate/IRSymbolTable.kt b/intermediate/src/prog8/intermediate/IRSymbolTable.kt index 1f7f03073..7390c09b8 100644 --- a/intermediate/src/prog8/intermediate/IRSymbolTable.kt +++ b/intermediate/src/prog8/intermediate/IRSymbolTable.kt @@ -150,9 +150,9 @@ open class IRStNode(val name: String, ) class IRStMemVar(name: String, - val dt: DataType, - val address: UInt, - val length: Int? // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte + val dt: DataType, + val address: UInt, + val length: Int? // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte ) : IRStNode(name, IRStNodeType.MEMVAR) { companion object { fun from(variable: StMemVar): IRStMemVar { @@ -166,7 +166,7 @@ class IRStMemVar(name: String, } init { - require(dt!=DataType.BOOL && dt!=DataType.ARRAY_BOOL) + require(!dt.isBool && !dt.isBoolArray) } val typeString: String = dt.typeString(length) @@ -195,7 +195,7 @@ class IRStStaticVariable(name: String, val onetimeInitializationArrayValue: IRStArray?, val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte val zpwish: ZeropageWish, // used in the variable allocator - val align: Int, + val align: Int ) : IRStNode(name, IRStNodeType.STATICVAR) { companion object { fun from(variable: StStaticVariable): IRStStaticVariable { @@ -212,7 +212,7 @@ class IRStStaticVariable(name: String, init { if(align > 0) { - require(dt == DataType.STR || dt in ArrayDatatypes) + require(dt.isString || dt.isArray) require(zpwish != ZeropageWish.REQUIRE_ZEROPAGE && zpwish != ZeropageWish.PREFER_ZEROPAGE) } } diff --git a/intermediate/src/prog8/intermediate/Utils.kt b/intermediate/src/prog8/intermediate/Utils.kt index 958367bc2..1904773b0 100644 --- a/intermediate/src/prog8/intermediate/Utils.kt +++ b/intermediate/src/prog8/intermediate/Utils.kt @@ -8,24 +8,34 @@ import prog8.code.right fun DataType.typeString(length: Int?): String { val lengthStr = if(length==0) "" else length.toString() - return when (this) { - DataType.BOOL -> "bool" // in IR , a boolean is represented by an ubyte. - DataType.UBYTE -> "ubyte" - DataType.BYTE -> "byte" - DataType.UWORD -> "uword" - DataType.WORD -> "word" - DataType.LONG -> "long" - DataType.FLOAT -> "float" - DataType.STR -> "ubyte[$lengthStr]" // here string doesn't exist as a seperate datatype anymore - DataType.ARRAY_BOOL -> "bool[$lengthStr]" // in IR , a boolean is represented by an ubyte. - DataType.ARRAY_UB -> "ubyte[$lengthStr]" - DataType.ARRAY_B -> "byte[$lengthStr]" - DataType.ARRAY_UW -> "uword[$lengthStr]" - DataType.ARRAY_W -> "word[$lengthStr]" - DataType.ARRAY_F -> "float[$lengthStr]" - DataType.ARRAY_UW_SPLIT -> "@split uword[$lengthStr]" // should be 2 separate byte arrays by now really - DataType.ARRAY_W_SPLIT -> "@split word[$lengthStr]" // should be 2 separate byte arrays by now really - DataType.UNDEFINED -> throw IllegalArgumentException("wrong dt") + return when (this.base) { + BaseDataType.BOOL -> "bool" + BaseDataType.UBYTE -> "ubyte" + BaseDataType.BYTE -> "byte" + BaseDataType.UWORD -> "uword" + BaseDataType.WORD -> "word" + BaseDataType.LONG -> "long" + BaseDataType.FLOAT -> "float" + BaseDataType.STR -> "ubyte[$lengthStr]" // here string doesn't exist as a seperate datatype anymore + BaseDataType.ARRAY -> { + when(this.sub?.dt) { + BaseDataType.UBYTE -> "ubyte[$lengthStr]" + BaseDataType.UWORD -> "uword[$lengthStr]" + BaseDataType.BYTE -> "byte[$lengthStr]" + BaseDataType.WORD -> "word[$lengthStr]" + BaseDataType.BOOL -> "bool[$lengthStr]" + BaseDataType.FLOAT -> "float[$lengthStr]" + else -> throw IllegalArgumentException("invalid sub type") + } + } + BaseDataType.ARRAY_SPLITW -> { + when(this.sub?.dt) { + BaseDataType.UWORD -> "@split uword[$lengthStr]" // should be 2 separate byte arrays by now really? + BaseDataType.WORD -> "@split word[$lengthStr]" // should be 2 separate byte arrays by now really? + else -> throw IllegalArgumentException("invalid sub type") + } + } + BaseDataType.UNDEFINED -> throw IllegalArgumentException("wrong dt") } } @@ -332,14 +342,16 @@ internal fun parseRegisterOrStatusflag(sourceregs: String): RegisterOrStatusflag fun irType(type: DataType): IRDataType { - return when(type) { - DataType.BOOL, - DataType.UBYTE, - DataType.BYTE -> IRDataType.BYTE - DataType.UWORD, - DataType.WORD -> IRDataType.WORD - DataType.FLOAT -> IRDataType.FLOAT - in PassByReferenceDatatypes -> IRDataType.WORD + if(type.base.isPassByRef) + return IRDataType.WORD + + return when(type.base) { + BaseDataType.BOOL, + BaseDataType.UBYTE, + BaseDataType.BYTE -> IRDataType.BYTE + BaseDataType.UWORD, + BaseDataType.WORD -> IRDataType.WORD + BaseDataType.FLOAT -> IRDataType.FLOAT else -> throw AssemblyError("no IR datatype for $type") } } diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 617f0e337..89e10e37c 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -1,10 +1,8 @@ package prog8.vm import prog8.code.Either -import prog8.code.core.ArrayDatatypes import prog8.code.core.AssemblyError import prog8.code.core.DataType -import prog8.code.core.SplitWordArrayTypes import prog8.code.left import prog8.code.right import prog8.intermediate.* @@ -202,27 +200,28 @@ class VmProgramLoader { // zero out uninitialized ('bss') variables. if(variable.uninitialized) { - if(variable.dt in ArrayDatatypes) { + if(variable.dt.isArray) { + val dt = variable.dt repeat(variable.length!!) { - when(variable.dt) { - DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_BOOL -> { + when { + dt.isString || dt.isBoolArray || dt.isByteArray -> { memory.setUB(addr, 0u) addr++ } - DataType.ARRAY_UW, DataType.ARRAY_W -> { - memory.setUW(addr, 0u) - addr += 2 - } - DataType.ARRAY_F -> { - memory.setFloat(addr, 0.0) - addr += program.options.compTarget.machine.FLOAT_MEM_SIZE - } - in SplitWordArrayTypes -> { + dt.isSplitWordArray -> { // lo bytes come after the hi bytes memory.setUB(addr, 0u) memory.setUB(addr+variable.length!!, 0u) addr++ } + dt.isWordArray -> { + memory.setUW(addr, 0u) + addr += 2 + } + dt.isFloatArray -> { + memory.setFloat(addr, 0.0) + addr += program.options.compTarget.machine.FLOAT_MEM_SIZE + } else -> throw IRParseException("invalid dt") } } @@ -230,12 +229,12 @@ class VmProgramLoader { } variable.onetimeInitializationNumericValue?.let { - when(variable.dt) { - DataType.UBYTE, DataType.BOOL -> memory.setUB(addr, it.toInt().toUByte()) - DataType.BYTE -> memory.setSB(addr, it.toInt().toByte()) - DataType.UWORD -> memory.setUW(addr, it.toInt().toUShort()) - DataType.WORD -> memory.setSW(addr, it.toInt().toShort()) - DataType.FLOAT -> memory.setFloat(addr, it) + when { + variable.dt.isUnsignedByte || variable.dt.isBool -> memory.setUB(addr, it.toInt().toUByte()) + variable.dt.isSignedByte -> memory.setSB(addr, it.toInt().toByte()) + variable.dt.isUnsignedWord -> memory.setUW(addr, it.toInt().toUShort()) + variable.dt.isSignedWord -> memory.setSW(addr, it.toInt().toShort()) + variable.dt.isFloat -> memory.setFloat(addr, it) else -> throw IRParseException("invalid dt") } } @@ -256,8 +255,8 @@ class VmProgramLoader { program: IRProgram ) { var address = startAddress - when (variable.dt) { - DataType.ARRAY_BOOL -> { + when { + variable.dt.isBoolArray -> { for (elt in iElts) { val value = getInitializerValue(variable.dt, elt, symbolAddresses) value.fold( @@ -267,7 +266,7 @@ class VmProgramLoader { address++ } } - DataType.STR, DataType.ARRAY_UB -> { + variable.dt.isString || variable.dt.isUnsignedByteArray -> { for (elt in iElts) { val value = getInitializerValue(variable.dt, elt, symbolAddresses) value.fold( @@ -278,7 +277,7 @@ class VmProgramLoader { } } - DataType.ARRAY_B -> { + variable.dt.isSignedByteArray -> { for (elt in iElts) { val value = getInitializerValue(variable.dt, elt, symbolAddresses) value.fold( @@ -289,29 +288,7 @@ class VmProgramLoader { } } - DataType.ARRAY_UW -> { - for (elt in iElts) { - val value = getInitializerValue(variable.dt, elt, symbolAddresses) - value.fold( - { memory.setUW(address, it.toInt().toUShort()) }, - { throw IRParseException("didn't expect bool") } - ) - address += 2 - } - } - - DataType.ARRAY_W -> { - for (elt in iElts) { - val value = getInitializerValue(variable.dt, elt, symbolAddresses) - value.fold( - { memory.setSW(address, it.toInt().toShort()) }, - { throw IRParseException("didn't expect bool") } - ) - address += 2 - } - } - - in SplitWordArrayTypes -> { + variable.dt.isSplitWordArray -> { for (elt in iElts) { val value = getInitializerValue(variable.dt, elt, symbolAddresses) value.fold( @@ -326,7 +303,29 @@ class VmProgramLoader { } } - DataType.ARRAY_F -> { + variable.dt.isUnsignedWordArray -> { + for (elt in iElts) { + val value = getInitializerValue(variable.dt, elt, symbolAddresses) + value.fold( + { memory.setUW(address, it.toInt().toUShort()) }, + { throw IRParseException("didn't expect bool") } + ) + address += 2 + } + } + + variable.dt.isSignedWordArray -> { + for (elt in iElts) { + val value = getInitializerValue(variable.dt, elt, symbolAddresses) + value.fold( + { memory.setSW(address, it.toInt().toShort()) }, + { throw IRParseException("didn't expect bool") } + ) + address += 2 + } + } + + variable.dt.isFloatArray -> { for (elt in iElts) { val value = getInitializerValue(variable.dt, elt, symbolAddresses) value.fold( @@ -350,8 +349,8 @@ class VmProgramLoader { program: IRProgram ) { var address = startAddress - when (variable.dt) { - DataType.STR, DataType.ARRAY_UB -> { + when { + variable.dt.isString || variable.dt.isUnsignedByteArray -> { val value = getInitializerValue(variable.dt, iElt, symbolAddresses) value.fold( { @@ -365,7 +364,7 @@ class VmProgramLoader { ) } - DataType.ARRAY_B -> { + variable.dt.isSignedByteArray -> { val value = getInitializerValue(variable.dt, iElt, symbolAddresses) value.fold( { @@ -379,35 +378,7 @@ class VmProgramLoader { ) } - DataType.ARRAY_UW -> { - val value = getInitializerValue(variable.dt, iElt, symbolAddresses) - value.fold( - { - val integer = it.toInt().toUShort() - repeat(variable.length!!) { - memory.setUW(address, integer) - address += 2 - } - }, - { throw IRParseException("didn't expect bool") } - ) - } - - DataType.ARRAY_W -> { - val value = getInitializerValue(variable.dt, iElt, symbolAddresses) - value.fold( - { - val integer = it.toInt().toShort() - repeat(variable.length!!) { - memory.setSW(address, integer) - address += 2 - } - }, - { throw IRParseException("didn't expect bool") } - ) - } - - in SplitWordArrayTypes -> { + variable.dt.isSplitWordArray -> { val value = getInitializerValue(variable.dt, iElt, symbolAddresses) value.fold( { @@ -424,7 +395,35 @@ class VmProgramLoader { ) } - DataType.ARRAY_F -> { + variable.dt.isUnsignedWordArray -> { + val value = getInitializerValue(variable.dt, iElt, symbolAddresses) + value.fold( + { + val integer = it.toInt().toUShort() + repeat(variable.length!!) { + memory.setUW(address, integer) + address += 2 + } + }, + { throw IRParseException("didn't expect bool") } + ) + } + + variable.dt.isSignedWordArray -> { + val value = getInitializerValue(variable.dt, iElt, symbolAddresses) + value.fold( + { + val integer = it.toInt().toShort() + repeat(variable.length!!) { + memory.setSW(address, integer) + address += 2 + } + }, + { throw IRParseException("didn't expect bool") } + ) + } + + variable.dt.isFloatArray -> { val value = getInitializerValue(variable.dt, iElt, symbolAddresses) value.fold( { d -> @@ -443,8 +442,8 @@ class VmProgramLoader { private fun getInitializerValue(arrayDt: DataType, elt: IRStArrayElement, symbolAddresses: MutableMap): Either { if(elt.addressOfSymbol!=null) { - when(arrayDt) { - DataType.ARRAY_UB, DataType.STR, DataType.ARRAY_B, DataType.ARRAY_BOOL -> { + when { + arrayDt.isString || arrayDt.isByteArray || arrayDt.isBoolArray -> { val name = elt.addressOfSymbol!! val symbolAddress = if(name.startsWith('<')) { symbolAddresses[name.drop(1)]?.and(255) diff --git a/virtualmachine/src/prog8/vm/VmVariableAllocator.kt b/virtualmachine/src/prog8/vm/VmVariableAllocator.kt index e465c9e0e..b1198bcf4 100644 --- a/virtualmachine/src/prog8/vm/VmVariableAllocator.kt +++ b/virtualmachine/src/prog8/vm/VmVariableAllocator.kt @@ -1,6 +1,8 @@ package prog8.vm -import prog8.code.core.* +import prog8.code.core.IMemSizer +import prog8.code.core.IStringEncoding +import prog8.code.core.InternalCompilerException import prog8.intermediate.IRSymbolTable internal class VmVariableAllocator(st: IRSymbolTable, val encoding: IStringEncoding, memsizer: IMemSizer) { @@ -16,10 +18,10 @@ internal class VmVariableAllocator(st: IRSymbolTable, val encoding: IStringEncod var nextLocation = 0 for (variable in st.allVariables()) { val memsize = - when (variable.dt) { - DataType.STR -> variable.onetimeInitializationStringValue!!.first.length + 1 // include the zero byte - in NumericDatatypes, DataType.BOOL -> memsizer.memorySize(variable.dt) - in ArrayDatatypes -> memsizer.memorySize(variable.dt, variable.length!!) + when { + variable.dt.isString -> variable.onetimeInitializationStringValue!!.first.length + 1 // include the zero byte + variable.dt.isNumericOrBool -> memsizer.memorySize(variable.dt, null) + variable.dt.isArray -> memsizer.memorySize(variable.dt, variable.length!!) else -> throw InternalCompilerException("weird dt") }