frontend: implement basic scope analysis

This commit is contained in:
2023-09-14 14:16:08 -07:00
parent aadc8282a5
commit 821aa3563a
15 changed files with 172 additions and 45 deletions

View File

@ -9,6 +9,7 @@ import gay.pizza.pork.parser.Tokenizer
class World(val importSource: ImportSource) {
private val internalUnits = mutableMapOf<String, CompilationUnit>()
private val importedUnits = mutableMapOf<CompilationUnit, Set<CompilationUnit>>()
val units: List<CompilationUnit>
get() = internalUnits.values.toList()
@ -37,6 +38,7 @@ class World(val importSource: ImportSource) {
val importedUnit = loadOneUnit(importLocator)
units.add(importedUnit)
}
importedUnits[unit] = units
return units
}
@ -46,6 +48,9 @@ class World(val importSource: ImportSource) {
return unit
}
fun importedBy(unit: CompilationUnit): Set<CompilationUnit> =
importedUnits[unit] ?: emptySet()
private fun pickContentSource(form: String): ContentSource =
importSource.provideContentSource(form)

View File

@ -0,0 +1,36 @@
package gay.pizza.pork.frontend.scope
import gay.pizza.pork.ast.CompilationUnit
import gay.pizza.pork.ast.Symbol
class CompilationUnitScope(val worldScope: WorldScope, val unit: CompilationUnit) {
val externalSymbols = mutableSetOf<ScopeSymbol>()
val internalSymbols = mutableSetOf<ScopeSymbol>()
fun index() {
for (definition in unit.definitions) {
val scopeSymbol = ScopeSymbol(unit, definition)
if (definition.modifiers.export) {
externalSymbols.add(scopeSymbol)
}
internalSymbols.add(scopeSymbol)
}
}
fun findInternallyVisibleSymbols(): Set<VisibleScopeSymbol> {
val allSymbols = mutableMapOf<Symbol, VisibleScopeSymbol>()
val imports = worldScope.world.importedBy(unit)
for (import in imports) {
val scope = worldScope.index(import)
for (importedSymbol in scope.externalSymbols) {
allSymbols[importedSymbol.symbol] = VisibleScopeSymbol(unit, importedSymbol)
}
}
for (internalSymbol in internalSymbols) {
allSymbols[internalSymbol.symbol] = VisibleScopeSymbol(unit, internalSymbol)
}
return allSymbols.values.toSet()
}
}

View File

@ -0,0 +1,11 @@
package gay.pizza.pork.frontend.scope
import gay.pizza.pork.ast.Definition
import gay.pizza.pork.ast.Node
class ScopeSymbol(
val compilationUnit: Node,
val definition: Definition
) {
val symbol = definition.symbol
}

View File

@ -0,0 +1,8 @@
package gay.pizza.pork.frontend.scope
import gay.pizza.pork.ast.CompilationUnit
class VisibleScopeSymbol(val visibleToUnit: CompilationUnit, val scopeSymbol: ScopeSymbol) {
val isInternalSymbol: Boolean
get() = visibleToUnit == scopeSymbol.compilationUnit
}

View File

@ -0,0 +1,24 @@
package gay.pizza.pork.frontend.scope
import gay.pizza.pork.ast.CompilationUnit
import gay.pizza.pork.frontend.World
class WorldScope(val world: World) {
private val compilationUnitScopes = mutableMapOf<CompilationUnit, CompilationUnitScope>()
fun indexAll() {
for (unit in world.units) {
index(unit)
}
}
fun index(unit: CompilationUnit): CompilationUnitScope =
scope(unit).apply {
index()
}
fun scope(unit: CompilationUnit): CompilationUnitScope =
compilationUnitScopes.computeIfAbsent(unit) {
CompilationUnitScope(this, unit)
}
}