mirror of
https://github.com/irmen/prog8.git
synced 2025-01-10 20:30:23 +00:00
updated unit tests and some basic changes for them
This commit is contained in:
parent
1ca3f64bf0
commit
f40b7b62bb
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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") }
|
||||
|
@ -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") }
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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") {
|
||||
|
@ -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")
|
||||
}
|
||||
})
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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") {
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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"
|
||||
}
|
||||
})
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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") }
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user