mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 03:54:27 +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.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.ast.walk.IAstVisitor
|
import prog8.ast.walk.IAstVisitor
|
||||||
|
import prog8.compiler.astprocessing.isInRegularRAMof
|
||||||
import prog8.compiler.target.ICompilationTarget
|
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.
|
// But it can only be done if the target variable IS NOT OCCURRING AS AN OPERAND ITSELF.
|
||||||
if(!assignment.isAugmentable
|
if(!assignment.isAugmentable
|
||||||
&& assignment.target.identifier != null
|
&& assignment.target.identifier != null
|
||||||
&& compTarget.isInRegularRAM(assignment.target, program)) {
|
&& assignment.target.isInRegularRAMof(compTarget.machine)) {
|
||||||
val binExpr = assignment.value as? BinaryExpression
|
val binExpr = assignment.value as? BinaryExpression
|
||||||
if (binExpr != null && binExpr.operator !in comparisonOperators) {
|
if (binExpr != null && binExpr.operator !in comparisonOperators) {
|
||||||
if (binExpr.left !is BinaryExpression) {
|
if (binExpr.left !is BinaryExpression) {
|
||||||
|
@ -215,12 +215,12 @@ fun parseImports(filepath: Path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget): CompilationOptions {
|
fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget): CompilationOptions {
|
||||||
val mainModule = program.mainModule
|
val toplevelModule = program.toplevelModule
|
||||||
val outputDirective = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" } as? Directive)
|
val outputDirective = (toplevelModule.statements.singleOrNull { it is Directive && it.directive == "%output" } as? Directive)
|
||||||
val launcherDirective = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" } as? Directive)
|
val launcherDirective = (toplevelModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" } as? Directive)
|
||||||
val outputTypeStr = outputDirective?.args?.single()?.name?.uppercase()
|
val outputTypeStr = outputDirective?.args?.single()?.name?.uppercase()
|
||||||
val launcherTypeStr = launcherDirective?.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()
|
as? Directive)?.args?.single()?.name?.uppercase()
|
||||||
val allOptions = program.modules.flatMap { it.statements }.filter { it is Directive && it.directive == "%option" }
|
val allOptions = program.modules.flatMap { it.statements }.filter { it is Directive && it.directive == "%option" }
|
||||||
.flatMap { (it as Directive).args }.toSet()
|
.flatMap { (it as Directive).args }.toSet()
|
||||||
@ -242,7 +242,7 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget
|
|||||||
zpType = ZeropageType.BASICSAFE
|
zpType = ZeropageType.BASICSAFE
|
||||||
}
|
}
|
||||||
|
|
||||||
val zpReserved = mainModule.statements
|
val zpReserved = toplevelModule.statements
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it is Directive && it.directive == "%zpreserved" }
|
.filter { it is Directive && it.directive == "%zpreserved" }
|
||||||
.map { (it as Directive).args }
|
.map { (it as Directive).args }
|
||||||
@ -280,6 +280,8 @@ private fun processAst(programAst: Program, errors: IErrorReporter, compilerOpti
|
|||||||
programAst.checkIdentifiers(errors, compilerOptions)
|
programAst.checkIdentifiers(errors, compilerOptions)
|
||||||
errors.report()
|
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
|
// 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)
|
programAst.charLiteralsToUByteLiterals(errors, compilerOptions.compTarget)
|
||||||
errors.report()
|
errors.report()
|
||||||
programAst.constantFold(errors, compilerOptions.compTarget)
|
programAst.constantFold(errors, compilerOptions.compTarget)
|
||||||
|
@ -35,13 +35,17 @@ class ModuleImporter(private val program: Program,
|
|||||||
file = filePath.normalize().toFile(),
|
file = filePath.normalize().toFile(),
|
||||||
reason = "searched in $searchIn"))
|
reason = "searched in $searchIn"))
|
||||||
1 -> candidates.first()
|
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)"
|
val logMsg = "importing '${filePath.nameWithoutExtension}' (from file $srcPath)"
|
||||||
println(logMsg)
|
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? {
|
fun importLibraryModule(name: String): Module? {
|
||||||
@ -51,20 +55,24 @@ class ModuleImporter(private val program: Program,
|
|||||||
return executeImportDirective(import, null)
|
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)
|
val moduleAst = Prog8Parser.parseModule(src)
|
||||||
program.addModule(moduleAst)
|
program.addModule(moduleAst)
|
||||||
|
|
||||||
// accept additional imports
|
// accept additional imports
|
||||||
val lines = moduleAst.statements.toMutableList()
|
try {
|
||||||
lines.asSequence()
|
val lines = moduleAst.statements.toMutableList()
|
||||||
|
lines.asSequence()
|
||||||
.mapIndexed { i, it -> i to it }
|
.mapIndexed { i, it -> i to it }
|
||||||
.filter { (it.second as? Directive)?.directive == "%import" }
|
.filter { (it.second as? Directive)?.directive == "%import" }
|
||||||
.forEach { executeImportDirective(it.second as Directive, moduleAst) }
|
.forEach { executeImportDirective(it.second as Directive, moduleAst) }
|
||||||
|
moduleAst.statements = lines
|
||||||
moduleAst.statements = lines
|
return moduleAst
|
||||||
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? {
|
private fun executeImportDirective(import: Directive, importingModule: Module?): Module? {
|
||||||
@ -104,7 +112,8 @@ class ModuleImporter(private val program: Program,
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
removeDirectivesFromImportedModule(importedModule)
|
if(importedModule!=null)
|
||||||
|
removeDirectivesFromImportedModule(importedModule)
|
||||||
return importedModule
|
return importedModule
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +142,7 @@ class ModuleImporter(private val program: Program,
|
|||||||
} else {
|
} else {
|
||||||
val dropCurDir = if(sourcePaths.isNotEmpty() && sourcePaths[0].name == ".") 1 else 0
|
val dropCurDir = if(sourcePaths.isNotEmpty() && sourcePaths[0].name == ".") 1 else 0
|
||||||
sourcePaths.drop(dropCurDir) +
|
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(importingModule.position.file).parent ?: Path("")) +
|
||||||
listOf(Path(".", "prog8lib"))
|
listOf(Path(".", "prog8lib"))
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import prog8.compiler.ZeropageType
|
|||||||
import prog8.compiler.functions.BuiltinFunctions
|
import prog8.compiler.functions.BuiltinFunctions
|
||||||
import prog8.compiler.functions.builtinFunctionReturnType
|
import prog8.compiler.functions.builtinFunctionReturnType
|
||||||
import prog8.compiler.target.ICompilationTarget
|
import prog8.compiler.target.ICompilationTarget
|
||||||
import prog8.parser.SourceCode
|
|
||||||
import java.io.CharConversionException
|
import java.io.CharConversionException
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -46,7 +45,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
|
|
||||||
if(compilerOptions.floats) {
|
if(compilerOptions.floats) {
|
||||||
if (compilerOptions.zeropage !in arrayOf(ZeropageType.FLOATSAFE, ZeropageType.BASICSAFE, ZeropageType.DONTUSE ))
|
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)
|
super.visit(program)
|
||||||
|
@ -3,11 +3,9 @@ package prog8.compiler.astprocessing
|
|||||||
import prog8.ast.Node
|
import prog8.ast.Node
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.FatalAstException
|
import prog8.ast.base.VarDeclType
|
||||||
import prog8.ast.expressions.CharLiteral
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
import prog8.ast.statements.AssignTarget
|
||||||
import prog8.ast.expressions.RangeExpr
|
|
||||||
import prog8.ast.expressions.StringLiteralValue
|
|
||||||
import prog8.ast.statements.Directive
|
import prog8.ast.statements.Directive
|
||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
@ -16,6 +14,7 @@ import prog8.compiler.CompilationOptions
|
|||||||
import prog8.compiler.IErrorReporter
|
import prog8.compiler.IErrorReporter
|
||||||
import prog8.compiler.IStringEncoding
|
import prog8.compiler.IStringEncoding
|
||||||
import prog8.compiler.target.ICompilationTarget
|
import prog8.compiler.target.ICompilationTarget
|
||||||
|
import prog8.compiler.target.IMachineDefinition
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
|
||||||
@ -127,26 +126,6 @@ internal fun Program.checkIdentifiers(errors: IErrorReporter, options: Compilati
|
|||||||
lit2decl.visit(this)
|
lit2decl.visit(this)
|
||||||
lit2decl.applyModifications()
|
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) {
|
internal fun Program.variousCleanups(program: Program, errors: IErrorReporter) {
|
||||||
@ -186,3 +165,47 @@ internal fun Program.moveMainAndStartToFirst() {
|
|||||||
modules[0].statements.add(0, directive)
|
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
|
val machine: IMachineDefinition
|
||||||
override fun encodeString(str: String, altEncoding: Boolean): List<Short>
|
override fun encodeString(str: String, altEncoding: Boolean): List<Short>
|
||||||
override fun decodeString(bytes: List<Short>, altEncoding: Boolean): String
|
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.statements.Assignment
|
||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
|
import prog8.compiler.astprocessing.isInRegularRAMof
|
||||||
import prog8.compiler.target.ICompilationTarget
|
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)
|
if(assignment.target isSameAs binExpr.left || assignment.target isSameAs binExpr.right)
|
||||||
return noModifications
|
return noModifications
|
||||||
|
|
||||||
@ -77,9 +78,9 @@ X = BinExpr X = LeftExpr
|
|||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isSimpleTarget(target: AssignTarget, program: Program) =
|
private fun isSimpleTarget(target: AssignTarget) =
|
||||||
if (target.identifier!=null || target.memoryAddress!=null)
|
if (target.identifier!=null || target.memoryAddress!=null)
|
||||||
compTarget.isInRegularRAM(target, program)
|
target.isInRegularRAMof(compTarget.machine)
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import prog8.ast.statements.*
|
|||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.compiler.IErrorReporter
|
import prog8.compiler.IErrorReporter
|
||||||
|
import prog8.compiler.astprocessing.isInRegularRAMof
|
||||||
import prog8.compiler.target.ICompilationTarget
|
import prog8.compiler.target.ICompilationTarget
|
||||||
|
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ internal class UnusedCodeRemover(private val program: Program,
|
|||||||
val assign1 = stmtPairs[0] as? Assignment
|
val assign1 = stmtPairs[0] as? Assignment
|
||||||
val assign2 = stmtPairs[1] as? Assignment
|
val assign2 = stmtPairs[1] as? Assignment
|
||||||
if (assign1 != null && assign2 != null && !assign2.isAugmentable) {
|
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())))
|
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!
|
// only remove the second assignment if its value is a simple expression!
|
||||||
when(assign2.value) {
|
when(assign2.value) {
|
||||||
|
@ -71,7 +71,7 @@ locallabel:
|
|||||||
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
module.linkParents(program.namespace)
|
module.linkIntoProgram(program)
|
||||||
return program
|
return program
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test
|
|||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
import org.junit.jupiter.api.Disabled
|
import org.junit.jupiter.api.Disabled
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
|
import prog8.ast.internedStringsModuleName
|
||||||
import prog8.compiler.IErrorReporter
|
import prog8.compiler.IErrorReporter
|
||||||
import prog8.compiler.ModuleImporter
|
import prog8.compiler.ModuleImporter
|
||||||
import prog8.parser.ParseError
|
import prog8.parser.ParseError
|
||||||
@ -207,7 +208,6 @@ class TestModuleImporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled("TODO: module that imports faulty module should not be kept in Program.modules")
|
|
||||||
fun testImportingFileWithSyntaxError_twice() {
|
fun testImportingFileWithSyntaxError_twice() {
|
||||||
doTestImportingFileWithSyntaxError(2)
|
doTestImportingFileWithSyntaxError(2)
|
||||||
}
|
}
|
||||||
@ -227,7 +227,8 @@ class TestModuleImporter {
|
|||||||
assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6))
|
assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6))
|
||||||
assertThat("endCol; should be 0-based", it.position.endCol, 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)
|
val result2 = importer.importLibraryModule(filenameWithExt)
|
||||||
assertThat(count[n] + " call / with .p8 extension", result2, Is(nullValue()))
|
assertThat(count[n] + " call / with .p8 extension", result2, Is(nullValue()))
|
||||||
assertFalse(importer.errors.noErrors(), count[n] + " call / with .p8 extension")
|
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()
|
errors.report()
|
||||||
assertThat(program.modules.size, equalTo(1))
|
assertThat(program.modules.size, equalTo(1))
|
||||||
}
|
}
|
||||||
@ -303,7 +304,8 @@ class TestModuleImporter {
|
|||||||
assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6))
|
assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6))
|
||||||
assertThat("endCol; should be 0-based", it.position.endCol, 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()
|
importer.errors.report()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,7 +316,6 @@ class TestModuleImporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled("TODO: module that imports faulty module should not be kept in Program.modules")
|
|
||||||
fun testImportingFileWithSyntaxError_twice() {
|
fun testImportingFileWithSyntaxError_twice() {
|
||||||
doTestImportingFileWithSyntaxError(2)
|
doTestImportingFileWithSyntaxError(2)
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ class TestCompilerOnCharLit {
|
|||||||
"char literal should have been replaced by ubyte literal")
|
"char literal should have been replaced by ubyte literal")
|
||||||
val arg = funCall.args[0] as NumericLiteralValue
|
val arg = funCall.args[0] as NumericLiteralValue
|
||||||
assertEquals(DataType.UBYTE, arg.type)
|
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
|
@Test
|
||||||
@ -77,7 +77,7 @@ class TestCompilerOnCharLit {
|
|||||||
"char literal should have been replaced by ubyte literal")
|
"char literal should have been replaced by ubyte literal")
|
||||||
val initializerValue = decl.value as NumericLiteralValue
|
val initializerValue = decl.value as NumericLiteralValue
|
||||||
assertEquals(DataType.UBYTE, initializerValue.type)
|
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
|
@Test
|
||||||
@ -105,12 +105,12 @@ class TestCompilerOnCharLit {
|
|||||||
assertEquals(DataType.UBYTE, decl.datatype)
|
assertEquals(DataType.UBYTE, decl.datatype)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
platform.encodeString("\n", false)[0],
|
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 -> {
|
is NumericLiteralValue -> {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
platform.encodeString("\n", false)[0],
|
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
|
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,
|
* They are not really unit tests, but rather tests of the whole process,
|
||||||
* from source file loading all the way through to running 64tass.
|
* 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)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
class TestCompilerOnExamples {
|
class TestCompilerOnExamples {
|
||||||
private val examplesDir = assumeDirectory(workingDir, "../examples")
|
private val examplesDir = assumeDirectory(workingDir, "../examples")
|
||||||
@ -49,7 +49,7 @@ class TestCompilerOnExamples {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
// @Disabled
|
// @Disabled("disable to save some time")
|
||||||
fun bothCx16AndC64() = mapCombinations(
|
fun bothCx16AndC64() = mapCombinations(
|
||||||
dim1 = listOf(
|
dim1 = listOf(
|
||||||
"animals",
|
"animals",
|
||||||
@ -80,7 +80,7 @@ class TestCompilerOnExamples {
|
|||||||
)
|
)
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
// @Disabled
|
// @Disabled("disable to save some time")
|
||||||
fun onlyC64() = mapCombinations(
|
fun onlyC64() = mapCombinations(
|
||||||
dim1 = listOf(
|
dim1 = listOf(
|
||||||
"balloonflight",
|
"balloonflight",
|
||||||
@ -99,7 +99,7 @@ class TestCompilerOnExamples {
|
|||||||
)
|
)
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
// @Disabled
|
// @Disabled("disable to save some time")
|
||||||
fun onlyCx16() = mapCombinations(
|
fun onlyCx16() = mapCombinations(
|
||||||
dim1 = listOf(
|
dim1 = listOf(
|
||||||
"vtui/testvtui",
|
"vtui/testvtui",
|
||||||
|
@ -19,7 +19,7 @@ import kotlin.test.assertTrue
|
|||||||
class TestImportedModulesOrderAndOptions {
|
class TestImportedModulesOrderAndOptions {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testImportedModuleOrderCorrect() {
|
fun testImportedModuleOrderAndMainModuleCorrect() {
|
||||||
val result = compileText(C64Target, false, """
|
val result = compileText(C64Target, false, """
|
||||||
%import textio
|
%import textio
|
||||||
%import floats
|
%import floats
|
||||||
@ -30,7 +30,7 @@ main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
""").assertSuccess()
|
""").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 }
|
val moduleNames = result.programAst.modules.map { it.name }
|
||||||
assertTrue(moduleNames[0].startsWith("on_the_fly_test"), "main module must be first")
|
assertTrue(moduleNames[0].startsWith("on_the_fly_test"), "main module must be first")
|
||||||
@ -43,6 +43,8 @@ main {
|
|||||||
"math",
|
"math",
|
||||||
"prog8_lib"
|
"prog8_lib"
|
||||||
), moduleNames.drop(1), "module order in parse tree")
|
), moduleNames.drop(1), "module order in parse tree")
|
||||||
|
|
||||||
|
assertTrue(result.programAst.toplevelModule.name.startsWith("on_the_fly_test"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -59,7 +61,7 @@ main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
""").assertSuccess()
|
""").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)
|
val options = determineCompilationOptions(result.programAst, C64Target)
|
||||||
assertTrue(options.floats)
|
assertTrue(options.floats)
|
||||||
assertEquals(ZeropageType.DONTUSE, options.zeropage)
|
assertEquals(ZeropageType.DONTUSE, options.zeropage)
|
||||||
@ -86,7 +88,7 @@ main {
|
|||||||
filepath.toFile().writeText(sourceText)
|
filepath.toFile().writeText(sourceText)
|
||||||
val (program, options, importedfiles) = parseImports(filepath, errors, C64Target, emptyList())
|
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(1, importedfiles.size, "all imports other than the test source must have been internal resources library files")
|
||||||
assertEquals(listOf(
|
assertEquals(listOf(
|
||||||
internedStringsModuleName,
|
internedStringsModuleName,
|
||||||
|
@ -5,7 +5,6 @@ import org.junit.jupiter.api.TestInstance
|
|||||||
import prog8.ast.Module
|
import prog8.ast.Module
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.ParentSentinel
|
|
||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
import prog8.ast.base.VarDeclType
|
import prog8.ast.base.VarDeclType
|
||||||
import prog8.ast.expressions.ArrayIndexedExpression
|
import prog8.ast.expressions.ArrayIndexedExpression
|
||||||
@ -13,6 +12,7 @@ import prog8.ast.expressions.IdentifierReference
|
|||||||
import prog8.ast.expressions.NumericLiteralValue
|
import prog8.ast.expressions.NumericLiteralValue
|
||||||
import prog8.ast.expressions.PrefixExpression
|
import prog8.ast.expressions.PrefixExpression
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
|
import prog8.compiler.astprocessing.isInRegularRAMof
|
||||||
import prog8.compiler.target.C64Target
|
import prog8.compiler.target.C64Target
|
||||||
import prog8.parser.SourceCode
|
import prog8.parser.SourceCode
|
||||||
import prog8tests.helpers.DummyFunctions
|
import prog8tests.helpers.DummyFunctions
|
||||||
@ -29,24 +29,23 @@ class TestMemory {
|
|||||||
|
|
||||||
var memexpr = NumericLiteralValue.optimalInteger(0x0000, Position.DUMMY)
|
var memexpr = NumericLiteralValue.optimalInteger(0x0000, Position.DUMMY)
|
||||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
|
||||||
|
|
||||||
memexpr = NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY)
|
memexpr = NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), 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)
|
memexpr = NumericLiteralValue.optimalInteger(0x9fff, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), 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)
|
memexpr = NumericLiteralValue.optimalInteger(0xc000, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), 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)
|
memexpr = NumericLiteralValue.optimalInteger(0xcfff, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -54,20 +53,19 @@ class TestMemory {
|
|||||||
|
|
||||||
var memexpr = NumericLiteralValue.optimalInteger(0xa000, Position.DUMMY)
|
var memexpr = NumericLiteralValue.optimalInteger(0xa000, Position.DUMMY)
|
||||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
|
||||||
|
|
||||||
memexpr = NumericLiteralValue.optimalInteger(0xafff, Position.DUMMY)
|
memexpr = NumericLiteralValue.optimalInteger(0xafff, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), 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)
|
memexpr = NumericLiteralValue.optimalInteger(0xd000, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), 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)
|
memexpr = NumericLiteralValue.optimalInteger(0xffff, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -75,15 +73,15 @@ class TestMemory {
|
|||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
var target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.VAR)
|
var target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.VAR)
|
||||||
|
|
||||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||||
target = createTestProgramForMemoryRefViaVar(program, 0xd020, VarDeclType.VAR)
|
target = createTestProgramForMemoryRefViaVar(program, 0xd020, VarDeclType.VAR)
|
||||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||||
target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.CONST)
|
target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.CONST)
|
||||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||||
target = createTestProgramForMemoryRefViaVar(program, 0xd020, VarDeclType.CONST)
|
target = createTestProgramForMemoryRefViaVar(program, 0xd020, VarDeclType.CONST)
|
||||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||||
target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.MEMORY)
|
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 {
|
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 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 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"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
module.linkParents(program.namespace)
|
module.linkIntoProgram(program)
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +99,7 @@ class TestMemory {
|
|||||||
fun testInValidRamC64_memory_expression() {
|
fun testInValidRamC64_memory_expression() {
|
||||||
val memexpr = PrefixExpression("+", NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY)
|
val memexpr = PrefixExpression("+", NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY)
|
||||||
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -114,8 +111,8 @@ class TestMemory {
|
|||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
module.linkParents(program.namespace)
|
module.linkIntoProgram(program)
|
||||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -128,8 +125,8 @@ class TestMemory {
|
|||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
module.linkParents(program.namespace)
|
module.linkIntoProgram(program)
|
||||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -142,8 +139,8 @@ class TestMemory {
|
|||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
module.linkParents(program.namespace)
|
module.linkIntoProgram(program)
|
||||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -156,8 +153,8 @@ class TestMemory {
|
|||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
module.linkParents(program.namespace)
|
module.linkIntoProgram(program)
|
||||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -171,8 +168,8 @@ class TestMemory {
|
|||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
module.linkParents(program.namespace)
|
module.linkIntoProgram(program)
|
||||||
assertTrue(C64Target.isInRegularRAM(target, program))
|
assertTrue(target.isInRegularRAMof(C64Target.machine))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -186,7 +183,7 @@ class TestMemory {
|
|||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
module.linkParents(program.namespace)
|
module.linkIntoProgram(program)
|
||||||
assertFalse(C64Target.isInRegularRAM(target, program))
|
assertFalse(target.isInRegularRAMof(C64Target.machine))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
main {
|
main {
|
||||||
str myBar = "main.bar"
|
str myBar = "main.bar"
|
||||||
;foo_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() {
|
sub start() {
|
||||||
txt.print(myBar)
|
txt.print(myBar)
|
||||||
txt.print(&foo_bar)
|
txt.print(&foo_bar)
|
||||||
|
@ -259,11 +259,12 @@ class Program(val name: String,
|
|||||||
require(null == _modules.firstOrNull { it.name == module.name })
|
require(null == _modules.firstOrNull { it.name == module.name })
|
||||||
{ "module '${module.name}' already present" }
|
{ "module '${module.name}' already present" }
|
||||||
_modules.add(module)
|
_modules.add(module)
|
||||||
module.linkParents(namespace)
|
module.linkIntoProgram(this)
|
||||||
module.program = this
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun removeModule(module: Module) = _modules.remove(module)
|
||||||
|
|
||||||
fun moveModuleToFront(module: Module): Program {
|
fun moveModuleToFront(module: Module): Program {
|
||||||
require(_modules.contains(module))
|
require(_modules.contains(module))
|
||||||
{ "Not a module of this program: '${module.name}'"}
|
{ "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 }
|
get() = modules.first { it.name!=internedStringsModuleName }
|
||||||
|
|
||||||
val definedLoadAddress: Int
|
val definedLoadAddress: Int
|
||||||
get() = mainModule.loadAddress
|
get() = toplevelModule.loadAddress
|
||||||
|
|
||||||
var actualLoadAddress: Int = 0
|
var actualLoadAddress: Int = 0
|
||||||
private val internedStringsUnique = mutableMapOf<Pair<String, Boolean>, List<String>>()
|
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)
|
require(node is Module && replacement is Module)
|
||||||
val idx = _modules.indexOfFirst { it===node }
|
val idx = _modules.indexOfFirst { it===node }
|
||||||
_modules[idx] = replacement
|
_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>,
|
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)}
|
statements.forEach {it.linkParents(this)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun linkIntoProgram(program: Program) {
|
||||||
|
this.program = program
|
||||||
|
linkParents(program.namespace)
|
||||||
|
}
|
||||||
|
|
||||||
override val definingScope: INameScope
|
override val definingScope: INameScope
|
||||||
get() = program.namespace
|
get() = program.namespace
|
||||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
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 accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
||||||
|
|
||||||
override fun referencesIdentifier(vararg scopedName: String) = expression.referencesIdentifier(*scopedName)
|
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? {
|
override fun constValue(program: Program): NumericLiteralValue? {
|
||||||
val cv = expression.constValue(program) ?: return null
|
val cv = expression.constValue(program) ?: return null
|
||||||
val cast = cv.cast(type)
|
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 constValue(program: Program): NumericLiteralValue? = null
|
||||||
override fun referencesIdentifier(vararg scopedName: String) = false
|
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: IAstVisitor) = visitor.visit(this)
|
||||||
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
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 accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
||||||
|
|
||||||
override fun referencesIdentifier(vararg scopedName: String) = false
|
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 constValue(program: Program): NumericLiteralValue? = null
|
||||||
|
|
||||||
override fun toString(): String {
|
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 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)
|
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 accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||||
|
|
||||||
override fun toString(): String = "'${escape(value.toString())}'"
|
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)
|
operator fun compareTo(other: CharLiteral): Int = value.compareTo(other.value)
|
||||||
override fun hashCode(): Int = Objects.hash(value, altEncoding)
|
override fun hashCode(): Int = Objects.hash(value, altEncoding)
|
||||||
override fun equals(other: Any?): Boolean {
|
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 accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
||||||
|
|
||||||
override fun toString(): String = "'${escape(value)}'"
|
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)
|
operator fun compareTo(other: StringLiteralValue): Int = value.compareTo(other.value)
|
||||||
override fun hashCode(): Int = Objects.hash(value, altEncoding)
|
override fun hashCode(): Int = Objects.hash(value, altEncoding)
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
|
@ -31,12 +31,9 @@ object Prog8Parser {
|
|||||||
parser.addErrorListener(antlrErrorListener)
|
parser.addErrorListener(antlrErrorListener)
|
||||||
|
|
||||||
val parseTree = parser.module()
|
val parseTree = parser.module()
|
||||||
|
|
||||||
val module = ParsedModule(src)
|
val module = ParsedModule(src)
|
||||||
|
|
||||||
// .linkParents called in ParsedModule.add
|
|
||||||
parseTree.directive().forEach { module.add(it.toAst()) }
|
parseTree.directive().forEach { module.add(it.toAst()) }
|
||||||
// TODO: remove Encoding
|
|
||||||
parseTree.block().forEach { module.add(it.toAst(module.isLibrary)) }
|
parseTree.block().forEach { module.add(it.toAst(module.isLibrary)) }
|
||||||
|
|
||||||
return module
|
return module
|
||||||
@ -95,10 +92,13 @@ object Prog8Parser {
|
|||||||
private class AntlrErrorListener(val src: SourceCode): BaseErrorListener() {
|
private class AntlrErrorListener(val src: SourceCode): BaseErrorListener() {
|
||||||
override fun syntaxError(recognizer: Recognizer<*, *>?, offendingSymbol: Any?, line: Int, charPositionInLine: Int, msg: String, e: RecognitionException?) {
|
override fun syntaxError(recognizer: Recognizer<*, *>?, offendingSymbol: Any?, line: Int, charPositionInLine: Int, msg: String, e: RecognitionException?) {
|
||||||
if (e == null) {
|
if (e == null) {
|
||||||
TODO("no RecognitionException - create your own ParseError")
|
throw ParseError(msg, Position(src.origin, line, charPositionInLine, charPositionInLine), RuntimeException("parse error"))
|
||||||
//throw ParseError()
|
|
||||||
} else {
|
} else {
|
||||||
throw ParseError(msg, e.getPosition(src.origin), e)
|
if(e.offendingToken==null) {
|
||||||
|
throw ParseError(msg, Position(src.origin, line, charPositionInLine, charPositionInLine), e)
|
||||||
|
} else {
|
||||||
|
throw ParseError(msg, e.getPosition(src.origin), e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ object Prog8Parser {
|
|||||||
val offending = this.offendingToken
|
val offending = this.offendingToken
|
||||||
val line = offending.line
|
val line = offending.line
|
||||||
val beginCol = offending.charPositionInLine
|
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)
|
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.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
import prog8.ast.IFunctionCall
|
import prog8.ast.IFunctionCall
|
||||||
|
import prog8.ast.Module
|
||||||
import prog8.ast.Node
|
import prog8.ast.Node
|
||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
import prog8.ast.expressions.CharLiteral
|
import prog8.ast.expressions.CharLiteral
|
||||||
@ -17,12 +18,11 @@ import prog8.parser.SourceCode
|
|||||||
import prog8tests.helpers.assumeNotExists
|
import prog8tests.helpers.assumeNotExists
|
||||||
import prog8tests.helpers.assumeReadableFile
|
import prog8tests.helpers.assumeReadableFile
|
||||||
import prog8tests.helpers.fixturesDir
|
import prog8tests.helpers.fixturesDir
|
||||||
|
import kotlin.io.path.Path
|
||||||
|
import kotlin.io.path.isRegularFile
|
||||||
import kotlin.io.path.name
|
import kotlin.io.path.name
|
||||||
import kotlin.io.path.nameWithoutExtension
|
import kotlin.io.path.nameWithoutExtension
|
||||||
import kotlin.test.assertContains
|
import kotlin.test.*
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertFailsWith
|
|
||||||
import kotlin.test.assertIs
|
|
||||||
|
|
||||||
|
|
||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
@ -219,7 +219,7 @@ class TestProg8Parser {
|
|||||||
val module = parseModule(SourceCode.Text(srcText))
|
val module = parseModule(SourceCode.Text(srcText))
|
||||||
|
|
||||||
// Note: assertContains has *actual* as first param
|
// Note: assertContains has *actual* as first param
|
||||||
assertContains(module.name, Regex("^<String@[0-9a-f]+>$"))
|
assertContains(module.name, Regex("^<String@[0-9a-f\\-]+>$"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -289,7 +289,7 @@ class TestProg8Parser {
|
|||||||
try {
|
try {
|
||||||
parseModule(SourceCode.Text(srcText))
|
parseModule(SourceCode.Text(srcText))
|
||||||
} catch (e: ParseError) {
|
} 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()
|
""".trimIndent()
|
||||||
val module = parseModule(SourceCode.Text(srcText))
|
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
|
@Test
|
||||||
@ -330,9 +330,9 @@ class TestProg8Parser {
|
|||||||
val mpf = module.position.file
|
val mpf = module.position.file
|
||||||
assertPositionOf(module, SourceCode.relative(path).toString(), 1, 0) // TODO: endCol wrong
|
assertPositionOf(module, SourceCode.relative(path).toString(), 1, 0) // TODO: endCol wrong
|
||||||
val mainBlock = module.statements.filterIsInstance<Block>()[0]
|
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]
|
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
|
@Nested
|
||||||
inner class CharLiterals {
|
inner class CharLiterals {
|
||||||
|
|
||||||
|
@ -1,30 +1,32 @@
|
|||||||
package prog8tests
|
package prog8tests
|
||||||
|
|
||||||
|
import org.hamcrest.MatcherAssert.assertThat
|
||||||
|
import org.hamcrest.core.StringStartsWith
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
import prog8.parser.SourceCode
|
import prog8.parser.SourceCode
|
||||||
import prog8.parser.SourceCode.Companion.libraryFilePrefix
|
import prog8.parser.SourceCode.Companion.libraryFilePrefix
|
||||||
import prog8tests.helpers.*
|
import prog8tests.helpers.*
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
import kotlin.test.assertContains
|
import kotlin.test.*
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertFailsWith
|
|
||||||
import kotlin.test.assertTrue
|
|
||||||
|
|
||||||
|
|
||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
class TestSourceCode {
|
class TestSourceCode {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testFactoryMethod_Of() {
|
fun testFromString() {
|
||||||
val text = """
|
val text = """
|
||||||
main { }
|
main { }
|
||||||
""".trimIndent()
|
"""
|
||||||
val src = SourceCode.Text(text)
|
val src = SourceCode.Text(text)
|
||||||
val actualText = src.getCharStream().toString()
|
val actualText = src.getCharStream().toString()
|
||||||
|
|
||||||
assertContains(src.origin, Regex("^<String@[0-9a-f]+>$"))
|
assertContains(src.origin, Regex("^<String@[0-9a-f\\-]+>$"))
|
||||||
assertEquals(text, actualText)
|
assertEquals(text, actualText)
|
||||||
|
assertFalse(src.isFromResources)
|
||||||
|
assertFalse(src.isFromFilesystem)
|
||||||
|
assertThat(src.toString(), StringStartsWith("prog8.parser.SourceCode"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -54,6 +56,8 @@ class TestSourceCode {
|
|||||||
val expectedOrigin = SourceCode.relative(path).toString()
|
val expectedOrigin = SourceCode.relative(path).toString()
|
||||||
assertEquals(expectedOrigin, src.origin)
|
assertEquals(expectedOrigin, src.origin)
|
||||||
assertEquals(path.toFile().readText(), src.asString())
|
assertEquals(path.toFile().readText(), src.asString())
|
||||||
|
assertFalse(src.isFromResources)
|
||||||
|
assertTrue(src.isFromFilesystem)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -75,6 +79,8 @@ class TestSourceCode {
|
|||||||
|
|
||||||
assertEquals("$libraryFilePrefix/$pathString", src.origin)
|
assertEquals("$libraryFilePrefix/$pathString", src.origin)
|
||||||
assertEquals(srcFile.readText(), src.asString())
|
assertEquals(srcFile.readText(), src.asString())
|
||||||
|
assertTrue(src.isFromResources)
|
||||||
|
assertFalse(src.isFromFilesystem)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -50,12 +50,12 @@ class ProgramTests {
|
|||||||
assertSame(program, m1.program)
|
assertSame(program, m1.program)
|
||||||
assertSame(program.namespace, m1.parent)
|
assertSame(program.namespace, m1.parent)
|
||||||
|
|
||||||
assertFailsWith<IllegalArgumentException> { program.addModule(m1) }
|
assertThat("module may not occur multiple times",
|
||||||
.let { assertThat(it.message, containsString(m1.name)) }
|
assertFailsWith<IllegalArgumentException> { program.addModule(m1) }.message, containsString(m1.name))
|
||||||
|
|
||||||
val m2 = Module(mutableListOf(), m1.position, m1.source)
|
val m2 = Module(mutableListOf(), m1.position, m1.source)
|
||||||
assertFailsWith<IllegalArgumentException> { program.addModule(m2) }
|
assertThat("other module but with same name may not occur multiple times",
|
||||||
.let { assertThat(it.message, containsString(m2.name)) }
|
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 {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
|
ubyte aa=99
|
||||||
|
aa++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ Blocked by Commander-x16 v39 release
|
|||||||
|
|
||||||
Future
|
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.
|
- 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 })
|
- replace certain uses of inferredType.getOr(DataType.UNDEFINED) by i.getOrElse({ errorhandler })
|
||||||
- see if we can remove more "[InferredType].getOr(DataType.UNDEFINED)"
|
- 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)
|
; Not yet implemented in ROM: cx16.FB_set_palette(&colors, 0, len(colors)*3)
|
||||||
palette.set_rgb(&colors, len(colors))
|
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.FB_init()
|
||||||
cx16.VERA_DC_VSCALE = 0 ; display trick spoiler.......: stretch display all the way to the bottom
|
cx16.VERA_DC_VSCALE = 0 ; display trick spoiler.......: stretch display all the way to the bottom
|
||||||
cx16.set_rasterirq(&irq.irqhandler, 0)
|
cx16.set_rasterirq(&irq.irqhandler, 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user