mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
optimized name checking, no longer depends on scopedname
This commit is contained in:
parent
62ceace941
commit
5502a3e3ee
@ -88,7 +88,7 @@ private fun compileMain(args: Array<String>) {
|
|||||||
println("Syntax check...")
|
println("Syntax check...")
|
||||||
val heap = HeapValues()
|
val heap = HeapValues()
|
||||||
val time1= measureTimeMillis {
|
val time1= measureTimeMillis {
|
||||||
moduleAst.checkIdentifiers(heap)
|
moduleAst.checkIdentifiers(namespace)
|
||||||
}
|
}
|
||||||
//println(" time1: $time1")
|
//println(" time1: $time1")
|
||||||
val time2 = measureTimeMillis {
|
val time2 = measureTimeMillis {
|
||||||
@ -104,9 +104,7 @@ private fun compileMain(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
//println(" time4: $time4")
|
//println(" time4: $time4")
|
||||||
|
|
||||||
val allScopedSymbolDefinitions = moduleAst.checkIdentifiers(heap) // useful for checking symbol usage later?
|
moduleAst.checkIdentifiers(namespace)
|
||||||
// moduleAst.simplifyExpressions(namespace, heap)
|
|
||||||
// moduleAst.optimizeStatements(namespace, heap)
|
|
||||||
if(optimize) {
|
if(optimize) {
|
||||||
// optimize the parse tree
|
// optimize the parse tree
|
||||||
println("Optimizing...")
|
println("Optimizing...")
|
||||||
|
@ -326,6 +326,7 @@ inline fun <reified T> findParentNode(node: Node): T? {
|
|||||||
interface IStatement : Node {
|
interface IStatement : Node {
|
||||||
fun process(processor: IAstProcessor) : IStatement
|
fun process(processor: IAstProcessor) : IStatement
|
||||||
fun makeScopedName(name: String): String {
|
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)
|
// this is usually cached in a lazy property on the statement object itself (label, subroutine, vardecl)
|
||||||
val scope = mutableListOf<String>()
|
val scope = mutableListOf<String>()
|
||||||
var statementScope = this.parent
|
var statementScope = this.parent
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
package prog8.ast
|
package prog8.ast
|
||||||
|
|
||||||
import prog8.compiler.HeapValues
|
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the validity of all identifiers (no conflicts)
|
* 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.
|
* 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.
|
* 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> {
|
fun Module.checkIdentifiers(namespace: INameScope) {
|
||||||
val checker = AstIdentifiersChecker(heap)
|
val checker = AstIdentifiersChecker(namespace)
|
||||||
this.process(checker)
|
this.process(checker)
|
||||||
|
|
||||||
// add any anonymous variables for heap values that are used,
|
// 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)
|
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()
|
private val checkResult: MutableList<AstException> = mutableListOf()
|
||||||
|
|
||||||
var symbols: MutableMap<String, IStatement> = mutableMapOf()
|
var blocks: MutableMap<String, Block> = mutableMapOf()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun result(): List<AstException> {
|
fun result(): List<AstException> {
|
||||||
@ -58,16 +55,16 @@ private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun nameError(name: String, position: Position, existing: IStatement) {
|
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 {
|
override fun process(block: Block): IStatement {
|
||||||
val existing = symbols[block.name]
|
val existing = blocks[block.name]
|
||||||
if(existing!=null) {
|
if(existing!=null)
|
||||||
nameError(block.name, block.position, existing)
|
nameError(block.name, block.position, existing)
|
||||||
} else {
|
else
|
||||||
symbols[block.name] = block
|
blocks[block.name] = block
|
||||||
}
|
|
||||||
return super.process(block)
|
return super.process(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,14 +87,10 @@ private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
|
|||||||
// the builtin functions can't be redefined
|
// the builtin functions can't be redefined
|
||||||
checkResult.add(NameError("builtin function cannot be redefined", decl.position))
|
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 existing = namespace.lookup(listOf(decl.name), decl)
|
||||||
val scopedName = decl.scopedname
|
if (existing != null && existing !== decl)
|
||||||
val existing = symbols[scopedName]
|
|
||||||
if(existing!=null) {
|
|
||||||
nameError(decl.name, decl.position, existing)
|
nameError(decl.name, decl.position, existing)
|
||||||
} else {
|
|
||||||
symbols[scopedName] = decl
|
|
||||||
}
|
|
||||||
return super.process(decl)
|
return super.process(decl)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,14 +102,9 @@ private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
|
|||||||
if (subroutine.parameters.any { it.name in BuiltinFunctions })
|
if (subroutine.parameters.any { it.name in BuiltinFunctions })
|
||||||
checkResult.add(NameError("builtin function name cannot be used as parameter", subroutine.position))
|
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 existing = namespace.lookup(listOf(subroutine.name), subroutine)
|
||||||
val scopedName = subroutine.scopedname
|
if (existing != null && existing !== subroutine)
|
||||||
val existing = symbols[scopedName]
|
|
||||||
if (existing != null) {
|
|
||||||
nameError(subroutine.name, subroutine.position, existing)
|
nameError(subroutine.name, subroutine.position, existing)
|
||||||
} else {
|
|
||||||
symbols[scopedName] = subroutine
|
|
||||||
}
|
|
||||||
|
|
||||||
// check that there are no local variables that redefine the subroutine's parameters
|
// check that there are no local variables that redefine the subroutine's parameters
|
||||||
val allDefinedNames = subroutine.allLabelsAndVariables()
|
val allDefinedNames = subroutine.allLabelsAndVariables()
|
||||||
@ -153,14 +141,9 @@ private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
|
|||||||
// the builtin functions can't be redefined
|
// the builtin functions can't be redefined
|
||||||
checkResult.add(NameError("builtin function cannot be redefined", label.position))
|
checkResult.add(NameError("builtin function cannot be redefined", label.position))
|
||||||
} else {
|
} else {
|
||||||
// TODO: check for name conflict only has to be done within the same scope, no need to get the full scoped name
|
val existing = namespace.lookup(listOf(label.name), label)
|
||||||
val scopedName = label.scopedname
|
if (existing != null && existing !== label)
|
||||||
val existing = symbols[scopedName]
|
|
||||||
if (existing != null) {
|
|
||||||
nameError(label.name, label.position, existing)
|
nameError(label.name, label.position, existing)
|
||||||
} else {
|
|
||||||
symbols[scopedName] = label
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return super.process(label)
|
return super.process(label)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,22 @@
|
|||||||
|
|
||||||
sub start() {
|
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 {
|
if A>10 {
|
||||||
A=44
|
A=44
|
||||||
while true {
|
while true {
|
||||||
|
Loading…
Reference in New Issue
Block a user