updated unit tests and some basic changes for them

This commit is contained in:
Irmen de Jong 2024-02-04 23:41:01 +01:00
parent 1ca3f64bf0
commit f40b7b62bb
23 changed files with 437 additions and 787 deletions

View File

@ -79,28 +79,28 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
"sort" to FSignature(false, listOf(FParam("array", ArrayDatatypes)), null),
"reverse" to FSignature(false, listOf(FParam("array", ArrayDatatypes)), null),
// cmp returns a status in the carry flag, but not a proper return value
"cmp" to FSignature(false, listOf(FParam("value1", IntegerDatatypesNoBool), FParam("value2", NumericDatatypesNoBool)), null),
"cmp" to FSignature(false, listOf(FParam("value1", IntegerDatatypes), FParam("value2", NumericDatatypes)), null),
"prog8_lib_stringcompare" to FSignature(true, listOf(FParam("str1", arrayOf(DataType.STR)), FParam("str2", arrayOf(DataType.STR))), DataType.BYTE),
"prog8_lib_arraycopy" to FSignature(false, listOf(FParam("source", ArrayDatatypes), FParam("target", ArrayDatatypes)), null),
"prog8_lib_square_byte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE, DataType.UBYTE))), DataType.UBYTE),
"prog8_lib_square_word" to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD, DataType.UWORD))), DataType.UWORD),
"abs" to FSignature(true, listOf(FParam("value", NumericDatatypesNoBool)), null),
"abs" to FSignature(true, listOf(FParam("value", NumericDatatypes)), null),
"abs__byte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE))), DataType.BYTE),
"abs__word" to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD))), DataType.WORD),
"abs__float" to FSignature(true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT),
"len" to FSignature(true, listOf(FParam("values", IterableDatatypes)), DataType.UWORD),
// normal functions follow:
"sizeof" to FSignature(true, listOf(FParam("object", DataType.entries.toTypedArray())), DataType.UBYTE),
"sgn" to FSignature(true, listOf(FParam("value", NumericDatatypesNoBool)), DataType.BYTE),
"sqrt" to FSignature(true, listOf(FParam("value", NumericDatatypesNoBool)), null),
"sgn" to FSignature(true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE),
"sqrt" to FSignature(true, listOf(FParam("value", NumericDatatypes)), null),
"sqrt__ubyte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UBYTE))), DataType.UBYTE),
"sqrt__uword" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD))), DataType.UBYTE),
"sqrt__float" to FSignature(true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT),
"divmod" to FSignature(false, listOf(FParam("number", arrayOf(DataType.UBYTE, DataType.UWORD)), FParam("divident", arrayOf(DataType.UBYTE, DataType.UWORD)), FParam("division", arrayOf(DataType.UBYTE, DataType.UWORD)), FParam("remainder", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
"divmod__ubyte" to FSignature(false, listOf(FParam("number", arrayOf(DataType.UBYTE)), FParam("divident", arrayOf(DataType.UBYTE)), FParam("division", arrayOf(DataType.UBYTE)), FParam("remainder", arrayOf(DataType.UBYTE))), null),
"divmod__uword" to FSignature(false, listOf(FParam("number", arrayOf(DataType.UWORD)), FParam("divident", arrayOf(DataType.UWORD)), FParam("division", arrayOf(DataType.UWORD)), FParam("remainder", arrayOf(DataType.UWORD))), null),
"any" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE),
"all" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE),
"any" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), DataType.BOOL),
"all" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), DataType.BOOL),
"lsb" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE),
"msb" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE),
"mkword" to FSignature(true, listOf(FParam("msb", arrayOf(DataType.UBYTE)), FParam("lsb", arrayOf(DataType.UBYTE))), DataType.UWORD),

View File

@ -24,8 +24,8 @@ enum class DataType {
*/
infix fun isAssignableTo(targetType: DataType) =
when(this) {
BOOL -> targetType.oneOf(BOOL, BYTE, UBYTE, WORD, UWORD, LONG, FLOAT)
UBYTE -> targetType.oneOf(UBYTE, WORD, UWORD, LONG, FLOAT, BOOL)
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)
@ -41,9 +41,9 @@ enum class DataType {
infix fun largerThan(other: DataType) =
when {
this == other -> false
this in ByteDatatypes -> false
this in WordDatatypes -> other in ByteDatatypes
this == LONG -> other in ByteDatatypes+WordDatatypes
this in ByteDatatypesWithBoolean -> false
this in WordDatatypes -> other in ByteDatatypesWithBoolean
this == LONG -> other in ByteDatatypesWithBoolean+WordDatatypes
this == STR && other == UWORD || this == UWORD && other == STR -> false
else -> true
}
@ -51,7 +51,7 @@ enum class DataType {
infix fun equalsSize(other: DataType) =
when {
this == other -> true
this in ByteDatatypes -> other in ByteDatatypes
this in ByteDatatypesWithBoolean -> other in ByteDatatypesWithBoolean
this in WordDatatypes -> other in WordDatatypes
this== STR && other== UWORD || this== UWORD && other== STR -> true
else -> false
@ -124,12 +124,13 @@ enum class BranchCondition {
}
val ByteDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.BOOL)
val ByteDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE)
val ByteDatatypesWithBoolean = ByteDatatypes + DataType.BOOL
val WordDatatypes = arrayOf(DataType.UWORD, DataType.WORD)
val IntegerDatatypesNoBool = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.LONG)
val IntegerDatatypes = IntegerDatatypesNoBool + DataType.BOOL
val NumericDatatypesNoBool = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.LONG, DataType.FLOAT)
val NumericDatatypes = NumericDatatypesNoBool + DataType.BOOL
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)
@ -141,7 +142,7 @@ val IterableDatatypes = arrayOf(
DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT,
DataType.ARRAY_F, DataType.ARRAY_BOOL
)
val PassByValueDatatypes = NumericDatatypes
val PassByValueDatatypes = NumericDatatypesWithBoolean
val PassByReferenceDatatypes = IterableDatatypes
val ArrayToElementTypes = mapOf(
DataType.STR to DataType.UBYTE,

View File

@ -11,4 +11,6 @@ interface IErrorReporter {
if(numErrors>0)
throw ErrorsReportedException("There are $numErrors errors, $numWarnings warnings, and $numInfos infos.")
}
fun noErrorForLine(position: Position): Boolean
}

View File

