mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
frontend: implement basic scope analysis
This commit is contained in:
parent
aadc8282a5
commit
821aa3563a
@ -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)
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -19,6 +19,9 @@ abstract class Tool {
|
||||
abstract fun createContentSource(): ContentSource
|
||||
abstract fun rootFilePath(): String
|
||||
|
||||
val rootImportLocator: ImportLocator
|
||||
get() = ImportLocator("local", rootFilePath())
|
||||
|
||||
fun tokenize(): TokenStream =
|
||||
Tokenizer(createCharSource()).tokenize()
|
||||
|
||||
@ -33,16 +36,20 @@ abstract class Tool {
|
||||
fun <T> visit(visitor: NodeVisitor<T>): T = visitor.visit(parse())
|
||||
|
||||
fun loadMainFunction(scope: Scope, setupEvaluator: Evaluator.() -> Unit = {}): CallableFunction {
|
||||
val world = buildWorld()
|
||||
val evaluator = Evaluator(world, scope)
|
||||
setupEvaluator(evaluator)
|
||||
val resultingScope = evaluator.evaluate(rootImportLocator)
|
||||
return resultingScope.value("main") as CallableFunction
|
||||
}
|
||||
|
||||
fun buildWorld(): World {
|
||||
val fileContentSource = createContentSource()
|
||||
val dynamicImportSource = DynamicImportSource()
|
||||
dynamicImportSource.addContentSource("std", PorkStdlib)
|
||||
dynamicImportSource.addContentSource("local", fileContentSource)
|
||||
dynamicImportSource.addContentSource("java", JavaAutogenContentSource)
|
||||
val world = World(dynamicImportSource)
|
||||
val evaluator = Evaluator(world, scope)
|
||||
setupEvaluator(evaluator)
|
||||
val resultingScope = evaluator.evaluate(ImportLocator("local", rootFilePath()))
|
||||
return resultingScope.value("main") as CallableFunction
|
||||
return World(dynamicImportSource)
|
||||
}
|
||||
|
||||
fun run(scope: Scope, quiet: Boolean = false) {
|
||||
|
@ -1,10 +1,11 @@
|
||||
package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.ast.Node
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
|
||||
object DiscardNodeAttribution : NodeAttribution {
|
||||
override fun push(token: Token) {}
|
||||
override fun <T : Node> adopt(node: T) {}
|
||||
override fun <T : Node> guarded(block: () -> T): T =
|
||||
override fun <T : Node> guarded(type: NodeType?, block: () -> T): T =
|
||||
block()
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.ast.Node
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
|
||||
interface NodeAttribution {
|
||||
fun push(token: Token)
|
||||
fun <T: Node> adopt(node: T)
|
||||
fun <T: Node> guarded(block: () -> T): T
|
||||
fun <T: Node> guarded(type: NodeType?, block: () -> T): T
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
private var storedSymbol: Symbol? = null
|
||||
private var storedDefinitionModifiers: DefinitionModifiers? = null
|
||||
|
||||
override fun parseBlock(): Block = guarded {
|
||||
override fun parseBlock(): Block = guarded(NodeType.Block) {
|
||||
expect(TokenType.LeftCurly)
|
||||
val items = collect(TokenType.RightCurly) {
|
||||
parseExpression()
|
||||
@ -45,7 +45,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
}
|
||||
|
||||
if (expression is SymbolReference && peek(TokenType.Equals)) {
|
||||
return@guarded guarded {
|
||||
return@guarded guarded(NodeType.SetAssignment) {
|
||||
attribution.adopt(expression)
|
||||
expect(TokenType.Equals)
|
||||
val value = parseExpression()
|
||||
@ -73,7 +73,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
TokenType.Or
|
||||
)
|
||||
) {
|
||||
guarded {
|
||||
guarded(NodeType.InfixOperation) {
|
||||
val infixToken = next()
|
||||
val infixOperator = ParserHelpers.convertInfixOperator(infixToken)
|
||||
InfixOperation(expression, infixOperator, parseExpression())
|
||||
@ -81,7 +81,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
} else expression
|
||||
}
|
||||
|
||||
override fun parseBooleanLiteral(): BooleanLiteral = guarded {
|
||||
override fun parseBooleanLiteral(): BooleanLiteral = guarded(NodeType.BooleanLiteral) {
|
||||
if (next(TokenType.True)) {
|
||||
BooleanLiteral(true)
|
||||
} else if (next(TokenType.False)) {
|
||||
@ -91,12 +91,12 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseBreak(): Break = guarded {
|
||||
override fun parseBreak(): Break = guarded(NodeType.Break) {
|
||||
expect(TokenType.Break)
|
||||
Break()
|
||||
}
|
||||
|
||||
override fun parseCompilationUnit(): CompilationUnit = guarded {
|
||||
override fun parseCompilationUnit(): CompilationUnit = guarded(NodeType.CompilationUnit) {
|
||||
val declarations = mutableListOf<Declaration>()
|
||||
val definitions = mutableListOf<Definition>()
|
||||
var declarationAccepted = true
|
||||
@ -118,7 +118,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
CompilationUnit(declarations, definitions)
|
||||
}
|
||||
|
||||
override fun parseContinue(): Continue = guarded {
|
||||
override fun parseContinue(): Continue = guarded(NodeType.Continue) {
|
||||
expect(TokenType.Continue)
|
||||
Continue()
|
||||
}
|
||||
@ -167,11 +167,11 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
maybeParseDefinition() ?: throw ParseError("Unable to parse definition")
|
||||
}
|
||||
|
||||
override fun parseDoubleLiteral(): DoubleLiteral = guarded {
|
||||
override fun parseDoubleLiteral(): DoubleLiteral = guarded(NodeType.DoubleLiteral) {
|
||||
DoubleLiteral(expect(TokenType.NumberLiteral).text.toDouble())
|
||||
}
|
||||
|
||||
override fun parseForIn(): ForIn = guarded {
|
||||
override fun parseForIn(): ForIn = guarded(NodeType.ForIn) {
|
||||
expect(TokenType.For)
|
||||
val symbol = parseSymbol()
|
||||
expect(TokenType.In)
|
||||
@ -180,11 +180,10 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
ForIn(symbol, value, block)
|
||||
}
|
||||
|
||||
override fun parseFunctionCall(): FunctionCall = guarded {
|
||||
override fun parseFunctionCall(): FunctionCall =
|
||||
parseFunctionCall(null)
|
||||
}
|
||||
|
||||
fun parseFunctionCall(target: Symbol?): FunctionCall = guarded {
|
||||
fun parseFunctionCall(target: Symbol?): FunctionCall = guarded(NodeType.FunctionCall) {
|
||||
val symbol = target ?: parseSymbol()
|
||||
val arguments = collect(TokenType.RightParentheses, TokenType.Comma) {
|
||||
parseExpression()
|
||||
@ -193,7 +192,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
FunctionCall(symbol, arguments)
|
||||
}
|
||||
|
||||
override fun parseFunctionDefinition(): FunctionDefinition = guarded {
|
||||
override fun parseFunctionDefinition(): FunctionDefinition = guarded(NodeType.FunctionDefinition) {
|
||||
val modifiers = storedDefinitionModifiers ?: parseDefinitionModifiers()
|
||||
expect(TokenType.Func)
|
||||
val name = parseSymbol()
|
||||
@ -218,7 +217,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
FunctionDefinition(modifiers, name, arguments, block, native)
|
||||
}
|
||||
|
||||
override fun parseIf(): If = guarded {
|
||||
override fun parseIf(): If = guarded(NodeType.If) {
|
||||
expect(TokenType.If)
|
||||
val condition = parseExpression()
|
||||
val thenBlock = parseBlock()
|
||||
@ -229,7 +228,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
If(condition, thenBlock, elseBlock)
|
||||
}
|
||||
|
||||
override fun parseImportDeclaration(): ImportDeclaration = guarded {
|
||||
override fun parseImportDeclaration(): ImportDeclaration = guarded(NodeType.ImportDeclaration) {
|
||||
expect(TokenType.Import)
|
||||
val form = parseSymbol()
|
||||
val components = oneAndContinuedBy(TokenType.Dot) {
|
||||
@ -238,7 +237,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
ImportDeclaration(form, components)
|
||||
}
|
||||
|
||||
override fun parseInfixOperation(): InfixOperation = guarded {
|
||||
override fun parseInfixOperation(): InfixOperation = guarded(NodeType.InfixOperation) {
|
||||
val infixToken = next()
|
||||
val infixOperator = ParserHelpers.convertInfixOperator(infixToken)
|
||||
InfixOperation(parseExpression(), infixOperator, parseExpression())
|
||||
@ -258,11 +257,11 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseIntegerLiteral(): IntegerLiteral = guarded {
|
||||
override fun parseIntegerLiteral(): IntegerLiteral = guarded(NodeType.IntegerLiteral) {
|
||||
IntegerLiteral(expect(TokenType.NumberLiteral).text.toInt())
|
||||
}
|
||||
|
||||
override fun parseLetAssignment(): LetAssignment = guarded {
|
||||
override fun parseLetAssignment(): LetAssignment = guarded(NodeType.LetAssignment) {
|
||||
expect(TokenType.Let)
|
||||
val symbol = parseSymbol()
|
||||
expect(TokenType.Equals)
|
||||
@ -270,7 +269,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
LetAssignment(symbol, value)
|
||||
}
|
||||
|
||||
override fun parseLetDefinition(): LetDefinition = guarded {
|
||||
override fun parseLetDefinition(): LetDefinition = guarded(NodeType.LetDefinition) {
|
||||
val definitionModifiers = storedDefinitionModifiers ?: parseDefinitionModifiers()
|
||||
expect(TokenType.Let)
|
||||
val name = parseSymbol()
|
||||
@ -279,7 +278,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
LetDefinition(definitionModifiers, name, value)
|
||||
}
|
||||
|
||||
override fun parseListLiteral(): ListLiteral = guarded {
|
||||
override fun parseListLiteral(): ListLiteral = guarded(NodeType.ListLiteral) {
|
||||
expect(TokenType.LeftBracket)
|
||||
val items = collect(TokenType.RightBracket, TokenType.Comma) {
|
||||
parseExpression()
|
||||
@ -288,50 +287,50 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
ListLiteral(items)
|
||||
}
|
||||
|
||||
override fun parseLongLiteral(): LongLiteral = guarded {
|
||||
override fun parseLongLiteral(): LongLiteral = guarded(NodeType.LongLiteral) {
|
||||
LongLiteral(expect(TokenType.NumberLiteral).text.toLong())
|
||||
}
|
||||
|
||||
override fun parseNative(): Native = guarded {
|
||||
override fun parseNative(): Native = guarded(NodeType.Native) {
|
||||
expect(TokenType.Native)
|
||||
val form = parseSymbol()
|
||||
val definition = parseStringLiteral()
|
||||
Native(form, definition)
|
||||
}
|
||||
|
||||
override fun parseNoneLiteral(): NoneLiteral = guarded {
|
||||
override fun parseNoneLiteral(): NoneLiteral = guarded(NodeType.NoneLiteral) {
|
||||
expect(TokenType.None)
|
||||
NoneLiteral()
|
||||
}
|
||||
|
||||
override fun parseParentheses(): Parentheses = guarded {
|
||||
override fun parseParentheses(): Parentheses = guarded(NodeType.Parentheses) {
|
||||
expect(TokenType.LeftParentheses)
|
||||
val expression = parseExpression()
|
||||
expect(TokenType.RightParentheses)
|
||||
Parentheses(expression)
|
||||
}
|
||||
|
||||
override fun parsePrefixOperation(): PrefixOperation = guarded {
|
||||
override fun parsePrefixOperation(): PrefixOperation = guarded(NodeType.PrefixOperation) {
|
||||
expect(TokenType.Not, TokenType.Plus, TokenType.Minus, TokenType.Tilde) {
|
||||
PrefixOperation(ParserHelpers.convertPrefixOperator(it), parseExpression())
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseSetAssignment(): SetAssignment = guarded {
|
||||
override fun parseSetAssignment(): SetAssignment = guarded(NodeType.SetAssignment) {
|
||||
val symbol = storedSymbol ?: parseSymbol()
|
||||
expect(TokenType.Equals)
|
||||
val value = parseExpression()
|
||||
SetAssignment(symbol, value)
|
||||
}
|
||||
|
||||
override fun parseStringLiteral(): StringLiteral = guarded {
|
||||
override fun parseStringLiteral(): StringLiteral = guarded(NodeType.StringLiteral) {
|
||||
expect(TokenType.StringLiteral) {
|
||||
val content = StringEscape.unescape(StringEscape.unquote(it.text))
|
||||
StringLiteral(content)
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseSuffixOperation(): SuffixOperation = guarded {
|
||||
override fun parseSuffixOperation(): SuffixOperation = guarded(NodeType.SuffixOperation) {
|
||||
val reference = parseSymbolReference()
|
||||
expect(TokenType.PlusPlus, TokenType.MinusMinus) {
|
||||
SuffixOperation(ParserHelpers.convertSuffixOperator(it), reference)
|
||||
@ -352,15 +351,15 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseSymbol(): Symbol = guarded {
|
||||
override fun parseSymbol(): Symbol = guarded(NodeType.Symbol) {
|
||||
expect(TokenType.Symbol) { Symbol(it.text) }
|
||||
}
|
||||
|
||||
override fun parseSymbolReference(): SymbolReference = guarded {
|
||||
override fun parseSymbolReference(): SymbolReference = guarded(NodeType.SymbolReference) {
|
||||
SymbolReference(parseSymbol())
|
||||
}
|
||||
|
||||
override fun parseVarAssignment(): VarAssignment = guarded {
|
||||
override fun parseVarAssignment(): VarAssignment = guarded(NodeType.VarAssignment) {
|
||||
expect(TokenType.Var)
|
||||
val symbol = parseSymbol()
|
||||
expect(TokenType.Equals)
|
||||
@ -368,7 +367,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
VarAssignment(symbol, value)
|
||||
}
|
||||
|
||||
override fun parseWhile(): While = guarded {
|
||||
override fun parseWhile(): While = guarded(NodeType.While) {
|
||||
expect(TokenType.While)
|
||||
val condition = parseExpression()
|
||||
val block = parseBlock()
|
||||
|
@ -2,6 +2,7 @@ package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.ast.Node
|
||||
import gay.pizza.pork.ast.NodeParser
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
|
||||
abstract class ParserBase(val source: TokenSource, val attribution: NodeAttribution) : NodeParser {
|
||||
class ExpectedTokenError(got: Token, vararg expectedTypes: TokenType) : ParseError(
|
||||
@ -9,7 +10,8 @@ abstract class ParserBase(val source: TokenSource, val attribution: NodeAttribut
|
||||
" but got type ${got.type} '${got.text}'"
|
||||
)
|
||||
|
||||
protected fun <T: Node> guarded(block: () -> T): T = attribution.guarded(block)
|
||||
protected fun <T: Node> guarded(type: NodeType? = null, block: () -> T): T =
|
||||
attribution.guarded(type, block)
|
||||
|
||||
protected fun <T> collect(
|
||||
peeking: TokenType,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.ast.Node
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.ast.data
|
||||
|
||||
open class ParserNodeAttribution : NodeAttribution {
|
||||
@ -22,7 +23,7 @@ open class ParserNodeAttribution : NodeAttribution {
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : Node> guarded(block: () -> T): T {
|
||||
override fun <T : Node> guarded(type: NodeType?, block: () -> T): T {
|
||||
var store = mutableListOf<Token>()
|
||||
current = store
|
||||
stack.add(store)
|
||||
|
@ -1,7 +1,10 @@
|
||||
package gay.pizza.pork.idea
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import gay.pizza.pork.ast.Node
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.parser.TokenType
|
||||
|
||||
|
@ -2,6 +2,7 @@ package gay.pizza.pork.idea
|
||||
|
||||
import com.intellij.lang.PsiBuilder
|
||||
import gay.pizza.pork.ast.Node
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.parser.ParseError
|
||||
import gay.pizza.pork.parser.ParserNodeAttribution
|
||||
import java.util.IdentityHashMap
|
||||
@ -9,14 +10,14 @@ import java.util.IdentityHashMap
|
||||
class PsiBuilderMarkAttribution(val builder: PsiBuilder) : ParserNodeAttribution() {
|
||||
private val map = IdentityHashMap<Node, Node>()
|
||||
|
||||
override fun <T : Node> guarded(block: () -> T): T {
|
||||
override fun <T : Node> guarded(type: NodeType?, block: () -> T): T {
|
||||
val marker = builder.mark()
|
||||
val result = try {
|
||||
val item = super.guarded(block)
|
||||
val item = super.guarded(type, block)
|
||||
marker.done(PorkElementTypes.elementTypeFor(item.type))
|
||||
item
|
||||
} catch (e: PsiBuilderTokenSource.BadCharacterError) {
|
||||
marker.error("Bad character.")
|
||||
marker.error("Invalid character")
|
||||
while (!builder.eof()) {
|
||||
builder.advanceLexer()
|
||||
}
|
||||
|
@ -15,7 +15,8 @@ class RootCommand : CliktCommand(
|
||||
ReprintCommand(),
|
||||
ParseCommand(),
|
||||
AstCommand(),
|
||||
AttributeCommand()
|
||||
AttributeCommand(),
|
||||
ScopeAnalysisCommand()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
package gay.pizza.pork.tool
|
||||
|
||||
import com.github.ajalt.clikt.core.CliktCommand
|
||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||
import gay.pizza.dough.fs.PlatformFsProvider
|
||||
import gay.pizza.pork.frontend.scope.WorldScope
|
||||
import gay.pizza.pork.minimal.FileTool
|
||||
|
||||
class ScopeAnalysisCommand : CliktCommand(help = "Run Scope Analysis", name = "scope-analysis") {
|
||||
val path by argument("file")
|
||||
|
||||
override fun run() {
|
||||
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||
val world = tool.buildWorld()
|
||||
val root = world.load(tool.rootImportLocator)
|
||||
val scope = WorldScope(world).apply { index(root) }
|
||||
val rootScope = scope.scope(root)
|
||||
val visibleScopeSymbols = rootScope.findInternallyVisibleSymbols()
|
||||
for (visibleScopeSymbol in visibleScopeSymbols) {
|
||||
println(
|
||||
"symbol ${visibleScopeSymbol.scopeSymbol.symbol.id} " +
|
||||
"type=${visibleScopeSymbol.scopeSymbol.definition.type.name} " +
|
||||
"internal=${visibleScopeSymbol.isInternalSymbol}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user