mirror of
https://github.com/irmen/prog8.git
synced 2025-08-19 10:27:43 +00:00
callgraph
This commit is contained in:
@@ -71,7 +71,6 @@ internal fun Program.moveMainAndStartToFirst() {
|
|||||||
|
|
||||||
val directives = modules[0].statements.filterIsInstance<Directive>()
|
val directives = modules[0].statements.filterIsInstance<Directive>()
|
||||||
val start = this.entrypoint()
|
val start = this.entrypoint()
|
||||||
if(start!=null) {
|
|
||||||
val mod = start.definingModule()
|
val mod = start.definingModule()
|
||||||
val block = start.definingBlock()
|
val block = start.definingBlock()
|
||||||
if(!modules.remove(mod))
|
if(!modules.remove(mod))
|
||||||
@@ -96,4 +95,3 @@ internal fun Program.moveMainAndStartToFirst() {
|
|||||||
modules[0].statements.add(0, directive)
|
modules[0].statements.add(0, directive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@@ -6,6 +6,7 @@ import prog8.ast.Program
|
|||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
import prog8.ast.expressions.AddressOf
|
import prog8.ast.expressions.AddressOf
|
||||||
import prog8.ast.expressions.FunctionCall
|
import prog8.ast.expressions.FunctionCall
|
||||||
|
import prog8.ast.expressions.IdentifierReference
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.ast.walk.IAstVisitor
|
import prog8.ast.walk.IAstVisitor
|
||||||
import prog8.compiler.IErrorReporter
|
import prog8.compiler.IErrorReporter
|
||||||
@@ -17,11 +18,37 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
val importedBy = mutableMapOf<Module, Set<Module>>().withDefault { setOf() }
|
val importedBy = mutableMapOf<Module, Set<Module>>().withDefault { setOf() }
|
||||||
val calls = mutableMapOf<Subroutine, Set<Subroutine>>().withDefault { setOf() }
|
val calls = mutableMapOf<Subroutine, Set<Subroutine>>().withDefault { setOf() }
|
||||||
val calledBy = mutableMapOf<Subroutine, Set<Node>>().withDefault { setOf() }
|
val calledBy = mutableMapOf<Subroutine, Set<Node>>().withDefault { setOf() }
|
||||||
|
private val allIdentifiers = mutableSetOf<IdentifierReference>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
visit(program)
|
visit(program)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val usedSubroutines: Set<Subroutine> by lazy {
|
||||||
|
// TODO also check inline assembly if it uses the subroutine
|
||||||
|
calledBy.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
private val usedBlocks: Set<Block> by lazy {
|
||||||
|
// TODO also check inline assembly if it uses the block
|
||||||
|
val blocksFromSubroutines = usedSubroutines.map { it.definingBlock() }
|
||||||
|
val blocksFromLibraries = program.allBlocks().filter { it.isInLibrary }
|
||||||
|
val used = mutableSetOf<Block>()
|
||||||
|
|
||||||
|
allIdentifiers.forEach {
|
||||||
|
if(it.definingBlock() in blocksFromSubroutines) {
|
||||||
|
val target = it.targetStatement(program)!!.definingBlock()
|
||||||
|
used.add(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
used + blocksFromLibraries + program.entrypoint().definingBlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val usedModules: Set<Module> by lazy {
|
||||||
|
program.modules.toSet() // TODO
|
||||||
|
}
|
||||||
|
|
||||||
override fun visit(directive: Directive) {
|
override fun visit(directive: Directive) {
|
||||||
val thisModule = directive.definingModule()
|
val thisModule = directive.definingModule()
|
||||||
if (directive.directive == "%import") {
|
if (directive.directive == "%import") {
|
||||||
@@ -77,6 +104,10 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
super.visit(jump)
|
super.visit(jump)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visit(identifier: IdentifierReference) {
|
||||||
|
allIdentifiers.add(identifier)
|
||||||
|
}
|
||||||
|
|
||||||
fun checkRecursiveCalls(errors: IErrorReporter) {
|
fun checkRecursiveCalls(errors: IErrorReporter) {
|
||||||
val cycles = recursionCycles()
|
val cycles = recursionCycles()
|
||||||
if(cycles.any()) {
|
if(cycles.any()) {
|
||||||
@@ -128,13 +159,11 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unused(sub: Subroutine): Boolean {
|
fun unused(module: Module) = module !in usedModules
|
||||||
return calledBy[sub].isNullOrEmpty() // TODO also check inline assembly if it uses the subroutine
|
|
||||||
}
|
|
||||||
|
|
||||||
fun unused(block: Block): Boolean {
|
fun unused(sub: Subroutine) = sub !in usedSubroutines
|
||||||
return false // TODO implement unused check for Block, also check inline asm
|
|
||||||
}
|
fun unused(block: Block) = block !in usedBlocks
|
||||||
|
|
||||||
fun unused(decl: VarDecl): Boolean {
|
fun unused(decl: VarDecl): Boolean {
|
||||||
return false // TODO implement unused check for vardecls, also check inline asm
|
return false // TODO implement unused check for vardecls, also check inline asm
|
||||||
@@ -144,10 +173,6 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
return false // TODO implement unused check for struct decls, also check inline asm
|
return false // TODO implement unused check for struct decls, also check inline asm
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unused(module: Module): Boolean {
|
|
||||||
return false // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun unused(label: Label) = false // just always output labels
|
inline fun unused(label: Label) = false // just always output labels
|
||||||
|
|
||||||
fun unused(stmt: ISymbolStatement): Boolean {
|
fun unused(stmt: ISymbolStatement): Boolean {
|
||||||
|
@@ -283,15 +283,13 @@ class Program(val name: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun entrypoint(): Subroutine? {
|
fun entrypoint(): Subroutine {
|
||||||
val mainBlocks = allBlocks().filter { it.name=="main" }
|
val mainBlocks = allBlocks().filter { it.name=="main" }
|
||||||
if(mainBlocks.size > 1)
|
if(mainBlocks.size > 1)
|
||||||
throw FatalAstException("more than one 'main' block")
|
throw FatalAstException("more than one 'main' block")
|
||||||
return if(mainBlocks.isEmpty()) {
|
if(mainBlocks.isEmpty())
|
||||||
null
|
throw FatalAstException("no 'main' block")
|
||||||
} else {
|
return mainBlocks[0].subScope("start") as Subroutine
|
||||||
mainBlocks[0].subScope("start") as Subroutine?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun internString(string: StringLiteralValue): List<String> {
|
fun internString(string: StringLiteralValue): List<String> {
|
||||||
|
@@ -720,7 +720,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
|||||||
|
|
||||||
fun targetStatement(program: Program) =
|
fun targetStatement(program: Program) =
|
||||||
if(nameInSource.size==1 && nameInSource[0] in program.builtinFunctions.names)
|
if(nameInSource.size==1 && nameInSource[0] in program.builtinFunctions.names)
|
||||||
BuiltinFunctionStatementPlaceholder(nameInSource[0], position)
|
BuiltinFunctionStatementPlaceholder(nameInSource[0], position, parent)
|
||||||
else
|
else
|
||||||
program.namespace.lookup(nameInSource, this)
|
program.namespace.lookup(nameInSource, this)
|
||||||
|
|
||||||
|
@@ -35,8 +35,7 @@ sealed class Statement : Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class BuiltinFunctionStatementPlaceholder(val name: String, override val position: Position) : Statement() {
|
class BuiltinFunctionStatementPlaceholder(val name: String, override val position: Position, override var parent: Node) : Statement() {
|
||||||
override var parent: Node = ParentSentinel
|
|
||||||
override fun linkParents(parent: Node) {}
|
override fun linkParents(parent: Node) {}
|
||||||
override fun accept(visitor: IAstVisitor) = throw FatalAstException("should not iterate over this node")
|
override fun accept(visitor: IAstVisitor) = throw FatalAstException("should not iterate over this node")
|
||||||
override fun accept(visitor: AstWalker, parent: Node) = throw FatalAstException("should not iterate over this node")
|
override fun accept(visitor: AstWalker, parent: Node) = throw FatalAstException("should not iterate over this node")
|
||||||
|
Reference in New Issue
Block a user