@ -5,7 +5,7 @@ import prog8.code.core.*
internal object DummyMemsizer : IMemSizer {
override fun memorySize(dt: DataType) = when(dt) {
in ByteDatatypes -> 1
in ByteDatatypesWithBoolean -> 1
DataType.FLOAT -> 5
else -> 2
}
@ -58,6 +58,7 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
}
override fun noErrors(): Boolean = errors.isEmpty()
override fun noErrorForLine(position: Position) = !errors.any { ":${position.line}:" in it }
override fun report() {
infos.forEach { println("UNITTEST COMPILATION REPORT: INFO: $it") }

View File

@ -3,7 +3,7 @@ import prog8.code.core.*
internal object DummyMemsizer : IMemSizer {
override fun memorySize(dt: DataType) = when(dt) {
in ByteDatatypes -> 1
in ByteDatatypesWithBoolean -> 1
DataType.FLOAT -> 5
else -> 2
}
@ -56,6 +56,7 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
}
override fun noErrors(): Boolean = errors.isEmpty()
override fun noErrorForLine(position: Position) = !errors.any { ":${position.line}:" in it }
override fun report() {
infos.forEach { println("UNITTEST COMPILATION REPORT: INFO: $it") }

View File

@ -125,7 +125,7 @@ class TestVmCodeGen: FunSpec({
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, 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))
if1.add(cmp1)
@ -133,7 +133,7 @@ class TestVmCodeGen: FunSpec({
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression("!=", DataType.UBYTE, 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))
if2.add(cmp2)
@ -141,7 +141,7 @@ class TestVmCodeGen: FunSpec({
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if2)
val if3 = PtIfElse(Position.DUMMY)
val cmp3 = PtBinaryExpression("<", DataType.UBYTE, 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))
if3.add(cmp3)
@ -149,7 +149,7 @@ class TestVmCodeGen: FunSpec({
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if3)
val if4 = PtIfElse(Position.DUMMY)
val cmp4 = PtBinaryExpression(">", DataType.UBYTE, 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))
if4.add(cmp4)
@ -188,7 +188,7 @@ class TestVmCodeGen: FunSpec({
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, 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))
if1.add(cmp1)
@ -196,7 +196,7 @@ class TestVmCodeGen: FunSpec({
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression("!=", DataType.UBYTE, 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))
if2.add(cmp2)
@ -204,7 +204,7 @@ class TestVmCodeGen: FunSpec({
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if2)
val if3 = PtIfElse(Position.DUMMY)
val cmp3 = PtBinaryExpression("<", DataType.UBYTE, 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))
if3.add(cmp3)
@ -212,7 +212,7 @@ class TestVmCodeGen: FunSpec({
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if3)
val if4 = PtIfElse(Position.DUMMY)
val cmp4 = PtBinaryExpression(">", DataType.UBYTE, 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))
if4.add(cmp4)
@ -247,7 +247,7 @@ class TestVmCodeGen: FunSpec({
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, 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))
if1.add(cmp1)
@ -255,7 +255,7 @@ class TestVmCodeGen: FunSpec({
if1.add(PtNodeGroup())
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression(">", DataType.UBYTE, 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))
if2.add(cmp2)
@ -294,7 +294,7 @@ class TestVmCodeGen: FunSpec({
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.BYTE, 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))
if1.add(cmp1)
@ -302,7 +302,7 @@ class TestVmCodeGen: FunSpec({
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression("!=", DataType.BYTE, 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))
if2.add(cmp2)
@ -310,7 +310,7 @@ class TestVmCodeGen: FunSpec({
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if2)
val if3 = PtIfElse(Position.DUMMY)
val cmp3 = PtBinaryExpression("<", DataType.BYTE, 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))
if3.add(cmp3)
@ -318,7 +318,7 @@ class TestVmCodeGen: FunSpec({
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if3)
val if4 = PtIfElse(Position.DUMMY)
val cmp4 = PtBinaryExpression(">", DataType.BYTE, 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))
if4.add(cmp4)
@ -357,7 +357,7 @@ class TestVmCodeGen: FunSpec({
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.BYTE, 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))
if1.add(cmp1)
@ -365,7 +365,7 @@ class TestVmCodeGen: FunSpec({
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression("!=", DataType.BYTE, 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))
if2.add(cmp2)
@ -373,7 +373,7 @@ class TestVmCodeGen: FunSpec({
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if2)
val if3 = PtIfElse(Position.DUMMY)
val cmp3 = PtBinaryExpression("<", DataType.BYTE, 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))
if3.add(cmp3)
@ -381,7 +381,7 @@ class TestVmCodeGen: FunSpec({
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
sub.add(if3)
val if4 = PtIfElse(Position.DUMMY)
val cmp4 = PtBinaryExpression(">", DataType.BYTE, 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))
if4.add(cmp4)
@ -416,7 +416,7 @@ class TestVmCodeGen: FunSpec({
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
sub.add(PtVariable("ub1", DataType.UBYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
val if1 = PtIfElse(Position.DUMMY)
val cmp1 = PtBinaryExpression("==", DataType.UBYTE, 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))
if1.add(cmp1)
@ -424,7 +424,7 @@ class TestVmCodeGen: FunSpec({
if1.add(PtNodeGroup())
sub.add(if1)
val if2 = PtIfElse(Position.DUMMY)
val cmp2 = PtBinaryExpression(">", DataType.UBYTE, 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))
if2.add(cmp2)

View File

@ -19,8 +19,8 @@ internal val constEvaluatorsForBuiltinFuncs: Map<String, ConstExpressionCaller>
"sqrt__ubyte" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, false) { sqrt(it.toDouble()) } },
"sqrt__uword" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, false) { sqrt(it.toDouble()) } },
"sqrt__float" to { a, p, prg -> oneFloatArgOutputFloat(a, p, prg) { sqrt(it) } },
"any" to { a, p, prg -> collectionArg(a, p, prg, ::builtinAny) },
"all" to { a, p, prg -> collectionArg(a, p, prg, ::builtinAll) },
"any" to { a, p, prg -> collectionArgBoolResult(a, p, prg) { array->array.any { it!=0.0 } } },
"all" to { a, p, prg -> collectionArgBoolResult(a, p, prg) { array->array.all { it!=0.0 } } },
"lsb" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x and 255).toDouble() } },
"msb" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 8 and 255).toDouble()} },
"mkword" to ::builtinMkword,
@ -38,10 +38,6 @@ internal val constEvaluatorsForBuiltinFuncs: Map<String, ConstExpressionCaller>
"max__word" to ::builtinMaxWord
)
private fun builtinAny(array: List<Double>): Double = if(array.any { it!=0.0 }) 1.0 else 0.0
private fun builtinAll(array: List<Double>): Double = if(array.all { it!=0.0 }) 1.0 else 0.0
internal fun builtinFunctionReturnType(function: String): InferredTypes.InferredType {
if(function in arrayOf("set_carry", "set_irqd", "clear_carry", "clear_irqd"))
return InferredTypes.InferredType.void()
@ -63,7 +59,7 @@ private fun oneIntArgOutputInt(args: List<Expression>, 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) IntegerDatatypesNoBool else arrayOf(DataType.UBYTE, DataType.UWORD)
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)
@ -81,7 +77,7 @@ private fun oneFloatArgOutputFloat(args: List<Expression>, position: Position, p
return NumericLiteral(DataType.FLOAT, function(constval.number), args[0].position)
}
private fun collectionArg(args: List<Expression>, position: Position, program: Program, function: (arg: List<Double>)->Double): NumericLiteral {
private fun collectionArgBoolResult(args: List<Expression>, position: Position, program: Program, function: (arg: List<Double>)->Boolean): NumericLiteral {
if(args.size!=1)
throw SyntaxError("builtin function requires one non-scalar argument", position)
@ -89,8 +85,7 @@ private fun collectionArg(args: List<Expression>, position: Position, program: P
val constElements = array.value.map{it.constValue(program)?.number}
if(constElements.contains(null))
throw NotConstArgumentException()
return NumericLiteral.optimalNumeric(function(constElements.mapNotNull { it }), args[0].position)
return NumericLiteral.fromBoolean(function(constElements.mapNotNull { it }), args[0].position)
}
private fun builtinAbs(args: List<Expression>, position: Position, program: Program): NumericLiteral {
@ -100,7 +95,7 @@ private fun builtinAbs(args: List<Expression>, position: Position, program: Prog
val constval = args[0].constValue(program) ?: throw NotConstArgumentException()
return when (constval.type) {
in IntegerDatatypesNoBool -> NumericLiteral.optimalInteger(abs(constval.number.toInt()), args[0].position)
in IntegerDatatypes -> NumericLiteral.optimalInteger(abs(constval.number.toInt()), args[0].position)
else -> throw SyntaxError("abs requires one integer argument", position)
}
}
@ -161,7 +156,7 @@ private fun builtinLen(args: List<Expression>, position: Position, program: Prog
val refLv = target.value as? StringLiteral ?: throw CannotEvaluateException("len", "stringsize unknown")
NumericLiteral.optimalInteger(refLv.value.length, args[0].position)
}
in NumericDatatypes -> throw SyntaxError("cannot use len on numeric value, did you mean sizeof?", args[0].position)
in NumericDatatypes, DataType.BOOL -> throw SyntaxError("cannot use len on numeric value, did you mean sizeof?", args[0].position)
else -> throw InternalCompilerException("weird datatype")
}
}

View File

@ -43,6 +43,7 @@ internal class ErrorReporter: IErrorReporter {
if(msg !in alreadyReportedMessages) {
when(it.severity) {
MessageSeverity.ERROR -> {
System.out.flush()
printer.print("\u001b[91mERROR\u001B[0m ") // bright red
numErrors++
}
@ -66,4 +67,6 @@ internal class ErrorReporter: IErrorReporter {
}
override fun noErrors() = messages.none { it.severity==MessageSeverity.ERROR }
override fun noErrorForLine(position: Position) = !messages.any { it.position.line==position.line && it.severity!=MessageSeverity.INFO }
}

View File

@ -48,13 +48,13 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
return listOf(IAstModification.ReplaceNode(typecast, constValue, parent))
if(typecast.expression is NumericLiteral) {
val value = (typecast.expression as NumericLiteral).cast(typecast.type)
val value = (typecast.expression as NumericLiteral).cast(typecast.type) // TODO: add param typecast.implicit
if(value.isValid)
return listOf(IAstModification.ReplaceNode(typecast, value.value!!, parent))
return listOf(IAstModification.ReplaceNode(typecast, value.value!!, parent)) // TODO: value.valueOrZero()
}
val sourceDt = typecast.expression.inferType(program)
if(sourceDt istype typecast.type || (sourceDt istype DataType.BOOL && typecast.type==DataType.UBYTE))
if(sourceDt istype typecast.type)
return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
if(parent is Assignment) {
@ -65,13 +65,6 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
}
}
// if the expression is a comparison expression, or a logical expression, it produces the
// correct 'boolean' byte result so the cast can be removed. Only if target is Integer.
val binExpr = typecast.expression as? BinaryExpression
if(binExpr!=null && binExpr.operator in ComparisonOperators + LogicalOperators && typecast.type in IntegerDatatypesNoBool) {
return listOf(IAstModification.ReplaceNode(typecast, binExpr, parent))
}
return noModifications
}
@ -152,6 +145,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
}
}
/* TODO: is this really no longer needed in boolean branch?
if(expr.operator in LogicalOperators) {
// remove redundant !=0 comparisons from logical expressions such as: a!=0 xor b --> a xor b (only for byte operands!)
val leftExpr = expr.left as? BinaryExpression
@ -171,6 +165,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
return listOf(IAstModification.ReplaceNode(rightExpr, rightExpr.left, expr))
}
}
*/
return noModifications
}

