mirror of
https://github.com/irmen/prog8.git
synced 2024-09-28 17:54:58 +00:00
+ expose #55: float[] initializer as range where no array size is stated
This commit is contained in:
parent
ac37319d20
commit
34ba07ee3b
@ -11,6 +11,8 @@ import prog8.ast.base.DataType
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.expressions.NumericLiteralValue
|
||||
import prog8.ast.expressions.RangeExpr
|
||||
import prog8.ast.statements.ForLoop
|
||||
import prog8.compiler.target.Cx16Target
|
||||
|
||||
|
||||
@ -30,8 +32,14 @@ class TestCompilerOnCharLit {
|
||||
@Test
|
||||
fun testCharLitAsRomsubArg() {
|
||||
val platform = Cx16Target
|
||||
val result = compileFile(platform, optimize = false, fixturesDir, "charLitAsRomsubArg.p8")
|
||||
.assertSuccess()
|
||||
val result = compileText(platform, false, """
|
||||
main {
|
||||
romsub ${"$"}FFD2 = chrout(ubyte ch @ A)
|
||||
sub start() {
|
||||
chrout('\n')
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
@ -47,8 +55,15 @@ class TestCompilerOnCharLit {
|
||||
@Test
|
||||
fun testCharVarAsRomsubArg() {
|
||||
val platform = Cx16Target
|
||||
val result = compileFile(platform, optimize = false, fixturesDir, "charVarAsRomsubArg.p8")
|
||||
.assertSuccess()
|
||||
val result = compileText(platform, false, """
|
||||
main {
|
||||
romsub ${"$"}FFD2 = chrout(ubyte ch @ A)
|
||||
sub start() {
|
||||
ubyte ch = '\n'
|
||||
chrout(ch)
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
@ -75,8 +90,15 @@ class TestCompilerOnCharLit {
|
||||
@Test
|
||||
fun testCharConstAsRomsubArg() {
|
||||
val platform = Cx16Target
|
||||
val result = compileFile(platform, optimize = false, fixturesDir,"charConstAsRomsubArg.p8")
|
||||
.assertSuccess()
|
||||
val result = compileText(platform, false, """
|
||||
main {
|
||||
romsub ${"$"}FFD2 = chrout(ubyte ch @ A)
|
||||
sub start() {
|
||||
const ubyte ch = '\n'
|
||||
chrout(ch)
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
@ -99,6 +121,7 @@ class TestCompilerOnCharLit {
|
||||
}
|
||||
else -> assertIs<IdentifierReference>(funCall.args[0]) // make test fail
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
267
compiler/test/TestCompilerOnRanges.kt
Normal file
267
compiler/test/TestCompilerOnRanges.kt
Normal file
@ -0,0 +1,267 @@
|
||||
package prog8tests
|
||||
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestFactory
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.DynamicTest.dynamicTest
|
||||
import kotlin.test.*
|
||||
import prog8tests.helpers.*
|
||||
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.ForLoop
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.compiler.target.C64Target
|
||||
import prog8.compiler.target.Cx16Target
|
||||
import prog8.optimizer.ConstantIdentifierReplacer
|
||||
|
||||
|
||||
/**
|
||||
* ATTENTION: this is just kludge!
|
||||
* They are not really unit tests, but rather tests of the whole process,
|
||||
* from source file loading all the way through to running 64tass.
|
||||
*/
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class TestCompilerOnRanges {
|
||||
|
||||
@BeforeAll
|
||||
fun setUp() {
|
||||
sanityCheckDirectories("compiler")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUByteArrayInitializerWithRange_char_to_char() {
|
||||
val platform = Cx16Target
|
||||
val result = compileText(platform, true, """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte[] cs = @'a' to 'z' ; values are computed at compile time
|
||||
cs[0] = 23 ; keep optimizer from removing it
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val decl = startSub
|
||||
.statements.filterIsInstance<VarDecl>()[0]
|
||||
val rhsValues = (decl.value as ArrayLiteralValue)
|
||||
.value // Array<Expression>
|
||||
.map { (it as NumericLiteralValue).number.toInt() }
|
||||
val expectedStart = platform.encodeString("a", true)[0].toInt()
|
||||
val expectedEnd = platform.encodeString("z", false)[0].toInt()
|
||||
val expectedStr = "$expectedStart .. $expectedEnd"
|
||||
|
||||
val actualStr = "${rhsValues.first()} .. ${rhsValues.last()}"
|
||||
assertEquals(expectedStr, actualStr,".first .. .last")
|
||||
assertEquals(expectedEnd - expectedStart + 1, rhsValues.last() - rhsValues.first() + 1, "rangeExpr.size()")
|
||||
}
|
||||
|
||||
@Test
|
||||
// @Disabled("bug in ConstantIdentifierReplacer.before(VarDecl)@decl.datatype==ARRAY_F")
|
||||
fun testFloatArrayInitializerWithRange_char_to_char() {
|
||||
val platform = C64Target
|
||||
val result = compileText(platform, optimize = false, """
|
||||
%option enable_floats
|
||||
main {
|
||||
sub start() {
|
||||
float[] cs = @'a' to 'z' ; values are computed at compile time
|
||||
cs[0] = 23 ; keep optimizer from removing it
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val decl = startSub
|
||||
.statements.filterIsInstance<VarDecl>()[0]
|
||||
val rhsValues = (decl.value as ArrayLiteralValue)
|
||||
.value // Array<Expression>
|
||||
.map { (it as NumericLiteralValue).number.toInt() }
|
||||
val expectedStart = platform.encodeString("a", true)[0].toInt()
|
||||
val expectedEnd = platform.encodeString("z", false)[0].toInt()
|
||||
val expectedStr = "$expectedStart .. $expectedEnd"
|
||||
|
||||
val actualStr = "${rhsValues.first()} .. ${rhsValues.last()}"
|
||||
assertEquals(expectedStr, actualStr,".first .. .last")
|
||||
assertEquals(expectedEnd - expectedStart + 1, rhsValues.size, "rangeExpr.size()")
|
||||
}
|
||||
|
||||
inline fun Subroutine.decl(varName: String): VarDecl {
|
||||
return statements.filterIsInstance<VarDecl>()
|
||||
.first { it.name == varName }
|
||||
}
|
||||
inline fun <reified T : Expression> VarDecl.rhs() : T {
|
||||
return value as T
|
||||
}
|
||||
inline fun <reified T : Expression> ArrayLiteralValue.elements() : List<T> {
|
||||
return value.map { it as T }
|
||||
}
|
||||
|
||||
fun <N : Number> assertEndpoints(expFirst: N, expLast: N, actual: Iterable<N>, msg: String = ".first .. .last") {
|
||||
val expectedStr = "$expFirst .. $expLast"
|
||||
val actualStr = "${actual.first()} .. ${actual.last()}"
|
||||
assertEquals(expectedStr, actualStr,".first .. .last")
|
||||
}
|
||||
|
||||
|
||||
@TestFactory
|
||||
fun floatArrayInitializerWithRange() = mapCombinations(
|
||||
dim1 = listOf("", "42", "41"), // sizeInDecl
|
||||
dim2 = listOf("%option enable_floats", ""), // optEnableFloats
|
||||
dim3 = listOf(Cx16Target, C64Target), // platform
|
||||
dim4 = listOf(false, true), // optimize
|
||||
combine4 = { sizeInDecl, optEnableFloats, platform, optimize ->
|
||||
val displayName =
|
||||
when (sizeInDecl) {
|
||||
"" -> "no"
|
||||
"42" -> "correct"
|
||||
else -> "wrong"
|
||||
} + " array size given" +
|
||||
", " + (if (optEnableFloats == "") "without" else "with") + " %option enable_floats" +
|
||||
", ${platform.name}, optimize: $optimize"
|
||||
dynamicTest(displayName) {
|
||||
val result = compileText(platform, optimize, """
|
||||
$optEnableFloats
|
||||
main {
|
||||
sub start() {
|
||||
float[$sizeInDecl] cs = 1 to 42 ; values are computed at compile time
|
||||
cs[0] = 23 ; keep optimizer from removing it
|
||||
}
|
||||
}
|
||||
""")
|
||||
if ((sizeInDecl == "42") && (optEnableFloats != "")){
|
||||
result.assertSuccess()
|
||||
} else {
|
||||
result.assertFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testForLoopWithRange_char_to_char() {
|
||||
val platform = Cx16Target
|
||||
val result = compileText(platform, true, """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte i
|
||||
for i in @'a' to 'f' {
|
||||
i += i ; keep optimizer from removing it
|
||||
}
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val iterable = startSub
|
||||
.statements.filterIsInstance<ForLoop>()
|
||||
.map { it.iterable }[0]
|
||||
val rangeExpr = iterable as RangeExpr
|
||||
|
||||
val expectedStart = platform.encodeString("a", true)[0].toInt()
|
||||
val expectedEnd = platform.encodeString("f", false)[0].toInt()
|
||||
val expectedStr = "$expectedStart .. $expectedEnd"
|
||||
|
||||
val intProgression = rangeExpr.toConstantIntegerRange()
|
||||
val actualStr = "${intProgression?.first} .. ${intProgression?.last}"
|
||||
assertEquals(expectedStr, actualStr,".first .. .last")
|
||||
assertEquals(expectedEnd - expectedStart + 1, rangeExpr.size(), "rangeExpr.size()")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testForLoopWithRange_bool_to_bool() {
|
||||
val result = compileText(Cx16Target, true, """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte i
|
||||
for i in false to true {
|
||||
i += i ; keep optimizer from removing it
|
||||
}
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val rangeExpr = startSub
|
||||
.statements.filterIsInstance<ForLoop>()
|
||||
.map { it.iterable }
|
||||
.filterIsInstance<RangeExpr>()[0]
|
||||
|
||||
assertEquals(2, rangeExpr.size())
|
||||
val intProgression = rangeExpr.toConstantIntegerRange()
|
||||
assertEquals(0, intProgression?.first)
|
||||
assertEquals(1, intProgression?.last)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testForLoopWithRange_ubyte_to_ubyte() {
|
||||
val result = compileText(Cx16Target, true, """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte i
|
||||
for i in 1 to 9 {
|
||||
i += i ; keep optimizer from removing it
|
||||
}
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val rangeExpr = startSub
|
||||
.statements.filterIsInstance<ForLoop>()
|
||||
.map { it.iterable }
|
||||
.filterIsInstance<RangeExpr>()[0]
|
||||
|
||||
assertEquals(9, rangeExpr.size())
|
||||
val intProgression = rangeExpr.toConstantIntegerRange()
|
||||
assertEquals(1, intProgression?.first)
|
||||
assertEquals(9, intProgression?.last)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testForLoopWithRange_str_downto_str() {
|
||||
val result = compileText(Cx16Target, true, """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte i
|
||||
for i in "start" downto "end" {
|
||||
i += i ; keep optimizer from removing it
|
||||
}
|
||||
}
|
||||
}
|
||||
""").assertFailure()
|
||||
//TODO("test exact compile error(s)")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testForLoopWithIterable_str() {
|
||||
val result = compileText(Cx16Target, false, """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte i
|
||||
for i in "something" {
|
||||
i += i ; keep optimizer from removing it
|
||||
}
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val iterable = startSub
|
||||
.statements.filterIsInstance<ForLoop>()
|
||||
.map { it.iterable }
|
||||
.filterIsInstance<IdentifierReference>()[0]
|
||||
|
||||
assertEquals(DataType.STR, iterable.inferType(program).typeOrElse(DataType.UNDEFINED))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
main {
|
||||
romsub $FFD2 = chrout(ubyte ch @ A)
|
||||
sub start() {
|
||||
const ubyte ch = '\n'
|
||||
chrout(ch)
|
||||
}
|
||||
}
|
6
compiler/test/fixtures/charLitAsRomsubArg.p8
vendored
6
compiler/test/fixtures/charLitAsRomsubArg.p8
vendored
@ -1,6 +0,0 @@
|
||||
main {
|
||||
romsub $FFD2 = chrout(ubyte ch @ A)
|
||||
sub start() {
|
||||
chrout('\n')
|
||||
}
|
||||
}
|
7
compiler/test/fixtures/charVarAsRomsubArg.p8
vendored
7
compiler/test/fixtures/charVarAsRomsubArg.p8
vendored
@ -1,7 +0,0 @@
|
||||
main {
|
||||
romsub $FFD2 = chrout(ubyte ch @ A)
|
||||
sub start() {
|
||||
ubyte ch = '\n'
|
||||
chrout(ch)
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ import prog8.parser.SourceCode
|
||||
import prog8.ast.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.expressions.CharLiteral
|
||||
import prog8.ast.expressions.*
|
||||
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
@ -431,4 +431,53 @@ class TestProg8Parser {
|
||||
assertEquals('x', rhs.value, "char literal's .value")
|
||||
assertEquals(true, rhs.altEncoding, "char literal's .altEncoding")
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testForloop() {
|
||||
val module = parseModule(SourceCode.of("""
|
||||
main {
|
||||
sub start() {
|
||||
ubyte ub
|
||||
for ub in "start" downto "end" { ; #0
|
||||
}
|
||||
for ub in "something" { ; #1
|
||||
}
|
||||
for ub in @'a' to 'f' { ; #2
|
||||
}
|
||||
for ub in false to true { ; #3
|
||||
}
|
||||
for ub in 9 to 1 { ; #4 - yes, *parser* should NOT check!
|
||||
}
|
||||
}
|
||||
}
|
||||
"""))
|
||||
val iterables = module
|
||||
.statements.filterIsInstance<Block>()[0]
|
||||
.statements.filterIsInstance<Subroutine>()[0]
|
||||
.statements.filterIsInstance<ForLoop>()
|
||||
.map { it.iterable }
|
||||
|
||||
assertEquals(5, iterables.size)
|
||||
|
||||
val it0 = iterables[0] as RangeExpr
|
||||
assertIs<StringLiteralValue>(it0.from, "parser should leave it as is")
|
||||
assertIs<StringLiteralValue>(it0.to, "parser should leave it as is")
|
||||
|
||||
val it1 = iterables[1] as StringLiteralValue
|
||||
assertEquals("something", it1.value, "parser should leave it as is")
|
||||
|
||||
val it2 = iterables[2] as RangeExpr
|
||||
assertIs<CharLiteral>(it2.from, "parser should leave it as is")
|
||||
assertIs<CharLiteral>(it2.to, "parser should leave it as is")
|
||||
|
||||
val it3 = iterables[3] as RangeExpr
|
||||
// TODO: intro BoolLiteral
|
||||
assertIs<NumericLiteralValue>(it3.from, "parser should leave it as is")
|
||||
assertIs<NumericLiteralValue>(it3.to, "parser should leave it as is")
|
||||
|
||||
val it4 = iterables[4] as RangeExpr
|
||||
assertIs<NumericLiteralValue>(it4.from, "parser should leave it as is")
|
||||
assertIs<NumericLiteralValue>(it4.to, "parser should leave it as is")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user