mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
callgraph
This commit is contained in:
parent
619fa9b65e
commit
530d03d284
@ -71,29 +71,27 @@ internal fun Program.moveMainAndStartToFirst() {
|
||||
|
||||
val directives = modules[0].statements.filterIsInstance<Directive>()
|
||||
val start = this.entrypoint()
|
||||
if(start!=null) {
|
||||
val mod = start.definingModule()
|
||||
val block = start.definingBlock()
|
||||
if(!modules.remove(mod))
|
||||
throw FatalAstException("module wrong")
|
||||
modules.add(0, mod)
|
||||
mod.remove(block)
|
||||
var afterDirective = mod.statements.indexOfFirst { it !is Directive }
|
||||
if(afterDirective<0)
|
||||
mod.statements.add(block)
|
||||
else
|
||||
mod.statements.add(afterDirective, block)
|
||||
block.remove(start)
|
||||
afterDirective = block.statements.indexOfFirst { it !is Directive }
|
||||
if(afterDirective<0)
|
||||
block.statements.add(start)
|
||||
else
|
||||
block.statements.add(afterDirective, start)
|
||||
val mod = start.definingModule()
|
||||
val block = start.definingBlock()
|
||||
if(!modules.remove(mod))
|
||||
throw FatalAstException("module wrong")
|
||||
modules.add(0, mod)
|
||||
mod.remove(block)
|
||||
var afterDirective = mod.statements.indexOfFirst { it !is Directive }
|
||||
if(afterDirective<0)
|
||||
mod.statements.add(block)
|
||||
else
|
||||
mod.statements.add(afterDirective, block)
|
||||
block.remove(start)
|
||||
afterDirective = block.statements.indexOfFirst { it !is Directive }
|
||||
if(afterDirective<0)
|
||||
block.statements.add(start)
|
||||
else
|
||||
block.statements.add(afterDirective, start)
|
||||
|
||||
// overwrite the directives in the module containing the entrypoint
|
||||
for(directive in directives) {
|
||||
modules[0].statements.removeAll { it is Directive && it.directive == directive.directive }
|
||||
modules[0].statements.add(0, directive)
|
||||
}
|
||||
// overwrite the directives in the module containing the entrypoint
|
||||
for(directive in directives) {
|
||||
modules[0].statements.removeAll { it is Directive && it.directive == directive.directive }
|
||||
modules[0].statements.add(0, directive)
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import prog8.ast.Program
|
||||
import prog8.ast.base.Position
|
||||
import prog8.ast.expressions.AddressOf
|
||||
import prog8.ast.expressions.FunctionCall
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.IAstVisitor
|
||||
import prog8.compiler.IErrorReporter
|
||||
@ -17,11 +18,37 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
val importedBy = mutableMapOf<Module, Set<Module>>().withDefault { setOf() }
|
||||
val calls = mutableMapOf<Subroutine, Set<Subroutine>>().withDefault { setOf() }
|
||||
val calledBy = mutableMapOf<Subroutine, Set<Node>>().withDefault { setOf() }
|
||||
private val allIdentifiers = mutableSetOf<IdentifierReference>()
|
||||
|
||||
init {
|
||||
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) {
|
||||
val thisModule = directive.definingModule()
|
||||
if (directive.directive == "%import") {
|
||||
@ -77,6 +104,10 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
super.visit(jump)
|
||||
}
|
||||
|
||||
override fun visit(identifier: IdentifierReference) {
|
||||
allIdentifiers.add(identifier)
|
||||
}
|
||||
|
||||
fun checkRecursiveCalls(errors: IErrorReporter) {
|
||||
val cycles = recursionCycles()
|
||||
if(cycles.any()) {
|
||||
@ -128,13 +159,11 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
return false
|
||||
}
|
||||
|
||||
fun unused(sub: Subroutine): Boolean {
|
||||
return calledBy[sub].isNullOrEmpty() // TODO also check inline assembly if it uses the subroutine
|
||||
}
|
||||
fun unused(module: Module) = module !in usedModules
|
||||
|
||||
fun unused(block: Block): Boolean {
|
||||
return false // TODO implement unused check for Block, also check inline asm
|
||||
}
|
||||
fun unused(sub: Subroutine) = sub !in usedSubroutines
|
||||
|
||||
fun unused(block: Block) = block !in usedBlocks
|
||||
|
||||
fun unused(decl: VarDecl): Boolean {
|
||||
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
|
||||
}
|
||||
|
||||
fun unused(module: Module): Boolean {
|
||||
return false // TODO
|
||||
}
|
||||
|
||||
inline fun unused(label: Label) = false // just always output labels
|
||||
|
||||
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" }
|
||||
if(mainBlocks.size > 1)
|
||||
throw FatalAstException("more than one 'main' block")
|
||||
return if(mainBlocks.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
mainBlocks[0].subScope("start") as Subroutine?
|
||||
}
|
||||
if(mainBlocks.isEmpty())
|
||||
throw FatalAstException("no 'main' block")
|
||||
return mainBlocks[0].subScope("start") as Subroutine
|
||||
}
|
||||
|
||||
fun internString(string: StringLiteralValue): List<String> {
|
||||
|
@ -720,7 +720,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
||||
|
||||
fun targetStatement(program: Program) =
|
||||
if(nameInSource.size==1 && nameInSource[0] in program.builtinFunctions.names)
|
||||
BuiltinFunctionStatementPlaceholder(nameInSource[0], position)
|
||||
BuiltinFunctionStatementPlaceholder(nameInSource[0], position, parent)
|
||||
else
|
||||
program.namespace.lookup(nameInSource, this)
|
||||
|
||||
|
@ -35,8 +35,7 @@ sealed class Statement : Node {
|
||||
}
|
||||
|
||||
|
||||
class BuiltinFunctionStatementPlaceholder(val name: String, override val position: Position) : Statement() {
|
||||
override var parent: Node = ParentSentinel
|
||||
class BuiltinFunctionStatementPlaceholder(val name: String, override val position: Position, override var parent: Node) : Statement() {
|
||||
override fun linkParents(parent: 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")
|
||||
|
Loading…
x
Reference in New Issue
Block a user