package prog8tests.ast import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.string.shouldContain import io.kotest.matchers.types.instanceOf import prog8.ast.IFunctionCall import prog8.ast.expressions.* import prog8.ast.statements.Assignment import prog8.ast.statements.InlineAssembly import prog8.ast.statements.VarDecl import prog8.code.core.DataType import prog8.code.core.Position import prog8.code.target.C64Target import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.compileText class TestVariousCompilerAst: FunSpec({ test("symbol names in inline assembly blocks") { val names1 = InlineAssembly(""" """, false, Position.DUMMY).names names1 shouldBe emptySet() val names2 = InlineAssembly(""" label: lda #255") { val src=""" main { sub start() { uword pointer = ${'$'}2000 @(pointer+${'$'}1000) = 123 ubyte @shared ub = @(pointer+${'$'}1000) pointer[${'$'}1000] = 99 ub = pointer[${'$'}1000] uword index = ${'$'}1000 pointer[index] = 55 ub = pointer[index] } }""" compileText(C64Target(), optimize=false, src, writeAssembly=false) shouldNotBe null } test("bitshift left of const byte not converted to word") { val src=""" main { sub start() { ubyte shift = 10 uword value = 1< ubyte { return lsb(x+y) } sub start() { 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 ubyte[] array2 = [1,2,3] } } }""" val result = compileText(C64Target(), optimize=false, src, writeAssembly=false)!! val stmts = result.compilerAst.entrypoint.statements stmts.size shouldBe 9 } test("alternative notation for negative containment check") { val src=""" main { sub start() { ubyte[] array=[1,2,3] cx16.r0L = not (3 in array) cx16.r1L = 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 BinaryExpression val value2 = (stmts[2] as Assignment).value as BinaryExpression value1.operator shouldBe "==" value1.left shouldBe instanceOf() (value1.right as NumericLiteral).number shouldBe 0.0 value2.operator shouldBe "==" value2.left shouldBe instanceOf() (value2.right as NumericLiteral).number shouldBe 0.0 } test("const pointer variable indexing works") { val src=""" main { sub start() { const uword pointer=$1000 cx16.r0L = pointer[2] pointer[2] = cx16.r0L } } """ compileText(C64Target(), optimize=false, src, writeAssembly=false) shouldNotBe null } test("unroll good") { val src=""" main { sub start() { unroll 200 { cx16.r0++ poke(2000,2) } } } """ val errors = ErrorReporterForTests(keepMessagesAfterReporting = true) compileText(C64Target(), optimize=false, src, writeAssembly=false, errors=errors) shouldNotBe null errors.warnings.size shouldBe 1 errors.warnings[0] shouldContain "large number of unrolls" } test("unroll bad") { val src=""" main { sub start() { repeat { unroll 80 { cx16.r0++ when cx16.r0 { 1 -> cx16.r0++ else -> cx16.r0++ } break } } } } """ val errors = ErrorReporterForTests() compileText(C64Target(), optimize=false, src, writeAssembly=false, errors = errors) shouldBe null errors.errors.size shouldBe 2 errors.errors[0] shouldContain "invalid statement in unroll loop" errors.errors[1] shouldContain "invalid statement in unroll loop" } })