mirror of
https://github.com/irmen/prog8.git
synced 2025-01-13 10:29:52 +00:00
Merge branch 'v7.1'
This commit is contained in:
commit
f0cff661df
@ -9,6 +9,7 @@ import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.ast.walk.IAstVisitor
|
||||
import prog8.compiler.astprocessing.isInRegularRAMof
|
||||
import prog8.compiler.target.ICompilationTarget
|
||||
|
||||
|
||||
@ -39,7 +40,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
|
||||
// But it can only be done if the target variable IS NOT OCCURRING AS AN OPERAND ITSELF.
|
||||
if(!assignment.isAugmentable
|
||||
&& assignment.target.identifier != null
|
||||
&& compTarget.isInRegularRAM(assignment.target, program)) {
|
||||
&& assignment.target.isInRegularRAMof(compTarget.machine)) {
|
||||
val binExpr = assignment.value as? BinaryExpression
|
||||
if (binExpr != null && binExpr.operator !in comparisonOperators) {
|
||||
if (binExpr.left !is BinaryExpression) {
|
||||
|
@ -215,12 +215,12 @@ fun parseImports(filepath: Path,
|
||||
}
|
||||
|
||||
fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget): CompilationOptions {
|
||||
val mainModule = program.mainModule
|
||||
val outputDirective = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" } as? Directive)
|
||||
val launcherDirective = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" } as? Directive)
|
||||
val toplevelModule = program.toplevelModule
|
||||
val outputDirective = (toplevelModule.statements.singleOrNull { it is Directive && it.directive == "%output" } as? Directive)
|
||||
val launcherDirective = (toplevelModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" } as? Directive)
|
||||
val outputTypeStr = outputDirective?.args?.single()?.name?.uppercase()
|
||||
val launcherTypeStr = launcherDirective?.args?.single()?.name?.uppercase()
|
||||
val zpoption: String? = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%zeropage" }
|
||||
val zpoption: String? = (toplevelModule.statements.singleOrNull { it is Directive && it.directive == "%zeropage" }
|
||||
as? Directive)?.args?.single()?.name?.uppercase()
|
||||
val allOptions = program.modules.flatMap { it.statements }.filter { it is Directive && it.directive == "%option" }
|
||||
.flatMap { (it as Directive).args }.toSet()
|
||||
@ -242,7 +242,7 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget
|
||||
zpType = ZeropageType.BASICSAFE
|
||||
}
|
||||
|
||||
val zpReserved = mainModule.statements
|
||||
val zpReserved = toplevelModule.statements
|
||||
.asSequence()
|
||||
.filter { it is Directive && it.directive == "%zpreserved" }
|
||||
.map { (it as Directive).args }
|
||||
@ -280,6 +280,8 @@ private fun processAst(programAst: Program, errors: IErrorReporter, compilerOpti
|
||||
programAst.checkIdentifiers(errors, compilerOptions)
|
||||
errors.report()
|
||||
// TODO: turning char literals into UBYTEs via an encoding should really happen in code gen - but for that we'd need DataType.CHAR
|
||||
// NOTE: we will then lose the opportunity to do constant-folding on any expression containing a char literal, but how often will those occur?
|
||||
// Also they might be optimized away eventually in codegen or by the assembler even
|
||||
programAst.charLiteralsToUByteLiterals(errors, compilerOptions.compTarget)
|
||||
errors.report()
|
||||
programAst.constantFold(errors, compilerOptions.compTarget)
|
||||
|
@ -35,13 +35,17 @@ class ModuleImporter(private val program: Program,
|
||||
file = filePath.normalize().toFile(),
|
||||
reason = "searched in $searchIn"))
|
||||
1 -> candidates.first()
|
||||
else -> candidates.first() // TODO: report error if more than 1 candidate?
|
||||
else -> candidates.first() // when more candiates, pick the one from the first location
|
||||
}
|
||||
|
||||
val logMsg = "importing '${filePath.nameWithoutExtension}' (from file $srcPath)"
|
||||
println(logMsg)
|
||||
|
||||
return Ok(importModule(SourceCode.File(srcPath)))
|
||||
val module = importModule(SourceCode.File(srcPath))
|
||||
return if(module==null)
|
||||
Err(NoSuchFileException(srcPath.toFile()))
|
||||
else
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
fun importLibraryModule(name: String): Module? {
|
||||
@ -51,20 +55,24 @@ class ModuleImporter(private val program: Program,
|
||||
return executeImportDirective(import, null)
|
||||
}
|
||||
|
||||
//private fun importModule(stream: CharStream, modulePath: Path, isLibrary: Boolean): Module {
|
||||
private fun importModule(src: SourceCode) : Module {
|
||||
private fun importModule(src: SourceCode) : Module? {
|
||||
val moduleAst = Prog8Parser.parseModule(src)
|
||||
program.addModule(moduleAst)
|
||||
|
||||
// accept additional imports
|
||||
try {
|
||||
val lines = moduleAst.statements.toMutableList()
|
||||
lines.asSequence()
|
||||
.mapIndexed { i, it -> i to it }
|
||||
.filter { (it.second as? Directive)?.directive == "%import" }
|
||||
.forEach { executeImportDirective(it.second as Directive, moduleAst) }
|
||||
|
||||
moduleAst.statements = lines
|
||||
return moduleAst
|
||||
} catch (x: Exception) {
|
||||
// in case of error, make sure the module we're importing is no longer in the Ast
|
||||
program.removeModule(moduleAst)
|
||||
throw x
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeImportDirective(import: Directive, importingModule: Module?): Module? {
|
||||
@ -104,6 +112,7 @@ class ModuleImporter(private val program: Program,
|
||||
}
|
||||
)
|
||||
|
||||
if(importedModule!=null)
|
||||
removeDirectivesFromImportedModule(importedModule)
|
||||
return importedModule
|
||||
}
|
||||
@ -133,7 +142,7 @@ class ModuleImporter(private val program: Program,
|
||||
} else {
|
||||
val dropCurDir = if(sourcePaths.isNotEmpty() && sourcePaths[0].name == ".") 1 else 0
|
||||
sourcePaths.drop(dropCurDir) +
|
||||
// FIXME: won't work until Prog8Parser is fixed s.t. it fully initialzes the modules it returns
|
||||
// TODO: won't work until Prog8Parser is fixed s.t. it fully initializes the modules it returns. // hm, what won't work?)
|
||||
listOf(Path(importingModule.position.file).parent ?: Path("")) +
|
||||
listOf(Path(".", "prog8lib"))
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import prog8.compiler.ZeropageType
|
||||
import prog8.compiler.functions.BuiltinFunctions
|
||||
import prog8.compiler.functions.builtinFunctionReturnType
|
||||
import prog8.compiler.target.ICompilationTarget
|
||||
import prog8.parser.SourceCode
|
||||
import java.io.CharConversionException
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
@ -46,7 +45,7 @@ internal class AstChecker(private val program: Program,
|
||||
|
||||
if(compilerOptions.floats) {
|
||||
if (compilerOptions.zeropage !in arrayOf(ZeropageType.FLOATSAFE, ZeropageType.BASICSAFE, ZeropageType.DONTUSE ))
|
||||
errors.err("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'", program.mainModule.position)
|
||||
errors.err("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'", program.toplevelModule.position)
|
||||
}
|
||||
|
||||
super.visit(program)
|
||||
|
@ -3,11 +3,9 @@ package prog8.compiler.astprocessing
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.expressions.CharLiteral
|
||||
import prog8.ast.expressions.NumericLiteralValue
|
||||
import prog8.ast.expressions.RangeExpr
|
||||
import prog8.ast.expressions.StringLiteralValue
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.AssignTarget
|
||||
import prog8.ast.statements.Directive
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
@ -16,6 +14,7 @@ import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.IErrorReporter
|
||||
import prog8.compiler.IStringEncoding
|
||||
import prog8.compiler.target.ICompilationTarget
|
||||
import prog8.compiler.target.IMachineDefinition
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
@ -127,26 +126,6 @@ internal fun Program.checkIdentifiers(errors: IErrorReporter, options: Compilati
|
||||
lit2decl.visit(this)
|
||||
lit2decl.applyModifications()
|
||||
}
|
||||
|
||||
// Check if each module has a unique name.
|
||||
// If not report those that haven't.
|
||||
// TODO: move check for unique module names to earlier stage and/or to unit tests
|
||||
val namesToModules = mapOf<String, MutableList<prog8.ast.Module>>().toMutableMap()
|
||||
for (m in modules) {
|
||||
val others = namesToModules[m.name]
|
||||
if (others == null) {
|
||||
namesToModules[m.name] = listOf(m).toMutableList()
|
||||
} else {
|
||||
others.add(m)
|
||||
}
|
||||
}
|
||||
val nonUniqueNames = namesToModules.keys
|
||||
.map { Pair(it, namesToModules[it]!!.size) }
|
||||
.filter { it.second > 1 }
|
||||
.map { "\"${it.first}\" (x${it.second})"}
|
||||
if (nonUniqueNames.isNotEmpty()) {
|
||||
throw FatalAstException("modules must have unique names; of the ttl ${modules.size} these have not: $nonUniqueNames")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Program.variousCleanups(program: Program, errors: IErrorReporter) {
|
||||
@ -186,3 +165,47 @@ internal fun Program.moveMainAndStartToFirst() {
|
||||
modules[0].statements.add(0, directive)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun AssignTarget.isInRegularRAMof(machine: IMachineDefinition): Boolean {
|
||||
val memAddr = memoryAddress
|
||||
val arrayIdx = arrayindexed
|
||||
val ident = identifier
|
||||
when {
|
||||
memAddr != null -> {
|
||||
return when (memAddr.addressExpression) {
|
||||
is NumericLiteralValue -> {
|
||||
machine.isRegularRAMaddress((memAddr.addressExpression as NumericLiteralValue).number.toInt())
|
||||
}
|
||||
is IdentifierReference -> {
|
||||
val program = definingModule.program
|
||||
val decl = (memAddr.addressExpression as IdentifierReference).targetVarDecl(program)
|
||||
if ((decl?.type == VarDeclType.VAR || decl?.type == VarDeclType.CONST) && decl.value is NumericLiteralValue)
|
||||
machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt())
|
||||
else
|
||||
false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
arrayIdx != null -> {
|
||||
val program = definingModule.program
|
||||
val targetStmt = arrayIdx.arrayvar.targetVarDecl(program)
|
||||
return if (targetStmt?.type == VarDeclType.MEMORY) {
|
||||
val addr = targetStmt.value as? NumericLiteralValue
|
||||
if (addr != null)
|
||||
machine.isRegularRAMaddress(addr.number.toInt())
|
||||
else
|
||||
false
|
||||
} else true
|
||||
}
|
||||
ident != null -> {
|
||||
val program = definingModule.program
|
||||
val decl = ident.targetVarDecl(program)!!
|
||||
return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteralValue)
|
||||
machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt())
|
||||
else
|
||||
true
|
||||
}
|
||||
else -> return true
|
||||
}
|
||||
}
|
||||
|
@ -24,49 +24,6 @@ interface ICompilationTarget: IStringEncoding, IMemSizer {
|
||||
val machine: IMachineDefinition
|
||||
override fun encodeString(str: String, altEncoding: Boolean): List<Short>
|
||||
override fun decodeString(bytes: List<Short>, altEncoding: Boolean): String
|
||||
|
||||
// TODO: rename param target, and also AST node AssignTarget - *different meaning of "target"!*
|
||||
// TODO: remove param program - can be obtained from AST node
|
||||
fun isInRegularRAM(target: AssignTarget, program: Program): Boolean {
|
||||
val memAddr = target.memoryAddress
|
||||
val arrayIdx = target.arrayindexed
|
||||
val ident = target.identifier
|
||||
when {
|
||||
memAddr != null -> {
|
||||
return when (memAddr.addressExpression) {
|
||||
is NumericLiteralValue -> {
|
||||
machine.isRegularRAMaddress((memAddr.addressExpression as NumericLiteralValue).number.toInt())
|
||||
}
|
||||
is IdentifierReference -> {
|
||||
val decl = (memAddr.addressExpression as IdentifierReference).targetVarDecl(program)
|
||||
if ((decl?.type == VarDeclType.VAR || decl?.type == VarDeclType.CONST) && decl.value is NumericLiteralValue)
|
||||
machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt())
|
||||
else
|
||||
false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
arrayIdx != null -> {
|
||||
val targetStmt = arrayIdx.arrayvar.targetVarDecl(program)
|
||||
return if (targetStmt?.type == VarDeclType.MEMORY) {
|
||||
val addr = targetStmt.value as? NumericLiteralValue
|
||||
if (addr != null)
|
||||
machine.isRegularRAMaddress(addr.number.toInt())
|
||||
else
|
||||
false
|
||||
} else true
|
||||
}
|
||||
ident != null -> {
|
||||
val decl = ident.targetVarDecl(program)!!
|
||||
return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteralValue)
|
||||
machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt())
|
||||
else
|
||||
true
|
||||
}
|
||||
else -> return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,6 +9,7 @@ import prog8.ast.statements.AssignTarget
|
||||
import prog8.ast.statements.Assignment
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.compiler.astprocessing.isInRegularRAMof
|
||||
import prog8.compiler.target.ICompilationTarget
|
||||
|
||||
|
||||
@ -54,7 +55,7 @@ X = BinExpr X = LeftExpr
|
||||
|
||||
|
||||
*/
|
||||
if(binExpr.operator in augmentAssignmentOperators && isSimpleTarget(assignment.target, program)) {
|
||||
if(binExpr.operator in augmentAssignmentOperators && isSimpleTarget(assignment.target)) {
|
||||
if(assignment.target isSameAs binExpr.left || assignment.target isSameAs binExpr.right)
|
||||
return noModifications
|
||||
|
||||
@ -77,9 +78,9 @@ X = BinExpr X = LeftExpr
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun isSimpleTarget(target: AssignTarget, program: Program) =
|
||||
private fun isSimpleTarget(target: AssignTarget) =
|
||||
if (target.identifier!=null || target.memoryAddress!=null)
|
||||
compTarget.isInRegularRAM(target, program)
|
||||
target.isInRegularRAMof(compTarget.machine)
|
||||
else
|
||||
false
|
||||
|
||||
|
@ -10,6 +10,7 @@ import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.compiler.IErrorReporter
|
||||
import prog8.compiler.astprocessing.isInRegularRAMof
|
||||
import prog8.compiler.target.ICompilationTarget
|
||||
|
||||
|
||||
@ -122,7 +123,7 @@ internal class UnusedCodeRemover(private val program: Program,
|
||||
val assign1 = stmtPairs[0] as? Assignment
|
||||
val assign2 = stmtPairs[1] as? Assignment
|
||||
if (assign1 != null && assign2 != null && !assign2.isAugmentable) {
|
||||
if (assign1.target.isSameAs(assign2.target, program) && compTarget.isInRegularRAM(assign1.target, program)) {
|
||||
if (assign1.target.isSameAs(assign2.target, program) && assign1.target.isInRegularRAMof(compTarget.machine)) {
|
||||
if(assign2.target.identifier==null || !assign2.value.referencesIdentifier(*(assign2.target.identifier!!.nameInSource.toTypedArray())))
|
||||
// only remove the second assignment if its value is a simple expression!
|
||||
when(assign2.value) {
|
||||
|
@ -71,7 +71,7 @@ locallabel:
|
||||
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
.addModule(module)
|
||||
module.linkParents(program.namespace)
|
||||
module.linkIntoProgram(program)
|
||||
return program
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.internedStringsModuleName
|
||||
import prog8.compiler.IErrorReporter
|
||||
import prog8.compiler.ModuleImporter
|
||||
import prog8.parser.ParseError
|
||||
@ -207,7 +208,6 @@ class TestModuleImporter {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("TODO: module that imports faulty module should not be kept in Program.modules")
|
||||
fun testImportingFileWithSyntaxError_twice() {
|
||||
doTestImportingFileWithSyntaxError(2)
|
||||
}
|
||||
@ -227,7 +227,8 @@ class TestModuleImporter {
|
||||
assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6))
|
||||
assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6))
|
||||
}
|
||||
assertThat(program.modules.size, equalTo(2))
|
||||
assertThat("imported module with error in it should not be present", program.modules.size, equalTo(1))
|
||||
assertThat(program.modules[0].name, equalTo(internedStringsModuleName))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,7 +259,7 @@ class TestModuleImporter {
|
||||
val result2 = importer.importLibraryModule(filenameWithExt)
|
||||
assertThat(count[n] + " call / with .p8 extension", result2, Is(nullValue()))
|
||||
assertFalse(importer.errors.noErrors(), count[n] + " call / with .p8 extension")
|
||||
assertEquals(errors.errors.single(), "no module found with name i_do_not_exist.p8") // TODO don't add a p8 extension in the import logic...
|
||||
assertEquals(errors.errors.single(), "no module found with name i_do_not_exist.p8")
|
||||
errors.report()
|
||||
assertThat(program.modules.size, equalTo(1))
|
||||
}
|
||||
@ -303,7 +304,8 @@ class TestModuleImporter {
|
||||
assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6))
|
||||
assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6))
|
||||
}
|
||||
assertThat(program.modules.size, equalTo(2))
|
||||
assertThat("imported module with error in it should not be present", program.modules.size, equalTo(1))
|
||||
assertThat(program.modules[0].name, equalTo(internedStringsModuleName))
|
||||
importer.errors.report()
|
||||
}
|
||||
}
|
||||
@ -314,7 +316,6 @@ class TestModuleImporter {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("TODO: module that imports faulty module should not be kept in Program.modules")
|
||||
fun testImportingFileWithSyntaxError_twice() {
|
||||
doTestImportingFileWithSyntaxError(2)
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class TestCompilerOnCharLit {
|
||||
"char literal should have been replaced by ubyte literal")
|
||||
val arg = funCall.args[0] as NumericLiteralValue
|
||||
assertEquals(DataType.UBYTE, arg.type)
|
||||
assertEquals(platform.encodeString("\n", false)[0], arg.number.toShort()) // TODO: short/int/UBYTE - which should it be?
|
||||
assertEquals(platform.encodeString("\n", false)[0], arg.number.toShort())
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -77,7 +77,7 @@ class TestCompilerOnCharLit {
|
||||
"char literal should have been replaced by ubyte literal")
|
||||
val initializerValue = decl.value as NumericLiteralValue
|
||||
assertEquals(DataType.UBYTE, initializerValue.type)
|
||||
assertEquals(platform.encodeString("\n", false)[0], initializerValue.number.toShort()) // TODO: short/int/UBYTE - which should it be?
|
||||
assertEquals(platform.encodeString("\n", false)[0], initializerValue.number.toShort())
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -105,12 +105,12 @@ class TestCompilerOnCharLit {
|
||||
assertEquals(DataType.UBYTE, decl.datatype)
|
||||
assertEquals(
|
||||
platform.encodeString("\n", false)[0],
|
||||
(decl.value as NumericLiteralValue).number.toShort()) // TODO: short/int/UBYTE - which should it be?
|
||||
(decl.value as NumericLiteralValue).number.toShort())
|
||||
}
|
||||
is NumericLiteralValue -> {
|
||||
assertEquals(
|
||||
platform.encodeString("\n", false)[0],
|
||||
arg.number.toShort()) // TODO: short/int/UBYTE - which should it be?
|
||||
arg.number.toShort())
|
||||
}
|
||||
else -> assertIs<IdentifierReference>(funCall.args[0]) // make test fail
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import kotlin.io.path.exists
|
||||
* They are not really unit tests, but rather tests of the whole process,
|
||||
* from source file loading all the way through to running 64tass.
|
||||
*/
|
||||
//@Disabled("to save some time")
|
||||
// @Disabled("disable to save some time")
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class TestCompilerOnExamples {
|
||||
private val examplesDir = assumeDirectory(workingDir, "../examples")
|
||||
@ -49,7 +49,7 @@ class TestCompilerOnExamples {
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
// @Disabled
|
||||
// @Disabled("disable to save some time")
|
||||
fun bothCx16AndC64() = mapCombinations(
|
||||
dim1 = listOf(
|
||||
"animals",
|
||||
@ -80,7 +80,7 @@ class TestCompilerOnExamples {
|
||||
)
|
||||
|
||||
@TestFactory
|
||||
// @Disabled
|
||||
// @Disabled("disable to save some time")
|
||||
fun onlyC64() = mapCombinations(
|
||||
dim1 = listOf(
|
||||
"balloonflight",
|
||||
@ -99,7 +99,7 @@ class TestCompilerOnExamples {
|
||||
)
|
||||
|
||||
@TestFactory
|
||||
// @Disabled
|
||||
// @Disabled("disable to save some time")
|
||||
fun onlyCx16() = mapCombinations(
|
||||
dim1 = listOf(
|
||||
"vtui/testvtui",
|
||||
|
@ -19,7 +19,7 @@ import kotlin.test.assertTrue
|
||||
class TestImportedModulesOrderAndOptions {
|
||||
|
||||
@Test
|
||||
fun testImportedModuleOrderCorrect() {
|
||||
fun testImportedModuleOrderAndMainModuleCorrect() {
|
||||
val result = compileText(C64Target, false, """
|
||||
%import textio
|
||||
%import floats
|
||||
@ -30,7 +30,7 @@ main {
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
assertTrue(result.programAst.mainModule.name.startsWith("on_the_fly_test"))
|
||||
assertTrue(result.programAst.toplevelModule.name.startsWith("on_the_fly_test"))
|
||||
|
||||
val moduleNames = result.programAst.modules.map { it.name }
|
||||
assertTrue(moduleNames[0].startsWith("on_the_fly_test"), "main module must be first")
|
||||
@ -43,6 +43,8 @@ main {
|
||||
"math",
|
||||
"prog8_lib"
|
||||
), moduleNames.drop(1), "module order in parse tree")
|
||||
|
||||
assertTrue(result.programAst.toplevelModule.name.startsWith("on_the_fly_test"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -59,7 +61,7 @@ main {
|
||||
}
|
||||
}
|
||||
""").assertSuccess()
|
||||
assertTrue(result.programAst.mainModule.name.startsWith("on_the_fly_test"))
|
||||
assertTrue(result.programAst.toplevelModule.name.startsWith("on_the_fly_test"))
|
||||
val options = determineCompilationOptions(result.programAst, C64Target)
|
||||
assertTrue(options.floats)
|
||||
assertEquals(ZeropageType.DONTUSE, options.zeropage)
|
||||
@ -86,7 +88,7 @@ main {
|
||||
filepath.toFile().writeText(sourceText)
|
||||
val (program, options, importedfiles) = parseImports(filepath, errors, C64Target, emptyList())
|
||||
|
||||
assertEquals(filenameBase, program.mainModule.name)
|
||||
assertEquals(filenameBase, program.toplevelModule.name)
|
||||
assertEquals(1, importedfiles.size, "all imports other than the test source must have been internal resources library files")
|
||||
assertEquals(listOf(
|
||||
internedStringsModuleName,
|
||||
|
@ -5,7 +5,6 @@ import org.junit.jupiter.api.TestInstance
|
||||
import prog8.ast.Module
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.DataType
|
||||
import prog8.ast.base.ParentSentinel
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.expressions.ArrayIndexedExpression
|
||||
@ -13,6 +12,7 @@ import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.expressions.NumericLiteralValue
|
||||
import prog8.ast.expressions.PrefixExpression
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.astprocessing.isInRegularRAMof
|
||||
import prog8.compiler.target.C64Target
|
||||
import prog8.parser.SourceCode
|
||||
import prog8tests.helpers.DummyFunctions
|
||||
@ -29,24 +29,23 @@ class TestMemory {
|
||||
|
||||
var memexpr = NumericLiteralValue.optimalInteger(0x0000, Position.DUMMY)
|
||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
|
||||
memexpr = NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
|
||||
memexpr = NumericLiteralValue.optimalInteger(0x9fff, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
|
||||
memexpr = NumericLiteralValue.optimalInteger(0xc000, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
|
||||
memexpr = NumericLiteralValue.optimalInteger(0xcfff, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -54,20 +53,19 @@ class TestMemory {
|
||||
|
||||
var memexpr = NumericLiteralValue.optimalInteger(0xa000, Position.DUMMY)
|
||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
||||
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||
|
||||
memexpr = NumericLiteralValue.optimalInteger(0xafff, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
||||
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||
|
||||
memexpr = NumericLiteralValue.optimalInteger(0xd000, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
||||
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||
|
||||
memexpr = NumericLiteralValue.optimalInteger(0xffff, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
||||
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -75,15 +73,15 @@ class TestMemory {
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
var target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.VAR)
|
||||
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
target = createTestProgramForMemoryRefViaVar(program, 0xd020, VarDeclType.VAR)
|
||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
||||
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||
target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.CONST)
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
target = createTestProgramForMemoryRefViaVar(program, 0xd020, VarDeclType.CONST)
|
||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
||||
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||
target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.MEMORY)
|
||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
||||
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||
}
|
||||
|
||||
private fun createTestProgramForMemoryRefViaVar(program: Program, address: Int, vartype: VarDeclType): AssignTarget {
|
||||
@ -93,7 +91,7 @@ class TestMemory {
|
||||
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
||||
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
module.linkParents(program.namespace)
|
||||
module.linkIntoProgram(program)
|
||||
return target
|
||||
}
|
||||
|
||||
@ -101,8 +99,7 @@ class TestMemory {
|
||||
fun testInValidRamC64_memory_expression() {
|
||||
val memexpr = PrefixExpression("+", NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
||||
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -114,8 +111,8 @@ class TestMemory {
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
.addModule(module)
|
||||
module.linkParents(program.namespace)
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
module.linkIntoProgram(program)
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -128,8 +125,8 @@ class TestMemory {
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
.addModule(module)
|
||||
module.linkParents(program.namespace)
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
module.linkIntoProgram(program)
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -142,8 +139,8 @@ class TestMemory {
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
.addModule(module)
|
||||
module.linkParents(program.namespace)
|
||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
||||
module.linkIntoProgram(program)
|
||||
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -156,8 +153,8 @@ class TestMemory {
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
.addModule(module)
|
||||
module.linkParents(program.namespace)
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
module.linkIntoProgram(program)
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -171,8 +168,8 @@ class TestMemory {
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
.addModule(module)
|
||||
module.linkParents(program.namespace)
|
||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
||||
module.linkIntoProgram(program)
|
||||
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -186,7 +183,7 @@ class TestMemory {
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||
.addModule(module)
|
||||
module.linkParents(program.namespace)
|
||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
||||
module.linkIntoProgram(program)
|
||||
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
main {
|
||||
str myBar = "main.bar"
|
||||
;foo_bar:
|
||||
; %asminclude "foo_bar.asm" ; FIXME: should be accessible from inside start() but give assembler error. See github issue #62
|
||||
; %asminclude "foo_bar.asm" ; TODO: should be accessible from inside start() but give assembler error. See github issue #62
|
||||
sub start() {
|
||||
txt.print(myBar)
|
||||
txt.print(&foo_bar)
|
||||
|
@ -259,11 +259,12 @@ class Program(val name: String,
|
||||
require(null == _modules.firstOrNull { it.name == module.name })
|
||||
{ "module '${module.name}' already present" }
|
||||
_modules.add(module)
|
||||
module.linkParents(namespace)
|
||||
module.program = this
|
||||
module.linkIntoProgram(this)
|
||||
return this
|
||||
}
|
||||
|
||||
fun removeModule(module: Module) = _modules.remove(module)
|
||||
|
||||
fun moveModuleToFront(module: Module): Program {
|
||||
require(_modules.contains(module))
|
||||
{ "Not a module of this program: '${module.name}'"}
|
||||
@ -285,11 +286,11 @@ class Program(val name: String,
|
||||
}
|
||||
}
|
||||
|
||||
val mainModule: Module // TODO: rename Program.mainModule - it's NOT necessarily the one containing the main *block*!
|
||||
val toplevelModule: Module
|
||||
get() = modules.first { it.name!=internedStringsModuleName }
|
||||
|
||||
val definedLoadAddress: Int
|
||||
get() = mainModule.loadAddress
|
||||
get() = toplevelModule.loadAddress
|
||||
|
||||
var actualLoadAddress: Int = 0
|
||||
private val internedStringsUnique = mutableMapOf<Pair<String, Boolean>, List<String>>()
|
||||
@ -342,9 +343,8 @@ class Program(val name: String,
|
||||
require(node is Module && replacement is Module)
|
||||
val idx = _modules.indexOfFirst { it===node }
|
||||
_modules[idx] = replacement
|
||||
replacement.parent = this // TODO: why not replacement.program = this; replacement.linkParents(namespace)?!
|
||||
replacement.linkIntoProgram(this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open class Module(final override var statements: MutableList<Statement>,
|
||||
@ -370,6 +370,11 @@ open class Module(final override var statements: MutableList<Statement>,
|
||||
statements.forEach {it.linkParents(this)}
|
||||
}
|
||||
|
||||
fun linkIntoProgram(program: Program) {
|
||||
this.program = program
|
||||
linkParents(program.namespace)
|
||||
}
|
||||
|
||||
override val definingScope: INameScope
|
||||
get() = program.namespace
|
||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||
|
@ -301,7 +301,7 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
|
||||
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
||||
|
||||
override fun referencesIdentifier(vararg scopedName: String) = expression.referencesIdentifier(*scopedName)
|
||||
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(type)
|
||||
override fun inferType(program: Program) = InferredTypes.knownFor(type)
|
||||
override fun constValue(program: Program): NumericLiteralValue? {
|
||||
val cv = expression.constValue(program) ?: return null
|
||||
val cast = cv.cast(type)
|
||||
@ -334,7 +334,7 @@ data class AddressOf(var identifier: IdentifierReference, override val position:
|
||||
|
||||
override fun constValue(program: Program): NumericLiteralValue? = null
|
||||
override fun referencesIdentifier(vararg scopedName: String) = false
|
||||
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(DataType.UWORD)
|
||||
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UWORD)
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
||||
}
|
||||
@ -359,7 +359,7 @@ class DirectMemoryRead(var addressExpression: Expression, override val position:
|
||||
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
||||
|
||||
override fun referencesIdentifier(vararg scopedName: String) = false
|
||||
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(DataType.UBYTE)
|
||||
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UBYTE)
|
||||
override fun constValue(program: Program): NumericLiteralValue? = null
|
||||
|
||||
override fun toString(): String {
|
||||
@ -422,7 +422,7 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
|
||||
|
||||
override fun toString(): String = "NumericLiteral(${type.name}:$number)"
|
||||
|
||||
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(type)
|
||||
override fun inferType(program: Program) = InferredTypes.knownFor(type)
|
||||
|
||||
override fun hashCode(): Int = Objects.hash(type, number)
|
||||
|
||||
@ -518,7 +518,7 @@ class CharLiteral(val value: Char,
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
|
||||
override fun toString(): String = "'${escape(value.toString())}'"
|
||||
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(DataType.UNDEFINED) // FIXME: CharLiteral.inferType
|
||||
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UBYTE)
|
||||
operator fun compareTo(other: CharLiteral): Int = value.compareTo(other.value)
|
||||
override fun hashCode(): Int = Objects.hash(value, altEncoding)
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@ -550,7 +550,7 @@ class StringLiteralValue(val value: String,
|
||||
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
||||
|
||||
override fun toString(): String = "'${escape(value)}'"
|
||||
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(DataType.STR)
|
||||
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.STR)
|
||||
operator fun compareTo(other: StringLiteralValue): Int = value.compareTo(other.value)
|
||||
override fun hashCode(): Int = Objects.hash(value, altEncoding)
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
@ -31,12 +31,9 @@ object Prog8Parser {
|
||||
parser.addErrorListener(antlrErrorListener)
|
||||
|
||||
val parseTree = parser.module()
|
||||
|
||||
val module = ParsedModule(src)
|
||||
|
||||
// .linkParents called in ParsedModule.add
|
||||
parseTree.directive().forEach { module.add(it.toAst()) }
|
||||
// TODO: remove Encoding
|
||||
parseTree.block().forEach { module.add(it.toAst(module.isLibrary)) }
|
||||
|
||||
return module
|
||||
@ -95,19 +92,22 @@ object Prog8Parser {
|
||||
private class AntlrErrorListener(val src: SourceCode): BaseErrorListener() {
|
||||
override fun syntaxError(recognizer: Recognizer<*, *>?, offendingSymbol: Any?, line: Int, charPositionInLine: Int, msg: String, e: RecognitionException?) {
|
||||
if (e == null) {
|
||||
TODO("no RecognitionException - create your own ParseError")
|
||||
//throw ParseError()
|
||||
throw ParseError(msg, Position(src.origin, line, charPositionInLine, charPositionInLine), RuntimeException("parse error"))
|
||||
} else {
|
||||
if(e.offendingToken==null) {
|
||||
throw ParseError(msg, Position(src.origin, line, charPositionInLine, charPositionInLine), e)
|
||||
} else {
|
||||
throw ParseError(msg, e.getPosition(src.origin), e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun RecognitionException.getPosition(file: String): Position {
|
||||
val offending = this.offendingToken
|
||||
val line = offending.line
|
||||
val beginCol = offending.charPositionInLine
|
||||
val endCol = beginCol + offending.stopIndex - offending.startIndex // TODO: point to col *after* token?
|
||||
val endCol = beginCol + offending.stopIndex - offending.startIndex // TODO: point to col *after* token? / why, what's wrong with endCol being inclusive
|
||||
return Position(file, line, beginCol, endCol)
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Module
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.expressions.CharLiteral
|
||||
@ -17,12 +18,11 @@ import prog8.parser.SourceCode
|
||||
import prog8tests.helpers.assumeNotExists
|
||||
import prog8tests.helpers.assumeReadableFile
|
||||
import prog8tests.helpers.fixturesDir
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.name
|
||||
import kotlin.io.path.nameWithoutExtension
|
||||
import kotlin.test.assertContains
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertIs
|
||||
import kotlin.test.*
|
||||
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
@ -219,7 +219,7 @@ class TestProg8Parser {
|
||||
val module = parseModule(SourceCode.Text(srcText))
|
||||
|
||||
// Note: assertContains has *actual* as first param
|
||||
assertContains(module.name, Regex("^<String@[0-9a-f]+>$"))
|
||||
assertContains(module.name, Regex("^<String@[0-9a-f\\-]+>$"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -289,7 +289,7 @@ class TestProg8Parser {
|
||||
try {
|
||||
parseModule(SourceCode.Text(srcText))
|
||||
} catch (e: ParseError) {
|
||||
assertPosition(e.position, Regex("^<String@[0-9a-f]+>$"), 1, 4, 4)
|
||||
assertPosition(e.position, Regex("^<String@[0-9a-f\\-]+>$"), 1, 4, 4)
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,7 +312,7 @@ class TestProg8Parser {
|
||||
}
|
||||
""".trimIndent()
|
||||
val module = parseModule(SourceCode.Text(srcText))
|
||||
assertPositionOf(module, Regex("^<String@[0-9a-f]+>$"), 1, 0) // TODO: endCol wrong
|
||||
assertPositionOf(module, Regex("^<String@[0-9a-f\\-]+>$"), 1, 0) // TODO: endCol wrong
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -330,9 +330,9 @@ class TestProg8Parser {
|
||||
val mpf = module.position.file
|
||||
assertPositionOf(module, SourceCode.relative(path).toString(), 1, 0) // TODO: endCol wrong
|
||||
val mainBlock = module.statements.filterIsInstance<Block>()[0]
|
||||
assertPositionOf(mainBlock, mpf, 1, 0) // TODO: endCol wrong!
|
||||
assertPositionOf(mainBlock, mpf, 2, 0) // TODO: endCol wrong!
|
||||
val startSub = mainBlock.statements.filterIsInstance<Subroutine>()[0]
|
||||
assertPositionOf(startSub, mpf, 2, 4) // TODO: endCol wrong!
|
||||
assertPositionOf(startSub, mpf, 3, 4) // TODO: endCol wrong!
|
||||
}
|
||||
|
||||
|
||||
@ -378,6 +378,59 @@ class TestProg8Parser {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class PositionFile {
|
||||
@Test
|
||||
fun `isn't absolute for filesystem paths`() {
|
||||
val path = assumeReadableFile(fixturesDir, "simple_main.p8")
|
||||
val module = parseModule(SourceCode.File(path))
|
||||
assertSomethingForAllNodes(module) {
|
||||
assertFalse(Path(it.position.file).isAbsolute)
|
||||
assertTrue(Path(it.position.file).isRegularFile())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `is mangled string id for string sources`()
|
||||
{
|
||||
val srcText="""
|
||||
%zeropage basicsafe
|
||||
main {
|
||||
sub start() {
|
||||
ubyte aa=99
|
||||
aa++
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
val module = parseModule(SourceCode.Text(srcText))
|
||||
assertSomethingForAllNodes(module) {
|
||||
assertTrue(it.position.file.startsWith(SourceCode.stringSourcePrefix))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `is library prefixed path for resources`()
|
||||
{
|
||||
val resource = SourceCode.Resource("prog8lib/math.p8")
|
||||
val module = parseModule(resource)
|
||||
assertSomethingForAllNodes(module) {
|
||||
assertTrue(it.position.file.startsWith(SourceCode.libraryFilePrefix))
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
} }
|
||||
|
||||
@Nested
|
||||
inner class CharLiterals {
|
||||
|
||||
|
@ -1,30 +1,32 @@
|
||||
package prog8tests
|
||||
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.core.StringStartsWith
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import prog8.parser.SourceCode
|
||||
import prog8.parser.SourceCode.Companion.libraryFilePrefix
|
||||
import prog8tests.helpers.*
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.test.assertContains
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.*
|
||||
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class TestSourceCode {
|
||||
|
||||
@Test
|
||||
fun testFactoryMethod_Of() {
|
||||
fun testFromString() {
|
||||
val text = """
|
||||
main { }
|
||||
""".trimIndent()
|
||||
"""
|
||||
val src = SourceCode.Text(text)
|
||||
val actualText = src.getCharStream().toString()
|
||||
|
||||
assertContains(src.origin, Regex("^<String@[0-9a-f]+>$"))
|
||||
assertContains(src.origin, Regex("^<String@[0-9a-f\\-]+>$"))
|
||||
assertEquals(text, actualText)
|
||||
assertFalse(src.isFromResources)
|
||||
assertFalse(src.isFromFilesystem)
|
||||
assertThat(src.toString(), StringStartsWith("prog8.parser.SourceCode"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -54,6 +56,8 @@ class TestSourceCode {
|
||||
val expectedOrigin = SourceCode.relative(path).toString()
|
||||
assertEquals(expectedOrigin, src.origin)
|
||||
assertEquals(path.toFile().readText(), src.asString())
|
||||
assertFalse(src.isFromResources)
|
||||
assertTrue(src.isFromFilesystem)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -75,6 +79,8 @@ class TestSourceCode {
|
||||
|
||||
assertEquals("$libraryFilePrefix/$pathString", src.origin)
|
||||
assertEquals(srcFile.readText(), src.asString())
|
||||
assertTrue(src.isFromResources)
|
||||
assertFalse(src.isFromFilesystem)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -50,12 +50,12 @@ class ProgramTests {
|
||||
assertSame(program, m1.program)
|
||||
assertSame(program.namespace, m1.parent)
|
||||
|
||||
assertFailsWith<IllegalArgumentException> { program.addModule(m1) }
|
||||
.let { assertThat(it.message, containsString(m1.name)) }
|
||||
assertThat("module may not occur multiple times",
|
||||
assertFailsWith<IllegalArgumentException> { program.addModule(m1) }.message, containsString(m1.name))
|
||||
|
||||
val m2 = Module(mutableListOf(), m1.position, m1.source)
|
||||
assertFailsWith<IllegalArgumentException> { program.addModule(m2) }
|
||||
.let { assertThat(it.message, containsString(m2.name)) }
|
||||
assertThat("other module but with same name may not occur multiple times",
|
||||
assertFailsWith<IllegalArgumentException> { program.addModule(m2) }.message, containsString(m2.name))
|
||||
}
|
||||
}
|
||||
|
||||
|
3
compilerAst/test/fixtures/simple_main.p8
vendored
3
compilerAst/test/fixtures/simple_main.p8
vendored
@ -1,4 +1,7 @@
|
||||
%zeropage basicsafe
|
||||
main {
|
||||
sub start() {
|
||||
ubyte aa=99
|
||||
aa++
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ Blocked by Commander-x16 v39 release
|
||||
|
||||
Future
|
||||
^^^^^^
|
||||
- get rid of all TODO's and FIXME's in the code
|
||||
- get rid of all TODO's in the code
|
||||
- improve testability further, add more tests, address more questions/issues from the testability discussions.
|
||||
- replace certain uses of inferredType.getOr(DataType.UNDEFINED) by i.getOrElse({ errorhandler })
|
||||
- see if we can remove more "[InferredType].getOr(DataType.UNDEFINED)"
|
||||
|
@ -22,7 +22,7 @@ main {
|
||||
|
||||
; Not yet implemented in ROM: cx16.FB_set_palette(&colors, 0, len(colors)*3)
|
||||
palette.set_rgb(&colors, len(colors))
|
||||
cx16.screen_set_mode(128) ; low-res bitmap 256 colors
|
||||
void cx16.screen_set_mode(128) ; low-res bitmap 256 colors
|
||||
cx16.FB_init()
|
||||
cx16.VERA_DC_VSCALE = 0 ; display trick spoiler.......: stretch display all the way to the bottom
|
||||
cx16.set_rasterirq(&irq.irqhandler, 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user