mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
ast: generate graph
This commit is contained in:
parent
0bc3128b9d
commit
f433ba2776
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ out/
|
||||
/work
|
||||
/kotlin-js-store
|
||||
/.fleet/*
|
||||
.DS_Store
|
||||
|
81
ast/src/main/graph/types.dot
Normal file
81
ast/src/main/graph/types.dot
Normal file
@ -0,0 +1,81 @@
|
||||
digraph A {
|
||||
type_Node [shape=box,label="Node"]
|
||||
type_Expression [shape=box,label="Expression"]
|
||||
type_Symbol [shape=box,label="Symbol"]
|
||||
type_Declaration [shape=box,label="Declaration"]
|
||||
type_Definition [shape=box,label="Definition"]
|
||||
type_DefinitionModifiers [shape=box,label="DefinitionModifiers"]
|
||||
type_Block [shape=box,label="Block"]
|
||||
type_CompilationUnit [shape=box,label="CompilationUnit"]
|
||||
type_LetAssignment [shape=box,label="LetAssignment"]
|
||||
type_InfixOperator [shape=box,label="InfixOperator"]
|
||||
type_InfixOperation [shape=box,label="InfixOperation"]
|
||||
type_BooleanLiteral [shape=box,label="BooleanLiteral"]
|
||||
type_FunctionCall [shape=box,label="FunctionCall"]
|
||||
type_FunctionDefinition [shape=box,label="FunctionDefinition"]
|
||||
type_If [shape=box,label="If"]
|
||||
type_ImportDeclaration [shape=box,label="ImportDeclaration"]
|
||||
type_IntegerLiteral [shape=box,label="IntegerLiteral"]
|
||||
type_DoubleLiteral [shape=box,label="DoubleLiteral"]
|
||||
type_ListLiteral [shape=box,label="ListLiteral"]
|
||||
type_Parentheses [shape=box,label="Parentheses"]
|
||||
type_PrefixOperator [shape=box,label="PrefixOperator"]
|
||||
type_PrefixOperation [shape=box,label="PrefixOperation"]
|
||||
type_StringLiteral [shape=box,label="StringLiteral"]
|
||||
type_SymbolReference [shape=box,label="SymbolReference"]
|
||||
type_While [shape=box,label="While"]
|
||||
type_Break [shape=box,label="Break"]
|
||||
type_Continue [shape=box,label="Continue"]
|
||||
type_Native [shape=box,label="Native"]
|
||||
type_Node -> type_Expression
|
||||
type_Node -> type_Symbol
|
||||
type_Node -> type_Declaration
|
||||
type_Node -> type_Definition
|
||||
type_Node -> type_Block
|
||||
type_Node -> type_CompilationUnit
|
||||
type_Node -> type_Native
|
||||
type_Expression -> type_LetAssignment
|
||||
type_Expression -> type_InfixOperation
|
||||
type_Expression -> type_BooleanLiteral
|
||||
type_Expression -> type_FunctionCall
|
||||
type_Expression -> type_If
|
||||
type_Expression -> type_IntegerLiteral
|
||||
type_Expression -> type_DoubleLiteral
|
||||
type_Expression -> type_ListLiteral
|
||||
type_Expression -> type_Parentheses
|
||||
type_Expression -> type_PrefixOperation
|
||||
type_Expression -> type_StringLiteral
|
||||
type_Expression -> type_SymbolReference
|
||||
type_Expression -> type_While
|
||||
type_Expression -> type_Break
|
||||
type_Expression -> type_Continue
|
||||
type_Definition -> type_FunctionDefinition
|
||||
type_Declaration -> type_ImportDeclaration
|
||||
type_Definition -> type_Symbol [style=dotted]
|
||||
type_Definition -> type_DefinitionModifiers [style=dotted]
|
||||
type_Block -> type_Expression [style=dotted]
|
||||
type_CompilationUnit -> type_Declaration [style=dotted]
|
||||
type_CompilationUnit -> type_Definition [style=dotted]
|
||||
type_LetAssignment -> type_Symbol [style=dotted]
|
||||
type_LetAssignment -> type_Expression [style=dotted]
|
||||
type_InfixOperation -> type_Expression [style=dotted]
|
||||
type_InfixOperation -> type_InfixOperator [style=dotted]
|
||||
type_FunctionCall -> type_Symbol [style=dotted]
|
||||
type_FunctionCall -> type_Expression [style=dotted]
|
||||
type_FunctionDefinition -> type_DefinitionModifiers [style=dotted]
|
||||
type_FunctionDefinition -> type_Symbol [style=dotted]
|
||||
type_FunctionDefinition -> type_Block [style=dotted]
|
||||
type_FunctionDefinition -> type_Native [style=dotted]
|
||||
type_If -> type_Expression [style=dotted]
|
||||
type_If -> type_Block [style=dotted]
|
||||
type_ImportDeclaration -> type_Symbol [style=dotted]
|
||||
type_ListLiteral -> type_Expression [style=dotted]
|
||||
type_Parentheses -> type_Expression [style=dotted]
|
||||
type_PrefixOperation -> type_PrefixOperator [style=dotted]
|
||||
type_PrefixOperation -> type_Expression [style=dotted]
|
||||
type_SymbolReference -> type_Symbol [style=dotted]
|
||||
type_While -> type_Expression [style=dotted]
|
||||
type_While -> type_Block [style=dotted]
|
||||
type_Native -> type_Symbol [style=dotted]
|
||||
type_Native -> type_StringLiteral [style=dotted]
|
||||
}
|
@ -1,12 +1,18 @@
|
||||
package gay.pizza.pork.buildext
|
||||
|
||||
import gay.pizza.pork.buildext.ast.AstCodegen
|
||||
import gay.pizza.pork.buildext.ast.AstGraph
|
||||
import gay.pizza.pork.buildext.ast.AstWorld
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import java.io.File
|
||||
import kotlin.io.path.createDirectories
|
||||
import kotlin.io.path.deleteIfExists
|
||||
import kotlin.io.path.writeText
|
||||
|
||||
open class GenerateAstCode : DefaultTask() {
|
||||
init {
|
||||
@ -22,8 +28,18 @@ open class GenerateAstCode : DefaultTask() {
|
||||
@get:OutputDirectory
|
||||
var outputDirectory: File = project.file("src/main/kotlin/gay/pizza/pork/ast")
|
||||
|
||||
@get:OutputFile
|
||||
var typeGraphFile: File = project.file("src/main/graph/types.dot")
|
||||
|
||||
@TaskAction
|
||||
fun generate() {
|
||||
AstCodegen.run(codePackage, astDescriptionFile.toPath(), outputDirectory.toPath())
|
||||
val world = AstWorld.read(astDescriptionFile.toPath())
|
||||
AstCodegen.run(codePackage, world, outputDirectory.toPath())
|
||||
|
||||
val typeGraphPath = typeGraphFile.toPath()
|
||||
typeGraphPath.deleteIfExists()
|
||||
typeGraphPath.parent.createDirectories()
|
||||
val graph = AstGraph.from(world)
|
||||
typeGraphPath.writeText(graph.renderDotGraph())
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
@file:Suppress("ConstPropertyName")
|
||||
package gay.pizza.pork.buildext.ast
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import gay.pizza.pork.buildext.codegen.*
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Path
|
||||
@ -407,15 +404,10 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
||||
companion object {
|
||||
private const val enableVisitAnyInline = false
|
||||
|
||||
fun run(pkg: String, astDescriptionFile: Path, outputDirectory: Path) {
|
||||
fun run(pkg: String, world: AstWorld, outputDirectory: Path) {
|
||||
if (!outputDirectory.exists()) {
|
||||
outputDirectory.createDirectories()
|
||||
}
|
||||
val astYamlText = astDescriptionFile.readText()
|
||||
val mapper = ObjectMapper(YAMLFactory())
|
||||
mapper.registerModules(KotlinModule.Builder().build())
|
||||
val astDescription = mapper.readValue(astYamlText, AstDescription::class.java)
|
||||
val world = AstWorld.build(astDescription)
|
||||
val codegen = AstCodegen(pkg, outputDirectory, world)
|
||||
codegen.generate()
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
package gay.pizza.pork.buildext.ast
|
||||
|
||||
class AstGraph {
|
||||
private val nodes = mutableSetOf<AstType>()
|
||||
private val children = mutableMapOf<AstType, MutableSet<AstType>>()
|
||||
private val valueReferences = mutableMapOf<AstType, MutableSet<AstType>>()
|
||||
|
||||
fun add(type: AstType) {
|
||||
nodes.add(type)
|
||||
if (type.parent != null) {
|
||||
children.getOrPut(type.parent!!) {
|
||||
mutableSetOf()
|
||||
}.add(type)
|
||||
add(type.parent!!)
|
||||
}
|
||||
|
||||
if (type.values != null) {
|
||||
for (value in type.values!!) {
|
||||
if (value.typeRef.type != null) {
|
||||
valueReferences.getOrPut(type) {
|
||||
mutableSetOf()
|
||||
}.add(value.typeRef.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun renderDotGraph(): String = buildString {
|
||||
appendLine("digraph A {")
|
||||
for (node in nodes) {
|
||||
appendLine(" type_${node.name} [shape=box,label=\"${node.name}\"]")
|
||||
}
|
||||
|
||||
for ((parent, children) in children) {
|
||||
for (child in children) {
|
||||
appendLine( " type_${parent.name} -> type_${child.name}")
|
||||
}
|
||||
}
|
||||
|
||||
for ((type, uses) in valueReferences) {
|
||||
for (use in uses) {
|
||||
appendLine(" type_${type.name} -> type_${use.name} [style=dotted]")
|
||||
}
|
||||
}
|
||||
|
||||
appendLine("}")
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun from(world: AstWorld): AstGraph {
|
||||
val graph = AstGraph()
|
||||
for (type in world.typeRegistry.types) {
|
||||
graph.add(type)
|
||||
}
|
||||
return graph
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +1,38 @@
|
||||
package gay.pizza.pork.buildext.ast
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.readText
|
||||
|
||||
class AstWorld {
|
||||
val typeRegistry: AstTypeRegistry = AstTypeRegistry()
|
||||
|
||||
fun typesInDependencyOrder(): List<AstType> {
|
||||
val typesInNameOrder = typeRegistry.types.sortedBy { it.name }
|
||||
val typesInDependencyOrder = mutableListOf<AstType>()
|
||||
for (type in typesInNameOrder) {
|
||||
|
||||
fun add(type: AstType, resolving: MutableSet<AstType>) {
|
||||
if (resolving.contains(type)) {
|
||||
val cyclePath = resolving.joinToString(" -> ") { it.name }
|
||||
throw RuntimeException("Dependency cycle detected: $cyclePath")
|
||||
}
|
||||
resolving.add(type)
|
||||
|
||||
if (type.parent != null) {
|
||||
if (!typesInDependencyOrder.contains(type.parent)) {
|
||||
typesInDependencyOrder.add(type.parent!!)
|
||||
}
|
||||
add(type.parent!!, resolving)
|
||||
}
|
||||
|
||||
if (!typesInDependencyOrder.contains(type)) {
|
||||
typesInDependencyOrder.add(type)
|
||||
}
|
||||
}
|
||||
|
||||
for (type in typesInNameOrder) {
|
||||
add(type, mutableSetOf())
|
||||
}
|
||||
|
||||
return typesInDependencyOrder
|
||||
}
|
||||
|
||||
@ -55,5 +71,13 @@ class AstWorld {
|
||||
}
|
||||
return world
|
||||
}
|
||||
|
||||
fun read(path: Path): AstWorld {
|
||||
val astYamlText = path.readText()
|
||||
val mapper = ObjectMapper(YAMLFactory())
|
||||
mapper.registerModules(KotlinModule.Builder().build())
|
||||
val astDescription = mapper.readValue(astYamlText, AstDescription::class.java)
|
||||
return build(astDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,10 @@ import kotlin.io.path.Path
|
||||
object RunCodegenIde {
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
val world = AstWorld.read(Path("src/main/ast/pork.yml"))
|
||||
AstCodegen.run(
|
||||
pkg = "gay.pizza.pork.ast",
|
||||
astDescriptionFile = Path("src/main/ast/pork.yml"),
|
||||
world = world,
|
||||
outputDirectory = Path("src/main/kotlin/gay/pizza/pork/ast")
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user