2021-10-29 03:00:30 +00:00
package prog8tests.ast
2021-06-13 12:59:57 +00:00
2021-12-05 17:39:34 +00:00
import com.github.michaelbull.result.getOrElse
2021-11-09 00:13:23 +00:00
import io.kotest.assertions.fail
2021-11-07 20:18:18 +00:00
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.assertions.withClue
2021-11-07 16:25:53 +00:00
import io.kotest.core.spec.style.FunSpec
2021-11-18 00:05:16 +00:00
import io.kotest.matchers.or
2021-11-07 20:18:18 +00:00
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.string.shouldStartWith
import io.kotest.matchers.types.instanceOf
2021-10-10 22:22:04 +00:00
import prog8.ast.IFunctionCall
2021-10-18 22:26:02 +00:00
import prog8.ast.Module
2021-10-10 22:22:04 +00:00
import prog8.ast.Node
2021-10-29 22:05:55 +00:00
import prog8.ast.Program
2021-10-20 21:08:40 +00:00
import prog8.ast.base.DataType
2021-10-10 22:22:04 +00:00
import prog8.ast.base.Position
2021-11-08 17:38:04 +00:00
import prog8.ast.expressions.*
2021-10-10 22:22:04 +00:00
import prog8.ast.statements.*
2021-12-28 13:23:36 +00:00
import prog8.codegen.target.C64Target
2022-01-19 20:13:02 +00:00
import prog8.codegen.target.cbm.PetsciiEncoding
2022-01-18 20:21:49 +00:00
import prog8.compilerinterface.Encoding
2021-06-19 16:10:26 +00:00
import prog8.parser.ParseError
import prog8.parser.Prog8Parser.parseModule
2021-06-21 10:02:36 +00:00
import prog8.parser.SourceCode
2021-12-04 17:20:22 +00:00
import prog8tests.helpers.*
2021-10-18 22:26:02 +00:00
import kotlin.io.path.Path
import kotlin.io.path.isRegularFile
2021-10-10 22:22:04 +00:00
import kotlin.io.path.name
import kotlin.io.path.nameWithoutExtension
2021-06-21 10:02:36 +00:00
2021-06-13 12:59:57 +00:00
2021-11-07 16:25:53 +00:00
class TestProg8Parser : FunSpec ( {
2021-07-04 16:09:16 +00:00
2021-11-07 16:25:53 +00:00
context ( " Newline at end " ) {
test ( " is not required - #40, fixed by #45 " ) {
val nl = " \n " // say, Unix-style (different flavours tested elsewhere)
val src = SourceCode . Text ( " foo { " + nl + " } " ) // source ends with '}' (= NO newline, issue #40)
2021-06-13 12:59:57 +00:00
2021-11-07 16:25:53 +00:00
// #40: Prog8ANTLRParser would report (throw) "missing <EOL> at '<EOF>'"
val module = parseModule ( src )
2021-11-07 20:18:18 +00:00
module . statements . size shouldBe 1
2021-11-07 16:25:53 +00:00
}
2021-06-13 18:47:14 +00:00
2021-11-07 16:25:53 +00:00
test ( " is still accepted - #40, fixed by #45 " ) {
val nl = " \n " // say, Unix-style (different flavours tested elsewhere)
val srcText = " foo { " + nl + " } " + nl // source does end with a newline (issue #40)
val module = parseModule ( SourceCode . Text ( srcText ) )
2021-11-07 20:18:18 +00:00
module . statements . size shouldBe 1
2021-08-02 12:52:46 +00:00
}
2021-11-07 16:25:53 +00:00
}
2021-06-13 18:47:14 +00:00
2021-11-07 16:25:53 +00:00
context ( " Newline " ) {
test ( " is required after each block except the last " ) {
2021-08-02 12:52:46 +00:00
val nl = " \n " // say, Unix-style (different flavours tested elsewhere)
2021-06-13 18:47:14 +00:00
2021-08-02 12:52:46 +00:00
// BAD: 2nd block `bar` does NOT start on new line; however, there's is a nl at the very end
val srcBad = " foo { " + nl + " } " + " bar { " + nl + " } " + nl
2021-06-13 20:49:54 +00:00
2021-08-02 12:52:46 +00:00
// GOOD: 2nd block `bar` does start on a new line; however, a nl at the very end ain't needed
val srcGood = " foo { " + nl + " } " + nl + " bar { " + nl + " } "
2021-06-13 20:49:54 +00:00
2021-11-07 20:18:18 +00:00
shouldThrow < ParseError > { parseModule ( SourceCode . Text ( srcBad ) ) }
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( srcGood ) )
2021-11-07 20:18:18 +00:00
module . statements . size shouldBe 2
2021-08-02 12:52:46 +00:00
}
2021-06-18 19:55:03 +00:00
2021-11-07 16:25:53 +00:00
test ( " is required between two Blocks or Directives - #47 " ) {
2021-08-02 12:52:46 +00:00
// block and block
2021-11-07 20:18:18 +00:00
shouldThrow < ParseError > { parseModule ( SourceCode . Text ( """
2021-08-02 12:52:46 +00:00
blockA {
} blockB {
}
""" )) }
// block and directive
2021-11-07 20:18:18 +00:00
shouldThrow < ParseError > { parseModule ( SourceCode . Text ( """
2021-08-02 12:52:46 +00:00
blockB {
} % import textio
""" )) }
// The following two are bogus due to directive *args* expected to follow the directive name.
// Leaving them in anyways.
// dir and block
2021-11-07 20:18:18 +00:00
shouldThrow < ParseError > { parseModule ( SourceCode . Text ( """
2021-08-02 12:52:46 +00:00
% import textio blockB {
}
""" )) }
2021-11-07 20:18:18 +00:00
shouldThrow < ParseError > { parseModule ( SourceCode . Text ( """
2021-08-02 12:52:46 +00:00
% import textio % import syslib
""" )) }
}
2021-06-18 19:55:03 +00:00
2021-11-07 16:25:53 +00:00
test ( " can be Win, Unix or mixed, even mixed " ) {
2021-08-02 12:52:46 +00:00
val nlWin = " \r \n "
val nlUnix = " \n "
val nlMac = " \r "
//parseModule(Paths.get("test", "fixtures", "mac_newlines.p8").toAbsolutePath())
// a good mix of all kinds of newlines:
val srcText =
" foo { " +
nlMac +
nlWin +
" } " +
nlMac + // <-- do test a single \r (!) where an EOL is expected
" bar { " +
nlUnix +
" } " +
nlUnix + nlMac // both should be "eaten up" by just one EOL token
" combi { " +
nlMac + nlWin + nlUnix // all three should be "eaten up" by just one EOL token
" } " +
nlUnix // end with newline (see testModuleSourceNeedNotEndWithNewline)
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( srcText ) )
2021-11-07 20:18:18 +00:00
module . statements . size shouldBe 2
2021-08-02 12:52:46 +00:00
}
2021-06-18 19:55:03 +00:00
}
2021-11-07 16:25:53 +00:00
context ( " EOLsInterleavedWithComments " ) {
2021-08-02 12:52:46 +00:00
2021-11-07 16:25:53 +00:00
test ( " are ok before first block - #47 " ) {
2021-08-02 12:52:46 +00:00
// issue: #47
val srcText = """
; comment
; comment
blockA {
}
"""
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( srcText ) )
2021-11-07 20:18:18 +00:00
module . statements . size shouldBe 1
2021-08-02 12:52:46 +00:00
}
2021-06-19 18:27:04 +00:00
2021-11-07 16:25:53 +00:00
test ( " are ok between blocks - #47 " ) {
2021-08-02 12:52:46 +00:00
// issue: #47
val srcText = """
blockA {
}
; comment
; comment
blockB {
}
"""
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( srcText ) )
2021-11-07 20:18:18 +00:00
module . statements . size shouldBe 2
2021-08-02 12:52:46 +00:00
}
2021-07-11 15:32:29 +00:00
2021-11-07 16:25:53 +00:00
test ( " are ok after last block - #47 " ) {
2021-08-02 12:52:46 +00:00
// issue: #47
val srcText = """
blockA {
}
; comment
; comment
"""
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( srcText ) )
2021-11-07 20:18:18 +00:00
module . statements . size shouldBe 1
2021-08-02 12:52:46 +00:00
}
2021-06-19 18:27:04 +00:00
}
2021-11-07 16:25:53 +00:00
context ( " ImportDirectives " ) {
test ( " should not be looked into by the parser " ) {
2021-08-02 12:52:46 +00:00
val importedNoExt = assumeNotExists ( fixturesDir , " i_do_not_exist " )
assumeNotExists ( fixturesDir , " i_do_not_exist.p8 " )
val text = " %import ${importedNoExt.name} "
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( text ) )
2021-07-10 19:03:14 +00:00
2021-11-07 20:18:18 +00:00
module . statements . size shouldBe 1
2021-08-02 12:52:46 +00:00
}
2021-07-10 19:03:14 +00:00
}
2021-11-07 16:25:53 +00:00
context ( " EmptySourcecode " ) {
test ( " from an empty string should result in empty Module " ) {
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( " " ) )
2021-11-07 20:18:18 +00:00
module . statements . size shouldBe 0
2021-08-02 12:52:46 +00:00
}
2021-07-04 16:09:16 +00:00
2021-11-07 16:25:53 +00:00
test ( " from an empty file should result in empty Module " ) {
2021-12-04 17:20:22 +00:00
val path = assumeReadableFile ( fixturesDir , " ast_empty.p8 " )
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . File ( path ) )
2021-11-07 20:18:18 +00:00
module . statements . size shouldBe 0
2021-08-02 12:52:46 +00:00
}
2021-07-04 16:09:16 +00:00
}
2021-11-07 16:25:53 +00:00
context ( " NameOfModule " ) {
test ( " parsed from a string " ) {
2021-08-02 12:52:46 +00:00
val srcText = """
main {
}
""" .trimIndent()
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( srcText ) )
2021-07-04 16:09:16 +00:00
2021-08-02 12:52:46 +00:00
// Note: assertContains has *actual* as first param
2021-11-07 20:18:18 +00:00
module . name shouldContain Regex ( " ^<String@[0-9a-f \\ -]+> $ " )
2021-08-02 12:52:46 +00:00
}
2021-07-04 16:09:16 +00:00
2021-11-07 16:25:53 +00:00
test ( " parsed from a file " ) {
2021-12-04 17:20:22 +00:00
val path = assumeReadableFile ( fixturesDir , " ast_simple_main.p8 " )
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . File ( path ) )
2021-11-07 20:18:18 +00:00
module . name shouldBe path . nameWithoutExtension
2021-08-02 12:52:46 +00:00
}
2021-07-04 16:09:16 +00:00
}
2021-11-07 16:25:53 +00:00
context ( " PositionOfAstNodesAndParseErrors " ) {
2021-08-02 12:52:46 +00:00
2021-11-07 16:25:53 +00:00
fun assertPosition (
2021-08-02 12:52:46 +00:00
actual : Position ,
expFile : String ? = null ,
expLine : Int ? = null ,
expStartCol : Int ? = null ,
expEndCol : Int ? = null
) {
require ( ! listOf ( expLine , expStartCol , expEndCol ) . all { it == null } )
2021-11-07 20:18:18 +00:00
if ( expLine != null ) actual . line shouldBe expLine
if ( expStartCol != null ) actual . startCol shouldBe expStartCol
if ( expEndCol != null ) actual . endCol shouldBe expEndCol
if ( expFile != null ) actual . file shouldBe expFile
2021-08-02 12:52:46 +00:00
}
2021-07-04 16:09:16 +00:00
2021-11-07 16:25:53 +00:00
fun assertPosition (
2021-08-02 12:52:46 +00:00
actual : Position ,
expFile : Regex ? = null ,
expLine : Int ? = null ,
expStartCol : Int ? = null ,
expEndCol : Int ? = null
) {
require ( ! listOf ( expLine , expStartCol , expEndCol ) . all { it == null } )
2021-11-07 20:18:18 +00:00
if ( expLine != null ) actual . line shouldBe expLine
if ( expStartCol != null ) actual . startCol shouldBe expStartCol
if ( expEndCol != null ) actual . endCol shouldBe expEndCol
if ( expFile != null ) actual . file shouldContain expFile
2021-08-02 12:52:46 +00:00
}
2021-07-04 16:09:16 +00:00
2021-11-07 16:25:53 +00:00
fun assertPositionOf (
2021-08-02 12:52:46 +00:00
actual : Node ,
expFile : String ? = null ,
expLine : Int ? = null ,
expStartCol : Int ? = null ,
expEndCol : Int ? = null
) =
assertPosition ( actual . position , expFile , expLine , expStartCol , expEndCol )
2021-11-07 16:25:53 +00:00
fun assertPositionOf (
2021-08-02 12:52:46 +00:00
actual : Node ,
expFile : Regex ? = null ,
expLine : Int ? = null ,
expStartCol : Int ? = null ,
expEndCol : Int ? = null
) =
assertPosition ( actual . position , expFile , expLine , expStartCol , expEndCol )
2021-11-07 16:25:53 +00:00
test ( " in ParseError from bad string source code " ) {
2021-08-02 12:52:46 +00:00
val srcText = " bad * { } \n "
2021-11-07 20:18:18 +00:00
val e = shouldThrow < ParseError > { parseModule ( SourceCode . Text ( srcText ) ) }
2021-11-05 21:46:13 +00:00
assertPosition ( e . position , Regex ( " ^<String@[0-9a-f \\ -]+> $ " ) , 1 , 4 , 4 )
2021-08-02 12:52:46 +00:00
}
2021-07-04 16:09:16 +00:00
2021-11-07 16:25:53 +00:00
test ( " in ParseError from bad file source code " ) {
2021-12-04 17:20:22 +00:00
val path = assumeReadableFile ( fixturesDir , " ast_file_with_syntax_error.p8 " )
2021-06-18 19:55:03 +00:00
2021-11-07 20:18:18 +00:00
val e = shouldThrow < ParseError > { parseModule ( SourceCode . File ( path ) ) }
2021-11-05 21:46:13 +00:00
assertPosition ( e . position , SourceCode . relative ( path ) . toString ( ) , 2 , 6 )
2021-07-04 16:09:16 +00:00
}
2021-06-19 16:10:26 +00:00
2021-11-07 16:25:53 +00:00
test ( " of Module parsed from a string " ) {
2021-08-02 12:52:46 +00:00
val srcText = """
main {
}
2021-11-05 21:46:13 +00:00
"""
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( srcText ) )
2021-11-05 21:46:13 +00:00
assertPositionOf ( module , Regex ( " ^<String@[0-9a-f \\ -]+> $ " ) , 1 , 0 )
2021-06-19 16:10:26 +00:00
}
2021-06-18 19:55:03 +00:00
2021-11-07 16:25:53 +00:00
test ( " of Module parsed from a file " ) {
2021-12-04 17:20:22 +00:00
val path = assumeReadableFile ( fixturesDir , " ast_simple_main.p8 " )
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . File ( path ) )
2021-11-05 21:46:13 +00:00
assertPositionOf ( module , SourceCode . relative ( path ) . toString ( ) , 1 , 0 )
2021-08-02 12:52:46 +00:00
}
2021-07-04 16:09:16 +00:00
2021-11-07 16:25:53 +00:00
test ( " of non-root Nodes parsed from file " ) {
2021-12-04 17:20:22 +00:00
val path = assumeReadableFile ( fixturesDir , " ast_simple_main.p8 " )
2021-07-04 16:09:16 +00:00
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . File ( path ) )
2021-08-02 12:52:46 +00:00
val mpf = module . position . file
2021-11-05 21:46:13 +00:00
assertPositionOf ( module , SourceCode . relative ( path ) . toString ( ) , 1 , 0 )
2021-08-02 12:52:46 +00:00
val mainBlock = module . statements . filterIsInstance < Block > ( ) [ 0 ]
2021-12-04 15:46:26 +00:00
assertPositionOf ( mainBlock , mpf , 2 , 1 , 4 )
2021-08-02 12:52:46 +00:00
val startSub = mainBlock . statements . filterIsInstance < Subroutine > ( ) [ 0 ]
2021-12-04 15:46:26 +00:00
assertPositionOf ( startSub , mpf , 3 , 5 , 7 )
2021-08-02 12:52:46 +00:00
}
2021-07-04 16:09:16 +00:00
2021-11-07 16:25:53 +00:00
test ( " of non-root Nodes parsed from a string " ) {
2021-08-02 12:52:46 +00:00
val srcText = """
2021-11-05 21:46:13 +00:00
% zeropage basicsafe
2021-08-02 12:52:46 +00:00
main {
sub start ( ) {
ubyte foo = 42
ubyte bar
when ( foo ) {
2021-11-05 21:46:13 +00:00
23 -> bar = 'x'
2021-08-02 12:52:46 +00:00
42 -> bar = 'y'
else -> bar = 'z'
}
2021-07-04 16:09:16 +00:00
}
}
2021-08-02 12:52:46 +00:00
""" .trimIndent()
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( srcText ) )
2021-08-02 12:52:46 +00:00
val mpf = module . position . file
val targetDirective = module . statements . filterIsInstance < Directive > ( ) [ 0 ]
2021-12-04 15:46:26 +00:00
assertPositionOf ( targetDirective , mpf , 1 , 1 , 9 )
2021-08-02 12:52:46 +00:00
val mainBlock = module . statements . filterIsInstance < Block > ( ) [ 0 ]
2021-12-04 15:46:26 +00:00
assertPositionOf ( mainBlock , mpf , 2 , 1 , 4 )
2021-08-02 12:52:46 +00:00
val startSub = mainBlock . statements . filterIsInstance < Subroutine > ( ) [ 0 ]
2021-12-04 15:46:26 +00:00
assertPositionOf ( startSub , mpf , 3 , 5 , 7 )
2021-08-02 12:52:46 +00:00
val declFoo = startSub . statements . filterIsInstance < VarDecl > ( ) [ 0 ]
2021-12-04 15:46:26 +00:00
assertPositionOf ( declFoo , mpf , 4 , 9 , 13 )
2021-08-02 12:52:46 +00:00
val rhsFoo = declFoo . value !!
2021-12-04 15:46:26 +00:00
assertPositionOf ( rhsFoo , mpf , 4 , 21 , 22 )
2021-08-02 12:52:46 +00:00
val declBar = startSub . statements . filterIsInstance < VarDecl > ( ) [ 1 ]
2021-12-04 15:46:26 +00:00
assertPositionOf ( declBar , mpf , 5 , 9 , 13 )
2021-12-28 12:56:47 +00:00
val whenStmt = startSub . statements . filterIsInstance < When > ( ) [ 0 ]
2021-12-04 15:46:26 +00:00
assertPositionOf ( whenStmt , mpf , 6 , 9 , 12 )
assertPositionOf ( whenStmt . choices [ 0 ] , mpf , 7 , 13 , 14 )
assertPositionOf ( whenStmt . choices [ 1 ] , mpf , 8 , 13 , 14 )
assertPositionOf ( whenStmt . choices [ 2 ] , mpf , 9 , 13 , 16 )
2021-08-02 12:52:46 +00:00
}
2021-07-04 16:09:16 +00:00
}
2021-11-07 16:25:53 +00:00
context ( " PositionFile " ) {
fun assertSomethingForAllNodes ( module : Module , asserter : ( Node ) -> Unit ) {
asserter ( module )
module . statements . forEach ( asserter )
module . statements . filterIsInstance < Block > ( ) . forEach { b ->
asserter ( b )
b . statements . forEach ( asserter )
b . statements . filterIsInstance < Subroutine > ( ) . forEach { s ->
asserter ( s )
s . statements . forEach ( asserter )
}
}
}
test ( " isn't absolute for filesystem paths " ) {
2021-12-04 17:20:22 +00:00
val path = assumeReadableFile ( fixturesDir , " ast_simple_main.p8 " )
2021-10-18 22:26:02 +00:00
val module = parseModule ( SourceCode . File ( path ) )
assertSomethingForAllNodes ( module ) {
2021-11-07 20:18:18 +00:00
Path ( it . position . file ) . isAbsolute shouldBe false
Path ( it . position . file ) . isRegularFile ( ) shouldBe true
2021-10-18 22:26:02 +00:00
}
}
2021-11-07 16:25:53 +00:00
test ( " is mangled string id for string sources " )
2021-10-18 22:26:02 +00:00
{
val srcText = """
% zeropage basicsafe
main {
sub start ( ) {
ubyte aa = 99
aa ++
}
}
""" .trimIndent()
val module = parseModule ( SourceCode . Text ( srcText ) )
assertSomethingForAllNodes ( module ) {
2021-11-07 20:18:18 +00:00
it . position . file shouldStartWith SourceCode . stringSourcePrefix
2021-10-18 22:26:02 +00:00
}
}
2021-11-07 16:25:53 +00:00
test ( " is library prefixed path for resources " )
2021-10-18 22:26:02 +00:00
{
val resource = SourceCode . Resource ( " prog8lib/math.p8 " )
val module = parseModule ( resource )
assertSomethingForAllNodes ( module ) {
2021-11-07 20:18:18 +00:00
it . position . file shouldStartWith SourceCode . libraryFilePrefix
2021-10-18 22:26:02 +00:00
}
}
2021-11-07 16:25:53 +00:00
}
2021-10-18 22:26:02 +00:00
2021-11-07 16:25:53 +00:00
context ( " CharLiterals " ) {
2021-06-21 18:16:50 +00:00
2021-11-07 16:25:53 +00:00
test ( " in argument position, no altEnc " ) {
2021-10-13 16:55:56 +00:00
val src = SourceCode . Text ( """
2021-08-02 12:52:46 +00:00
main {
sub start ( ) {
chrout ( '\n' )
}
}
""" )
val module = parseModule ( src )
2021-06-21 18:16:50 +00:00
2021-08-02 12:52:46 +00:00
val startSub = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < Subroutine > ( ) [ 0 ]
val funCall = startSub . statements . filterIsInstance < IFunctionCall > ( ) . first ( )
2021-06-21 18:16:50 +00:00
2021-11-07 20:18:18 +00:00
funCall . args [ 0 ] shouldBe ( instanceOf < CharLiteral > ( ) )
2021-08-02 12:52:46 +00:00
val char = funCall . args [ 0 ] as CharLiteral
2021-11-07 20:18:18 +00:00
char . value shouldBe '\n'
2021-08-02 12:52:46 +00:00
}
2021-06-21 18:16:50 +00:00
2022-01-18 20:21:49 +00:00
test ( " on rhs of block-level var decl, default encoding " ) {
2021-10-13 16:55:56 +00:00
val src = SourceCode . Text ( """
2021-08-02 12:52:46 +00:00
main {
2021-06-21 18:16:50 +00:00
ubyte c = 'x'
}
2021-08-02 12:52:46 +00:00
""" )
val module = parseModule ( src )
val decl = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( ) [ 0 ]
val rhs = decl . value as CharLiteral
2022-01-18 20:21:49 +00:00
rhs . encoding shouldBe Encoding . PETSCII
2021-11-07 20:18:18 +00:00
rhs . value shouldBe 'x'
2021-08-02 12:52:46 +00:00
}
2021-06-21 18:16:50 +00:00
2022-01-18 20:21:49 +00:00
test ( " on rhs of block-level const decl, with screencode enc (old syntax) " ) {
2021-10-13 16:55:56 +00:00
val src = SourceCode . Text ( """
2021-08-02 12:52:46 +00:00
main {
2021-06-21 18:16:50 +00:00
const ubyte c = @ 'x'
}
2021-08-02 12:52:46 +00:00
""" )
val module = parseModule ( src )
val decl = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( ) [ 0 ]
val rhs = decl . value as CharLiteral
2022-01-18 20:21:49 +00:00
rhs . encoding shouldBe Encoding . SCREENCODES
2021-11-07 20:18:18 +00:00
rhs . value shouldBe 'x'
2021-08-02 12:52:46 +00:00
}
2021-07-13 07:47:31 +00:00
2022-01-19 00:08:24 +00:00
test ( " on rhs of block-level const decl, with screencode enc (new syntax) " ) {
2022-01-18 20:21:49 +00:00
val src = SourceCode . Text ( """
main {
const ubyte c = sc : 'x'
}
""" )
val module = parseModule ( src )
val decl = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( ) [ 0 ]
val rhs = decl . value as CharLiteral
rhs . encoding shouldBe Encoding . SCREENCODES
rhs . value shouldBe 'x'
}
2022-01-19 00:08:24 +00:00
test ( " on rhs of block-level const decl, with iso encoding " ) {
2022-01-18 20:21:49 +00:00
val src = SourceCode . Text ( """
main {
const ubyte c = iso : '_'
}
""" )
val module = parseModule ( src )
val decl = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( ) [ 0 ]
val rhs = decl . value as CharLiteral
rhs . encoding shouldBe Encoding . ISO
rhs . value shouldBe '_'
}
test ( " on rhs of subroutine-level var decl, default encoding " ) {
2021-10-13 16:55:56 +00:00
val src = SourceCode . Text ( """
2021-08-02 12:52:46 +00:00
main {
sub start ( ) {
ubyte c = 'x'
2021-07-13 07:47:31 +00:00
}
2021-08-02 12:52:46 +00:00
}
""" )
val module = parseModule ( src )
val decl = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < Subroutine > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( ) [ 0 ]
val rhs = decl . value as CharLiteral
2021-11-07 20:18:18 +00:00
rhs . value shouldBe 'x'
2022-01-18 20:21:49 +00:00
rhs . encoding shouldBe Encoding . PETSCII
2021-08-02 12:52:46 +00:00
}
2022-01-18 20:21:49 +00:00
test ( " on rhs of subroutine-level const decl, screencode (old syntax) " ) {
2021-10-13 16:55:56 +00:00
val src = SourceCode . Text ( """
2021-08-02 12:52:46 +00:00
main {
sub start ( ) {
const ubyte c = @ 'x'
2021-07-13 07:47:31 +00:00
}
2021-08-02 12:52:46 +00:00
}
""" )
val module = parseModule ( src )
val decl = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < Subroutine > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( ) [ 0 ]
val rhs = decl . value as CharLiteral
2022-01-18 20:21:49 +00:00
rhs . encoding shouldBe Encoding . SCREENCODES
2021-11-07 20:18:18 +00:00
rhs . value shouldBe 'x'
2022-01-18 20:21:49 +00:00
}
2022-01-19 00:08:24 +00:00
test ( " on rhs of subroutine-level const decl, screencode (new syntax) " ) {
2022-01-18 20:21:49 +00:00
val src = SourceCode . Text ( """
main {
sub start ( ) {
const ubyte c = sc : 'x'
}
}
""" )
val module = parseModule ( src )
val decl = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < Subroutine > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( ) [ 0 ]
val rhs = decl . value as CharLiteral
rhs . encoding shouldBe Encoding . SCREENCODES
rhs . value shouldBe 'x'
}
2022-01-19 00:08:24 +00:00
test ( " on rhs of subroutine-level const decl, iso encoding " ) {
2022-01-18 20:21:49 +00:00
val src = SourceCode . Text ( """
main {
sub start ( ) {
const ubyte c = iso : '_'
}
}
""" )
val module = parseModule ( src )
val decl = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < Subroutine > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( ) [ 0 ]
val rhs = decl . value as CharLiteral
rhs . encoding shouldBe Encoding . ISO
rhs . value shouldBe '_'
2021-08-02 12:52:46 +00:00
}
}
2022-01-18 20:21:49 +00:00
context ( " Strings " ) {
2022-01-19 00:08:24 +00:00
test ( " default encoding " ) {
val source = """
main {
str name = " name "
} """
val module = parseModule ( SourceCode . Text ( source ) )
val decl = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( ) [ 0 ]
2022-02-10 23:21:40 +00:00
val rhs = decl . value as StringLiteral
2022-01-19 00:08:24 +00:00
rhs . encoding shouldBe Encoding . PETSCII
rhs . value shouldBe " name "
}
test ( " old syntax alt encoding " ) {
val source = """
main {
str name = @ " name "
} """
val module = parseModule ( SourceCode . Text ( source ) )
val decl = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( ) [ 0 ]
2022-02-10 23:21:40 +00:00
val rhs = decl . value as StringLiteral
2022-01-19 00:08:24 +00:00
rhs . encoding shouldBe Encoding . SCREENCODES
rhs . value shouldBe " name "
}
test ( " new syntax encodings " ) {
val source = """
main {
str name1 = petscii : " Name "
str name2 = sc : " Name "
str name3 = iso : " Name "
} """
val module = parseModule ( SourceCode . Text ( source ) )
val ( decl1 , decl2 , decl3 ) = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < VarDecl > ( )
2022-02-10 23:21:40 +00:00
val rhs1 = decl1 . value as StringLiteral
val rhs2 = decl2 . value as StringLiteral
val rhs3 = decl3 . value as StringLiteral
2022-01-19 00:08:24 +00:00
rhs1 . encoding shouldBe Encoding . PETSCII
rhs1 . value shouldBe " Name "
rhs2 . encoding shouldBe Encoding . SCREENCODES
rhs2 . value shouldBe " Name "
rhs3 . encoding shouldBe Encoding . ISO
rhs3 . value shouldBe " Name "
}
2022-01-18 20:21:49 +00:00
}
2021-11-07 16:25:53 +00:00
context ( " Ranges " ) {
2021-08-02 12:52:46 +00:00
2021-11-07 16:25:53 +00:00
test ( " in for-loops " ) {
2021-10-13 16:55:56 +00:00
val module = parseModule ( SourceCode . Text ( """
2021-08-02 12:52:46 +00:00
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 !
}
2021-07-13 07:47:31 +00:00
}
}
2021-08-02 12:52:46 +00:00
""" ))
val iterables = module
. statements . filterIsInstance < Block > ( ) [ 0 ]
. statements . filterIsInstance < Subroutine > ( ) [ 0 ]
. statements . filterIsInstance < ForLoop > ( )
. map { it . iterable }
2021-11-07 20:18:18 +00:00
iterables . size shouldBe 5
2021-08-02 12:52:46 +00:00
2022-01-07 20:02:37 +00:00
val it0 = iterables [ 0 ] as RangeExpression
2022-02-10 23:21:40 +00:00
it0 . from shouldBe instanceOf < StringLiteral > ( )
it0 . to shouldBe instanceOf < StringLiteral > ( )
2021-08-02 12:52:46 +00:00
2022-02-10 23:21:40 +00:00
val it1 = iterables [ 1 ] as StringLiteral
2021-11-07 20:18:18 +00:00
it1 . value shouldBe " something "
2021-08-02 12:52:46 +00:00
2022-01-07 20:02:37 +00:00
val it2 = iterables [ 2 ] as RangeExpression
2021-11-07 20:18:18 +00:00
it2 . from shouldBe instanceOf < CharLiteral > ( )
it2 . to shouldBe instanceOf < CharLiteral > ( )
2021-08-02 12:52:46 +00:00
2022-01-07 20:02:37 +00:00
val it3 = iterables [ 3 ] as RangeExpression
2022-02-10 23:21:40 +00:00
it3 . from shouldBe instanceOf < NumericLiteral > ( )
it3 . to shouldBe instanceOf < NumericLiteral > ( )
2021-08-02 12:52:46 +00:00
2022-01-07 20:02:37 +00:00
val it4 = iterables [ 4 ] as RangeExpression
2022-02-10 23:21:40 +00:00
it4 . from shouldBe instanceOf < NumericLiteral > ( )
it4 . to shouldBe instanceOf < NumericLiteral > ( )
2021-08-02 12:52:46 +00:00
}
2021-07-13 07:47:31 +00:00
}
2021-08-02 12:52:46 +00:00
2021-11-07 16:25:53 +00:00
test ( " testCharLiteralConstValue " ) {
2022-01-18 20:21:49 +00:00
val char1 = CharLiteral ( 'A' , Encoding . PETSCII , Position . DUMMY )
val char2 = CharLiteral ( 'z' , Encoding . SCREENCODES , Position . DUMMY )
val char3 = CharLiteral ( '_' , Encoding . ISO , Position . DUMMY )
2021-10-29 22:05:55 +00:00
val program = Program ( " test " , DummyFunctions , DummyMemsizer , AsciiStringEncoder )
2021-11-07 20:18:18 +00:00
char1 . constValue ( program ) . number . toInt ( ) shouldBe 65
char2 . constValue ( program ) . number . toInt ( ) shouldBe 122
2022-01-18 20:21:49 +00:00
char3 . constValue ( program ) . number . toInt ( ) shouldBe 95
2021-10-29 22:05:55 +00:00
}
2021-11-07 16:25:53 +00:00
test ( " testLiteralValueComparisons " ) {
2022-02-10 23:21:40 +00:00
val ten = NumericLiteral ( DataType . UWORD , 10.0 , Position . DUMMY )
val nine = NumericLiteral ( DataType . UBYTE , 9.0 , Position . DUMMY )
2021-11-07 20:18:18 +00:00
ten shouldBe ten
nine shouldNotBe ten
( ten != ten ) shouldBe false
( ten != nine ) shouldBe true
2021-10-20 21:08:40 +00:00
2021-11-07 20:18:18 +00:00
( ten > nine ) shouldBe true
( ten >= nine ) shouldBe true
( ten >= ten ) shouldBe true
( ten > ten ) shouldBe false
2021-10-20 21:08:40 +00:00
2021-11-07 20:18:18 +00:00
( ten < nine ) shouldBe false
( ten <= nine ) shouldBe false
( ten <= ten ) shouldBe true
( ten < ten ) shouldBe false
2021-10-20 21:08:40 +00:00
2022-02-10 23:21:40 +00:00
val abc = StringLiteral ( " abc " , Encoding . PETSCII , Position . DUMMY )
val abd = StringLiteral ( " abd " , Encoding . PETSCII , Position . DUMMY )
2021-11-07 20:18:18 +00:00
abc shouldBe abc
( abc != abd ) shouldBe true
( abc != abc ) shouldBe false
2021-10-20 21:08:40 +00:00
}
2021-10-26 22:05:46 +00:00
2021-11-07 16:25:53 +00:00
test ( " testAnonScopeStillContainsVarsDirectlyAfterParse " ) {
2021-10-26 22:05:46 +00:00
val src = SourceCode . Text ( """
main {
sub start ( ) {
repeat {
ubyte xx = 99
xx ++
}
}
}
""" )
val module = parseModule ( src )
val mainBlock = module . statements . single ( ) as Block
val start = mainBlock . statements . single ( ) as Subroutine
val repeatbody = ( start . statements . single ( ) as RepeatLoop ) . body
2021-11-07 20:18:18 +00:00
withClue ( " no vars moved to main block " ) {
mainBlock . statements . any { it is VarDecl } shouldBe false
}
withClue ( " no vars moved to start sub " ) {
start . statements . any { it is VarDecl } shouldBe false
}
withClue ( " \" var is still in repeat block (anonymousscope " ) {
repeatbody . statements [ 0 ] shouldBe instanceOf < VarDecl > ( )
}
2022-02-10 23:21:40 +00:00
val initvalue = ( repeatbody . statements [ 0 ] as VarDecl ) . value as ? NumericLiteral
2021-11-07 20:18:18 +00:00
initvalue ?. number ?. toInt ( ) shouldBe 99
repeatbody . statements [ 1 ] shouldBe instanceOf < PostIncrDecr > ( )
2021-10-26 22:05:46 +00:00
// the ast processing steps used in the compiler, will eventually move the var up to the containing scope (subroutine).
}
2021-10-27 00:30:58 +00:00
2021-11-07 16:25:53 +00:00
test ( " testLabelsWithAnonScopesParsesFine " ) {
2021-10-27 00:30:58 +00:00
val src = SourceCode . Text ( """
main {
sub start ( ) {
goto mylabeloutside
if true {
if true {
goto labeloutside
goto iflabel
}
iflabel :
}
repeat {
goto labelinside
labelinside :
}
labeloutside :
}
}
""" )
val module = parseModule ( src )
val mainBlock = module . statements . single ( ) as Block
val start = mainBlock . statements . single ( ) as Subroutine
val labels = start . statements . filterIsInstance < Label > ( )
2021-11-07 20:18:18 +00:00
labels . size shouldBe 1
2021-10-27 00:30:58 +00:00
}
2021-11-08 17:38:04 +00:00
test ( " logical operator 'not' priority " ) {
val src = SourceCode . Text ( """
main {
sub start ( ) {
ubyte xx
xx = not 4 and not 5
xx = not 4 or not 5
xx = not 4 xor not 5
}
}
""" )
val module = parseModule ( src )
val start = ( module . statements . single ( ) as Block ) . statements . single ( ) as Subroutine
val andAssignmentExpr = ( start . statements [ 1 ] as Assignment ) . value
val orAssignmentExpr = ( start . statements [ 2 ] as Assignment ) . value
val xorAssignmentExpr = ( start . statements [ 3 ] as Assignment ) . value
fun correctPrios ( expr : Expression , operator : String ) {
withClue ( " not should have higher prio as the other logical operators " ) {
expr shouldBe instanceOf < BinaryExpression > ( )
val binExpr = expr as BinaryExpression
binExpr . operator shouldBe operator
( binExpr . left as PrefixExpression ) . operator shouldBe " not "
( binExpr . right as PrefixExpression ) . operator shouldBe " not "
}
}
correctPrios ( andAssignmentExpr , " and " )
correctPrios ( orAssignmentExpr , " or " )
correctPrios ( xorAssignmentExpr , " xor " )
}
2021-11-09 00:13:23 +00:00
test ( " inferred type correct for binaryexpression " ) {
val src = SourceCode . Text ( """
main {
ubyte bb
uword ww
ubyte bb2 = not bb or not ww ; expression combining ubyte and uword
}
""" )
val module = parseModule ( src )
val program = Program ( " test " , DummyFunctions , DummyMemsizer , DummyStringEncoder )
2021-11-18 00:05:16 +00:00
program . addModule ( module )
2021-11-09 00:13:23 +00:00
val bb2 = ( module . statements . single ( ) as Block ) . statements [ 2 ] as VarDecl
val expr = bb2 . value as BinaryExpression
println ( expr )
expr . operator shouldBe " or "
expr . left . inferType ( program ) . getOrElse { fail ( " dt " ) } shouldBe DataType . UBYTE
expr . right . inferType ( program ) . getOrElse { fail ( " dt " ) } shouldBe DataType . UWORD
expr . inferType ( program ) . getOrElse { fail ( " dt " ) } shouldBe DataType . UBYTE
}
2021-11-12 01:17:37 +00:00
test ( " inferred type for typecasted expressions with logical operators " ) {
val src = SourceCode . Text ( """
main {
ubyte bb
uword ww
uword qq = ( not bb as uword )
uword zz = not bb or not ww
ubyte bb2 = not bb or not ww
uword zz2 = ( not bb as uword ) or not ww
}
""" )
val module = parseModule ( src )
val program = Program ( " test " , DummyFunctions , DummyMemsizer , DummyStringEncoder )
2021-11-18 00:05:16 +00:00
program . addModule ( module )
2021-11-12 01:17:37 +00:00
val stmts = ( module . statements . single ( ) as Block ) . statements
stmts . size shouldBe 6
val qq = ( stmts [ 2 ] as VarDecl ) . value as TypecastExpression
val zz = ( stmts [ 3 ] as VarDecl ) . value as BinaryExpression
val bb2 = ( stmts [ 4 ] as VarDecl ) . value as BinaryExpression
val zz2 = ( stmts [ 5 ] as VarDecl ) . value as BinaryExpression
qq . inferType ( program ) . getOrElse { fail ( " dt " ) } shouldBe DataType . UWORD
zz . inferType ( program ) . getOrElse { fail ( " dt " ) } shouldBe DataType . UBYTE
bb2 . inferType ( program ) . getOrElse { fail ( " dt " ) } shouldBe DataType . UBYTE
zz2 . operator shouldBe " or "
val left = zz2 . left as TypecastExpression
val right = zz2 . right as PrefixExpression
left . inferType ( program ) . getOrElse { fail ( " dt " ) } shouldBe DataType . UWORD
right . inferType ( program ) . getOrElse { fail ( " dt " ) } shouldBe DataType . UWORD
zz2 . inferType ( program ) . getOrElse { fail ( " dt " ) } shouldBe DataType . UBYTE // 'or' causes UBYTE result
}
test ( " type cast from byte to ubyte as desired target type " ) {
val src = SourceCode . Text ( """
main {
ubyte r
ubyte ub = ( cos8 ( r ) / 2 + 100 ) as ubyte
} """ )
val module = parseModule ( src )
val program = Program ( " test " , DummyFunctions , DummyMemsizer , DummyStringEncoder )
2021-11-18 00:05:16 +00:00
program . addModule ( module )
2021-11-12 01:17:37 +00:00
val stmts = ( module . statements . single ( ) as Block ) . statements
stmts . size shouldBe 2
val ubexpr = ( stmts [ 1 ] as VarDecl ) . value as TypecastExpression
ubexpr . inferType ( program ) . getOrElse { fail ( " dt " ) } shouldBe DataType . UBYTE
}
2021-11-18 00:05:16 +00:00
2021-11-19 23:15:04 +00:00
test ( " assignment isAugmented correctness " ) {
2021-11-18 00:05:16 +00:00
val src = SourceCode . Text ( """
main {
sub start ( ) {
ubyte r
ubyte q
r = q * 3 ; # 1 no
r = r * 3 ; # 2 yes
r = 3 * r ; # 3 yes
r = 3 * q ; # 4 no
r = 5 + r ; # 5 yes
r = 5 - r ; # 6 no
r = r - 5 ; # 7 yes
r = not r ; # 8 yes
r = not q ; # 9 no
r = ( q + r ) + 5 ; # 10 yes
r = q + ( r + 5 ) ; # 11 yes
2021-11-20 00:21:33 +00:00
r = ( q + r ) - 5 ; # 12 yes
r = q + ( r - 5 ) ; # 13 yes
2021-11-18 00:05:16 +00:00
}
} """ )
val module = parseModule ( src )
val program = Program ( " test " , DummyFunctions , DummyMemsizer , DummyStringEncoder )
program . addModule ( module )
val stmts = program . entrypoint . statements
val expectedResults = listOf (
false , true , true ,
false , true , false ,
true , true , false ,
true , true , true ,
true
)
stmts . size shouldBe 15
expectedResults . size shouldBe stmts . size - 2
for ( ( idx , pp ) in stmts . drop ( 2 ) . zip ( expectedResults ) . withIndex ( ) ) {
val assign = pp . first as Assignment
val expected = pp . second
2021-11-20 00:21:33 +00:00
withClue ( " # ${idx+1} : should ${if(expected) "" else "n't"} be augmentable: $assign " ) {
2021-11-18 00:05:16 +00:00
assign . isAugmentable shouldBe expected
assign . value shouldBe ( instanceOf < PrefixExpression > ( ) or instanceOf < BinaryExpression > ( ) or instanceOf < TypecastExpression > ( ) )
}
}
}
2021-12-05 17:39:34 +00:00
test ( " test string x and u escape sequences " ) {
val text = """
main {
sub start ( ) {
str string = " \ x00 \ xff \u0041 "
ubyte zero = ' \ x00 '
ubyte ff = ' \ xff '
ubyte letter = ' \u0041 '
}
}
"""
2022-02-06 20:29:06 +00:00
val result = compileText ( C64Target ( ) , false , text , writeAssembly = false ) . assertSuccess ( )
2021-12-05 17:39:34 +00:00
val start = result . program . entrypoint
2022-02-10 23:21:40 +00:00
val string = ( start . statements [ 0 ] as VarDecl ) . value as StringLiteral
2021-12-05 17:39:34 +00:00
withClue ( " x-escapes are hacked to range 0x8000-0x80ff " ) {
string . value [ 0 ] . code shouldBe 0x8000
string . value [ 1 ] . code shouldBe 0x80ff
}
string . value [ 2 ] . code shouldBe 65
val zero = start . statements [ 2 ] as Assignment
2022-02-10 23:21:40 +00:00
zero . value shouldBe NumericLiteral ( DataType . UBYTE , 0.0 , Position . DUMMY )
2021-12-05 17:39:34 +00:00
val ff = start . statements [ 4 ] as Assignment
2022-02-10 23:21:40 +00:00
ff . value shouldBe NumericLiteral ( DataType . UBYTE , 255.0 , Position . DUMMY )
2021-12-05 17:39:34 +00:00
val letter = start . statements [ 6 ] as Assignment
2022-01-16 22:03:00 +00:00
// TODO characters should perhaps not be encoded until code generation, like strings... however this will prevent optimizing expressions with characters
2022-01-19 20:13:02 +00:00
val encodedletter = PetsciiEncoding . encodePetscii ( " A " , true ) . getOrElse { fail ( " petscii error " ) } . single ( )
2022-02-10 23:21:40 +00:00
letter . value shouldBe NumericLiteral ( DataType . UBYTE , encodedletter . toDouble ( ) , Position . DUMMY )
2021-12-05 17:39:34 +00:00
}
2022-01-05 23:01:49 +00:00
test ( " `in` containment checks " ) {
val text = """
main {
sub start ( ) {
str string = " hello "
ubyte [ ] array = [ 1 , 2 , 3 , 4 ]
ubyte cc
if cc in [ ' ' , '@' , 0 ] {
}
if cc in " email " {
}
cc = 99 in array
cc = '@' in string
}
}
"""
2022-02-06 20:29:06 +00:00
val result = compileText ( C64Target ( ) , false , text , writeAssembly = false ) . assertSuccess ( )
2022-01-05 23:01:49 +00:00
val start = result . program . entrypoint
val containmentChecks = start . statements . takeLast ( 4 )
( containmentChecks [ 0 ] as IfElse ) . condition shouldBe instanceOf < ContainmentCheck > ( )
( containmentChecks [ 1 ] as IfElse ) . condition shouldBe instanceOf < ContainmentCheck > ( )
( containmentChecks [ 2 ] as Assignment ) . value shouldBe instanceOf < ContainmentCheck > ( )
( containmentChecks [ 3 ] as Assignment ) . value shouldBe instanceOf < ContainmentCheck > ( )
}
test ( " invalid `in` containment checks " ) {
val text = """
main {
sub start ( ) {
ubyte cc
ubyte [ ] array = [ 1 , 2 , 3 ]
cc = 99 in 12345
cc = 9999 in array
}
}
"""
val errors = ErrorReporterForTests ( )
2022-02-06 20:29:06 +00:00
compileText ( C64Target ( ) , false , text , writeAssembly = false , errors = errors ) . assertFailure ( )
2022-01-05 23:01:49 +00:00
errors . errors . size shouldBe 2
errors . errors [ 0 ] shouldContain " must be an iterable type "
errors . errors [ 1 ] shouldContain " datatype doesn't match "
}
2022-01-13 01:29:55 +00:00
test ( " vardecl options any order okay " ) {
val text = """
main {
% option force _output
sub start ( ) {
2022-01-14 22:16:05 +00:00
ubyte @zp @shared @requirezp var1
2022-01-13 01:29:55 +00:00
ubyte @shared @zp var2
ubyte @zp var3
ubyte @shared var4
2022-01-14 22:16:05 +00:00
ubyte @requirezp var5
ubyte var6
2022-01-13 01:29:55 +00:00
}
}
"""
2022-02-06 20:29:06 +00:00
val result = compileText ( C64Target ( ) , false , text , writeAssembly = false ) . assertSuccess ( )
2022-01-13 01:29:55 +00:00
val stmt = result . program . entrypoint . statements
2022-01-14 22:16:05 +00:00
stmt . size shouldBe 12
2022-01-13 01:29:55 +00:00
val var1 = stmt [ 0 ] as VarDecl
var1 . sharedWithAsm shouldBe true
2022-01-14 22:16:05 +00:00
var1 . zeropage shouldBe ZeropageWish . REQUIRE _ZEROPAGE
2022-01-13 01:29:55 +00:00
val var2 = stmt [ 2 ] as VarDecl
var2 . sharedWithAsm shouldBe true
var2 . zeropage shouldBe ZeropageWish . PREFER _ZEROPAGE
val var3 = stmt [ 4 ] as VarDecl
var3 . sharedWithAsm shouldBe false
var3 . zeropage shouldBe ZeropageWish . PREFER _ZEROPAGE
val var4 = stmt [ 6 ] as VarDecl
var4 . sharedWithAsm shouldBe true
var4 . zeropage shouldBe ZeropageWish . DONTCARE
val var5 = stmt [ 8 ] as VarDecl
var5 . sharedWithAsm shouldBe false
2022-01-14 22:16:05 +00:00
var5 . zeropage shouldBe ZeropageWish . REQUIRE _ZEROPAGE
val var6 = stmt [ 10 ] as VarDecl
var6 . sharedWithAsm shouldBe false
var6 . zeropage shouldBe ZeropageWish . DONTCARE
2022-01-13 01:29:55 +00:00
}
2021-11-07 16:25:53 +00:00
} )