diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index a6f7de22a..ee274dfd8 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -88,7 +88,7 @@ private fun compileMain(args: Array) { 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) { } //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...") diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 614b70581..d0a485f2d 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -326,6 +326,7 @@ inline fun 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() var statementScope = this.parent diff --git a/compiler/src/prog8/ast/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/AstIdentifiersChecker.kt index 9bbad3400..23a3e8d2f 100644 --- a/compiler/src/prog8/ast/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/AstIdentifiersChecker.kt @@ -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 { - 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 { } 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 = mutableListOf() - var symbols: MutableMap = mutableMapOf() + var blocks: MutableMap = mutableMapOf() private set fun result(): List { @@ -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) } diff --git a/examples/test.p8 b/examples/test.p8 index fcf8d87dc..2c1b25485 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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 {