View File

@ -7,7 +7,7 @@ import prog8.ast.statements.Assignment
import prog8.ast.statements.FunctionCallStatement
import prog8.code.core.BuiltinFunctions
import prog8.code.core.DataType
import prog8.code.core.NumericDatatypesNoBool
import prog8.code.core.NumericDatatypes
import prog8.code.core.RegisterOrPair
import prog8.code.target.Cx16Target
import prog8tests.helpers.compileText
@ -18,7 +18,7 @@ class TestBuiltinFunctions: FunSpec({
val func = BuiltinFunctions.getValue("sgn")
func.parameters.size shouldBe 1
func.parameters[0].name shouldBe "value"
func.parameters[0].possibleDatatypes shouldBe NumericDatatypesNoBool
func.parameters[0].possibleDatatypes shouldBe NumericDatatypes
func.pure shouldBe true
func.returnType shouldBe DataType.BYTE

View File

@ -164,32 +164,6 @@ class TestCompilerOnRanges: FunSpec({
}
}
test("testForLoopWithRange_bool_to_bool") {
val platform = Cx16Target()
val result = compileText(platform, optimize = true, """
main {
sub start() {
ubyte i
for i in false to true {
i += i ; keep optimizer from removing it
}
}
}
""")!!
val program = result.compilerAst
val startSub = program.entrypoint
val rangeExpr = startSub
.statements.filterIsInstance<ForLoop>()
.map { it.iterable }
.filterIsInstance<RangeExpression>()[0]
rangeExpr.size() shouldBe 2
val intProgression = rangeExpr.toConstantIntegerRange()
intProgression?.first shouldBe 0
intProgression?.last shouldBe 1
}
test("testForLoopWithRange_ubyte_to_ubyte") {
val platform = Cx16Target()
val result = compileText(platform, optimize = true, """
@ -421,7 +395,7 @@ class TestCompilerOnRanges: FunSpec({
C64Target(), false, """
main {
sub start() {
ubyte xx
bool xx
uword ww
str name = "irmen"
ubyte[] values = [1,2,3,4,5,6,7]

View File

@ -105,11 +105,11 @@ class TestOptimization: FunSpec({
sub start() {
bool @shared a1
bool @shared a2
a1 = not a1 ; a1 = a1==0
a1 = not a1 ; a1 = not a1
a1 = not not a1 ; a1 = a1, so removed totally
a1 = not not not a1 ; a1 = a1==0
a1 = not a1 or not a2 ; a1 = (a1 and a2)==0
a1 = not a1 and not a2 ; a1 = (a1 or a2)==0
a1 = not not not a1 ; a1 = not a1
a1 = not a1 or not a2 ; a1 = not (a1 and a2)
a1 = not a1 and not a2 ; a1 = not (a1 or a2)
}
}
"""
@ -117,20 +117,18 @@ class TestOptimization: FunSpec({
val stmts = result.compilerAst.entrypoint.statements
stmts.size shouldBe 9
val value1 = (stmts[4] as Assignment).value as BinaryExpression
val value2 = (stmts[5] as Assignment).value as BinaryExpression
val value3 = (stmts[6] as Assignment).value as BinaryExpression
val value4 = (stmts[7] as Assignment).value as BinaryExpression
value1.operator shouldBe "=="
value1.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
value2.operator shouldBe "=="
value2.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
value3.operator shouldBe "=="
value3.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
(value3.left as BinaryExpression).operator shouldBe "and"
value4.operator shouldBe "=="
value4.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
(value4.left as BinaryExpression).operator shouldBe "or"
val value1 = (stmts[4] as Assignment).value as PrefixExpression
val value2 = (stmts[5] as Assignment).value as PrefixExpression
val value3 = (stmts[6] as Assignment).value as PrefixExpression
val value4 = (stmts[7] as Assignment).value as PrefixExpression
value1.operator shouldBe "not"
value2.operator shouldBe "not"
value3.operator shouldBe "not"
value4.operator shouldBe "not"
value1.expression shouldBe instanceOf<IdentifierReference>()
value2.expression shouldBe instanceOf<IdentifierReference>()
(value3.expression as BinaryExpression).operator shouldBe "and"
(value4.expression as BinaryExpression).operator shouldBe "or"
}
test("various 'not' operator rewrites with optimizations") {
@ -139,11 +137,11 @@ class TestOptimization: FunSpec({
sub start() {
bool @shared a1
bool @shared a2
a1 = not a1 ; a1 = a1==0
a1 = not not a1 ; a1 = a1, so removed totally
a1 = not not not a1 ; a1 = a1==0
a1 = not a1 or not a2 ; a1 = (a1 and a2)==0
a1 = not a1 and not a2 ; a1 = (a1 or a2)==0
a1 = not a1 ; a1 = not a1
a1 = not not a1 ; a1 = a1, so removed totally
a1 = not not not a1 ; a1 = not a1
a1 = not a1 or not a2 ; a1 = not (a1 and a2)
a1 = not a1 and not a2 ; a1 = not (a1 or a2)
}
}
"""
@ -151,20 +149,18 @@ class TestOptimization: FunSpec({
val stmts = result.compilerAst.entrypoint.statements
stmts.size shouldBe 9
val value1 = (stmts[4] as Assignment).value as BinaryExpression
val value2 = (stmts[5] as Assignment).value as BinaryExpression
val value3 = (stmts[6] as Assignment).value as BinaryExpression
val value4 = (stmts[7] as Assignment).value as BinaryExpression
value1.operator shouldBe "=="
value1.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
value2.operator shouldBe "=="
value2.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
value3.operator shouldBe "=="
value3.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
(value3.left as BinaryExpression).operator shouldBe "and"
value4.operator shouldBe "=="
value4.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
(value4.left as BinaryExpression).operator shouldBe "or"
val value1 = (stmts[4] as Assignment).value as PrefixExpression
val value2 = (stmts[5] as Assignment).value as PrefixExpression
val value3 = (stmts[6] as Assignment).value as PrefixExpression
val value4 = (stmts[7] as Assignment).value as PrefixExpression
value1.operator shouldBe "not"
value2.operator shouldBe "not"
value3.operator shouldBe "not"
value4.operator shouldBe "not"
value1.expression shouldBe instanceOf<IdentifierReference>()
value2.expression shouldBe instanceOf<IdentifierReference>()
(value3.expression as BinaryExpression).operator shouldBe "and"
(value4.expression as BinaryExpression).operator shouldBe "or"
}
test("asmgen correctly deals with float typecasting in augmented assignment") {
@ -215,7 +211,7 @@ class TestOptimization: FunSpec({
val src="""
main {
sub start() {
if cx16.r0 {
if cx16.r0!=0 {
uword xx ; to be removed
cx16.r0 = 0
}
@ -278,7 +274,7 @@ main {
z1 = 10
ubyte @shared z2
z2 = ~z2
ubyte @shared z3
bool @shared z3
z3 = not z3
uword @shared z4
z4 = (z4 as ubyte)
@ -294,8 +290,8 @@ main {
z1 = 10
ubyte z2
z2 = 255
ubyte z3
z3 = 1
bool z3
z3 = true
uword z4
z4 = 0
ubyte z5
@ -323,9 +319,9 @@ main {
z2decl.name shouldBe "z2"
z2init.value shouldBe NumericLiteral(DataType.UBYTE, 255.0, Position.DUMMY)
z3decl.name shouldBe "z3"
z3init.value shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
z3init.value shouldBe NumericLiteral(DataType.BOOL, 1.0, Position.DUMMY)
z4decl.name shouldBe "z4"
z4init.value shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
z4init.value shouldBe NumericLiteral(DataType.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)
@ -378,7 +374,7 @@ main {
ubyte @shared z1 = 1
ubyte @shared z2 = + 1
ubyte @shared z3 = ~ 1
ubyte @shared z4 = not 1
bool @shared z4 = not 1
byte @shared z5 = - 1
}
}
@ -400,8 +396,9 @@ main {
"""
val errors = ErrorReporterForTests()
compileText(C64Target(), optimize=false, src, writeAssembly=false, errors = errors) shouldBe null
errors.errors.size shouldBe 1
errors.errors.size shouldBe 2
errors.errors[0] shouldContain "out of range"
errors.errors[1] shouldContain "cannot assign word to byte"
}
test("out of range cast should give error") {
@ -495,13 +492,13 @@ main {
stmts.filterIsInstance<Assignment>().size shouldBe 5
val assignXX1 = stmts[1] as Assignment
assignXX1.target.identifier!!.nameInSource shouldBe listOf("xx")
assignXX1.value shouldBe NumericLiteral(DataType.UBYTE, 20.0, Position.DUMMY)
assignXX1.value shouldBe NumericLiteral(DataType.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.UBYTE, 10.0, Position.DUMMY)
xxValue.right shouldBe NumericLiteral(DataType.UWORD, 10.0, Position.DUMMY)
}
test("multi-comparison replaced by containment check") {
@ -603,7 +600,7 @@ main {
main{
sub start () {
uword @shared eRef
if eRef[3] and 10 {
if eRef[3] & 10 ==0 {
return
}
}
@ -780,11 +777,6 @@ main {
sub start() {
bool @shared a1
bool @shared a2
if a1==0 and a2==0
cx16.r0++
if a1==0 or a2==0
cx16.r0++
if not a1 or not a2
cx16.r0++
@ -794,19 +786,13 @@ main {
}"""
val result = compileText(Cx16Target(), true, src, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 8
st.size shouldBe 6
val if1c = (st[4] as IfElse).condition as PrefixExpression
val if2c = (st[5] as IfElse).condition as PrefixExpression
val if3c = (st[6] as IfElse).condition as PrefixExpression
val if4c = (st[7] as IfElse).condition as PrefixExpression
if1c.operator shouldBe "not"
if2c.operator shouldBe "not"
if3c.operator shouldBe "not"
if4c.operator shouldBe "not"
(if1c.expression as BinaryExpression).operator shouldBe "or"
(if2c.expression as BinaryExpression).operator shouldBe "and"
(if3c.expression as BinaryExpression).operator shouldBe "and"
(if4c.expression as BinaryExpression).operator shouldBe "or"
(if1c.expression as BinaryExpression).operator shouldBe "and"
(if2c.expression as BinaryExpression).operator shouldBe "or"
}
test("absorption laws") {

View File

@ -8,9 +8,9 @@ import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.types.instanceOf
import prog8.ast.IFunctionCall
import prog8.ast.expressions.*
import prog8.ast.printProgram
import prog8.ast.statements.Assignment
import prog8.ast.statements.IfElse
import prog8.ast.statements.VarDecl
import prog8.code.core.DataType
import prog8.code.core.Position
import prog8.code.target.C64Target
@ -39,29 +39,28 @@ class TestTypecasts: FunSpec({
test("not casting bool operands to logical operators") {
val text="""
%import textio
%zeropage basicsafe
main {
sub start() {
bool @shared bb2=true
bool @shared bb = bb2 and true
bool @shared bb3=false
bool @shared bb = bb2 and bb3
}
}"""
val result = compileText(C64Target(), false, text, writeAssembly = false)!!
val stmts = result.compilerAst.entrypoint.statements
stmts.size shouldBe 4
val expr = (stmts[3] as Assignment).value as BinaryExpression
stmts.size shouldBe 6
val expr = (stmts[5] as Assignment).value as BinaryExpression
expr.operator shouldBe "and"
expr.right shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
(expr.left as IdentifierReference).nameInSource shouldBe listOf("bb2") // no cast
(expr.right as IdentifierReference).nameInSource shouldBe listOf("bb3") // no cast
val result2 = compileText(C64Target(), true, text, writeAssembly = true)!!
val stmts2 = result2.compilerAst.entrypoint.statements
stmts2.size shouldBe 5
val expr2 = (stmts2[3] as Assignment).value as BinaryExpression
stmts2.size shouldBe 7
val expr2 = (stmts2[5] as Assignment).value as BinaryExpression
expr2.operator shouldBe "and"
expr2.right shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
(expr2.left as IdentifierReference).nameInSource shouldBe listOf("bb2") // no cast
(expr2.right as IdentifierReference).nameInSource shouldBe listOf("bb3") // no cast
}
test("bool expressions with functioncalls") {
@ -84,23 +83,24 @@ main {
bool @shared bvalue
bvalue = ub1 xor ub2 xor ub3 xor true
bvalue = ub1 xor ub2 xor ub3 xor ftrue(99)
bvalue = ub1 and ub2 and ftrue(99)
bvalue = ub1 xor ub2 xor ub3 xor ftrue(99)!=0
bvalue = ub1 and ub2 and ftrue(99)!=0
bvalue = ub1 xor ub2 xor ub3 xor btrue(99)
bvalue = ub1 and ub2 and btrue(99)
}
}"""
val result = compileText(C64Target(), true, text, writeAssembly = true)!!
val stmts = result.compilerAst.entrypoint.statements
printProgram(result.compilerAst)
/*
ubyte @shared ub1
ub1 = 1
ubyte @shared ub2
ub2 = 1
ubyte @shared ub3
ub3 = 1
ubyte @shared bvalue
bvalue = (((ub1 xor ub2) xor ub3) xor 1)
bool @shared ub1
ub1 = true
bool @shared ub2
ub2 = true
bool @shared ub3
ub3 = true
bool @shared bvalue
bvalue = not ((ub1 xor ub2) xor ub3)
bvalue = (((ub1 xor ub2) xor ub3) xor (ftrue(99)!=0))
bvalue = ((ub1 and ub2) and (ftrue(99)!=0))
bvalue = (((ub1 xor ub2) xor ub3) xor btrue(99))
@ -108,12 +108,12 @@ main {
return
*/
stmts.size shouldBe 13
val assignValue1 = (stmts[7] as Assignment).value as BinaryExpression
val assignValue1 = (stmts[7] as Assignment).value as PrefixExpression
val assignValue2 = (stmts[8] as Assignment).value as BinaryExpression
val assignValue3 = (stmts[9] as Assignment).value as BinaryExpression
val assignValue4 = (stmts[10] as Assignment).value as BinaryExpression
val assignValue5 = (stmts[11] as Assignment).value as BinaryExpression
assignValue1.operator shouldBe "xor"
assignValue1.operator shouldBe "not"
assignValue2.operator shouldBe "xor"
assignValue3.operator shouldBe "and"
assignValue4.operator shouldBe "xor"
@ -130,478 +130,6 @@ main {
assignValue5.right shouldBe instanceOf<IFunctionCall>()
}
test("simple logical with byte instead of bool ok with typecasting") {
val text="""
main {
ubyte ubb
sub start() {
ubb = ubb and 123
}
}"""
val result = compileText(C64Target(), true, text, writeAssembly = true)!!
val stmts = result.compilerAst.entrypoint.statements
stmts.size shouldBe 2
val assignValue = (stmts[0] as Assignment).value as BinaryExpression
assignValue.left shouldBe instanceOf<BinaryExpression>() // as a result of the cast to boolean
assignValue.operator shouldBe "and"
(assignValue.right as NumericLiteral).number shouldBe 1.0
}
test("logical with byte instead of bool") {
val text="""
%import textio
main {
sub ftrue(ubyte arg) -> ubyte {
arg++
return 128
}
sub ffalse(ubyte arg) -> ubyte {
arg++
return 0
}
sub start() {
ubyte ub1 = 2
ubyte ub2 = 4
ubyte ub3 = 8
ubyte ub4 = 0
ubyte bvalue
txt.print("const not 0: ")
txt.print_ub(not 129)
txt.nl()
txt.print("const not 1: ")
txt.print_ub(not 0)
txt.nl()
txt.print("const inv 126: ")
txt.print_ub(~ 129)
txt.nl()
txt.print("const inv 255: ")
txt.print_ub(~ 0)
txt.nl()
bvalue = 129
txt.print("bitwise inv 126: ")
bvalue = ~ bvalue
txt.print_ub(bvalue)
txt.nl()
bvalue = 0
txt.print("bitwise inv 255: ")
bvalue = ~ bvalue
txt.print_ub(bvalue)
txt.nl()
txt.print("bitwise or 14: ")
txt.print_ub(ub1 | ub2 | ub3 | ub4)
txt.nl()
txt.print("bitwise or 142: ")
txt.print_ub(ub1 | ub2 | ub3 | ub4 | 128)
txt.nl()
txt.print("bitwise and 0: ")
txt.print_ub(ub1 & ub2 & ub3 & ub4)
txt.nl()
txt.print("bitwise and 8: ")
txt.print_ub(ub3 & ub3 & 127)
txt.nl()
txt.print("bitwise xor 14: ")
txt.print_ub(ub1 ^ ub2 ^ ub3 ^ ub4)
txt.nl()
txt.print("bitwise xor 6: ")
txt.print_ub(ub1 ^ ub2 ^ ub3 ^ 8)
txt.nl()
txt.print("bitwise not 247: ")
txt.print_ub(~ub3)
txt.nl()
txt.print("bitwise not 255: ")
txt.print_ub(~ub4)
txt.nl()
txt.print("not 0: ")
bvalue = 3 * (ub4 | not (ub3 | ub3 | ub3))
txt.print_ub(bvalue)
if 3*(ub4 | not (ub1 | ub1 | ub1))
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("not 0: ")
bvalue = not ub3
txt.print_ub(bvalue)
if not ub1
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("not 1: ")
bvalue = not ub4
txt.print_ub(bvalue)
if not ub4
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
bvalue = bvalue and 128
txt.print("bvl 1: ")
txt.print_ub(bvalue)
if bvalue and 128
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 1: ")
bvalue = ub1 and ub2 and ub3
txt.print_ub(bvalue)
if ub1 and ub2 and ub3
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 1: ")
bvalue = ub1 and ub2 and ub3 and 64
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and 64
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 1: ")
bvalue = ub1 and ub2 and ub3 and ftrue(99)
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and ftrue(99)
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 0: ")
bvalue = ub1 and ub2 and ub3 and ub4
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and ub4
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("and 0: ")
bvalue = ub1 and ub2 and ub3 and ffalse(99)
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and ffalse(99)
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print(" or 1: ")
bvalue = ub1 or ub2 or ub3 or ub4
txt.print_ub(bvalue)
if ub1 or ub2 or ub3 or ub4
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print(" or 1: ")
bvalue = ub4 or ub4 or ub1
txt.print_ub(bvalue)
if ub4 or ub4 or ub1
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print(" or 1: ")
bvalue = ub1 or ub2 or ub3 or ftrue(99)
txt.print_ub(bvalue)
if ub1 or ub2 or ub3 or ftrue(99)
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("xor 1: ")
bvalue = ub1 xor ub2 xor ub3 xor ub4
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ub4
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("xor 1: ")
bvalue = ub1 xor ub2 xor ub3 xor ffalse(99)
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ffalse(99)
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("xor 0: ")
bvalue = ub1 xor ub2 xor ub3 xor ub4 xor true
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ub4 xor true
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("xor 0: ")
bvalue = ub1 xor ub2 xor ub3 xor ftrue(99)
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ftrue(99)
txt.print(" / fail")
else
txt.print(" / ok")
}
}
"""
val result = compileText(C64Target(), true, text, writeAssembly = true)!!
val stmts = result.compilerAst.entrypoint.statements
stmts.size shouldBeGreaterThan 10
}
test("logical with bools") {
val text="""
%import textio
main {
sub ftrue(ubyte arg) -> ubyte {
arg++
return 128
}
sub ffalse(ubyte arg) -> ubyte {
arg++
return 0
}
sub start() {
bool ub1 = 2
bool ub2 = 4
bool ub3 = 8
bool ub4 = 0
bool bvalue
txt.print("const not 0: ")
txt.print_ub(not 129)
txt.nl()
txt.print("const not 1: ")
txt.print_ub(not 0)
txt.nl()
txt.print("const inv 126: ")
txt.print_ub(~ 129)
txt.nl()
txt.print("const inv 255: ")
txt.print_ub(~ 0)
txt.nl()
; bvalue = 129
; txt.print("bitwise inv 126: ")
; bvalue = ~ bvalue
; txt.print_ub(bvalue)
; txt.nl()
; bvalue = 0
; txt.print("bitwise inv 255: ")
; bvalue = ~ bvalue
; txt.print_ub(bvalue)
; txt.nl()
txt.print("bitwise or 14: ")
txt.print_ub(ub1 | ub2 | ub3 | ub4)
txt.nl()
txt.print("bitwise or 142: ")
txt.print_ub(ub1 | ub2 | ub3 | ub4 | 128)
txt.nl()
txt.print("bitwise and 0: ")
txt.print_ub(ub1 & ub2 & ub3 & ub4)
txt.nl()
txt.print("bitwise and 8: ")
txt.print_ub(ub3 & ub3 & 127)
txt.nl()
txt.print("bitwise xor 14: ")
txt.print_ub(ub1 ^ ub2 ^ ub3 ^ ub4)
txt.nl()
txt.print("bitwise xor 6: ")
txt.print_ub(ub1 ^ ub2 ^ ub3 ^ 8)
txt.nl()
;txt.print("bitwise not 247: ")
;txt.print_ub(~ub3)
;txt.nl()
;txt.print("bitwise not 255: ")
;txt.print_ub(~ub4)
;txt.nl()
txt.print("not 0: ")
bvalue = 3 * (ub4 | not (ub3 | ub3 | ub3))
txt.print_ub(bvalue)
if 3*(ub4 | not (ub1 | ub1 | ub1))
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("not 0: ")
bvalue = not ub3
txt.print_ub(bvalue)
if not ub1
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("not 1: ")
bvalue = not ub4
txt.print_ub(bvalue)
if not ub4
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
bvalue = bvalue and 128
txt.print("bvl 1: ")
txt.print_ub(bvalue)
if bvalue and 128
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 1: ")
bvalue = ub1 and ub2 and ub3
txt.print_ub(bvalue)
if ub1 and ub2 and ub3
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 1: ")
bvalue = ub1 and ub2 and ub3 and 64
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and 64
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 1: ")
bvalue = ub1 and ub2 and ub3 and ftrue(99)
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and ftrue(99)
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 0: ")
bvalue = ub1 and ub2 and ub3 and ub4
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and ub4
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("and 0: ")
bvalue = ub1 and ub2 and ub3 and ffalse(99)
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and ffalse(99)
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print(" or 1: ")
bvalue = ub1 or ub2 or ub3 or ub4
txt.print_ub(bvalue)
if ub1 or ub2 or ub3 or ub4
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print(" or 1: ")
bvalue = ub4 or ub4 or ub1
txt.print_ub(bvalue)
if ub4 or ub4 or ub1
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print(" or 1: ")
bvalue = ub1 or ub2 or ub3 or ftrue(99)
txt.print_ub(bvalue)
if ub1 or ub2 or ub3 or ftrue(99)
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("xor 1: ")
bvalue = ub1 xor ub2 xor ub3 xor ub4
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ub4
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("xor 1: ")
bvalue = ub1 xor ub2 xor ub3 xor ffalse(99)
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ffalse(99)
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("xor 0: ")
bvalue = ub1 xor ub2 xor ub3 xor ub4 xor true
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ub4 xor true
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("xor 0: ")
bvalue = ub1 xor ub2 xor ub3 xor ftrue(99)
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ftrue(99)
txt.print(" / fail")
else
txt.print(" / ok")
}
}
"""
val result = compileText(C64Target(), true, text, writeAssembly = true)!!
val stmts = result.compilerAst.entrypoint.statements
stmts.size shouldBeGreaterThan 10
}
test("bool arrays") {
val text="""
main {
sub start() {
bool[] barray = [true, false, 1, 0, 222]
bool bb
ubyte xx
for bb in barray {
if bb
xx++
}
}
}"""
val result = compileText(C64Target(), false, text, writeAssembly = false)!!
val stmts = result.compilerAst.entrypoint.statements
stmts.size shouldBe 6
val arraydecl = stmts[0] as VarDecl
arraydecl.datatype shouldBe DataType.ARRAY_BOOL
val values = (arraydecl.value as ArrayLiteral).value
values.size shouldBe 5
values[0] shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
values[1] shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
values[2] shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
values[3] shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
values[4] shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
}
test("correct handling of bool parameters") {
val text="""
main {
@ -613,10 +141,9 @@ main {
sub start() {
bool boolvalue1 = true
bool boolvalue2 = false
uword xx
boolvalue1 = thing(true, false)
boolvalue2 = thing(xx, xx)
boolvalue2 = thing(false, true)
if boolvalue1 and boolvalue2
boolvalue1=false
@ -624,14 +151,14 @@ main {
}"""
val result = compileText(C64Target(), false, text, writeAssembly = false)!!
val stmts = result.compilerAst.entrypoint.statements
stmts.size shouldBe 9
val fcall1 = ((stmts[6] as Assignment).value as IFunctionCall)
fcall1.args[0] shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
fcall1.args[1] shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
val fcall2 = ((stmts[7] as Assignment).value as IFunctionCall)
(fcall2.args[0] as TypecastExpression).type shouldBe DataType.BOOL
(fcall2.args[1] as TypecastExpression).type shouldBe DataType.BOOL
val ifCond = (stmts[8] as IfElse).condition as BinaryExpression
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)
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)
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")
(ifCond.right as IdentifierReference).nameInSource shouldBe listOf("boolvalue2")
@ -642,17 +169,17 @@ main {
main {
sub start() {
uword camg
ubyte @shared interlaced
bool @shared interlaced
interlaced = (camg & ${'$'}0004) != 0
interlaced++
cx16.r0L++
interlaced = (${'$'}0004 & camg) != 0
interlaced++
cx16.r0L++
uword @shared ww
ww = (camg & ${'$'}0004)
ww++
ww = (${'$'}0004 & camg)
ubyte @shared wordNr2 = (interlaced >= ${'$'}33) + (interlaced >= ${'$'}66) + (interlaced >= ${'$'}99) + (interlaced >= ${'$'}CC)
ubyte @shared value
bool @shared collected = (value >= ${'$'}33) or (value >= ${'$'}66) or (value >= ${'$'}99) or (value >= ${'$'}CC)
}
}"""
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
@ -849,13 +376,13 @@ main {
if bb < 0 {
bb ++
}
if bb & 1 {
if bb & 1 !=0 {
bb++
}
if bb & 128 {
if bb & 128 !=0 {
bb++
}
if bb & 255 {
if bb & 255 !=0 {
bb++
}
@ -865,13 +392,13 @@ main {
if ww < 0 {
ww ++
}
if ww & 1 {
if ww & 1 !=0 {
ww++
}
if ww & 32768 {
if ww & 32768 != 0 {
ww++
}
if ww & 65535 {
if ww & 65535 != 0 {
ww++
}
}
@ -889,17 +416,17 @@ main {
byte bb
word ww
ubyte iteration_in_progress
bool iteration_in_progress
uword num_bytes
if not iteration_in_progress or not num_bytes {
if not iteration_in_progress or num_bytes==0 {
num_bytes++
}
if bb as ubyte {
if bb as ubyte !=0 {
bb++
}
if ww as uword {
if ww as uword !=0 {
ww++
}
}
@ -1071,8 +598,8 @@ main {
thing(large)
thing(320*240/8/8)
thing(320*HEIGHT/8/8)
thing(320*HEIGHT) ; overflow
large = 12345678 ; overflow
thing(320*HEIGHT) ; overflow
large = 12345678 ; overflow
}
sub thing(uword value) {
@ -1081,31 +608,169 @@ main {
}"""
val errors=ErrorReporterForTests()
compileText(C64Target(), false, src, writeAssembly = false, errors=errors) shouldBe null
errors.errors.size shouldBe 4
errors.errors.size shouldBe 3
errors.errors[0] shouldContain ":9:"
errors.errors[0] shouldContain "no cast"
errors.errors[1] shouldContain "overflow"
errors.errors[2] shouldContain "out of range"
errors.errors[3] shouldContain "overflow"
errors.errors[1] shouldContain ":10:"
errors.errors[1] shouldContain "out of range"
errors.errors[2] shouldContain ":10:"
errors.errors[2] shouldContain "doesn't match"
}
test("type fitting of const assignment values") {
test("various bool typecasts and type mismatches") {
val src="""
%option enable_floats
main {
sub start() {
float @shared fl
ubyte @shared flags
byte @shared flagss
uword @shared flagsw
word @shared flagssw
bool @shared bflags = 123
cx16.r0++
bflags = 123
cx16.r0++
bflags = 123 as bool
flags = bflags
flagss = bflags
flagsw = bflags
flagssw = bflags
fl = bflags
bflags = flags
bflags = flagss
bflags = flagsw
bflags = flagssw
bflags = fl
flags = bflags as ubyte
flagss = bflags as byte
flagsw = bflags as uword
flagssw = bflags as word
fl = bflags as float
bflags = flags as bool
bflags = flagss as bool
bflags = flagsw as bool
bflags = flagssw as bool
bflags = fl as bool
}
}"""
val errors=ErrorReporterForTests()
compileText(VMTarget(), false, src, writeAssembly = false, errors=errors) shouldBe null
errors.errors.size shouldBe 12
errors.errors.all { "type of value" in it } shouldBe true
errors.errors.all { "doesn't match" in it } shouldBe true
}
test("bool to byte cast in expression is not allowed") {
val text="""
main {
sub start() {
ubyte[3] values
func1(22 in values)
func2(22 in values)
ubyte @shared qq = 22 in values
byte @shared ww = 22 in values
}
sub func1(ubyte arg) {
arg++
}
sub func2(byte arg) {
arg++
}
}"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, text, writeAssembly = true, errors = errors) shouldBe null
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")
}
test("bool function parameters correct typing") {
val src = """
main {
sub start() {
bool bb = func(true)
void func(true)
; all these should fail:
void func(0)
void func(1)
void func(42)
void func(65535)
void func(655.444)
cx16.r0L = func(true)
}
sub func(bool draw) -> bool {
cx16.r0++
return true
}
}"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, src, writeAssembly = false, errors = errors) shouldBe null
errors.errors.size shouldBe 6
errors.errors[0] shouldContain("type mismatch")
errors.errors[1] shouldContain("type mismatch")
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")
}
test("no implicit bool-to-int cast") {
val src="""
main {
sub start() {
&ubyte mapped = 8000
mapped = 6144 >> 9
ubyte @shared ubb = 6144 >> 9
bool @shared bb = 6144
func(true)
func(true as ubyte)
cx16.r0L = true
cx16.r0L = true as ubyte
}
sub func(bool b) {
cx16.r0++
}
}"""
compileText(C64Target(), true, src, writeAssembly = false) shouldNotBe null
val errors = ErrorReporterForTests()
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")
}
val src2="""
test("no implicit int-to-bool cast") {
val src="""
main {
sub start() {
ubyte @shared ubb = 6144 >> 2 ; should still be type error
func1(true)
func2(true)
func1(true as ubyte)
func2(true as uword)
bool @shared bb1 = 1
bool @shared bb2 = 12345
bool @shared bb3 = 1 as bool
bool @shared bb4 = 12345 as bool
}
sub func1(ubyte ub) {
cx16.r0++
}
sub func2(uword uw) {
cx16.r0++
}
}"""
compileText(C64Target(), true, src2, writeAssembly = false) shouldBe null
val errors = ErrorReporterForTests()
compileText(C64Target(), false, src, writeAssembly = false, errors = errors) shouldBe null
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")
}
})

View File

@ -85,14 +85,15 @@ class TestAstChecks: FunSpec({
sub start() {
ubyte[] array = [1,2,3,4]
str s1 = "test"
bool bb1, bb2
ubyte ff = 1
txt.print(&s1+ff)
txt.print(&array+ff)
txt.print_uwhex(&s1+ff, true)
txt.print_uwhex(&array+ff, true)
; also good:
ff = (s1 == "derp")
ff = (s1 != "derp")
bb1 = (s1 == "derp")
bb2 = (s1 != "derp")
}
}
"""

View File

@ -65,11 +65,11 @@ class TestConst: FunSpec({
val subR5value = (stmts[7] as Assignment).value
val binexpr5 = subR5value as BinaryExpression
binexpr5.operator shouldBe "-"
binexpr5.right shouldBe NumericLiteral(DataType.UWORD, 1899.0, Position.DUMMY)
binexpr5.right shouldBe NumericLiteral(DataType.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.UWORD, 99.0, Position.DUMMY)
binexpr7.right shouldBe NumericLiteral(DataType.WORD, 99.0, Position.DUMMY)
}
test("const folding multiple scenarios * and / (floats)") {
@ -158,24 +158,24 @@ class TestConst: FunSpec({
val mulR0Value = (stmts[2] as Assignment).value
val binexpr0 = mulR0Value as BinaryExpression
binexpr0.operator shouldBe "*"
binexpr0.right shouldBe NumericLiteral(DataType.UWORD, 180.0, Position.DUMMY)
binexpr0.right shouldBe NumericLiteral(DataType.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.UWORD, 180.0, Position.DUMMY)
binexpr1.right shouldBe NumericLiteral(DataType.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.UWORD, 90.0, Position.DUMMY)
binexpr2.right shouldBe NumericLiteral(DataType.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.UWORD, 10.0, Position.DUMMY)
binexpr3.right shouldBe NumericLiteral(DataType.WORD, 10.0, Position.DUMMY)
binexpr3.left shouldBe instanceOf<BinaryExpression>()
val mulR4Value = (stmts[6] as Assignment).value
val binexpr4 = mulR4Value as BinaryExpression
binexpr4.operator shouldBe "/"
binexpr4.right shouldBe NumericLiteral(DataType.UWORD, 5.0, Position.DUMMY)
binexpr4.right shouldBe NumericLiteral(DataType.WORD, 5.0, Position.DUMMY)
binexpr4.left shouldBe instanceOf<BinaryExpression>()
}
@ -241,16 +241,16 @@ main {
main {
sub start() {
float fl = 1.2 ; no other assignments
cx16.r0L = string.isdigit(math.diff(119, floats.floor(floats.deg(fl)) as ubyte))
cx16.r1L = string.isletter(math.diff(119, floats.floor(floats.deg(1.2)) as ubyte))
bool @shared result1 = string.isdigit(math.diff(119, floats.floor(floats.deg(fl)) as ubyte))
bool @shared result2 = string.isletter(math.diff(119, floats.floor(floats.deg(1.2)) as ubyte))
}
}"""
val result = compileText(Cx16Target(), true, src, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 3
st.size shouldBe 5
(st[0] as VarDecl).type shouldBe VarDeclType.CONST
val assignv1 = (st[1] as Assignment).value
val assignv2 = (st[2] as Assignment).value
val assignv1 = (st[2] as Assignment).value
val assignv2 = (st[4] as Assignment).value
(assignv1 as NumericLiteral).number shouldBe 1.0
(assignv2 as NumericLiteral).number shouldBe 0.0
}

View File

@ -4,6 +4,7 @@ import io.kotest.assertions.fail
import io.kotest.core.spec.style.FunSpec
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.DataType
import prog8.code.core.Position
@ -20,10 +21,11 @@ class TestIntermediateAst: FunSpec({
%import graphics
main {
sub start() {
ubyte cc
bool cc
ubyte dd
ubyte[] array = [1,2,3]
cc = 11 in array
cc = sqrt(lsb(cc))
dd = sqrt(lsb(dd))
}
}
"""
@ -34,7 +36,7 @@ class TestIntermediateAst: FunSpec({
ast.name shouldBe result.compilerAst.name
ast.allBlocks().any() shouldBe true
val entry = ast.entrypoint() ?: fail("no main.start() found")
entry.children.size shouldBe 5
entry.children.size shouldBe 7
entry.name shouldBe "start"
entry.scopedName shouldBe "main.start"
val blocks = ast.allBlocks().toList()
@ -42,23 +44,30 @@ class TestIntermediateAst: FunSpec({
blocks[0].name shouldBe "main"
blocks[0].scopedName shouldBe "main"
val ccInit = entry.children[2] as PtAssignment
val ccInit = entry.children[3] as PtAssignment
ccInit.target.identifier?.name shouldBe "main.start.cc"
(ccInit.value as PtNumber).number shouldBe 0.0
(ccInit.value as PtBool).value shouldBe false
val ddInit = entry.children[4] as PtAssignment
ddInit.target.identifier?.name shouldBe "main.start.dd"
(ddInit.value as PtNumber).number shouldBe 0.0
val ccdecl = entry.children[0] as PtVariable
ccdecl.name shouldBe "cc"
ccdecl.scopedName shouldBe "main.start.cc"
ccdecl.type shouldBe DataType.UBYTE
val arraydecl = entry.children[1] as IPtVariable
ccdecl.type shouldBe DataType.BOOL
val dddecl = entry.children[1] as PtVariable
dddecl.name shouldBe "dd"
dddecl.scopedName shouldBe "main.start.dd"
dddecl.type shouldBe DataType.UBYTE
val arraydecl = entry.children[2] as IPtVariable
arraydecl.name shouldBe "array"
arraydecl.type shouldBe DataType.ARRAY_UB
val containment = (entry.children[3] as PtAssignment).value as PtContainmentCheck
(containment.element as PtNumber).number shouldBe 11.0
val fcall = (entry.children[4] as PtAssignment).value as PtFunctionCall
fcall.void shouldBe false
fcall.type shouldBe DataType.UBYTE
val ccAssignV = (entry.children[5] as PtAssignment).value
ccAssignV shouldBe instanceOf<PtContainmentCheck>()
val ddAssignV = (entry.children[6] as PtAssignment).value
ddAssignV shouldBe instanceOf<PtFunctionCall>()
}
test("isSame on binaryExpressions") {

View File

@ -914,7 +914,7 @@ class TestProg8Parser: FunSpec( {
val text="""
main {
sub start() {
ubyte @shared cc
bool @shared cc
ubyte[] array = [1,2,3]
cc = 99 in 12345
cc = 9999 in array

View File

@ -92,16 +92,17 @@ main {
sub start() {
str name = "name"
uword nameptr = &name
bool result
cx16.r0L= name=="foo"
cx16.r1L= name!="foo"
cx16.r2L= name<"foo"
cx16.r3L= name>"foo"
result = name=="foo"
result = name!="foo"
result = name<"foo"
result = name>"foo"
cx16.r0L= nameptr=="foo"
cx16.r1L= nameptr!="foo"
cx16.r2L= nameptr<"foo"
cx16.r3L= nameptr>"foo"
result = nameptr=="foo"
result = nameptr!="foo"
result = nameptr<"foo"
result = nameptr>"foo"
void compare(name, "foo")
void compare(name, "name")
@ -117,10 +118,10 @@ main {
}"""
val result = compileText(C64Target(), optimize=false, src, writeAssembly=true)!!
val stmts = result.compilerAst.entrypoint.statements
stmts.size shouldBe 16
stmts.size shouldBe 17
val result2 = compileText(VMTarget(), optimize=false, src, writeAssembly=true)!!
val stmts2 = result2.compilerAst.entrypoint.statements
stmts2.size shouldBe 16
stmts2.size shouldBe 17
}
test("string concatenation and repeats") {
@ -202,8 +203,8 @@ main {
uword[128] YY
ubyte[] ARRAY = [1, 5, 2]
repeat {
ubyte pixel_side1 = pget(2, YY[2]+1) in ARRAY
ubyte pixel_side2 = pget(2, 2) in ARRAY
bool pixel_side1 = pget(2, YY[2]+1) in ARRAY
bool pixel_side2 = pget(2, 2) in ARRAY
ubyte[] array2 = [1,2,3]
}
}
@ -218,16 +219,17 @@ main {
main {
sub start() {
ubyte[] array=[1,2,3]
cx16.r0L = not (3 in array)
cx16.r1L = 3 not in array
bool result
result = not (3 in array)
result = 3 not in array
}
}
"""
val result = compileText(C64Target(), optimize=false, src, writeAssembly=false)!!
val stmts = result.compilerAst.entrypoint.statements
stmts.size shouldBe 3
val value1 = (stmts[1] as Assignment).value as PrefixExpression
val value2 = (stmts[2] as Assignment).value as PrefixExpression
stmts.size shouldBe 4
val value1 = (stmts[2] as Assignment).value as PrefixExpression
val value2 = (stmts[3] as Assignment).value as PrefixExpression
value1.operator shouldBe "not"
value2.operator shouldBe "not"
value1.expression shouldBe instanceOf<ContainmentCheck>()
@ -281,23 +283,23 @@ main
{
sub start()
{
ubyte variable=55
ubyte @shared variable=55
when variable
{
33 -> cx16.r0++
else -> cx16.r1++
}
if variable {
if variable!=0 {
cx16.r0++
} else {
cx16.r1++
}
if variable { cx16.r0++ }
if variable!=0 { cx16.r0++ }
else { cx16.r1++ }
if variable
if variable!=0
{
cx16.r0++
}
@ -348,7 +350,10 @@ main
}
}"""
compileText(VMTarget(), optimize=false, src, writeAssembly=false) shouldNotBe null
val errors = ErrorReporterForTests()
compileText(VMTarget(), optimize=false, src, writeAssembly=false, errors = errors) shouldBe null
errors.errors.size shouldBe 1
errors.errors[0] shouldContain "use if"
}
test("char as str param is error") {
@ -447,26 +452,27 @@ main {
sub start() {
ubyte @shared n=20
ubyte @shared x=10
bool @shared result1, result2
if n < x {
; nothing here, conditional gets inverted
} else {
cx16.r0++
}
cx16.r0L = n<x == 0
cx16.r1L = not n<x
result1 = n<x == false
result2 = not n<x
}
}"""
val result=compileText(VMTarget(), optimize=true, src, writeAssembly=false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 7
st.size shouldBe 11
val ifCond = (st[4] as IfElse).condition as BinaryExpression
val ifCond = (st[8] as IfElse).condition as BinaryExpression
ifCond.operator shouldBe ">="
(ifCond.left as IdentifierReference).nameInSource shouldBe listOf("n")
(ifCond.right as IdentifierReference).nameInSource shouldBe listOf("x")
val assign1 = (st[5] as Assignment).value as BinaryExpression
val assign2 = (st[6] as Assignment).value as BinaryExpression
val assign1 = (st[9] as Assignment).value as BinaryExpression
val assign2 = (st[10] as Assignment).value as BinaryExpression
assign1.operator shouldBe ">="
(assign1.left as IdentifierReference).nameInSource shouldBe listOf("n")
(assign1.right as IdentifierReference).nameInSource shouldBe listOf("x")

View File

@ -1,9 +1,12 @@
package prog8tests.codegeneration
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import prog8.code.target.C64Target
import prog8.code.target.VMTarget
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
@ -84,19 +87,58 @@ class TestVariables: FunSpec({
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
test("initialization of boolean array with array") {
val text = """
main {
sub start() {
bool[3] sieve0 = [true, false, true]
}
}
"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
test("initialization of boolean array with wrong array type should fail") {
val text = """
main {
sub start() {
bool[] sieve0 = [true, false, 1]
bool[] sieve1 = [true, false, 42]
}
}
"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, text, writeAssembly = true, errors=errors) shouldBe null
errors.errors.size shouldBe 2
errors.errors[0] shouldContain "initialisation value has incompatible type"
errors.errors[1] shouldContain "initialisation value has incompatible type"
}
test("initialization of boolean array with single value") {
val text = """
main {
sub start() {
bool[10] sieve0 = false
bool[10] sieve1 = true
bool[10] sieve2 = 42
sieve0[0] = true
sieve1[0] = true
sieve2[0] = true
}
}
"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
test("initialization of boolean array with single value of wrong type fails") {
val text = """
main {
sub start() {
bool[10] sieve2 = 42
}
}
"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, text, writeAssembly = true, errors=errors) shouldBe null
errors.errors.size shouldBe 1
errors.errors[0] shouldContain "initializer value is not a boolean"
}
})

View File

@ -19,21 +19,6 @@ import prog8tests.helpers.compileText
import kotlin.io.path.readText
class TestVariousCodeGen: FunSpec({
test("bool to byte cast in expression is correct") {
val text="""
main {
sub start() {
ubyte[3] values
func(22 in values)
ubyte @shared qq = 22 in values
}
sub func(ubyte arg) {
arg++
}
}"""
compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null
}
test("nested scoping") {
val text="""
main {
@ -211,7 +196,7 @@ main {
ubyte[] otherarray = [1,2,3]
uword[] words = [1111,2222,"three",&localstr,&otherarray]
uword @shared zz = &words
ubyte result = 2222 in words
bool @shared result = 2222 in words
zz = words[2]
zz++
zz = words[3]

View File

@ -22,7 +22,7 @@ internal object DummyFunctions : IBuiltinFunctions {
internal object DummyMemsizer : IMemSizer {
override fun memorySize(dt: DataType) = when(dt) {
in ByteDatatypes -> 1
in ByteDatatypesWithBoolean -> 1
DataType.FLOAT -> 5
else -> 2
}

View File

@ -32,6 +32,7 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
}
override fun noErrors(): Boolean = errors.isEmpty()
override fun noErrorForLine(position: Position) = !errors.any { ":${position.line}:" in it }
override fun report() {
infos.forEach { println("UNITTEST COMPILATION REPORT: INFO: $it") }

View File

@ -25,10 +25,10 @@ main {
sub start() {
uword[] words = [1111,2222,0,4444,3333]
ubyte result = all(words)
result++
bool result = all(words)
cx16.r0++
result = any(words)
result++
cx16.r0++
sort(words)
reverse(words)
}
@ -47,7 +47,7 @@ main {
ubyte[] otherarray = [1,2,3]
uword[] words = [1111,2222,"three",&localstr,&otherarray]
uword @shared zz = &words
ubyte result = 2222 in words
bool result = 2222 in words
zz = words[2]
zz++
zz = words[3]
@ -93,7 +93,7 @@ mylabel0:
goto mylabel0
}
while cx16.r0 {
while cx16.r0==0 {
mylabel1:
goto mylabel1
}
@ -101,7 +101,7 @@ mylabel1:
do {
mylabel2:
goto mylabel2
} until cx16.r0
} until cx16.r0==1
repeat cx16.r0 {
mylabel3:
@ -319,7 +319,6 @@ main {
goto ending
if_cs
goto ending
if cx16.r0 goto ending
if cx16.r0==0 goto ending
if cx16.r0!=0 goto ending
if cx16.r0s>0 goto ending
@ -328,31 +327,15 @@ main {
}
}"""
val result = compileText(VMTarget(), true, src, writeAssembly = true)!!
result.compilerAst.entrypoint.statements.size shouldBe 9
result.compilerAst.entrypoint.statements.size shouldBe 8
val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
val irProgram = IRFileReader().read(virtfile)
val start = irProgram.blocks[0].children[0] as IRSubroutine
val instructions = start.chunks.flatMap { c->c.instructions }
instructions.size shouldBe 13
instructions.size shouldBe 11
instructions.last().opcode shouldBe Opcode.RETURN
}
test("compile virtual: various expressions") {
val text="""
main {
sub start() {
ubyte[3] values = [1,2,3]
func(33 + (22 in values)) ; bool cast to byte
cx16.r0L = 33 + (22 in values) ; bool cast to byte
func(values[cx16.r0L] + (22 in values)) ; containment in complex expression
}
sub func(ubyte arg) {
arg++
}
}"""
compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null
}
test("repeat counts (const)") {
val src="""
main {