mirror of
https://github.com/irmen/prog8.git
synced 2025-01-13 10:29:52 +00:00
callgraph: nameInAssemblyCode searches smarter (for unused())
This commit is contained in:
parent
ddf96943f0
commit
5c8c64242f
@ -6,12 +6,14 @@ import io.kotest.matchers.ints.shouldBeGreaterThanOrEqual
|
||||
import io.kotest.matchers.maps.shouldContainKey
|
||||
import io.kotest.matchers.maps.shouldNotContainKey
|
||||
import io.kotest.matchers.shouldBe
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.codegen.target.C64Target
|
||||
import prog8.compilerinterface.CallGraph
|
||||
import prog8tests.helpers.assertSuccess
|
||||
import prog8tests.helpers.compileText
|
||||
import prog8.parser.Prog8Parser.parseModule
|
||||
import prog8.parser.SourceCode
|
||||
import prog8tests.helpers.*
|
||||
|
||||
class TestCallgraph: FunSpec({
|
||||
test("testGraphForEmptySubs") {
|
||||
@ -121,4 +123,60 @@ class TestCallgraph: FunSpec({
|
||||
empties[1].position.line shouldBe 5
|
||||
empties[2].position.line shouldBe 6
|
||||
}
|
||||
|
||||
test("checking block and subroutine names usage in assembly code") {
|
||||
val source = """
|
||||
main {
|
||||
sub start() {
|
||||
%asm {{
|
||||
lda #<blockname
|
||||
lda #<blockname.subroutine
|
||||
correctlabel:
|
||||
nop
|
||||
}}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
blockname {
|
||||
sub subroutine() {
|
||||
@(1000) = 0
|
||||
}
|
||||
|
||||
sub correctlabel() {
|
||||
@(1000) = 0
|
||||
}
|
||||
}
|
||||
|
||||
; all block and subroutines below should NOT be found in asm because they're only substrings of the names in there
|
||||
locknam {
|
||||
sub rout() {
|
||||
@(1000) = 0
|
||||
}
|
||||
|
||||
sub orrectlab() {
|
||||
@(1000) = 0
|
||||
}
|
||||
}"""
|
||||
val module = parseModule(SourceCode.Text(source))
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
||||
program.addModule(module)
|
||||
val callgraph = CallGraph(program)
|
||||
val blockMain = program.allBlocks.single { it.name=="main" }
|
||||
val blockBlockname = program.allBlocks.single { it.name=="blockname" }
|
||||
val blockLocknam = program.allBlocks.single { it.name=="locknam" }
|
||||
val subStart = blockMain.statements.filterIsInstance<Subroutine>().single { it.name == "start" }
|
||||
val subSubroutine = blockBlockname.statements.filterIsInstance<Subroutine>().single { it.name == "subroutine" }
|
||||
val subCorrectlabel = blockBlockname.statements.filterIsInstance<Subroutine>().single { it.name == "correctlabel" }
|
||||
val subRout = blockLocknam.statements.filterIsInstance<Subroutine>().single { it.name == "rout" }
|
||||
val subOrrectlab = blockLocknam.statements.filterIsInstance<Subroutine>().single { it.name == "orrectlab" }
|
||||
callgraph.unused(blockMain) shouldBe false
|
||||
callgraph.unused(blockBlockname) shouldBe false
|
||||
callgraph.unused(blockLocknam) shouldBe true
|
||||
callgraph.unused(subStart) shouldBe false
|
||||
callgraph.unused(subSubroutine) shouldBe false
|
||||
callgraph.unused(subCorrectlabel) shouldBe false
|
||||
callgraph.unused(subRout) shouldBe true
|
||||
callgraph.unused(subOrrectlab) shouldBe true
|
||||
}
|
||||
})
|
||||
|
@ -612,10 +612,17 @@ class InlineAssembly(val assembly: String, override val position: Position) : St
|
||||
|
||||
override fun copy() = throw NotImplementedError("no support for duplicating a InlineAssembly")
|
||||
|
||||
|
||||
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
|
||||
val names: Set<String> by lazy {
|
||||
// A cache of all the words (identifiers) present in this block of assembly code
|
||||
// this is used when checking if prog8 names are referenced from assembly code
|
||||
// TODO: smarter pattern; don't include words in comments
|
||||
val wordPattern = Regex("""\b([_a-zA-Z][_a-zA-Z0-9]+?)\b""", RegexOption.MULTILINE)
|
||||
wordPattern.findAll(assembly).map { it.value }.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
class AnonymousScope(override var statements: MutableList<Statement>,
|
||||
|
@ -3,7 +3,6 @@ package prog8.compilerinterface
|
||||
import prog8.ast.Module
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
@ -222,8 +221,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
return allIdentifiersAndTargets.filter { decl===it.value }.map{ it.key }
|
||||
}
|
||||
|
||||
private fun nameInAssemblyCode(name: String) =
|
||||
allAssemblyNodes.any { it.assembly.contains(name) } // TODO be smarter about what to search in assembly (only labels starting in column 0?)
|
||||
private fun nameInAssemblyCode(name: String) = allAssemblyNodes.any { name in it.names }
|
||||
|
||||
inline fun unused(label: Label) = false // just always output labels
|
||||
|
||||
|
@ -4,7 +4,6 @@ TODO
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- Fix: don't report as recursion if code assigns address of its own subroutine to something, rather than calling it
|
||||
- nameInAssemblyCode() should search smarter (only labels in column 0? only full words, not part of a larger word? use regex? )
|
||||
|
||||
Need help with
|
||||
^^^^^^^^^^^^^^
|
||||
|
@ -1,30 +1,33 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
byte bb1 = -50
|
||||
byte bb2 = -51
|
||||
|
||||
word ww = func(bb1, bb2)
|
||||
txt.print_w(ww)
|
||||
txt.print(" <- must be -50\n")
|
||||
|
||||
ubyte ub1 = 50
|
||||
ubyte ub2 = 51
|
||||
uword uw = funcu(ub1, ub2)
|
||||
txt.print_uw(uw)
|
||||
txt.print(" <- must be 50\n")
|
||||
%asm {{
|
||||
lda #<blockname
|
||||
lda #<blockname.subroutine
|
||||
correctlabel:
|
||||
nop ; rout orrectlab locknam
|
||||
}}
|
||||
}
|
||||
|
||||
sub func(word x1, word y1) -> word {
|
||||
return x1
|
||||
;word zz = x1+1
|
||||
;return zz-1
|
||||
}
|
||||
|
||||
sub funcu(uword x1, uword y1) -> uword {
|
||||
uword zz = x1+1
|
||||
return zz-1
|
||||
blockname {
|
||||
sub subroutine() {
|
||||
@($c000) = 0
|
||||
}
|
||||
|
||||
sub correctlabel() {
|
||||
@($c000) = 0
|
||||
}
|
||||
}
|
||||
|
||||
; all block and subroutines below should NOT be found in asm because they're only substrings of the names in there, or in a comment
|
||||
locknam {
|
||||
sub rout() {
|
||||
@($c000) = 0
|
||||
}
|
||||
|
||||
sub orrectlab() {
|
||||
@($c000) = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user