making datatype more capable (subtypes)

This commit is contained in:
Irmen de Jong 2024-09-04 21:49:47 +02:00
parent e80c22275d
commit c41dc98936
34 changed files with 334 additions and 312 deletions

View File

@ -208,7 +208,7 @@ class StStaticVariable(name: String,
}
class StConstant(name: String, val dt: DataTypeFull, val value: Double, astNode: PtNode) :
class StConstant(name: String, val dt: BaseDataType, val value: Double, astNode: PtNode) :
StNode(name, StNodeType.CONSTANT, astNode)

View File

@ -48,7 +48,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.dt, node.value, node)
}
is PtLabel -> {
StNode(node.name, StNodeType.LABEL, node)

View File

@ -55,16 +55,18 @@ val BaseDataType.isPassByValue get() = !this.isIterable
sealed class SubType(val dt: BaseDataType) {
companion object {
private val types = 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
)
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): SubType =
types.getOrElse(dt) { throw IllegalArgumentException("invalid sub type") }
types.getOrElse(dt) { throw IllegalArgumentException("invalid sub type $dt possible ${types.keys}") }
}
}
@ -237,6 +239,8 @@ data class DataTypeFull(val dt: BaseDataType, val sub: SubType?) {
val isLong = dt == BaseDataType.LONG
val isStringly = dt == BaseDataType.STR || dt == BaseDataType.UWORD || (dt == BaseDataType.ARRAY && (sub?.dt == BaseDataType.UBYTE || sub?.dt == BaseDataType.BYTE))
val isSplitWordArray = dt.isSplitWordArray
val isSplitUnsignedWordArray = dt.isSplitWordArray && sub?.dt == BaseDataType.UWORD
val isSplitSignedWordArray = dt.isSplitWordArray && sub?.dt == BaseDataType.WORD
val isIterable = dt.isIterable
val isPassByRef = dt.isPassByRef
val isPassByValue = dt.isPassByValue

View File

@ -16,18 +16,18 @@ class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
override fun memorySize(dt: DataTypeFull, numElements: Int?): Int {
if(dt.isArray || dt.isSplitWordArray) {
require(numElements!=null)
return when(dt.sub) {
SubBool, SubSignedByte, SubUnsignedByte -> numElements
SubSignedWord, SubUnsignedWord -> numElements * 2
SubFloat -> numElements * machine.FLOAT_MEM_SIZE
null -> throw IllegalArgumentException("invalid sub type")
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")
}
}
require(numElements==null)
return when {
dt.isByteOrBool -> 1
dt.isFloat -> machine.FLOAT_MEM_SIZE
else -> 2
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
else -> 2 * (numElements ?: 1)
}
}

View File

@ -15,18 +15,17 @@ class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
override fun memorySize(dt: DataTypeFull, numElements: Int?): Int {
if(dt.isArray || dt.isSplitWordArray) {
require(numElements!=null)
return when(dt.sub) {
SubBool, SubSignedByte, SubUnsignedByte -> numElements
SubSignedWord, SubUnsignedWord -> numElements * 2
SubFloat -> numElements * machine.FLOAT_MEM_SIZE
null -> throw IllegalArgumentException("invalid sub type")
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")
}
}
require(numElements==null)
return when {
dt.isByteOrBool -> 1
dt.isFloat -> machine.FLOAT_MEM_SIZE
else -> 2
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
else -> 2 * (numElements ?: 1)
}
}

View File

@ -7,18 +7,17 @@ internal object CbmMemorySizer: IMemSizer {
override fun memorySize(dt: DataTypeFull, numElements: Int?): Int {
if(dt.isArray || dt.isSplitWordArray) {
require(numElements!=null)
return when(dt.sub) {
SubBool, SubSignedByte, SubUnsignedByte -> numElements
SubSignedWord, SubUnsignedWord -> numElements * 2
SubFloat -> numElements * Mflpt5.FLOAT_MEM_SIZE
null -> throw IllegalArgumentException("invalid sub type")
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")
}
}
require(numElements==null)
return when {
dt.isByteOrBool -> 1
dt.isFloat -> Mflpt5.FLOAT_MEM_SIZE
else -> 2
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isFloat -> Mflpt5.FLOAT_MEM_SIZE * (numElements ?: 1)
else -> 2 * (numElements ?: 1)
}
}

View File

@ -738,7 +738,7 @@ internal class ProgramAndVarsGen(
asmgen.out(" ${it.name} = ${it.address.toHex()}")
}
consts.sortedBy { it.name }.forEach {
if(it.dt.isFloat)
if(it.dt==BaseDataType.FLOAT)
asmgen.out(" ${it.name} = ${it.value}")
else
asmgen.out(" ${it.name} = ${it.value.toHex()}")

View File

@ -14,11 +14,10 @@ internal object DummyMemsizer : IMemSizer {
else -> throw IllegalArgumentException("invalid sub type")
}
}
require(numElements==null)
return when {
dt.isByteOrBool -> 1
dt.isFloat -> 5
else -> 2
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isFloat -> 5 * (numElements ?: 1)
else -> 2 * (numElements ?: 1)
}
}

View File

@ -12,11 +12,10 @@ internal object DummyMemsizer : IMemSizer {
else -> throw IllegalArgumentException("invalid sub type")
}
}
require(numElements==null)
return when {
dt.isByteOrBool -> 1
dt.isFloat -> 5
else -> 2
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isFloat -> 5 * (numElements ?: 1)
else -> 2 * (numElements ?: 1)
}
}

View File

