improve the way %option merge works, you can now merge your own code with library code for instance.

This commit is contained in:
Irmen de Jong 2023-11-14 22:47:31 +01:00
parent ad14c88fde
commit 42db3085df
6 changed files with 58 additions and 22 deletions

View File

@ -110,14 +110,18 @@ class ModuleImporter(private val program: Program,
// their content has to be merged into already existing other block with the same name. // their content has to be merged into already existing other block with the same name.
val blocks = importedModule.statements.filterIsInstance<Block>() val blocks = importedModule.statements.filterIsInstance<Block>()
for(block in blocks) { for(block in blocks) {
if("merge" in block.options()) { val blockHasMergeOption = "merge" in block.options()
val existingBlock = program.allBlocks.firstOrNull { it.name==block.name && it !== block} val existingBlock = program.allBlocks.firstOrNull { it.name==block.name && it !== block}
if(existingBlock!=null) { if(existingBlock!=null) {
val existingBlockHasMergeOption = "merge" in existingBlock.options()
if (blockHasMergeOption || existingBlockHasMergeOption) {
// transplant the contents
existingBlock.statements.addAll(block.statements.filter { it !is Directive }) existingBlock.statements.addAll(block.statements.filter { it !is Directive })
importedModule.statements.remove(block) importedModule.statements.remove(block)
} else {
val merges = block.statements.filter { it is Directive && it.directive=="%option" && it.args.any { a->a.name=="merge" } } if(blockHasMergeOption && !existingBlockHasMergeOption) {
block.statements.removeAll(merges.toSet()) existingBlock.statements.add(0, Directive("%option", listOf(DirectiveArg(null, "merge", null, block.position)), block.position))
}
} }
} }
} }

View File

@ -33,10 +33,13 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter,
override fun visit(block: Block) { override fun visit(block: Block) {
val existing = blocks[block.name] val existing = blocks[block.name]
if(existing!=null) { if(existing!=null) {
if(block.isInLibrary) // we allow duplicates if at least one of them has %option merge
nameError(existing.name, existing.position, block) if("merge" !in existing.options() + block.options()) {
else if (block.isInLibrary)
nameError(block.name, block.position, existing) nameError(existing.name, existing.position, block)
else
nameError(block.name, block.position, existing)
}
} }
else else
blocks[block.name] = block blocks[block.name] = block

View File

@ -3,10 +3,12 @@ package prog8tests
import io.kotest.assertions.withClue import io.kotest.assertions.withClue
import io.kotest.core.spec.style.FunSpec import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldStartWith import io.kotest.matchers.string.shouldStartWith
import prog8.code.core.ZeropageType import prog8.code.core.ZeropageType
import prog8.code.core.internedStringsModuleName import prog8.code.core.internedStringsModuleName
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8.code.target.VMTarget
import prog8.compiler.determineCompilationOptions import prog8.compiler.determineCompilationOptions
import prog8.compiler.parseMainModule import prog8.compiler.parseMainModule
import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.ErrorReporterForTests
@ -108,4 +110,29 @@ main {
} }
} }
test("merge option works on library modules") {
val src="""
%zeropage basicsafe
%import textio
txt {
%option merge
sub println(uword string) {
txt.print(string)
txt.nl()
}
}
main {
sub start() {
txt.lowercase()
txt.println("Hello, world1")
txt.println("Hello, world2")
txt.println("Hello, world3")
}
}"""
compileText(VMTarget(), optimize = false, src) shouldNotBe null
}
}) })

View File

@ -143,7 +143,7 @@ Directives
Warning: if you use this to align array variables in the block, these have to be initialized with a value to make them stay in the block and get aligned properly. Otherwise they'll end up at a random spot in the BSS section and the alignment doesn't apply there. Warning: if you use this to align array variables in the block, these have to be initialized with a value to make them stay in the block and get aligned properly. Otherwise they'll end up at a random spot in the BSS section and the alignment doesn't apply there.
- ``align_page`` (in a block) will make the assembler align the start address of this block on a page boundary in memory (so, the LSB of the address is 0). - ``align_page`` (in a block) will make the assembler align the start address of this block on a page boundary in memory (so, the LSB of the address is 0).
Warning: if you use this to align array variables in the block, these have to be initialized with a value to make them stay in the block and get aligned properly. Otherwise they'll end up at a random spot in the BSS section and the alignment doesn't apply there. Warning: if you use this to align array variables in the block, these have to be initialized with a value to make them stay in the block and get aligned properly. Otherwise they'll end up at a random spot in the BSS section and the alignment doesn't apply there.
- ``merge`` (in a block) will merge this block's contents into an already existing block with the same name. Useful in library scenarios. - ``merge`` (in a block) will merge this block's contents into an already existing block with the same name. Useful in library scenarios. Can result in a bunch of unused symbol warnings, this depends on the import order.
- ``splitarrays`` (block or module) makes all word-arrays in this scope lsb/msb split arrays (as if they all have the @split tag). See Arrays. - ``splitarrays`` (block or module) makes all word-arrays in this scope lsb/msb split arrays (as if they all have the @split tag). See Arrays.
- ``no_symbol_prefixing`` (block) makes the compiler *not* use symbol-prefixing when translating prog8 code into assembly. - ``no_symbol_prefixing`` (block) makes the compiler *not* use symbol-prefixing when translating prog8 code into assembly.
Only use this if you know what you're doing because it could result in invalid assembly code being generated. Only use this if you know what you're doing because it could result in invalid assembly code being generated.

View File

@ -2,8 +2,6 @@
TODO TODO
==== ====
- improve the working of %option merge: should be able to merge your own stuff into say textio. , and improve the docs about it too.
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
- [on branch: ir-less-branch-opcodes] IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction - [on branch: ir-less-branch-opcodes] IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction
- IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? Bitwise operations, etc), but only after setting the status bits is verified! - IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? Bitwise operations, etc), but only after setting the status bits is verified!

View File

@ -1,15 +1,19 @@
%zeropage basicsafe %zeropage basicsafe
%import textio
txt {
%option merge
sub println(uword string) {
txt.print(string)
txt.nl()
}
}
main { main {
sub start() { sub start() {
str name = "thing" txt.lowercase()
modify(name) txt.println("Hello, world1")
txt.println("Hello, world2")
sub modify(str arg) { txt.println("Hello, world3")
ubyte n=1
uword pointervar
arg[n+1] = arg[1]
pointervar[n+1] = pointervar[1]
}
} }
} }