removal of unused nodes

This commit is contained in:
Irmen de Jong 2018-08-31 21:46:14 +02:00
parent cc73d90d6e
commit 3e11d45883
7 changed files with 159 additions and 53 deletions

View File

@ -11,12 +11,15 @@
~ extra233 { ~ extra233 {
; this is imported ; this is imported
X = 42 const byte snerp=33
return 44 const byte snerp2 = snerp+22
sub foo() -> () { X = 42+snerp
A=99 return 44+snerp
return
sub foo234234() -> () {
A=99+snerp
return A+snerp2
} }
} }

View File

@ -14,20 +14,27 @@ fun main(args: Array<String>) {
println("\nIL65 compiler by Irmen de Jong (irmen@razorvine.net)") println("\nIL65 compiler by Irmen de Jong (irmen@razorvine.net)")
println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n") println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n")
// import main module and process additional imports
val filepath = Paths.get(args[0]).normalize() val filepath = Paths.get(args[0]).normalize()
val moduleAst = importModule(filepath) val moduleAst = importModule(filepath)
moduleAst.linkParents() moduleAst.linkParents()
val globalNamespace = moduleAst.namespace() val globalNamespace = moduleAst.namespace()
//globalNamespace.debugPrint() //globalNamespace.debugPrint()
// perform syntax checks and optimizations
moduleAst.checkIdentifiers(globalNamespace) moduleAst.checkIdentifiers(globalNamespace)
moduleAst.optimizeExpressions(globalNamespace) moduleAst.optimizeExpressions(globalNamespace)
moduleAst.optimizeStatements(globalNamespace) val allScopedSymbolDefinitions = moduleAst.checkIdentifiers(globalNamespace)
moduleAst.optimizeStatements(globalNamespace, allScopedSymbolDefinitions)
val globalNamespaceAfterOptimize = moduleAst.namespace() // it could have changed in the meantime val globalNamespaceAfterOptimize = moduleAst.namespace() // it could have changed in the meantime
moduleAst.checkValid(globalNamespaceAfterOptimize) // check if final tree is valid moduleAst.checkValid(globalNamespaceAfterOptimize) // check if final tree is valid
val allScopedSymbolDefinitions = moduleAst.checkIdentifiers(globalNamespace)
// determine special compiler options // determine special compiler options
val options = moduleAst.statements.filter { it is Directive && it.directive=="%option" }.flatMap { (it as Directive).args }.toSet() val options = moduleAst.statements.filter { it is Directive && it.directive=="%option" }.flatMap { (it as Directive).args }.toSet()
val outputType = (moduleAst.statements.singleOrNull { it is Directive && it.directive=="%output"} val outputType = (moduleAst.statements.singleOrNull { it is Directive && it.directive=="%output"}
as? Directive)?.args?.single()?.name?.toUpperCase() as? Directive)?.args?.single()?.name?.toUpperCase()
@ -42,6 +49,10 @@ fun main(args: Array<String>) {
if(zpType==null) ZeropageType.COMPATIBLE else ZeropageType.valueOf(zpType), if(zpType==null) ZeropageType.COMPATIBLE else ZeropageType.valueOf(zpType),
options.contains(DirectiveArg(null, "enable_floats", null)) options.contains(DirectiveArg(null, "enable_floats", null))
) )
// compile the syntax tree into intermediate form, and optimize that
val compiler = Compiler(compilerOptions, globalNamespaceAfterOptimize) val compiler = Compiler(compilerOptions, globalNamespaceAfterOptimize)
val intermediate = compiler.compile(moduleAst) val intermediate = compiler.compile(moduleAst)
intermediate.optimize() intermediate.optimize()
@ -49,8 +60,8 @@ fun main(args: Array<String>) {
// val assembler = intermediate.compileToAssembly() // val assembler = intermediate.compileToAssembly()
// assembler.assemble(compilerOptions, "input", "output") // assembler.assemble(compilerOptions, "input", "output")
// val monitorfile = assembler.generateBreakpointList() // val monitorfile = assembler.generateBreakpointList()
//
// start the vice emulator // // start the vice emulator
// val program = "foo" // val program = "foo"
// val cmdline = listOf("x64", "-moncommands", monitorfile, // val cmdline = listOf("x64", "-moncommands", monitorfile,
// "-autostartprgmode", "1", "-autostart-warp", "-autostart", program) // "-autostartprgmode", "1", "-autostart-warp", "-autostart", program)
@ -61,5 +72,3 @@ fun main(args: Array<String>) {
exitProcess(1) exitProcess(1)
} }
} }