@ -132,12 +132,12 @@ internal class AstChecker(private val program: Program,
val valueDt = returnStmt.value!!.inferType(program)
if(valueDt.isKnown) {
if (expectedReturnValues[0] != valueDt.getOrUndef()) {
if(valueDt istype DataType.BOOL && expectedReturnValues[0] == DataType.UBYTE) {
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].isUnsignedWord) {
// you can return a string or array when an uword (pointer) is returned
} else if(valueDt istype DataType.UWORD && expectedReturnValues[0].isString) {
} else if(valueDt issimpletype BaseDataType.UWORD && expectedReturnValues[0].isString) {
// you can return a uword pointer when the return type is a string
}
else {
@ -188,6 +188,9 @@ internal class AstChecker(private val program: Program,
}
val iterableDt = forLoop.iterable.inferType(program).getOr(DataTypeFull.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.isIterable) && forLoop.iterable !is RangeExpression) {
@ -200,9 +203,8 @@ internal class AstChecker(private val program: Program,
require(loopvar.datatype.isNumericOrBool)
when (loopvar.datatype.dt) {
BaseDataType.UBYTE -> {
if(iterableDt!= DataType.UBYTE && iterableDt!= DataType.ARRAY_UB && iterableDt != DataType.STR)
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)
}
BaseDataType.BOOL -> {
@ -210,21 +212,21 @@ internal class AstChecker(private val program: Program,
errors.err("bool loop variable can only loop over boolean array", forLoop.position)
}
BaseDataType.UWORD -> {
if(iterableDt!= DataType.UBYTE && iterableDt!= DataType.UWORD && iterableDt != DataType.STR &&
iterableDt != DataType.ARRAY_UB && iterableDt != DataType.ARRAY_UW &&
iterableDt != DataType.ARRAY_UW_SPLIT)
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)
}
BaseDataType.BYTE -> {
if(iterableDt!= DataType.BYTE && iterableDt!= DataType.ARRAY_B)
if(!iterableDt.isSignedByte && !iterableDt.isSignedByteArray) // TODO remove byte check?
errors.err("byte loop variable can only loop over bytes", forLoop.position)
}
BaseDataType.WORD -> {
if(iterableDt!= DataType.BYTE && iterableDt!= DataType.WORD &&
iterableDt != DataType.ARRAY_B && iterableDt!= DataType.ARRAY_W &&
iterableDt != DataType.ARRAY_W_SPLIT)
if(!iterableDt.isSignedByte && !iterableDt.isSignedWord && // TODO remove byte and word check?
!iterableDt.isSignedByteArray && !iterableDt.isSignedWordArray &&
!iterableDt.isSplitWordArray)
errors.err("word loop variable can only loop over bytes or words", forLoop.position)
}
BaseDataType.FLOAT -> {
@ -393,12 +395,11 @@ 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.isString && !param.first.type.isArray)
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) {
@ -408,12 +409,11 @@ internal class AstChecker(private val program: Program,
}
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) {
@ -497,7 +497,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.isPassByRef && 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)
}
}
@ -693,7 +693,7 @@ internal class AstChecker(private val program: Program,
}
// 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
@ -967,7 +967,7 @@ 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)
@ -977,10 +977,7 @@ internal class AstChecker(private val program: Program,
fun isPassByReferenceElement(e: Expression): Boolean {
if(e is IdentifierReference) {
val decl = e.targetVarDecl(program)
return if(decl!=null)
decl.datatype.isPassByRef
else
true // is probably a symbol that needs addr-of
return decl?.datatype?.isPassByRef ?: true // is probably a symbol that needs addr-of
}
return e is StringLiteral
}
@ -1027,7 +1024,7 @@ internal class AstChecker(private val program: Program,
return // any error should be reported elsewhere
if(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)
}
}
@ -1078,7 +1075,7 @@ 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)
}
}
@ -1093,9 +1090,9 @@ 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.isString && rightDt.isInteger && expr.operator=="*") {
@ -1123,12 +1120,12 @@ internal class AstChecker(private val program: Program,
} else {
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, true).isValid)
if(rightDt.largerSizeThan(origLeftDt) && !(expr.right as NumericLiteral).cast(origLeftDt.dt, 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) issimpletype BaseDataType.FLOAT)) {
val origRightDt = (expr.right as TypecastExpression).expression.inferType(program).getOrUndef()
if(leftDt.largerSizeThan(origRightDt) && !(expr.left as NumericLiteral).cast(origRightDt, true).isValid)
if(leftDt.largerSizeThan(origRightDt) && !(expr.left as NumericLiteral).cast(origRightDt.dt, true).isValid)
errors.err("operands are not the same type", expr.right.position)
}
}
@ -1157,7 +1154,7 @@ internal class AstChecker(private val program: Program,
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)
}
}
@ -1294,7 +1291,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)
}
}
@ -1409,7 +1406,7 @@ internal class AstChecker(private val program: Program,
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.isSigned) {
if(indexVariable.targetVarDecl(program)?.datatype?.isSigned==true) {
errors.err("variable array indexing can't be performed with signed variables", indexVariable.position)
return
}
@ -1476,7 +1473,7 @@ internal class AstChecker(private val program: Program,
when {
constvalue == null -> errors.err("choice value must be a constant", pos)
!constvalue.type.isIntegerOrBool -> errors.err("choice value must be a byte or word", pos)
conditionType isnot constvalue.type -> {
!(conditionType issimpletype constvalue.type) -> {
if(conditionType.isKnown) {
if(conditionType.isBool) {
if(constvalue.number!=0.0 && constvalue.number!=1.0)
@ -1749,23 +1746,23 @@ internal class AstChecker(private val program: Program,
}
}
val correct: Boolean
when (type) {
DataType.ARRAY_UB -> {
when {
type.isUnsignedByteArray -> {
correct = array.all { it in 0..255 }
}
DataType.ARRAY_B -> {
type.isSignedByteArray -> {
correct = array.all { it in -128..127 }
}
DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> {
type.isUnsignedWordArray || type.isSplitUnsignedWordArray -> {
correct = array.all { (it in 0..65535) }
}
DataType.ARRAY_W, DataType.ARRAY_W_SPLIT -> {
type.isSignedWordArray || type.isSplitSignedWordArray -> {
correct = array.all { it in -32768..32767 }
}
DataType.ARRAY_BOOL -> {
type.isBoolArray -> {
correct = array.all { it==0 || it==1 }
}
DataType.ARRAY_F -> correct = true
type.isFloatArray -> correct = true
else -> throw FatalAstException("invalid array type $type")
}
if (!correct)
@ -1788,14 +1785,14 @@ internal class AstChecker(private val program: Program,
return false
}
val result = when(targetDatatype) {
DataType.BOOL -> sourceDatatype.isBool
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.FLOAT -> sourceDatatype.isNumeric
DataType.STR -> sourceDatatype.isString
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.isFloat -> sourceDatatype.isNumeric
targetDatatype.isString -> sourceDatatype.isString
else -> {
errors.err("cannot assign new value to variable of type $targetDatatype", position)
false
@ -1805,7 +1802,7 @@ internal class AstChecker(private val program: Program,
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.isIterable && targetDatatype.isByte) {
@ -1819,10 +1816,10 @@ internal class AstChecker(private val program: Program,
else if(targetDatatype.isUnsignedWord && sourceDatatype.isPassByRef) {
// this is allowed: a pass-by-reference datatype into a uword (pointer value).
}
else if(sourceDatatype.isBool && targetDatatype!=DataType.BOOL) {
else if(sourceDatatype.isBool && !targetDatatype.isBool) {
errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position)
}
else if(targetDatatype.isBool && sourceDatatype!=DataType.BOOL) {
else if(targetDatatype.isBool && !sourceDatatype.isBool) {
errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position)
}
else {

View File

@ -27,7 +27,7 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
}
}
if(typecast.type==sourceDt)
if(typecast.type==sourceDt.dt)
return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
if(sourceDt.isPassByRef) {
@ -101,18 +101,18 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
val arg2 = bfcs.args[1]
val dt1 = arg1.inferType(program).getOrUndef()
val dt2 = arg2.inferType(program).getOrUndef()
if(dt1==DataType.BOOL && dt2==DataType.BOOL)
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, bfcs))
} else {
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, bfcs))
}
@ -125,9 +125,9 @@ 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.warn("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.warn("shift always results in 0", expr.position)
if(shifts.number<=255.0 && shifts.type.isWord) {
val byteVal = NumericLiteral(BaseDataType.UBYTE, shifts.number, shifts.position)

View File

@ -555,7 +555,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)

View File

@ -218,7 +218,7 @@ internal class StatementReorderer(
}
if(!assignment.isAugmentable) {
if (valueType.isString && (targetType issimpletype BaseDataType.STR || targetType istype DataType.ARRAY_B || targetType istype DataType.ARRAY_UB)) {
if (valueType.isString && (targetType issimpletype BaseDataType.STR || targetType.isByteArray)) {
// replace string assignment by a call to stringcopy
return copyStringValue(assignment)
}

View File

@ -42,7 +42,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
return noModifications
val modifications = mutableListOf<IAstModification>()
addTypecastOrCastedValueModification(modifications, declValue, decl.datatype, decl)
addTypecastOrCastedValueModification(modifications, declValue, decl.datatype.dt, decl)
return modifications
}
}
@ -104,36 +104,36 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
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.getOrUndef(), true, expr.left.position)
val cast = TypecastExpression(expr.left, rightDt.getOrUndef().dt, 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<IAstModification>()
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.getOrUndef(), true, expr.right.position)
val cast = TypecastExpression(expr.right, leftDt.getOrUndef().dt, 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<IAstModification>()
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
@ -151,8 +151,8 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
} else {
val modifications = mutableListOf<IAstModification>()
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.dt, expr)
toFix===expr.right -> addTypecastOrCastedValueModification(modifications, expr.right, commonDt.dt, expr)
else -> throw FatalAstException("confused binary expression side")
}
return modifications
@ -174,15 +174,15 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val valuetype = valueItype.getOrUndef()
if (valuetype != targettype) {
if (valuetype isAssignableTo targettype) {
if(valuetype in IterableDatatypes && targettype.isUnsignedWord)
if(valuetype.isIterable && targettype.isUnsignedWord)
// special case, don't typecast STR/arrays to UWORD, we support those assignments "directly"
return noModifications
val modifications = mutableListOf<IAstModification>()
addTypecastOrCastedValueModification(modifications, assignment.value, targettype, assignment)
addTypecastOrCastedValueModification(modifications, assignment.value, targettype.dt, assignment)
return modifications
} else {
fun castLiteral(cvalue2: NumericLiteral): List<IAstModification.ReplaceNode> {
val cast = cvalue2.cast(targettype, true)
val cast = cvalue2.cast(targettype.dt, true)
return if(cast.isValid)
listOf(IAstModification.ReplaceNode(assignment.value, cast.valueOrZero(), assignment))
else
@ -225,7 +225,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val modifications = mutableListOf<IAstModification>()
val params = when(val sub = call.target.targetStatement(program)) {
is BuiltinFunctionPlaceholder -> BuiltinFunctions.getValue(sub.name).parameters
is Subroutine -> sub.parameters.map { FParam(it.name, listOf(it.type).toTypedArray()) }
is Subroutine -> sub.parameters.map { FParam(it.name, listOf(it.type.dt).toTypedArray()) }
else -> emptyList()
}
@ -234,7 +234,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val argIdt = it.second.inferType(program)
if (argIdt.isKnown) {
val argDt = argIdt.getOrUndef()
if (argDt !in it.first.possibleDatatypes) {
if (argDt.dt !in it.first.possibleDatatypes) {
val identifier = it.second as? IdentifierReference
val number = it.second as? NumericLiteral
if(number!=null) {
@ -275,7 +275,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
override fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
// 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.warn("integer implicitly converted to float. Suggestion: use float literals, add an explicit cast, or revert to integer arithmetic", typecast.position)
else
@ -289,7 +289,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
// make sure the memory address is an uword
val modifications = mutableListOf<IAstModification>()
val dt = memread.addressExpression.inferType(program)
if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) {
if(dt.isKnown && !dt.getOr(DataTypeFull.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)
@ -303,7 +303,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
// make sure the memory address is an uword
val modifications = mutableListOf<IAstModification>()
val dt = memwrite.addressExpression.inferType(program)
if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) {
if(dt.isKnown && !dt.getOr(DataTypeFull.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)
@ -325,12 +325,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.dt, true)
if(cast.isValid)
returnStmt.value = cast.valueOrZero()
} else {
val modifications = mutableListOf<IAstModification>()
addTypecastOrCastedValueModification(modifications, returnValue, subReturnType, returnStmt)
addTypecastOrCastedValueModification(modifications, returnValue, subReturnType.dt, returnStmt)
return modifications
}
}
@ -345,7 +345,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
values?.toTypedArray()?.withIndex()?.forEach { (index, value) ->
val valueDt = value.inferType(program)
if(valueDt!=conditionDt) {
val castedValue = value.typecastTo(conditionDt.getOrUndef(), valueDt.getOrUndef(), true)
val castedValue = value.typecastTo(conditionDt.getOrUndef().dt, valueDt.getOrUndef(), true)
if(castedValue.first) {
castedValue.second.linkParents(whenChoice)
values[index] = castedValue.second
@ -362,7 +362,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val modifications = mutableListOf<IAstModification>()
val (commonDt, toChange) = BinaryExpression.commonDatatype(fromDt, toDt, range.from, range.to)
if(toChange!=null)
addTypecastOrCastedValueModification(modifications, toChange, commonDt, range)
addTypecastOrCastedValueModification(modifications, toChange, commonDt.dt, range)
return modifications
}
@ -373,12 +373,11 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
parent: Node
) {
val sourceDt = expressionToCast.inferType(program).getOrUndef()
if(sourceDt == requiredType)
if(sourceDt.dt == requiredType)
return
if(requiredType.isBool) {
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)

View File

@ -1,13 +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.RegisterOrPair
import prog8.code.core.isNumeric
import prog8.code.target.Cx16Target
import prog8tests.helpers.compileText
@ -17,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.floatFac1 shouldBe false
conv.returns.reg shouldBe RegisterOrPair.A
}
@ -37,7 +40,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.floatFac1 shouldBe false
@ -48,18 +51,18 @@ 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
val conv = func.callConvention(listOf(DataType.UWORD, DataType.UBYTE))
val conv = func.callConvention(listOf(BaseDataType.UWORD, BaseDataType.UBYTE))
conv.params.size shouldBe 2
conv.params[0].dt shouldBe DataType.UWORD
conv.params[0].dt shouldBe BaseDataType.UWORD
conv.params[0].reg shouldBe null
conv.params[0].variable shouldBe true
conv.params[1].dt shouldBe DataType.UBYTE
conv.params[1].dt shouldBe BaseDataType.UBYTE
conv.params[1].reg shouldBe null
conv.params[1].variable shouldBe true
conv.returns.dt shouldBe null

View File

@ -9,6 +9,8 @@ import prog8.ast.IFunctionCall
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteral
import prog8.ast.statements.VarDeclType
import prog8.code.core.BaseDataType
import prog8.code.core.DataTypeFull
import prog8.code.core.Encoding
import prog8.code.target.Cx16Target
import prog8tests.helpers.compileText
@ -40,7 +42,7 @@ class TestCompilerOnCharLit: FunSpec({
funCall.args[0] shouldBe instanceOf<NumericLiteral>()
}
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()
}
@ -64,7 +66,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 BaseDataType.UBYTE
withClue("initializer value should have been moved to separate assignment"){
decl.value shouldBe null
@ -75,7 +77,7 @@ class TestCompilerOnCharLit: FunSpec({
assignInitialValue.value shouldBe instanceOf<NumericLiteral>()
}
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()
}
@ -100,7 +102,7 @@ class TestCompilerOnCharLit: FunSpec({
is IdentifierReference -> {
val decl = arg.targetVarDecl(program)!!
decl.type shouldBe VarDeclType.CONST
decl.datatype shouldBe DataType.UBYTE
decl.datatype shouldBe DataTypeFull.forDt(BaseDataType.UBYTE)
(decl.value as NumericLiteral).number shouldBe platform.encodeString("\n", Encoding.PETSCII)[0]
}
is NumericLiteral -> {

View File

@ -26,7 +26,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", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors)
result.expectError { "should not be able to allocate anything" }
}
@ -34,28 +34,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", DataTypeFull.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", DataTypeFull.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", DataTypeFull.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", DataTypeFull.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", DataTypeFull.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", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors)
result.expectError { "nothing more available" }
}

View File

@ -12,9 +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.Position
import prog8.code.core.SourceCode
import prog8.code.core.ZeropageWish
import prog8.code.core.*
import prog8.code.target.C64Target
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
@ -113,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, Position.DUMMY)
val decl = VarDecl(vartype, VarDeclOrigin.USERCODE, DataTypeFull.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 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)
@ -151,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, Position.DUMMY)
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataTypeFull.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, 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)
@ -163,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, Position.DUMMY)
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataTypeFull.forDt(BaseDataType.UBYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 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)
@ -175,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, Position.DUMMY)
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataTypeFull.forDt(BaseDataType.UBYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 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)
@ -186,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, Position.DUMMY)
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataTypeFull.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, 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)
@ -199,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, Position.DUMMY)
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataTypeFull.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 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)
@ -212,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, Position.DUMMY)
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataTypeFull.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 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)

View File

@ -10,6 +10,8 @@ import prog8.ast.expressions.ArrayLiteral
import prog8.ast.expressions.InferredTypes
import prog8.ast.expressions.NumericLiteral
import prog8.ast.expressions.StringLiteral
import prog8.code.core.BaseDataType
import prog8.code.core.DataTypeFull
import prog8.code.core.Encoding
import prog8.code.core.Position
@ -108,9 +110,9 @@ class TestNumericLiteral: FunSpec({
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.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 lv1 = ArrayLiteral(InferredTypes.InferredType.known(DataTypeFull.arrayFor(BaseDataType.UBYTE)), arrayOf(lvOne, lvTwo, lvThree), dummyPos)
val lv2 = ArrayLiteral(InferredTypes.InferredType.known(DataTypeFull.arrayFor(BaseDataType.UBYTE)), arrayOf(lvOneR, lvTwoR, lvThreeR), dummyPos)
val lv3 = ArrayLiteral(InferredTypes.InferredType.known(DataTypeFull.arrayFor(BaseDataType.UBYTE)), arrayOf(lvOneR, lvTwoR, lvFour), dummyPos)
lv1 shouldBe lv2
lv1 shouldNotBe lv3
}
@ -152,34 +154,34 @@ class TestNumericLiteral: FunSpec({
}
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
}
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
}
})

View File

@ -16,6 +16,7 @@ import prog8.code.ast.PtAssignTarget
import prog8.code.ast.PtAssignment
import prog8.code.ast.PtFunctionCall
import prog8.code.core.BaseDataType
import prog8.code.core.DataTypeFull
import prog8.code.core.Position
import prog8.code.target.C64Target
import prog8.code.target.Cx16Target
@ -93,7 +94,7 @@ other {
test("generated constvalue from typecast inherits proper parent linkage") {
val number = NumericLiteral(BaseDataType.UBYTE, 11.0, Position.DUMMY)
val tc = TypecastExpression(number, DataType.BYTE, false, 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
@ -102,7 +103,7 @@ other {
val constvalue = tc.constValue(program)!!
constvalue shouldBe instanceOf<NumericLiteral>()
constvalue.number shouldBe 11.0
constvalue.type shouldBe DataType.BYTE
constvalue.type shouldBe BaseDataType.BYTE
constvalue.parent shouldBeSameInstanceAs tc.parent
}
@ -117,7 +118,7 @@ other {
val constvalue = pfx.constValue(program)!!
constvalue shouldBe instanceOf<NumericLiteral>()
constvalue.number shouldBe -11.0
constvalue.type shouldBe DataType.BYTE
constvalue.type shouldBe BaseDataType.BYTE
constvalue.parent shouldBeSameInstanceAs pfx.parent
}
@ -555,7 +556,7 @@ main {
arrayDecl.isArray shouldBe true
arrayDecl.arraysize?.constIndex() shouldBe 4
val arrayValue = arrayDecl.value as ArrayLiteral
arrayValue.type shouldBe InferredTypes.InferredType.known(DataType.ARRAY_UB)
arrayValue.type shouldBe InferredTypes.InferredType.known(DataTypeFull.arrayFor(BaseDataType.UBYTE))
arrayValue.value shouldBe listOf(
NumericLiteral.optimalInteger(1, Position.DUMMY),
NumericLiteral.optimalInteger(3, Position.DUMMY),
@ -927,13 +928,13 @@ main {
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<BinaryExpression>()
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<BinaryExpression>()

View File

@ -9,6 +9,7 @@ import prog8.code.ast.PtArray
import prog8.code.ast.PtNumber
import prog8.code.ast.PtString
import prog8.code.core.BaseDataType
import prog8.code.core.DataTypeFull
import prog8.code.core.Encoding
import prog8.code.core.Position
@ -107,11 +108,11 @@ class TestPtNumber: FunSpec({
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.ARRAY_UB, dummyPos)
val lv1 = PtArray(DataTypeFull.arrayFor(BaseDataType.UBYTE), dummyPos)
arrayOf(lvOne, lvTwo, lvThree).forEach { lv1.add(it) }
val lv2 = PtArray(DataType.ARRAY_UB, dummyPos)
val lv2 = PtArray(DataTypeFull.arrayFor(BaseDataType.UBYTE), dummyPos)
arrayOf(lvOneR, lvTwoR, lvThreeR).forEach { lv2.add(it) }
val lv3 = PtArray(DataType.ARRAY_UB, dummyPos)
val lv3 = PtArray(DataTypeFull.arrayFor(BaseDataType.UBYTE), dummyPos)
arrayOf(lvOneR, lvTwoR, lvFour).forEach { lv3.add(it) }
lv1 shouldBe lv2
lv1 shouldNotBe lv3

View File

@ -8,6 +8,8 @@ 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.DataTypeFull
import prog8.code.target.C64Target
import prog8.compiler.astprocessing.hasRtsInAsm
import prog8tests.helpers.ErrorReporterForTests
@ -67,12 +69,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 DataTypeFull.forDt(BaseDataType.UWORD)
func.parameters.single().type shouldBe DataTypeFull.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 DataTypeFull.forDt(BaseDataType.UWORD)
}
val assign = func.statements[2] as Assignment
assign.target.identifier!!.nameInSource shouldBe listOf("t2")
@ -126,8 +128,8 @@ class TestSubroutines: FunSpec({
asmfunc.hasRtsInAsm() 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 DataTypeFull.forDt(BaseDataType.UWORD)
func.parameters.single().type shouldBe DataTypeFull.forDt(BaseDataType.UWORD)
}
func.statements.size shouldBe 5
@ -135,7 +137,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 DataTypeFull.forDt(BaseDataType.UWORD)
}
val assign = func.statements[2] as Assignment
assign.target.identifier!!.nameInSource shouldBe listOf("t2")
@ -182,8 +184,8 @@ class TestSubroutines: FunSpec({
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
val func = mainBlock.statements.filterIsInstance<Subroutine>().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 DataTypeFull.forDt(BaseDataType.UWORD)
func.parameters.single().type shouldBe DataTypeFull.forDt(BaseDataType.UWORD)
}
}

View File

@ -7,9 +7,7 @@ import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.types.shouldBeSameInstanceAs
import prog8.code.*
import prog8.code.ast.*
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
@ -39,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", DataTypeFull.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", DataTypeFull.forDt(BaseDataType.BYTE), Position.DUMMY)) }
default.name shouldBe "default"
val msbFunc = st.lookupUnscopedOrElse("msb") { fail("msb must be found") }
@ -63,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 DataTypeFull.forDt(BaseDataType.BYTE)
val blockc = sub1.lookupUnscopedOrElse("blockc") { fail("blockc") } as StConstant
blockc.type shouldBe StNodeType.CONSTANT
@ -83,14 +81,14 @@ class TestSymbolTable: FunSpec({
}
test("static vars") {
val node = PtIdentifier("dummy", DataType.UBYTE, Position.DUMMY)
val stVar1 = StStaticVariable("initialized", DataType.UBYTE, 99.0, null, null, null, ZeropageWish.DONTCARE, node)
val stVar2 = StStaticVariable("uninitialized", DataType.UBYTE, null, null, null, null, ZeropageWish.DONTCARE, node)
val node = PtIdentifier("dummy", DataTypeFull.forDt(BaseDataType.UBYTE), Position.DUMMY)
val stVar1 = StStaticVariable("initialized", DataTypeFull.forDt(BaseDataType.UBYTE), 99.0, null, null, null, ZeropageWish.DONTCARE, node)
val stVar2 = StStaticVariable("uninitialized", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, null, null, ZeropageWish.DONTCARE, 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, null, arrayInitNonzero, 3, ZeropageWish.DONTCARE, node)
val stVar4 = StStaticVariable("initialized", DataType.ARRAY_UW, null, null, arrayInitAllzero, 3, ZeropageWish.DONTCARE, node)
val stVar5 = StStaticVariable("uninitialized", DataType.ARRAY_UW, null, null, null, 3, ZeropageWish.DONTCARE, node)
val stVar3 = StStaticVariable("initialized", DataTypeFull.arrayFor(BaseDataType.UWORD), null, null, arrayInitNonzero, 3, ZeropageWish.DONTCARE, node)
val stVar4 = StStaticVariable("initialized", DataTypeFull.arrayFor(BaseDataType.UWORD), null, null, arrayInitAllzero, 3, ZeropageWish.DONTCARE, node)
val stVar5 = StStaticVariable("uninitialized", DataTypeFull.arrayFor(BaseDataType.UWORD), null, null, null, 3, ZeropageWish.DONTCARE, node)
stVar1.uninitialized shouldBe false
stVar1.length shouldBe null
@ -111,18 +109,18 @@ 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", DataTypeFull.forDt(BaseDataType.UWORD), 12345.0, Position.DUMMY)
val astConstant2 = PtConstant("blockc", DataTypeFull.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, ZeropageWish.DONTCARE, null, null, Position.DUMMY)
val astSub1v2 = PtVariable("v2", DataType.BYTE, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
val astSub1v3 = PtVariable("v3", DataType.FLOAT, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
val astSub1v4 = PtVariable("slab1", DataType.UWORD, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
val astSub2v1 = PtVariable("v1", DataType.BYTE, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
val astSub2v2 = PtVariable("v2", DataType.BYTE, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
val astSub1v1 = PtVariable("v1", DataTypeFull.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE, null, null, Position.DUMMY)
val astSub1v2 = PtVariable("v2", DataTypeFull.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE,null, null, Position.DUMMY)
val astSub1v3 = PtVariable("v3", DataTypeFull.forDt(BaseDataType.FLOAT), ZeropageWish.DONTCARE,null, null, Position.DUMMY)
val astSub1v4 = PtVariable("slab1", DataTypeFull.forDt(BaseDataType.UWORD), ZeropageWish.DONTCARE,null, null, Position.DUMMY)
val astSub2v1 = PtVariable("v1", DataTypeFull.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE,null, null, Position.DUMMY)
val astSub2v2 = PtVariable("v2", DataTypeFull.forDt(BaseDataType.BYTE), ZeropageWish.DONTCARE,null, null, Position.DUMMY)
astSub1.add(astSub1v1)
astSub1.add(astSub1v2)
astSub1.add(astSub1v3)
@ -131,7 +129,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", DataTypeFull.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)
@ -152,14 +150,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, null, ZeropageWish.DONTCARE, astSub1v1))
sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, 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", DataTypeFull.forDt(BaseDataType.BYTE), null, null, null, null, ZeropageWish.DONTCARE, astSub1v1))
sub11.add(StStaticVariable("v2", DataTypeFull.forDt(BaseDataType.BYTE), null, null, null, null, ZeropageWish.DONTCARE, astSub1v2))
sub11.add(StMemVar("v3", DataTypeFull.forDt(BaseDataType.FLOAT), 12345u, null, astSub1v3))
sub11.add(StMemorySlab("slab1", 200u, 64u, astSub1v4))
sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, astSub2v1))
sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, astSub2v2))
sub12.add(StStaticVariable("v1", DataTypeFull.forDt(BaseDataType.BYTE), null, null, null, null, ZeropageWish.DONTCARE, astSub2v1))
sub12.add(StStaticVariable("v2", DataTypeFull.forDt(BaseDataType.BYTE), null, null, null, null, ZeropageWish.DONTCARE, astSub2v2))
val block2 = StNode("block2", StNodeType.BLOCK, astBlock2)
val sub21 = StNode("sub1", StNodeType.SUBROUTINE, astSub21)
val sub22 = StNode("sub2", StNodeType.SUBROUTINE, astSub22)

View File

@ -14,6 +14,7 @@ import prog8.ast.statements.IfElse
import prog8.code.ast.PtAsmSub
import prog8.code.ast.PtSub
import prog8.code.core.BaseDataType
import prog8.code.core.DataTypeFull
import prog8.code.core.Position
import prog8.code.target.C64Target
import prog8.code.target.VMTarget
@ -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<IdentifierReference>()
val assign1subtc = (assign1tc.expression as TypecastExpression)
assign1subtc.type shouldBe DataType.BYTE
assign1subtc.type shouldBe BaseDataType.BYTE
assign1subtc.expression shouldBe instanceOf<IdentifierReference>()
}
@ -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 DataTypeFull.forDt(BaseDataType.UWORD)
derp.parameters.single().type shouldBe DataTypeFull.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 DataTypeFull.forDt(BaseDataType.UWORD)
mult3.returns.single().second shouldBe DataTypeFull.forDt(BaseDataType.UWORD)
}
test("return 0 for str converted to uword") {

View File

@ -73,26 +73,26 @@ class TestC64Zeropage: FunSpec({
compTarget = c64target, loadAddress = 999u
))
var result = zp.allocate("", DataType.UBYTE, null, null, errors)
var result = zp.allocate("", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors)
result.onFailure { fail(it.toString()) }
result = zp.allocate("", DataType.UBYTE, null, null, errors)
result = zp.allocate("", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors)
result.onFailure { fail(it.toString()) }
result = zp.allocate("varname", DataType.UBYTE, null, null, errors)
result = zp.allocate("varname", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors)
result.onFailure { fail(it.toString()) }
shouldThrow<IllegalArgumentException> { zp.allocate("varname", DataType.UBYTE,null, null, errors) }
result = zp.allocate("varname2", DataType.UBYTE, null, null, errors)
shouldThrow<IllegalArgumentException> { zp.allocate("varname", DataTypeFull.forDt(BaseDataType.UBYTE),null, null, errors) }
result = zp.allocate("varname2", DataTypeFull.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))
var result = zp.allocate("", DataType.FLOAT, null, null, errors)
var result = zp.allocate("", DataTypeFull.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))
result = zp2.allocate("", DataType.FLOAT, null, null, errors)
result = zp2.allocate("", DataTypeFull.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))
zp3.allocate("", DataType.FLOAT, null, null, errors)
zp3.allocate("", DataTypeFull.forDt(BaseDataType.FLOAT), null, null, errors)
}
test("testZpModesWithFloats") {
@ -114,7 +114,7 @@ class TestC64Zeropage: FunSpec({
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u))
println(zp.free)
zp.availableBytes() shouldBe 0
val result = zp.allocate("", DataType.BYTE, null, null, errors)
val result = zp.allocate("", DataTypeFull.forDt(BaseDataType.BYTE), null, null, errors)
result.expectError { "expected error due to disabled ZP use" }
}
@ -127,9 +127,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))
zp4.availableBytes() shouldBe 207
zp4.allocate("test", DataType.UBYTE, null, null, errors)
zp4.allocate("test", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors)
zp4.availableBytes() shouldBe 206
zp4.allocate("test2", DataType.UBYTE, null, null, errors)
zp4.allocate("test2", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors)
zp4.availableBytes() shouldBe 205
}
@ -168,19 +168,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("", DataTypeFull.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("", DataTypeFull.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("", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors)
result.expectError { "expected allocation error" }
result = zp.allocate("", DataType.UWORD, null, null, errors)
result = zp.allocate("", DataTypeFull.forDt(BaseDataType.UWORD), null, null, errors)
result.expectError { "expected allocation error" }
}
@ -189,47 +189,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("", DataTypeFull.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("", DataTypeFull.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("", DataTypeFull.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("", DataTypeFull.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("", DataTypeFull.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))
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("", DataTypeFull.forDt(BaseDataType.WORD), null, null, errors).getOrElse{throw it}.address shouldBe 0x04u
zp.allocate("", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x06u
zp.allocate("", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x0au
zp.allocate("", DataTypeFull.forDt(BaseDataType.UWORD), null, null, errors).getOrElse{throw it}.address shouldBe 0x9bu
zp.allocate("", DataTypeFull.forDt(BaseDataType.UWORD), null, null, errors).getOrElse{throw it}.address shouldBe 0x9eu
zp.allocate("", DataTypeFull.forDt(BaseDataType.UWORD), null, null, errors).getOrElse{throw it}.address shouldBe 0xb0u
zp.allocate("", DataTypeFull.forDt(BaseDataType.UWORD), null, null, errors).getOrElse{throw it}.address shouldBe 0xbeu
zp.allocate("", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x0eu
zp.allocate("", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x92u
zp.allocate("", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0x96u
zp.allocate("", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0xa6u
zp.allocate("", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors).getOrElse{throw it}.address shouldBe 0xf9u
zp.availableBytes() shouldBe 0
}
@ -260,9 +260,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))
zp3.availableBytes() shouldBe 216
zp3.allocate("test", DataType.UBYTE, null, null, errors)
zp3.allocate("test", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors)
zp3.availableBytes() shouldBe 215
zp3.allocate("test2", DataType.UBYTE, null, null, errors)
zp3.allocate("test2", DataTypeFull.forDt(BaseDataType.UBYTE), null, null, errors)
zp3.availableBytes() shouldBe 214
}

View File

@ -209,13 +209,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
}

View File

@ -6,6 +6,8 @@ import io.kotest.matchers.ints.shouldBeGreaterThan
import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.instanceOf
import prog8.code.ast.*
import prog8.code.core.BaseDataType
import prog8.code.core.DataTypeFull
import prog8.code.core.Position
import prog8.code.target.C64Target
import prog8.compiler.astprocessing.IntermediateAstMaker
@ -53,15 +55,15 @@ class TestIntermediateAst: FunSpec({
val ccdecl = entry.children[0] as PtVariable
ccdecl.name shouldBe "cc"
ccdecl.scopedName shouldBe "main.start.cc"
ccdecl.type shouldBe DataType.BOOL
ccdecl.type shouldBe DataTypeFull.forDt(BaseDataType.BOOL)
val dddecl = entry.children[1] as PtVariable
dddecl.name shouldBe "dd"
dddecl.scopedName shouldBe "main.start.dd"
dddecl.type shouldBe DataType.UBYTE
dddecl.type shouldBe DataTypeFull.forDt(BaseDataType.UBYTE)
val arraydecl = entry.children[2] as IPtVariable
arraydecl.name shouldBe "array"
arraydecl.type shouldBe DataType.ARRAY_UB
arraydecl.type shouldBe DataTypeFull.arrayFor(BaseDataType.UBYTE)
val ccAssignV = (entry.children[5] as PtAssignment).value
ccAssignV shouldBe instanceOf<PtContainmentCheck>()
@ -70,28 +72,28 @@ class TestIntermediateAst: FunSpec({
}
test("isSame on binaryExpressions") {
val expr1 = PtBinaryExpression("/", DataType.UBYTE, Position.DUMMY)
val expr1 = PtBinaryExpression("/", DataTypeFull.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.UBYTE, Position.DUMMY)
val expr2 = PtBinaryExpression("/", DataTypeFull.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)
val expr3 = PtBinaryExpression("/", DataTypeFull.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)
val expr1 = PtBinaryExpression("+", DataTypeFull.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.UBYTE, Position.DUMMY)
val expr2 = PtBinaryExpression("+", DataTypeFull.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)
val expr3 = PtBinaryExpression("+", DataTypeFull.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

View File

@ -8,6 +8,8 @@ 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.DataTypeFull
import prog8.code.core.SourceCode
import prog8.code.target.Cx16Target
import prog8.code.target.VMTarget
@ -36,10 +38,10 @@ class TestSubroutines: FunSpec({
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
asmfunc.isAsmSubroutine shouldBe true
asmfunc.parameters.single().type shouldBe DataType.STR
asmfunc.parameters.single().type shouldBe DataTypeFull.forDt(BaseDataType.STR)
asmfunc.statements.isEmpty() shouldBe true
func.isAsmSubroutine shouldBe false
func.parameters.single().type shouldBe DataType.STR
func.parameters.single().type shouldBe DataTypeFull.forDt(BaseDataType.STR)
func.statements.isEmpty() shouldBe true
}
@ -61,10 +63,10 @@ class TestSubroutines: FunSpec({
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
asmfunc.isAsmSubroutine shouldBe true
asmfunc.parameters.single().type shouldBe DataType.ARRAY_UB
asmfunc.parameters.single().type shouldBe DataTypeFull.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 DataTypeFull.arrayFor(BaseDataType.UBYTE)
func.statements.isEmpty() shouldBe true
}

View File

@ -9,6 +9,8 @@ import io.kotest.matchers.types.instanceOf
import prog8.ast.IFunctionCall
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.code.core.BaseDataType
import prog8.code.core.DataTypeFull
import prog8.code.core.Position
import prog8.code.target.C64Target
import prog8.code.target.Cx16Target
@ -185,10 +187,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 DataTypeFull.forDt(BaseDataType.UWORD)
leftval1.number shouldBe 1.0
val leftval2 = assign2expr.left.constValue(result.compilerAst)!!
leftval2.type shouldBe DataType.UWORD
leftval2.type shouldBe DataTypeFull.forDt(BaseDataType.UWORD)
leftval2.number shouldBe 1.0
}
@ -541,12 +543,12 @@ main {
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.type shouldBe DataTypeFull.forDt(BaseDataType.UBYTE)
assignUbb.expression shouldBe instanceOf<IdentifierReference>()
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<ArrayIndexedExpression>()
}

View File

@ -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, Position.DUMMY)
val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", emptyList(), null, false, false, Position.DUMMY)
val varInSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataTypeFull.forDt(BaseDataType.UWORD), ZeropageWish.DONTCARE, null, "localvar", emptyList(), NumericLiteral.optimalInteger(1234, Position.DUMMY), false, false, Position.DUMMY)
val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataTypeFull.forDt(BaseDataType.UWORD), ZeropageWish.DONTCARE, null, "tgt", emptyList(), null, false, 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, Position.DUMMY)
val varInBlock = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataTypeFull.forDt(BaseDataType.UWORD), ZeropageWish.DONTCARE, null, "var_outside", emptyList(),null, false, 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", DataTypeFull.forDt(BaseDataType.UBYTE), Position.DUMMY)
val id2 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_W2", DataTypeFull.forDt(BaseDataType.UWORD), Position.DUMMY)
id1.parent = PtProgram("test", DummyMemsizer, DummyStringEncoder)
id2.parent = PtProgram("test", DummyMemsizer, DummyStringEncoder)
asmgen.asmSymbolName(id1) shouldBe "P8ZP_SCRATCH_REG"

View File

@ -10,6 +10,8 @@ import io.kotest.matchers.types.instanceOf
import prog8.code.ast.PtAssignment
import prog8.code.ast.PtBinaryExpression
import prog8.code.ast.PtVariable
import prog8.code.core.BaseDataType
import prog8.code.core.DataTypeFull
import prog8.code.target.*
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
@ -73,7 +75,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 DataTypeFull.arrayFor(BaseDataType.UWORD)
val assign = start.children[1] as PtAssignment
assign.target.identifier!!.name shouldBe "cx16.r0"
assign.value shouldBe instanceOf<PtBinaryExpression>()

View File

@ -24,20 +24,23 @@ internal object DummyMemsizer : IMemSizer {
override fun memorySize(dt: DataTypeFull, numElements: Int?): Int {
if(dt.isArray || dt.isSplitWordArray) {
require(numElements!=null)
return when(dt.sub) {
SubBool, SubSignedByte, SubUnsignedByte -> numElements
SubSignedWord, SubUnsignedWord -> numElements*2
SubFloat -> numElements*5
null -> throw IllegalArgumentException("invalid sub type")
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")
}
}
require(numElements==null)
return when {
dt.isByteOrBool -> 1
dt.isFloat -> 5
else -> 2
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isFloat -> 5 * (numElements ?: 1)
else -> 2 * (numElements ?: 1)
}
}
override fun memorySize(dt: SubType): Int {
return memorySize(DataTypeFull.forDt(dt.dt), null)
}
}
internal object DummyStringEncoder : IStringEncoding {
@ -78,4 +81,8 @@ internal object DummyCompilationTarget : ICompilationTarget {
override fun memorySize(dt: DataTypeFull, numElements: Int?): Int {
throw NotImplementedError("dummy")
}
override fun memorySize(dt: SubType): Int {
throw NotImplementedError("dummy")
}
}

View File

@ -17,7 +17,6 @@ object InferredTypes {
if(isUnknown || isVoid) transform(this) else datatype!!
infix fun istype(type: DataTypeFull): Boolean = if(isUnknown || isVoid) false else this.datatype==type // strict equality if known
infix fun issimpletype(type: BaseDataType): Boolean = if(isUnknown || isVoid) false else (this.datatype?.dt==type && this.datatype?.sub==null) // strict equality if known
fun oneOf(vararg types: DataTypeFull) = if(isUnknown || isVoid) false else this.datatype in types
companion object {
fun unknown() = InferredType(isUnknown = true, isVoid = false, datatype = null)
@ -56,6 +55,8 @@ object InferredTypes {
val isNumeric get() = datatype?.isNumeric==true
val isNumericOrBool get() = datatype?.isNumericOrBool==true
val isArray get() = datatype?.isArray==true
val isFloatArray get() = datatype?.isFloatArray==true
val isByteArray get() = datatype?.isByteArray==true
val isString get() = datatype?.isString==true
val isStringLy get() = datatype?.isStringly==true
val isIterable get() = datatype?.isIterable==true

View File

@ -1,7 +1,7 @@
TODO
====
is the second MemorySize() required?
add extra Memsizer unit tests
replace some when { xxx.isWord... } with (when xxx.dt) { UWORD -> ...} again