optimized name checking, no longer depends on scopedname

This commit is contained in:
Irmen de Jong 2019-03-28 21:30:30 +01:00
parent 62ceace941
commit 5502a3e3ee
4 changed files with 36 additions and 38 deletions

View File

@ -88,7 +88,7 @@ private fun compileMain(args: Array<String>) {
println("Syntax check...")
val heap = HeapValues()
val time1= measureTimeMillis {
moduleAst.checkIdentifiers(heap)
moduleAst.checkIdentifiers(namespace)
}
//println(" time1: $time1")
val time2 = measureTimeMillis {
@ -104,9 +104,7 @@ private fun compileMain(args: Array<String>) {
}
//println(" time4: $time4")
val allScopedSymbolDefinitions = moduleAst.checkIdentifiers(heap) // useful for checking symbol usage later?
// moduleAst.simplifyExpressions(namespace, heap)
// moduleAst.optimizeStatements(namespace, heap)
moduleAst.checkIdentifiers(namespace)
if(optimize) {
// optimize the parse tree
println("Optimizing...")

View File

@ -326,6 +326,7 @@ inline fun <reified T> findParentNode(node: Node): T? {
interface IStatement : Node {
fun process(processor: IAstProcessor) : IStatement
fun makeScopedName(name: String): String {
// TODO eventually get rid of this scopedName
// this is usually cached in a lazy property on the statement object itself (label, subroutine, vardecl)
val scope = mutableListOf<String>()
var statementScope = this.parent

View File

@ -1,17 +1,15 @@
package prog8.ast
import prog8.compiler.HeapValues
import prog8.functions.BuiltinFunctions
/**
* Checks the validity of all identifiers (no conflicts)
* Also builds a list of all (scoped) symbol definitions
* Also makes sure that subroutine's parameters also become local variable decls in the subroutine's scope.
* Finally, it also makes sure the datatype of all Var decls and sub Return values is set correctly.
*/
fun Module.checkIdentifiers(heap: HeapValues): MutableMap<String, IStatement> {
val checker = AstIdentifiersChecker(heap)
fun Module.checkIdentifiers(namespace: INameScope) {
val checker = AstIdentifiersChecker(namespace)
this.process(checker)
// add any anonymous variables for heap values that are used,
@ -43,14 +41,13 @@ fun Module.checkIdentifiers(heap: HeapValues): MutableMap<String, IStatement> {
}
printErrors(checker.result(), name)
return checker.symbols
}
private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
private class AstIdentifiersChecker(private val namespace: INameScope) : IAstProcessor {
private val checkResult: MutableList<AstException> = mutableListOf()
var symbols: MutableMap<String, IStatement> = mutableMapOf()
var blocks: MutableMap<String, Block> = mutableMapOf()
private set
fun result(): List<AstException> {
@ -58,16 +55,16 @@ private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
}
private fun nameError(name: String, position: Position, existing: IStatement) {
checkResult.add(NameError("name conflict '$name', first defined in ${existing.position.file} line ${existing.position.line}", position))
checkResult.add(NameError("name conflict '$name', also defined in ${existing.position.file} line ${existing.position.line}", position))
}
override fun process(block: Block): IStatement {
val existing = symbols[block.name]
if(existing!=null) {
val existing = blocks[block.name]
if(existing!=null)
nameError(block.name, block.position, existing)
} else {
symbols[block.name] = block
}
else
blocks[block.name] = block
return super.process(block)
}
@ -90,14 +87,10 @@ private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
// the builtin functions can't be redefined
checkResult.add(NameError("builtin function cannot be redefined", decl.position))
// TODO: check for name conflict only has to be done within the same scope, no need to get the full scoped name
val scopedName = decl.scopedname
val existing = symbols[scopedName]
if(existing!=null) {
val existing = namespace.lookup(listOf(decl.name), decl)
if (existing != null && existing !== decl)
nameError(decl.name, decl.position, existing)
} else {
symbols[scopedName] = decl
}
return super.process(decl)
}
@ -109,14 +102,9 @@ private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
if (subroutine.parameters.any { it.name in BuiltinFunctions })
checkResult.add(NameError("builtin function name cannot be used as parameter", subroutine.position))
// TODO: check for name conflict only has to be done within the same scope, no need to get the full scoped name
val scopedName = subroutine.scopedname
val existing = symbols[scopedName]
if (existing != null) {
val existing = namespace.lookup(listOf(subroutine.name), subroutine)
if (existing != null && existing !== subroutine)
nameError(subroutine.name, subroutine.position, existing)
} else {
symbols[scopedName] = subroutine
}
// check that there are no local variables that redefine the subroutine's parameters
val allDefinedNames = subroutine.allLabelsAndVariables()
@ -153,14 +141,9 @@ private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
// the builtin functions can't be redefined
checkResult.add(NameError("builtin function cannot be redefined", label.position))
} else {
// TODO: check for name conflict only has to be done within the same scope, no need to get the full scoped name
val scopedName = label.scopedname
val existing = symbols[scopedName]
if (existing != null) {
val existing = namespace.lookup(listOf(label.name), label)
if (existing != null && existing !== label)
nameError(label.name, label.position, existing)
} else {
symbols[scopedName] = label
}
}
return super.process(label)
}

View File

@ -6,6 +6,22 @@
sub start() {
byte var1
byte var1
sub subsub() {
byte var1
byte var1
}
sub subsub() {
byte var1
byte var2
byte var3
byte var2
}
if A>10 {
A=44
while true {