mirror of
https://github.com/irmen/prog8.git
synced 2025-08-16 05:27:31 +00:00
fix nested label lookups in anon scopes
fixed non-global qualified names lookup
This commit is contained in:
@@ -456,7 +456,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
val targetIdentifier = assignTarget.identifier
|
val targetIdentifier = assignTarget.identifier
|
||||||
if (targetIdentifier != null) {
|
if (targetIdentifier != null) {
|
||||||
val targetName = targetIdentifier.nameInSource
|
val targetName = targetIdentifier.nameInSource
|
||||||
when (val targetSymbol = program.namespace.lookup(targetName, assignment.definingScope)) {
|
when (val targetSymbol = assignment.definingScope.lookup(targetName, assignment.definingScope)) {
|
||||||
null -> {
|
null -> {
|
||||||
errors.err("undefined symbol: ${targetIdentifier.nameInSource.joinToString(".")}", targetIdentifier.position)
|
errors.err("undefined symbol: ${targetIdentifier.nameInSource.joinToString(".")}", targetIdentifier.position)
|
||||||
return
|
return
|
||||||
@@ -1073,7 +1073,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
override fun visit(postIncrDecr: PostIncrDecr) {
|
override fun visit(postIncrDecr: PostIncrDecr) {
|
||||||
if(postIncrDecr.target.identifier != null) {
|
if(postIncrDecr.target.identifier != null) {
|
||||||
val targetName = postIncrDecr.target.identifier!!.nameInSource
|
val targetName = postIncrDecr.target.identifier!!.nameInSource
|
||||||
val target = program.namespace.lookup(targetName, postIncrDecr.definingScope)
|
val target = postIncrDecr.definingScope.lookup(targetName, postIncrDecr.definingScope)
|
||||||
if(target==null) {
|
if(target==null) {
|
||||||
val symbol = postIncrDecr.target.identifier!!
|
val symbol = postIncrDecr.target.identifier!!
|
||||||
errors.err("undefined symbol: ${symbol.nameInSource.joinToString(".")}", symbol.position)
|
errors.err("undefined symbol: ${symbol.nameInSource.joinToString(".")}", symbol.position)
|
||||||
|
@@ -42,7 +42,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
|||||||
if(decl.name in compTarget.machine.opcodeNames)
|
if(decl.name in compTarget.machine.opcodeNames)
|
||||||
errors.err("can't use a cpu opcode name as a symbol: '${decl.name}'", decl.position)
|
errors.err("can't use a cpu opcode name as a symbol: '${decl.name}'", decl.position)
|
||||||
|
|
||||||
val existing = program.namespace.lookup(listOf(decl.name), decl.definingScope)
|
val existing = decl.definingScope.lookup(listOf(decl.name), decl.definingScope)
|
||||||
if (existing != null && existing !== decl)
|
if (existing != null && existing !== decl)
|
||||||
nameError(decl.name, decl.position, existing)
|
nameError(decl.name, decl.position, existing)
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
|||||||
// 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))
|
||||||
|
|
||||||
val existing = program.namespace.lookup(listOf(subroutine.name), subroutine)
|
val existing = subroutine.lookup(listOf(subroutine.name), subroutine)
|
||||||
if (existing != null && existing !== subroutine)
|
if (existing != null && existing !== subroutine)
|
||||||
nameError(subroutine.name, subroutine.position, existing)
|
nameError(subroutine.name, subroutine.position, existing)
|
||||||
|
|
||||||
|
@@ -58,7 +58,7 @@ class TestScoping {
|
|||||||
addr = &labelinside
|
addr = &labelinside
|
||||||
addr = &labeloutside
|
addr = &labeloutside
|
||||||
addr = &main.start.nested.nestedlabel
|
addr = &main.start.nested.nestedlabel
|
||||||
; addr = &nested.nestedlabel ; TODO should also work!!
|
addr = &nested.nestedlabel
|
||||||
goto labeloutside
|
goto labeloutside
|
||||||
goto iflabel
|
goto iflabel
|
||||||
goto main.start.nested.nestedlabel
|
goto main.start.nested.nestedlabel
|
||||||
@@ -72,11 +72,11 @@ class TestScoping {
|
|||||||
addr = &labelinside
|
addr = &labelinside
|
||||||
addr = &labeloutside
|
addr = &labeloutside
|
||||||
addr = &main.start.nested.nestedlabel
|
addr = &main.start.nested.nestedlabel
|
||||||
; addr = &nested.nestedlabel ; TODO should also work!!
|
addr = &nested.nestedlabel
|
||||||
goto iflabel
|
goto iflabel
|
||||||
goto labelinside
|
goto labelinside
|
||||||
goto main.start.nested.nestedlabel
|
goto main.start.nested.nestedlabel
|
||||||
; goto nested.nestedlabel ; TODO should also work!!
|
goto nested.nestedlabel
|
||||||
labelinside:
|
labelinside:
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,9 +92,9 @@ class TestScoping {
|
|||||||
addr = &labelinside
|
addr = &labelinside
|
||||||
addr = &labeloutside
|
addr = &labeloutside
|
||||||
addr = &main.start.nested.nestedlabel
|
addr = &main.start.nested.nestedlabel
|
||||||
; addr = &nested.nestedlabel ; TODO should also work!!
|
addr = &nested.nestedlabel
|
||||||
goto main.start.nested.nestedlabel
|
goto main.start.nested.nestedlabel
|
||||||
; goto nested.nestedlabel ; TODO should also work!!
|
goto nested.nestedlabel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@@ -105,8 +105,6 @@ class TestScoping {
|
|||||||
val start = mainBlock.statements.single() as Subroutine
|
val start = mainBlock.statements.single() as Subroutine
|
||||||
val labels = start.statements.filterIsInstance<Label>()
|
val labels = start.statements.filterIsInstance<Label>()
|
||||||
assertEquals(1, labels.size, "only one label in subroutine scope")
|
assertEquals(1, labels.size, "only one label in subroutine scope")
|
||||||
|
|
||||||
TODO("fix the partial scoped lookups above as well")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -162,7 +162,9 @@ interface IStatementContainer {
|
|||||||
interface INameScope: IStatementContainer, INamedStatement {
|
interface INameScope: IStatementContainer, INamedStatement {
|
||||||
fun subScope(name: String): INameScope? = statements.firstOrNull { it is INameScope && it.name==name } as? INameScope
|
fun subScope(name: String): INameScope? = statements.firstOrNull { it is INameScope && it.name==name } as? INameScope
|
||||||
|
|
||||||
fun lookup(scopedName: List<String>, localScope: INameScope) : Statement? { // TODO return INamedStatement instead?
|
// TODO is localscope really needed?
|
||||||
|
// TODO return INamedStatement instead?
|
||||||
|
fun lookup(scopedName: List<String>, localScope: INameScope) : Statement? {
|
||||||
return if(scopedName.size>1)
|
return if(scopedName.size>1)
|
||||||
lookupQualified(scopedName, localScope)
|
lookupQualified(scopedName, localScope)
|
||||||
else {
|
else {
|
||||||
@@ -173,22 +175,14 @@ interface INameScope: IStatementContainer, INamedStatement {
|
|||||||
private fun lookupQualified(scopedName: List<String>, startScope: INameScope): Statement? {
|
private fun lookupQualified(scopedName: List<String>, startScope: INameScope): Statement? {
|
||||||
// a scoped name refers to a name in another namespace.
|
// a scoped name refers to a name in another namespace.
|
||||||
// look "up" from our current scope to search for the correct one.
|
// look "up" from our current scope to search for the correct one.
|
||||||
if(scopedName==listOf("nested", "nestedlabel"))
|
val localScope = this.subScope(scopedName[0])
|
||||||
println("$scopedName") // TODO weg
|
if(localScope!=null)
|
||||||
|
return resolveLocally(localScope, scopedName.drop(1))
|
||||||
// TODO FIX qualified lookup.
|
|
||||||
|
|
||||||
var statementScope = startScope
|
var statementScope = startScope
|
||||||
while(statementScope !is GlobalNamespace) {
|
while(statementScope !is GlobalNamespace) {
|
||||||
if(statementScope !is Module && statementScope.name==scopedName[0]) {
|
if(statementScope !is Module && statementScope.name==scopedName[0]) {
|
||||||
// drill down to get the full scope
|
return resolveLocally(statementScope, scopedName.drop(1))
|
||||||
var scope: INameScope? = statementScope
|
|
||||||
for (name in scopedName.drop(1).dropLast(1)) {
|
|
||||||
scope = scope!!.subScope(name)
|
|
||||||
if (scope == null)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return scope!!.searchLabelOrVariableNotSubscoped(scopedName.last(), true)
|
|
||||||
} else {
|
} else {
|
||||||
statementScope = (statementScope as Node).definingScope
|
statementScope = (statementScope as Node).definingScope
|
||||||
}
|
}
|
||||||
@@ -204,6 +198,16 @@ interface INameScope: IStatementContainer, INamedStatement {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun resolveLocally(startScope: INameScope, name: List<String>): Statement? {
|
||||||
|
var scope: INameScope? = startScope
|
||||||
|
for(part in name.dropLast(1)) {
|
||||||
|
scope = scope!!.subScope(part)
|
||||||
|
if(scope==null)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return scope!!.searchLabelOrVariableNotSubscoped(name.last(), true)
|
||||||
|
}
|
||||||
|
|
||||||
private fun lookupUnqualified(name: String, startScope: INameScope): Statement? {
|
private fun lookupUnqualified(name: String, startScope: INameScope): Statement? {
|
||||||
val builtinFunctionsNames = (startScope as Node).definingModule.program.builtinFunctions.names
|
val builtinFunctionsNames = (startScope as Node).definingModule.program.builtinFunctions.names
|
||||||
if(name in builtinFunctionsNames) {
|
if(name in builtinFunctionsNames) {
|
||||||
@@ -445,6 +449,10 @@ class GlobalNamespace(val modules: Iterable<Module>): Node, INameScope {
|
|||||||
override val statements = mutableListOf<Statement>() // not used
|
override val statements = mutableListOf<Statement>() // not used
|
||||||
override var parent: Node = ParentSentinel
|
override var parent: Node = ParentSentinel
|
||||||
|
|
||||||
|
override fun lookup(scopedName: List<String>, localScope: INameScope): Statement? {
|
||||||
|
throw NotImplementedError("use lookup on actual ast node instead")
|
||||||
|
}
|
||||||
|
|
||||||
override fun linkParents(parent: Node) {
|
override fun linkParents(parent: Node) {
|
||||||
modules.forEach { it.linkParents(this) }
|
modules.forEach { it.linkParents(this) }
|
||||||
}
|
}
|
||||||
|
@@ -730,7 +730,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
|||||||
if(nameInSource.size==1 && nameInSource[0] in program.builtinFunctions.names)
|
if(nameInSource.size==1 && nameInSource[0] in program.builtinFunctions.names)
|
||||||
BuiltinFunctionStatementPlaceholder(nameInSource[0], position, parent)
|
BuiltinFunctionStatementPlaceholder(nameInSource[0], position, parent)
|
||||||
else
|
else
|
||||||
program.namespace.lookup(nameInSource, this.definingScope)
|
definingScope.lookup(nameInSource, definingScope)
|
||||||
|
|
||||||
fun targetVarDecl(program: Program): VarDecl? = targetStatement(program) as? VarDecl
|
fun targetVarDecl(program: Program): VarDecl? = targetStatement(program) as? VarDecl
|
||||||
fun targetSubroutine(program: Program): Subroutine? = targetStatement(program) as? Subroutine
|
fun targetSubroutine(program: Program): Subroutine? = targetStatement(program) as? Subroutine
|
||||||
@@ -747,8 +747,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun constValue(program: Program): NumericLiteralValue? {
|
override fun constValue(program: Program): NumericLiteralValue? {
|
||||||
val node = program.namespace.lookup(nameInSource, this.definingScope)
|
val node = definingScope.lookup(nameInSource, definingScope) ?: throw UndefinedSymbolError(this)
|
||||||
?: throw UndefinedSymbolError(this)
|
|
||||||
val vardecl = node as? VarDecl
|
val vardecl = node as? VarDecl
|
||||||
if(vardecl==null) {
|
if(vardecl==null) {
|
||||||
return null
|
return null
|
||||||
|
@@ -395,7 +395,7 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
|||||||
|
|
||||||
fun inferType(program: Program): InferredTypes.InferredType {
|
fun inferType(program: Program): InferredTypes.InferredType {
|
||||||
if (identifier != null) {
|
if (identifier != null) {
|
||||||
val symbol = program.namespace.lookup(identifier!!.nameInSource, this.definingScope) ?: return InferredTypes.unknown()
|
val symbol = definingScope.lookup(identifier!!.nameInSource, definingScope) ?: return InferredTypes.unknown()
|
||||||
if (symbol is VarDecl) return InferredTypes.knownFor(symbol.datatype)
|
if (symbol is VarDecl) return InferredTypes.knownFor(symbol.datatype)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user