View File

@ -61,50 +61,62 @@ class ExpressionException(message: String, val position: Position?) : AstExcepti
data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) { data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) {
override fun toString(): String = "[$file: line $line col $startCol-$endCol]" override fun toString(): String = "[$file: line $line col ${startCol+1}-${endCol+1}]"
} }
interface IAstProcessor { interface IAstProcessor {
fun process(module: Module) { fun process(module: Module) {
module.statements = module.statements.map { it.process(this) } module.statements = module.statements.map { it.process(this) }.toMutableList()
} }
fun process(expr: PrefixExpression): IExpression { fun process(expr: PrefixExpression): IExpression {
expr.expression = expr.expression.process(this) expr.expression = expr.expression.process(this)
return expr return expr
} }
fun process(expr: BinaryExpression): IExpression { fun process(expr: BinaryExpression): IExpression {
expr.left = expr.left.process(this) expr.left = expr.left.process(this)
expr.right = expr.right.process(this) expr.right = expr.right.process(this)
return expr return expr
} }
fun process(directive: Directive): IStatement { fun process(directive: Directive): IStatement {
return directive return directive
} }
fun process(block: Block): IStatement { fun process(block: Block): IStatement {
block.statements = block.statements.map { it.process(this) } block.statements = block.statements.map { it.process(this) }.toMutableList()
return block return block
} }
fun process(decl: VarDecl): IStatement { fun process(decl: VarDecl): IStatement {
decl.value = decl.value?.process(this) decl.value = decl.value?.process(this)
decl.arrayspec?.process(this) decl.arrayspec?.process(this)
return decl return decl
} }
fun process(subroutine: Subroutine): IStatement { fun process(subroutine: Subroutine): IStatement {
subroutine.statements = subroutine.statements.map { it.process(this) } subroutine.statements = subroutine.statements.map { it.process(this) }.toMutableList()
return subroutine return subroutine
} }
fun process(functionCall: FunctionCall): IExpression { fun process(functionCall: FunctionCall): IExpression {
functionCall.arglist = functionCall.arglist.map { it.process(this) } functionCall.arglist = functionCall.arglist.map { it.process(this) }
return functionCall return functionCall
} }
fun process(functionCall: FunctionCallStatement): IStatement { fun process(functionCall: FunctionCallStatement): IStatement {
functionCall.arglist = functionCall.arglist.map { it.process(this) } functionCall.arglist = functionCall.arglist.map { it.process(this) }
return functionCall return functionCall
} }
fun process(identifier: IdentifierReference): IExpression { fun process(identifier: IdentifierReference): IExpression {
// note: this is an identifier that is used in an expression.
// other identifiers are simply part of the other statements (such as jumps, subroutine defs etc)
return identifier return identifier
} }
fun process(jump: Jump): IStatement { fun process(jump: Jump): IStatement {
return jump return jump
} }
@ -137,7 +149,7 @@ interface Node {
interface IStatement : Node { interface IStatement : Node {
fun process(processor: IAstProcessor) : IStatement fun process(processor: IAstProcessor) : IStatement
fun scopedName(name: String): String { fun makeScopedName(name: String): List<String> {
val scope = mutableListOf<String>() val scope = mutableListOf<String>()
var statementScope = this.parent var statementScope = this.parent
while(statementScope!=null && statementScope !is Module) { while(statementScope!=null && statementScope !is Module) {
@ -147,7 +159,7 @@ interface IStatement : Node {
statementScope = statementScope.parent statementScope = statementScope.parent
} }
scope.add(name) scope.add(name)
return scope.joinToString(".") return scope
} }
} }
@ -160,7 +172,11 @@ interface IFunctionCall {
interface INameScope { interface INameScope {
val name: String val name: String
val position: Position? val position: Position?
var statements: List<IStatement> var statements: MutableList<IStatement>
fun usedNames(): Set<String>
fun registerUsedName(name: String)
fun subScopes() = statements.filter { it is INameScope } .map { it as INameScope }.associate { it.name to it } fun subScopes() = statements.filter { it is INameScope } .map { it as INameScope }.associate { it.name to it }
@ -188,6 +204,9 @@ interface INameScope {
statementScope = statementScope.parent statementScope = statementScope.parent
if (statementScope == null) if (statementScope == null)
return null return null
if(statementScope.parent==null && statementScope !is Module)
throw AstException("non-Module node has no parent! node: $statementScope at ${statementScope.position}")
val localScope = statementScope as INameScope val localScope = statementScope as INameScope
val result = localScope.definedNames()[scopedName[0]] val result = localScope.definedNames()[scopedName[0]]
if (result != null) if (result != null)
@ -213,6 +232,12 @@ interface INameScope {
} }
printNames(0, this) printNames(0, this)
} }
fun removeStatement(statement: IStatement) {
// remove a statement (most likely because it is never referenced such as a subroutine)
val removed = statements.remove(statement)
if(!removed) throw AstException("node to remove wasn't found")
}
} }
@ -236,13 +261,14 @@ data class AnonymousStatementList(override var parent: Node?, var statements: Li
data class Module(override val name: String, data class Module(override val name: String,
override var statements: List<IStatement>) : Node, INameScope { override var statements: MutableList<IStatement>) : Node, INameScope {
override var position: Position? = null override var position: Position? = null
override var parent: Node? = null override var parent: Node? = null
override fun linkParents(parent: Node) { override fun linkParents(parent: Node) {
this.parent=parent this.parent=parent
} }
fun linkParents() { fun linkParents() {
parent = null parent = null
statements.forEach {it.linkParents(this)} statements.forEach {it.linkParents(this)}
@ -254,17 +280,44 @@ data class Module(override val name: String,
fun namespace(): INameScope { fun namespace(): INameScope {
class GlobalNamespace(override val name: String, class GlobalNamespace(override val name: String,
override var statements: List<IStatement>, override var statements: MutableList<IStatement>,
override val position: Position?) : INameScope override val position: Position?) : INameScope {
private val scopedNamesUsed: MutableSet<String> = mutableSetOf("main") // main is always used
override fun usedNames(): Set<String> = scopedNamesUsed
override fun lookup(scopedName: List<String>, statement: Node): IStatement? {
val stmt = super.lookup(scopedName, statement)
if(stmt!=null) {
val targetScopedName = when(stmt) {
is Label -> stmt.makeScopedName(stmt.name)
is VarDecl -> stmt.makeScopedName(stmt.name)
is Block -> stmt.makeScopedName(stmt.name)
is Subroutine -> stmt.makeScopedName(stmt.name)
else -> throw NameError("wrong identifier target: $stmt", stmt.position)
}
registerUsedName(targetScopedName.joinToString("."))
}
return stmt
}
override fun registerUsedName(name: String) {
scopedNamesUsed.add(name)
}
}
return GlobalNamespace("<<<global>>>", statements, position) return GlobalNamespace("<<<global>>>", statements, position)
} }
override fun usedNames(): Set<String> = throw NotImplementedError("not implemented on sub-scopes")
override fun registerUsedName(name: String) = throw NotImplementedError("not implemented on sub-scopes")
} }
data class Block(override val name: String, data class Block(override val name: String,
val address: Int?, val address: Int?,
override var statements: List<IStatement>) : IStatement, INameScope { override var statements: MutableList<IStatement>) : IStatement, INameScope {
override var position: Position? = null override var position: Position? = null
override var parent: Node? = null override var parent: Node? = null
@ -278,6 +331,9 @@ data class Block(override val name: String,
override fun toString(): String { override fun toString(): String {
return "Block(name=$name, address=$address, ${statements.size} statements)" return "Block(name=$name, address=$address, ${statements.size} statements)"
} }
override fun usedNames(): Set<String> = throw NotImplementedError("not implemented on sub-scopes")
override fun registerUsedName(name: String) = throw NotImplementedError("not implemented on sub-scopes")
} }
@ -533,7 +589,7 @@ data class RegisterExpr(val register: Register) : IExpression {
} }
data class IdentifierReference(val scopedName: List<String>) : IExpression { data class IdentifierReference(val nameInSource: List<String>) : IExpression {
override var position: Position? = null override var position: Position? = null
override var parent: Node? = null override var parent: Node? = null
@ -542,9 +598,9 @@ data class IdentifierReference(val scopedName: List<String>) : IExpression {
} }
override fun constValue(namespace: INameScope): LiteralValue? { override fun constValue(namespace: INameScope): LiteralValue? {
val node = namespace.lookup(scopedName, this) val node = namespace.lookup(nameInSource, this)
?: ?:
throw ExpressionException("undefined symbol: ${scopedName.joinToString(".")}", position) throw ExpressionException("undefined symbol: ${nameInSource.joinToString(".")}", position)
val vardecl = node as? VarDecl val vardecl = node as? VarDecl
if(vardecl==null) { if(vardecl==null) {
throw ExpressionException("name should be a constant, instead of: ${node::class.simpleName}", position) throw ExpressionException("name should be a constant, instead of: ${node::class.simpleName}", position)
@ -555,7 +611,7 @@ data class IdentifierReference(val scopedName: List<String>) : IExpression {
} }
override fun process(processor: IAstProcessor) = processor.process(this) override fun process(processor: IAstProcessor) = processor.process(this)
override fun referencesIdentifier(name: String): Boolean = scopedName.last() == name // @todo is this correct all the time? override fun referencesIdentifier(name: String): Boolean = nameInSource.last() == name // @todo is this correct all the time?
} }
@ -600,8 +656,8 @@ data class FunctionCall(override var target: IdentifierReference, override var a
override fun constValue(namespace: INameScope): LiteralValue? { override fun constValue(namespace: INameScope): LiteralValue? {
// if the function is a built-in function and the args are consts, should evaluate! // if the function is a built-in function and the args are consts, should evaluate!
if(target.scopedName.size>1) return null if(target.nameInSource.size>1) return null
return when(target.scopedName[0]){ return when(target.nameInSource[0]){
"sin" -> builtin_sin(arglist, position, namespace) "sin" -> builtin_sin(arglist, position, namespace)
"cos" -> builtin_cos(arglist, position, namespace) "cos" -> builtin_cos(arglist, position, namespace)
"abs" -> builtin_abs(arglist, position, namespace) "abs" -> builtin_abs(arglist, position, namespace)
@ -656,15 +712,15 @@ data class Subroutine(override val name: String,
val parameters: List<SubroutineParameter>, val parameters: List<SubroutineParameter>,
val returnvalues: List<SubroutineReturnvalue>, val returnvalues: List<SubroutineReturnvalue>,
val address: Int?, val address: Int?,
override var statements: List<IStatement>) : IStatement, INameScope { override var statements: MutableList<IStatement>) : IStatement, INameScope {
override var position: Position? = null override var position: Position? = null
override var parent: Node? = null override var parent: Node? = null
override fun linkParents(parent: Node) { override fun linkParents(parent: Node) {
this.parent = parent this.parent = parent
parameters.forEach { it.parent=this } parameters.forEach { it.linkParents(this) }
returnvalues.forEach { it.parent=this } returnvalues.forEach { it.linkParents(this) }
statements.forEach { it.parent=this } statements.forEach { it.linkParents(this) }
} }
override fun process(processor: IAstProcessor) = processor.process(this) override fun process(processor: IAstProcessor) = processor.process(this)
@ -672,6 +728,9 @@ data class Subroutine(override val name: String,
override fun toString(): String { override fun toString(): String {
return "Subroutine(name=$name, address=$address, parameters=$parameters, returnvalues=$returnvalues, ${statements.size} statements)" return "Subroutine(name=$name, address=$address, parameters=$parameters, returnvalues=$returnvalues, ${statements.size} statements)"
} }
override fun usedNames(): Set<String> = throw NotImplementedError("not implemented on sub-scopes")
override fun registerUsedName(name: String) = throw NotImplementedError("not implemented on sub-scopes")
} }
@ -715,7 +774,7 @@ data class IfStatement(var condition: IExpression,
/***************** Antlr Extension methods to create AST ****************/ /***************** Antlr Extension methods to create AST ****************/
fun il65Parser.ModuleContext.toAst(name: String, withPosition: Boolean) : Module { fun il65Parser.ModuleContext.toAst(name: String, withPosition: Boolean) : Module {
val module = Module(name, modulestatement().map { it.toAst(withPosition) }) val module = Module(name, modulestatement().map { it.toAst(withPosition) }.toMutableList())
module.position = toPosition(withPosition) module.position = toPosition(withPosition)
return module return module
} }
@ -753,8 +812,8 @@ private fun il65Parser.BlockContext.toAst(withPosition: Boolean) : IStatement {
} }
private fun il65Parser.Statement_blockContext.toAst(withPosition: Boolean): List<IStatement> private fun il65Parser.Statement_blockContext.toAst(withPosition: Boolean): MutableList<IStatement>
= statement().map { it.toAst(withPosition) } = statement().map { it.toAst(withPosition) }.toMutableList()
private fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatement { private fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatement {
@ -918,7 +977,7 @@ private fun il65Parser.SubroutineContext.toAst(withPosition: Boolean) : Subrouti
if(sub_params()==null) emptyList() else sub_params().toAst(), if(sub_params()==null) emptyList() else sub_params().toAst(),
if(sub_returns()==null) emptyList() else sub_returns().toAst(), if(sub_returns()==null) emptyList() else sub_returns().toAst(),
sub_address()?.integerliteral()?.toAst(), sub_address()?.integerliteral()?.toAst(),
if(statement_block()==null) emptyList() else statement_block().toAst(withPosition)) if(statement_block()==null) mutableListOf() else statement_block().toAst(withPosition))
sub.position = toPosition(withPosition) sub.position = toPosition(withPosition)
return sub return sub
} }

View File

@ -309,8 +309,8 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor {
} }
private fun checkFunctionExists(target: IdentifierReference, statement: IStatement) { private fun checkFunctionExists(target: IdentifierReference, statement: IStatement) {
if(globalNamespace.lookup(target.scopedName, statement)==null) if(globalNamespace.lookup(target.nameInSource, statement)==null)
checkResult.add(SyntaxError("undefined function or subroutine: ${target.scopedName.joinToString(".")}", statement.position)) checkResult.add(SyntaxError("undefined function or subroutine: ${target.nameInSource.joinToString(".")}", statement.position))
} }
private fun checkValueRange(datatype: DataType, value: LiteralValue, position: Position?) : Boolean { private fun checkValueRange(datatype: DataType, value: LiteralValue, position: Position?) : Boolean {

View File

@ -35,50 +35,46 @@ class AstIdentifiersChecker(private val globalNamespace: INameScope) : IAstProce
} }
override fun process(block: Block): IStatement { override fun process(block: Block): IStatement {
val scopedName = block.scopedName(block.name) val scopedName = block.makeScopedName(block.name).joinToString(".")
val existing = symbols[scopedName] val existing = symbols[scopedName]
if(existing!=null) { if(existing!=null) {
nameError(block.name, block.position, existing) nameError(block.name, block.position, existing)
} else { } else {
symbols[scopedName] = block symbols[scopedName] = block
} }
super.process(block) return super.process(block)
return block
} }
override fun process(decl: VarDecl): IStatement { override fun process(decl: VarDecl): IStatement {
val scopedName = decl.scopedName(decl.name) val scopedName = decl.makeScopedName(decl.name).joinToString(".")
val existing = symbols[scopedName] val existing = symbols[scopedName]
if(existing!=null) { if(existing!=null) {
nameError(decl.name, decl.position, existing) nameError(decl.name, decl.position, existing)
} else { } else {
symbols[scopedName] = decl symbols[scopedName] = decl
} }
super.process(decl) return super.process(decl)
return decl
} }
override fun process(subroutine: Subroutine): IStatement { override fun process(subroutine: Subroutine): IStatement {
val scopedName = subroutine.scopedName(subroutine.name) val scopedName = subroutine.makeScopedName(subroutine.name).joinToString(".")
val existing = symbols[scopedName] val existing = symbols[scopedName]
if(existing!=null) { if(existing!=null) {
nameError(subroutine.name, subroutine.position, existing) nameError(subroutine.name, subroutine.position, existing)
} else { } else {
symbols[scopedName] = subroutine symbols[scopedName] = subroutine
} }
super.process(subroutine) return super.process(subroutine)
return subroutine
} }
override fun process(label: Label): IStatement { override fun process(label: Label): IStatement {
val scopedName = label.scopedName(label.name) val scopedName = label.makeScopedName(label.name).joinToString(".")
val existing = symbols[scopedName] val existing = symbols[scopedName]
if(existing!=null) { if(existing!=null) {
nameError(label.name, label.position, existing) nameError(label.name, label.position, existing)
} else { } else {
symbols[scopedName] = label symbols[scopedName] = label
} }
super.process(label) return super.process(label)
return label
} }
} }

View File

@ -161,7 +161,8 @@ class AssemblyResult(val name: String) {
} }
} }
fun genereateBreakpointList(): String { fun generateBreakpointList(): String {
// todo build breakpoint list!
/* /*
def generate_breakpoint_list(self, program_filename: str) -> str: def generate_breakpoint_list(self, program_filename: str) -> str:
breakpoints = [] breakpoints = []

View File

@ -3,9 +3,10 @@ package il65.optimizing
import il65.ast.* import il65.ast.*
fun Module.optimizeStatements(globalNamespace: INameScope) { fun Module.optimizeStatements(globalNamespace: INameScope, allScopedSymbolDefinitions: MutableMap<String, IStatement>) {
val optimizer = StatementOptimizer(globalNamespace) val optimizer = StatementOptimizer(globalNamespace)
this.process(optimizer) this.process(optimizer)
optimizer.removeUnusedNodes(globalNamespace.usedNames(), allScopedSymbolDefinitions)
if(optimizer.optimizationsDone==0) if(optimizer.optimizationsDone==0)
println("[${this.name}] 0 optimizations performed") println("[${this.name}] 0 optimizations performed")
@ -18,7 +19,6 @@ fun Module.optimizeStatements(globalNamespace: INameScope) {
} }
/* /*
todo remove unused blocks, subroutines and variable decls (replace with empty AnonymousStatementList)
todo statement optimization: create augmented assignment from assignment that only refers to its lvalue (A=A+10, A=4*A, ...) todo statement optimization: create augmented assignment from assignment that only refers to its lvalue (A=A+10, A=4*A, ...)
todo statement optimization: X+=1, X-=1 --> X++/X-- , todo statement optimization: X+=1, X-=1 --> X++/X-- ,
todo remove statements that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc todo remove statements that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc
@ -37,6 +37,32 @@ class StatementOptimizer(private val globalNamespace: INameScope) : IAstProcesso
optimizationsDone = 0 optimizationsDone = 0
} }
override fun process(functionCall: FunctionCall): IExpression {
val function = globalNamespace.lookup(functionCall.target.nameInSource, functionCall)
if(function!=null) {
val scopedName = when(function) {
is Label -> function.makeScopedName(function.name)
is Subroutine -> function.makeScopedName(function.name)
else -> throw AstException("invalid function call target node type")
}
globalNamespace.registerUsedName(scopedName.joinToString("."))
}
return super.process(functionCall)
}
override fun process(functionCall: FunctionCallStatement): IStatement {
val function = globalNamespace.lookup(functionCall.target.nameInSource, functionCall)
if(function!=null) {
val scopedName = when(function) {
is Label -> function.makeScopedName(function.name)
is Subroutine -> function.makeScopedName(function.name)
else -> throw AstException("invalid function call target node type")
}
globalNamespace.registerUsedName(scopedName.joinToString("."))
}
return super.process(functionCall)
}
override fun process(ifStatement: IfStatement): IStatement { override fun process(ifStatement: IfStatement): IStatement {
super.process(ifStatement) super.process(ifStatement)
val constvalue = ifStatement.condition.constValue(globalNamespace) val constvalue = ifStatement.condition.constValue(globalNamespace)
@ -53,4 +79,16 @@ class StatementOptimizer(private val globalNamespace: INameScope) : IAstProcesso
} }
return ifStatement return ifStatement
} }
fun removeUnusedNodes(usedNames: Set<String>, allScopedSymbolDefinitions: MutableMap<String, IStatement>) {
for ((name, value) in allScopedSymbolDefinitions) {
if(!usedNames.contains(name)) {
val parentScope = value.parent as INameScope
val localname = name.substringAfterLast(".")
println("${value.position} Warning: ${value::class.simpleName} '$localname' is never used")
parentScope.removeStatement(value)
optimizationsDone++
}
}
}
} }