mirror of
				https://github.com/GayPizzaSpecifications/pork.git
				synced 2025-11-03 17:39:38 +00:00 
			
		
		
		
	Auto-generate the AST.
This commit is contained in:
		
							
								
								
									
										10
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							@ -15,3 +15,13 @@ jobs:
 | 
				
			|||||||
        uses: gradle/gradle-build-action@v2
 | 
					        uses: gradle/gradle-build-action@v2
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          arguments: build
 | 
					          arguments: build
 | 
				
			||||||
 | 
					      - name: Archive Pork Bundle
 | 
				
			||||||
 | 
					        uses: actions/upload-artifact@v3
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: pork-bundle
 | 
				
			||||||
 | 
					          path: tool/build/distributions/pork.zip
 | 
				
			||||||
 | 
					      - name: Archive Pork Jar
 | 
				
			||||||
 | 
					        uses: actions/upload-artifact@v3
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: pork-jar
 | 
				
			||||||
 | 
					          path: tool/build/distributions/pork-all.jar
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								.github/workflows/graal.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.github/workflows/graal.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					name: graal
 | 
				
			||||||
 | 
					on: [push]
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  linux-amd64:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					    - name: Checkout Repository
 | 
				
			||||||
 | 
					      uses: actions/checkout@v3
 | 
				
			||||||
 | 
					    - name: Set up GraalVM
 | 
				
			||||||
 | 
					      uses: graalvm/setup-graalvm@v1
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        java-version: '17'
 | 
				
			||||||
 | 
					        distribution: 'graalvm'
 | 
				
			||||||
 | 
					    - name: Build with Gradle
 | 
				
			||||||
 | 
					      uses: gradle/gradle-build-action@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        arguments: nativeCompile
 | 
				
			||||||
 | 
					    - name: Archive Pork Executable
 | 
				
			||||||
 | 
					      uses: actions/upload-artifact@v3
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: pork-linux-amd64
 | 
				
			||||||
 | 
					        path: tool/build/native/nativeCompile/pork
 | 
				
			||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
  pork_module
 | 
					  id("gay.pizza.pork.module")
 | 
				
			||||||
 | 
					 | 
				
			||||||
  id("gay.pizza.pork.ast")
 | 
					  id("gay.pizza.pork.ast")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@ types:
 | 
				
			|||||||
    - name: declarations
 | 
					    - name: declarations
 | 
				
			||||||
      type: List<Declaration>
 | 
					      type: List<Declaration>
 | 
				
			||||||
    - name: definitions
 | 
					    - name: definitions
 | 
				
			||||||
      type: List<Declaration>
 | 
					      type: List<Definition>
 | 
				
			||||||
  LetAssignment:
 | 
					  LetAssignment:
 | 
				
			||||||
    parent: Expression
 | 
					    parent: Expression
 | 
				
			||||||
    values:
 | 
					    values:
 | 
				
			||||||
 | 
				
			|||||||
@ -9,15 +9,16 @@ class CompilationUnit(val declarations: List<Declaration>, val definitions: List
 | 
				
			|||||||
  override val type: NodeType = NodeType.CompilationUnit
 | 
					  override val type: NodeType = NodeType.CompilationUnit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
 | 
					  override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
 | 
				
			||||||
    visitor.visitAll(declarations)
 | 
					    visitor.visitAll(declarations, definitions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun equals(other: Any?): Boolean {
 | 
					  override fun equals(other: Any?): Boolean {
 | 
				
			||||||
    if (other !is CompilationUnit) return false
 | 
					    if (other !is CompilationUnit) return false
 | 
				
			||||||
    return other.declarations == declarations
 | 
					    return other.declarations == declarations && other.definitions == definitions
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun hashCode(): Int {
 | 
					  override fun hashCode(): Int {
 | 
				
			||||||
    var result = declarations.hashCode()
 | 
					    var result = declarations.hashCode()
 | 
				
			||||||
 | 
					    result = 31 * result + definitions.hashCode()
 | 
				
			||||||
    result = 31 * result + type.hashCode()
 | 
					    result = 31 * result + type.hashCode()
 | 
				
			||||||
    return result
 | 
					    return result
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
package gay.pizza.pork.ast
 | 
					package gay.pizza.pork.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
 | 
					@SerialName("declaration")
 | 
				
			||||||
sealed class Declaration : Node()
 | 
					sealed class Declaration : Node()
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,10 @@
 | 
				
			|||||||
package gay.pizza.pork.ast
 | 
					package gay.pizza.pork.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
 | 
					@SerialName("definition")
 | 
				
			||||||
sealed class Definition : Node() {
 | 
					sealed class Definition : Node() {
 | 
				
			||||||
  abstract val symbol: Symbol
 | 
					  abstract val symbol: Symbol
 | 
				
			||||||
  abstract val modifiers: DefinitionModifiers
 | 
					  abstract val modifiers: DefinitionModifiers
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
package gay.pizza.pork.ast
 | 
					package gay.pizza.pork.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
class DefinitionModifiers(
 | 
					@SerialName("definitionModifiers")
 | 
				
			||||||
  var export: Boolean
 | 
					class DefinitionModifiers(var export: Boolean)
 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
package gay.pizza.pork.ast
 | 
					package gay.pizza.pork.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
 | 
					@SerialName("expression")
 | 
				
			||||||
sealed class Expression : Node()
 | 
					sealed class Expression : Node()
 | 
				
			||||||
 | 
				
			|||||||
@ -5,24 +5,20 @@ import kotlinx.serialization.Serializable
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
@SerialName("functionDefinition")
 | 
					@SerialName("functionDefinition")
 | 
				
			||||||
class FunctionDefinition(
 | 
					class FunctionDefinition(override val modifiers: DefinitionModifiers, override val symbol: Symbol, val arguments: List<Symbol>, val block: Block) : Definition() {
 | 
				
			||||||
  override val modifiers: DefinitionModifiers,
 | 
					 | 
				
			||||||
  override val symbol: Symbol,
 | 
					 | 
				
			||||||
  val arguments: List<Symbol>,
 | 
					 | 
				
			||||||
  val block: Block
 | 
					 | 
				
			||||||
) : Definition() {
 | 
					 | 
				
			||||||
  override val type: NodeType = NodeType.FunctionDefinition
 | 
					  override val type: NodeType = NodeType.FunctionDefinition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
 | 
					  override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
 | 
				
			||||||
    visitor.visitNodes(symbol)
 | 
					    visitor.visitAll(listOf(symbol), arguments, listOf(block))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun equals(other: Any?): Boolean {
 | 
					  override fun equals(other: Any?): Boolean {
 | 
				
			||||||
    if (other !is FunctionDefinition) return false
 | 
					    if (other !is FunctionDefinition) return false
 | 
				
			||||||
    return other.symbol == symbol && other.arguments == arguments && other.block == block
 | 
					    return other.modifiers == modifiers && other.symbol == symbol && other.arguments == arguments && other.block == block
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun hashCode(): Int {
 | 
					  override fun hashCode(): Int {
 | 
				
			||||||
    var result = symbol.hashCode()
 | 
					    var result = modifiers.hashCode()
 | 
				
			||||||
 | 
					    result = 31 * result + symbol.hashCode()
 | 
				
			||||||
    result = 31 * result + arguments.hashCode()
 | 
					    result = 31 * result + arguments.hashCode()
 | 
				
			||||||
    result = 31 * result + block.hashCode()
 | 
					    result = 31 * result + block.hashCode()
 | 
				
			||||||
    result = 31 * result + type.hashCode()
 | 
					    result = 31 * result + type.hashCode()
 | 
				
			||||||
 | 
				
			|||||||
@ -5,11 +5,7 @@ import kotlinx.serialization.Serializable
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
@SerialName("if")
 | 
					@SerialName("if")
 | 
				
			||||||
class If(
 | 
					class If(val condition: Expression, val thenExpression: Expression, val elseExpression: Expression?) : Expression() {
 | 
				
			||||||
  val condition: Expression,
 | 
					 | 
				
			||||||
  val thenExpression: Expression,
 | 
					 | 
				
			||||||
  val elseExpression: Expression? = null
 | 
					 | 
				
			||||||
) : Expression() {
 | 
					 | 
				
			||||||
  override val type: NodeType = NodeType.If
 | 
					  override val type: NodeType = NodeType.If
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
 | 
					  override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
 | 
				
			||||||
@ -17,15 +13,13 @@ class If(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun equals(other: Any?): Boolean {
 | 
					  override fun equals(other: Any?): Boolean {
 | 
				
			||||||
    if (other !is If) return false
 | 
					    if (other !is If) return false
 | 
				
			||||||
    return other.condition == condition &&
 | 
					    return other.condition == condition && other.thenExpression == thenExpression && other.elseExpression == elseExpression
 | 
				
			||||||
      other.thenExpression == thenExpression &&
 | 
					 | 
				
			||||||
      other.elseExpression == elseExpression
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun hashCode(): Int {
 | 
					  override fun hashCode(): Int {
 | 
				
			||||||
    var result = condition.hashCode()
 | 
					    var result = condition.hashCode()
 | 
				
			||||||
    result = 31 * result + thenExpression.hashCode()
 | 
					    result = 31 * result + thenExpression.hashCode()
 | 
				
			||||||
    result = 31 * result + (elseExpression?.hashCode() ?: 0)
 | 
					    result = 31 * result + elseExpression.hashCode()
 | 
				
			||||||
    result = 31 * result + type.hashCode()
 | 
					    result = 31 * result + type.hashCode()
 | 
				
			||||||
    return result
 | 
					    return result
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -5,11 +5,7 @@ import kotlinx.serialization.Serializable
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
@SerialName("infixOperation")
 | 
					@SerialName("infixOperation")
 | 
				
			||||||
class InfixOperation(
 | 
					class InfixOperation(val left: Expression, val op: InfixOperator, val right: Expression) : Expression() {
 | 
				
			||||||
  val left: Expression,
 | 
					 | 
				
			||||||
  val op: InfixOperator,
 | 
					 | 
				
			||||||
  val right: Expression
 | 
					 | 
				
			||||||
) : Expression() {
 | 
					 | 
				
			||||||
  override val type: NodeType = NodeType.InfixOperation
 | 
					  override val type: NodeType = NodeType.InfixOperation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
 | 
					  override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
 | 
				
			||||||
@ -17,9 +13,7 @@ class InfixOperation(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  override fun equals(other: Any?): Boolean {
 | 
					  override fun equals(other: Any?): Boolean {
 | 
				
			||||||
    if (other !is InfixOperation) return false
 | 
					    if (other !is InfixOperation) return false
 | 
				
			||||||
    return other.op == op &&
 | 
					    return other.left == left && other.op == op && other.right == right
 | 
				
			||||||
      other.left == left &&
 | 
					 | 
				
			||||||
      other.right == right
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun hashCode(): Int {
 | 
					  override fun hashCode(): Int {
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ class IntLiteral(val value: Int) : Expression() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun hashCode(): Int {
 | 
					  override fun hashCode(): Int {
 | 
				
			||||||
    var result = value
 | 
					    var result = value.hashCode()
 | 
				
			||||||
    result = 31 * result + type.hashCode()
 | 
					    result = 31 * result + type.hashCode()
 | 
				
			||||||
    return result
 | 
					    return result
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,13 @@
 | 
				
			|||||||
package gay.pizza.pork.ast
 | 
					package gay.pizza.pork.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
 | 
					@SerialName("node")
 | 
				
			||||||
sealed class Node {
 | 
					sealed class Node {
 | 
				
			||||||
  abstract val type: NodeType
 | 
					  abstract val type: NodeType
 | 
				
			||||||
  open fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> = emptyList()
 | 
					
 | 
				
			||||||
 | 
					  open fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
 | 
				
			||||||
 | 
					    emptyList()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,26 +1,58 @@
 | 
				
			|||||||
package gay.pizza.pork.ast
 | 
					package gay.pizza.pork.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
 | 
					class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
 | 
				
			||||||
  override fun visitIntLiteral(node: IntLiteral): Unit = handle(node)
 | 
					  override fun visitBlock(node: Block): Unit =
 | 
				
			||||||
  override fun visitStringLiteral(node: StringLiteral): Unit = handle(node)
 | 
					    handle(node)
 | 
				
			||||||
  override fun visitBooleanLiteral(node: BooleanLiteral): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitListLiteral(node: ListLiteral): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitSymbol(node: Symbol): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitFunctionCall(node: FunctionCall): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitLetAssignment(node: LetAssignment): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitSymbolReference(node: SymbolReference): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitLambda(node: Lambda): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitParentheses(node: Parentheses): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitPrefixOperation(node: PrefixOperation): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitIf(node: If): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitInfixOperation(node: InfixOperation): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitFunctionDeclaration(node: FunctionDefinition): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitBlock(node: Block): Unit = handle(node)
 | 
					 | 
				
			||||||
  override fun visitImportDeclaration(node: ImportDeclaration): Unit = handle(node)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitCompilationUnit(node: CompilationUnit): Unit = handle(node)
 | 
					  override fun visitBooleanLiteral(node: BooleanLiteral): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun handle(node: Node) {
 | 
					  override fun visitCompilationUnit(node: CompilationUnit): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitFunctionCall(node: FunctionCall): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitFunctionDefinition(node: FunctionDefinition): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitIf(node: If): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitImportDeclaration(node: ImportDeclaration): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitInfixOperation(node: InfixOperation): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitIntLiteral(node: IntLiteral): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitLambda(node: Lambda): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitLetAssignment(node: LetAssignment): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitListLiteral(node: ListLiteral): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitParentheses(node: Parentheses): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitPrefixOperation(node: PrefixOperation): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitStringLiteral(node: StringLiteral): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitSymbol(node: Symbol): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun visitSymbolReference(node: SymbolReference): Unit =
 | 
				
			||||||
 | 
					    handle(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun handle(node: Node) {
 | 
				
			||||||
    handler(node)
 | 
					    handler(node)
 | 
				
			||||||
    node.visitChildren(this)
 | 
					    node.visitChildren(this)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -2,24 +2,24 @@ package gay.pizza.pork.ast
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
enum class NodeType(val parent: NodeType? = null) {
 | 
					enum class NodeType(val parent: NodeType? = null) {
 | 
				
			||||||
  Node,
 | 
					  Node,
 | 
				
			||||||
  Symbol(Node),
 | 
					  Block(Node),
 | 
				
			||||||
  Expression(Node),
 | 
					  Expression(Node),
 | 
				
			||||||
 | 
					  BooleanLiteral(Expression),
 | 
				
			||||||
 | 
					  CompilationUnit(Node),
 | 
				
			||||||
  Declaration(Node),
 | 
					  Declaration(Node),
 | 
				
			||||||
  Definition(Node),
 | 
					  Definition(Node),
 | 
				
			||||||
  Block(Node),
 | 
					 | 
				
			||||||
  CompilationUnit(Node),
 | 
					 | 
				
			||||||
  IntLiteral(Expression),
 | 
					 | 
				
			||||||
  BooleanLiteral(Expression),
 | 
					 | 
				
			||||||
  ListLiteral(Expression),
 | 
					 | 
				
			||||||
  StringLiteral(Expression),
 | 
					 | 
				
			||||||
  Parentheses(Expression),
 | 
					 | 
				
			||||||
  LetAssignment(Expression),
 | 
					 | 
				
			||||||
  Lambda(Expression),
 | 
					 | 
				
			||||||
  PrefixOperation(Expression),
 | 
					 | 
				
			||||||
  InfixOperation(Expression),
 | 
					 | 
				
			||||||
  SymbolReference(Expression),
 | 
					 | 
				
			||||||
  FunctionCall(Expression),
 | 
					  FunctionCall(Expression),
 | 
				
			||||||
 | 
					  FunctionDefinition(Definition),
 | 
				
			||||||
  If(Expression),
 | 
					  If(Expression),
 | 
				
			||||||
  ImportDeclaration(Declaration),
 | 
					  ImportDeclaration(Declaration),
 | 
				
			||||||
  FunctionDefinition(Definition)
 | 
					  InfixOperation(Expression),
 | 
				
			||||||
 | 
					  IntLiteral(Expression),
 | 
				
			||||||
 | 
					  Lambda(Expression),
 | 
				
			||||||
 | 
					  LetAssignment(Expression),
 | 
				
			||||||
 | 
					  ListLiteral(Expression),
 | 
				
			||||||
 | 
					  Parentheses(Expression),
 | 
				
			||||||
 | 
					  PrefixOperation(Expression),
 | 
				
			||||||
 | 
					  StringLiteral(Expression),
 | 
				
			||||||
 | 
					  Symbol(Node),
 | 
				
			||||||
 | 
					  SymbolReference(Expression)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,60 +1,64 @@
 | 
				
			|||||||
package gay.pizza.pork.ast
 | 
					package gay.pizza.pork.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface NodeVisitor<T> {
 | 
					interface NodeVisitor<T> {
 | 
				
			||||||
  fun visitIntLiteral(node: IntLiteral): T
 | 
					 | 
				
			||||||
  fun visitStringLiteral(node: StringLiteral): T
 | 
					 | 
				
			||||||
  fun visitBooleanLiteral(node: BooleanLiteral): T
 | 
					 | 
				
			||||||
  fun visitListLiteral(node: ListLiteral): T
 | 
					 | 
				
			||||||
  fun visitSymbol(node: Symbol): T
 | 
					 | 
				
			||||||
  fun visitFunctionCall(node: FunctionCall): T
 | 
					 | 
				
			||||||
  fun visitLetAssignment(node: LetAssignment): T
 | 
					 | 
				
			||||||
  fun visitSymbolReference(node: SymbolReference): T
 | 
					 | 
				
			||||||
  fun visitLambda(node: Lambda): T
 | 
					 | 
				
			||||||
  fun visitParentheses(node: Parentheses): T
 | 
					 | 
				
			||||||
  fun visitPrefixOperation(node: PrefixOperation): T
 | 
					 | 
				
			||||||
  fun visitIf(node: If): T
 | 
					 | 
				
			||||||
  fun visitInfixOperation(node: InfixOperation): T
 | 
					 | 
				
			||||||
  fun visitFunctionDeclaration(node: FunctionDefinition): T
 | 
					 | 
				
			||||||
  fun visitBlock(node: Block): T
 | 
					  fun visitBlock(node: Block): T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun visitImportDeclaration(node: ImportDeclaration): T
 | 
					  fun visitBooleanLiteral(node: BooleanLiteral): T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun visitCompilationUnit(node: CompilationUnit): T
 | 
					  fun visitCompilationUnit(node: CompilationUnit): T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun visitExpression(node: Expression): T = when (node) {
 | 
					  fun visitFunctionCall(node: FunctionCall): T
 | 
				
			||||||
    is IntLiteral -> visitIntLiteral(node)
 | 
					 | 
				
			||||||
    is StringLiteral -> visitStringLiteral(node)
 | 
					 | 
				
			||||||
    is BooleanLiteral -> visitBooleanLiteral(node)
 | 
					 | 
				
			||||||
    is ListLiteral -> visitListLiteral(node)
 | 
					 | 
				
			||||||
    is FunctionCall -> visitFunctionCall(node)
 | 
					 | 
				
			||||||
    is LetAssignment -> visitLetAssignment(node)
 | 
					 | 
				
			||||||
    is SymbolReference -> visitSymbolReference(node)
 | 
					 | 
				
			||||||
    is Lambda -> visitLambda(node)
 | 
					 | 
				
			||||||
    is Parentheses -> visitParentheses(node)
 | 
					 | 
				
			||||||
    is PrefixOperation -> visitPrefixOperation(node)
 | 
					 | 
				
			||||||
    is If -> visitIf(node)
 | 
					 | 
				
			||||||
    is InfixOperation -> visitInfixOperation(node)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun visitDeclaration(node: Declaration): T = when (node) {
 | 
					  fun visitFunctionDefinition(node: FunctionDefinition): T
 | 
				
			||||||
    is ImportDeclaration -> visitImportDeclaration(node)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun visitDefinition(node: Definition): T = when (node) {
 | 
					  fun visitIf(node: If): T
 | 
				
			||||||
    is FunctionDefinition -> visitFunctionDeclaration(node)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun visit(node: Node): T = when (node) {
 | 
					  fun visitImportDeclaration(node: ImportDeclaration): T
 | 
				
			||||||
    is Symbol -> visitSymbol(node)
 | 
					
 | 
				
			||||||
    is Expression -> visitExpression(node)
 | 
					  fun visitInfixOperation(node: InfixOperation): T
 | 
				
			||||||
    is CompilationUnit -> visitCompilationUnit(node)
 | 
					
 | 
				
			||||||
    is Block -> visitBlock(node)
 | 
					  fun visitIntLiteral(node: IntLiteral): T
 | 
				
			||||||
    is Declaration -> visitDeclaration(node)
 | 
					
 | 
				
			||||||
    is Definition -> visitDefinition(node)
 | 
					  fun visitLambda(node: Lambda): T
 | 
				
			||||||
  }
 | 
					
 | 
				
			||||||
 | 
					  fun visitLetAssignment(node: LetAssignment): T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun visitListLiteral(node: ListLiteral): T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun visitParentheses(node: Parentheses): T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun visitPrefixOperation(node: PrefixOperation): T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun visitStringLiteral(node: StringLiteral): T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun visitSymbol(node: Symbol): T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun visitSymbolReference(node: SymbolReference): T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun visitNodes(vararg nodes: Node?): List<T> =
 | 
					  fun visitNodes(vararg nodes: Node?): List<T> =
 | 
				
			||||||
    nodes.asSequence().filterNotNull().map { visit(it) }.toList()
 | 
					    nodes.asSequence().filterNotNull().map { visit(it) }.toList()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun visitAll(vararg nodeLists: List<Node>): List<T> =
 | 
					  fun visitAll(vararg nodeLists: List<Node>): List<T> =
 | 
				
			||||||
    nodeLists.asSequence().flatten().map { visit(it) }.toList()
 | 
					    nodeLists.asSequence().flatten().map { visit(it) }.toList()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun visit(node: Node): T =
 | 
				
			||||||
 | 
					    when (node) {
 | 
				
			||||||
 | 
					      is Symbol -> visitSymbol(node)
 | 
				
			||||||
 | 
					      is Block -> visitBlock(node)
 | 
				
			||||||
 | 
					      is CompilationUnit -> visitCompilationUnit(node)
 | 
				
			||||||
 | 
					      is LetAssignment -> visitLetAssignment(node)
 | 
				
			||||||
 | 
					      is InfixOperation -> visitInfixOperation(node)
 | 
				
			||||||
 | 
					      is BooleanLiteral -> visitBooleanLiteral(node)
 | 
				
			||||||
 | 
					      is FunctionCall -> visitFunctionCall(node)
 | 
				
			||||||
 | 
					      is FunctionDefinition -> visitFunctionDefinition(node)
 | 
				
			||||||
 | 
					      is If -> visitIf(node)
 | 
				
			||||||
 | 
					      is ImportDeclaration -> visitImportDeclaration(node)
 | 
				
			||||||
 | 
					      is IntLiteral -> visitIntLiteral(node)
 | 
				
			||||||
 | 
					      is Lambda -> visitLambda(node)
 | 
				
			||||||
 | 
					      is ListLiteral -> visitListLiteral(node)
 | 
				
			||||||
 | 
					      is Parentheses -> visitParentheses(node)
 | 
				
			||||||
 | 
					      is PrefixOperation -> visitPrefixOperation(node)
 | 
				
			||||||
 | 
					      is StringLiteral -> visitStringLiteral(node)
 | 
				
			||||||
 | 
					      is SymbolReference -> visitSymbolReference(node)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,8 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					  kotlin("jvm") version "1.9.10" apply false
 | 
				
			||||||
 | 
					  kotlin("plugin.serialization") version "1.9.10" apply false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tasks.withType<Wrapper> {
 | 
					tasks.withType<Wrapper> {
 | 
				
			||||||
  gradleVersion = "8.3"
 | 
					  gradleVersion = "8.3"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,182 +0,0 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.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.gradle.codegen.*
 | 
					 | 
				
			||||||
import java.nio.charset.StandardCharsets
 | 
					 | 
				
			||||||
import java.nio.file.Path
 | 
					 | 
				
			||||||
import kotlin.io.path.*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld) {
 | 
					 | 
				
			||||||
  private fun deleteAllContents() {
 | 
					 | 
				
			||||||
    for (child in outputDirectory.listDirectoryEntries("*.kt")) {
 | 
					 | 
				
			||||||
      child.deleteExisting()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fun generate() {
 | 
					 | 
				
			||||||
    deleteAllContents()
 | 
					 | 
				
			||||||
    for (type in world.typeRegistry.types) {
 | 
					 | 
				
			||||||
      writeAstType(type)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    writeNodeType()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun writeNodeType() {
 | 
					 | 
				
			||||||
    val enumClass = KotlinEnum(pkg, "NodeType")
 | 
					 | 
				
			||||||
    val parentMember = KotlinMember("parent", "NodeType?", value = "null")
 | 
					 | 
				
			||||||
    enumClass.members.add(parentMember)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val typesInNameOrder = world.typeRegistry.types.sortedBy { it.name }
 | 
					 | 
				
			||||||
    val typesInDependencyOrder = mutableListOf<AstType>()
 | 
					 | 
				
			||||||
    for (type in typesInNameOrder) {
 | 
					 | 
				
			||||||
      if (type.parent != null) {
 | 
					 | 
				
			||||||
        if (!typesInDependencyOrder.contains(type.parent)) {
 | 
					 | 
				
			||||||
          typesInDependencyOrder.add(type.parent!!)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (!typesInDependencyOrder.contains(type)) {
 | 
					 | 
				
			||||||
        typesInDependencyOrder.add(type)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (type in typesInDependencyOrder) {
 | 
					 | 
				
			||||||
      val role = world.typeRegistry.roleOfType(type)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (role == AstTypeRole.ValueHolder || role == AstTypeRole.Enum) {
 | 
					 | 
				
			||||||
        println(type)
 | 
					 | 
				
			||||||
        continue
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      val entry = KotlinEnumEntry(type.name)
 | 
					 | 
				
			||||||
      if (type.parent != null) {
 | 
					 | 
				
			||||||
        entry.parameters.add(type.parent!!.name)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      enumClass.entries.add(entry)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    write("NodeType.kt", KotlinWriter(enumClass))
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun writeAstType(type: AstType) {
 | 
					 | 
				
			||||||
    val role = world.typeRegistry.roleOfType(type)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val kotlinClassLike: KotlinClassLike
 | 
					 | 
				
			||||||
    if (role == AstTypeRole.Enum) {
 | 
					 | 
				
			||||||
      val kotlinEnum = KotlinEnum(pkg, type.name)
 | 
					 | 
				
			||||||
      kotlinClassLike = kotlinEnum
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      val kotlinClass = KotlinClass(pkg, type.name)
 | 
					 | 
				
			||||||
      kotlinClassLike = kotlinClass
 | 
					 | 
				
			||||||
      if (role == AstTypeRole.RootNode || role == AstTypeRole.HierarchyNode) {
 | 
					 | 
				
			||||||
        kotlinClass.sealed = true
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (role == AstTypeRole.RootNode) {
 | 
					 | 
				
			||||||
      val typeMember = KotlinMember(
 | 
					 | 
				
			||||||
        "type",
 | 
					 | 
				
			||||||
        "NodeType",
 | 
					 | 
				
			||||||
        abstract = true
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      kotlinClassLike.members.add(typeMember)
 | 
					 | 
				
			||||||
    } else if (role == AstTypeRole.AstNode) {
 | 
					 | 
				
			||||||
      val typeMember = KotlinMember(
 | 
					 | 
				
			||||||
        "type",
 | 
					 | 
				
			||||||
        "NodeType",
 | 
					 | 
				
			||||||
        overridden = true,
 | 
					 | 
				
			||||||
        value = "NodeType.${type.name}"
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      kotlinClassLike.members.add(typeMember)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (type.parent != null) {
 | 
					 | 
				
			||||||
      val parentName = type.parent!!.name
 | 
					 | 
				
			||||||
      kotlinClassLike.inherits.add("$parentName()")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (value in type.values) {
 | 
					 | 
				
			||||||
      val member = KotlinMember(value.name, toKotlinType(value.typeRef))
 | 
					 | 
				
			||||||
      member.abstract = value.abstract
 | 
					 | 
				
			||||||
      if (type.isParentAbstract(value)) {
 | 
					 | 
				
			||||||
        member.overridden = true
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      kotlinClassLike.members.add(member)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (role == AstTypeRole.Enum) {
 | 
					 | 
				
			||||||
      val kotlinEnum = kotlinClassLike as KotlinEnum
 | 
					 | 
				
			||||||
      for (entry in type.enums) {
 | 
					 | 
				
			||||||
        val orderOfKeys = entry.values.keys.sortedBy { key ->
 | 
					 | 
				
			||||||
          kotlinClassLike.members.indexOfFirst { it.name == key }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        val parameters = mutableListOf<String>()
 | 
					 | 
				
			||||||
        for (key in orderOfKeys) {
 | 
					 | 
				
			||||||
          val value = entry.values[key] ?: continue
 | 
					 | 
				
			||||||
          parameters.add("\"${value}\"")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        val enumEntry = KotlinEnumEntry(entry.name, parameters)
 | 
					 | 
				
			||||||
        kotlinEnum.entries.add(enumEntry)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (role == AstTypeRole.AstNode) {
 | 
					 | 
				
			||||||
      val equalsAndHashCodeFields = kotlinClassLike.members.map { it.name }
 | 
					 | 
				
			||||||
      val equalsFunction = KotlinFunction(
 | 
					 | 
				
			||||||
        "equals",
 | 
					 | 
				
			||||||
        returnType = "Boolean",
 | 
					 | 
				
			||||||
        overridden = true
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      equalsFunction.parameters.add(KotlinParameter(
 | 
					 | 
				
			||||||
        "other",
 | 
					 | 
				
			||||||
        "Any?"
 | 
					 | 
				
			||||||
      ))
 | 
					 | 
				
			||||||
      equalsFunction.body.add("if (other !is ${type.name}) return false")
 | 
					 | 
				
			||||||
      val predicate = equalsAndHashCodeFields.joinToString(" && ") {
 | 
					 | 
				
			||||||
        "other.${it} == $it"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      equalsFunction.body.add("return $predicate")
 | 
					 | 
				
			||||||
      kotlinClassLike.functions.add(equalsFunction)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val serialName = kotlinClassLike.name[0].lowercase() +
 | 
					 | 
				
			||||||
      kotlinClassLike.name.substring(1)
 | 
					 | 
				
			||||||
    kotlinClassLike.imports.add("kotlinx.serialization.SerialName")
 | 
					 | 
				
			||||||
    kotlinClassLike.imports.add("kotlinx.serialization.Serializable")
 | 
					 | 
				
			||||||
    kotlinClassLike.annotations.add("Serializable")
 | 
					 | 
				
			||||||
    kotlinClassLike.annotations.add("SerialName(\"$serialName\")")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    write("${type.name}.kt", KotlinWriter(kotlinClassLike))
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun toKotlinType(typeRef: AstTypeRef): String {
 | 
					 | 
				
			||||||
    val baseType = typeRef.type?.name ?: typeRef.primitive?.id
 | 
					 | 
				
			||||||
      ?: throw RuntimeException("Unable to determine base type.")
 | 
					 | 
				
			||||||
    return when (typeRef.form) {
 | 
					 | 
				
			||||||
      AstTypeRefForm.Single -> baseType
 | 
					 | 
				
			||||||
      AstTypeRefForm.Nullable -> "${baseType}?"
 | 
					 | 
				
			||||||
      AstTypeRefForm.List -> "List<${baseType}>"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun write(fileName: String, writer: KotlinWriter) {
 | 
					 | 
				
			||||||
    val path = outputDirectory.resolve(fileName)
 | 
					 | 
				
			||||||
    path.deleteIfExists()
 | 
					 | 
				
			||||||
    path.writeText(writer.toString(), StandardCharsets.UTF_8)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  companion object {
 | 
					 | 
				
			||||||
    fun run(pkg: String, astDescriptionFile: Path, outputDirectory: Path) {
 | 
					 | 
				
			||||||
      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()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,9 +0,0 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum class AstTypeRole {
 | 
					 | 
				
			||||||
  RootNode,
 | 
					 | 
				
			||||||
  HierarchyNode,
 | 
					 | 
				
			||||||
  AstNode,
 | 
					 | 
				
			||||||
  ValueHolder,
 | 
					 | 
				
			||||||
  Enum
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,7 +0,0 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.codegen
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class KotlinParameter(
 | 
					 | 
				
			||||||
  val name: String,
 | 
					 | 
				
			||||||
  val type: String,
 | 
					 | 
				
			||||||
  val defaultValue: String? = null
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
@ -1,25 +0,0 @@
 | 
				
			|||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
plugins {
 | 
					 | 
				
			||||||
  kotlin("jvm")
 | 
					 | 
				
			||||||
  kotlin("plugin.serialization")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
repositories {
 | 
					 | 
				
			||||||
  mavenCentral()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
java {
 | 
					 | 
				
			||||||
  val javaVersion = JavaVersion.toVersion(17)
 | 
					 | 
				
			||||||
  sourceCompatibility = javaVersion
 | 
					 | 
				
			||||||
  targetCompatibility = javaVersion
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
tasks.withType<KotlinCompile> {
 | 
					 | 
				
			||||||
  kotlinOptions.jvmTarget = "17"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dependencies {
 | 
					 | 
				
			||||||
  implementation("org.jetbrains.kotlin:kotlin-bom")
 | 
					 | 
				
			||||||
  implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -20,10 +20,18 @@ gradlePlugin {
 | 
				
			|||||||
  plugins {
 | 
					  plugins {
 | 
				
			||||||
    create("pork_ast") {
 | 
					    create("pork_ast") {
 | 
				
			||||||
      id = "gay.pizza.pork.ast"
 | 
					      id = "gay.pizza.pork.ast"
 | 
				
			||||||
      implementationClass = "gay.pizza.pork.gradle.PorkAstPlugin"
 | 
					      implementationClass = "gay.pizza.pork.buildext.PorkAstPlugin"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      displayName = "Pork AST"
 | 
					      displayName = "Pork AST"
 | 
				
			||||||
      description = "AST generation code for pork"
 | 
					      description = "AST generation code for pork"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create("pork_module") {
 | 
				
			||||||
 | 
					      id = "gay.pizza.pork.module"
 | 
				
			||||||
 | 
					      implementationClass = "gay.pizza.pork.buildext.PorkModulePlugin"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      displayName = "Pork Module"
 | 
				
			||||||
 | 
					      description = "Module convention for pork"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle
 | 
					package gay.pizza.pork.buildext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import gay.pizza.pork.gradle.ast.AstCodegen
 | 
					import gay.pizza.pork.buildext.ast.AstCodegen
 | 
				
			||||||
import org.gradle.api.DefaultTask
 | 
					import org.gradle.api.DefaultTask
 | 
				
			||||||
import org.gradle.api.tasks.Input
 | 
					import org.gradle.api.tasks.Input
 | 
				
			||||||
import org.gradle.api.tasks.InputFile
 | 
					import org.gradle.api.tasks.InputFile
 | 
				
			||||||
@ -17,10 +17,10 @@ open class GenerateAstCode : DefaultTask() {
 | 
				
			|||||||
  var astDescriptionFile: File = project.file("src/main/ast/pork.yml")
 | 
					  var astDescriptionFile: File = project.file("src/main/ast/pork.yml")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @get:Input
 | 
					  @get:Input
 | 
				
			||||||
  var codePackage: String = "gay.pizza.pork.gen"
 | 
					  var codePackage: String = "gay.pizza.pork.ast"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @get:OutputDirectory
 | 
					  @get:OutputDirectory
 | 
				
			||||||
  var outputDirectory: File = project.file("src/main/kotlin/gay/pizza/pork/gen")
 | 
					  var outputDirectory: File = project.file("src/main/kotlin/gay/pizza/pork/ast")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @TaskAction
 | 
					  @TaskAction
 | 
				
			||||||
  fun generate() {
 | 
					  fun generate() {
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle
 | 
					package gay.pizza.pork.buildext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.gradle.api.Plugin
 | 
					import org.gradle.api.Plugin
 | 
				
			||||||
import org.gradle.api.Project
 | 
					import org.gradle.api.Project
 | 
				
			||||||
@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.buildext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.gradle.api.JavaVersion
 | 
				
			||||||
 | 
					import org.gradle.api.Plugin
 | 
				
			||||||
 | 
					import org.gradle.api.Project
 | 
				
			||||||
 | 
					import org.gradle.api.plugins.JavaPluginExtension
 | 
				
			||||||
 | 
					import org.gradle.kotlin.dsl.apply
 | 
				
			||||||
 | 
					import org.gradle.kotlin.dsl.dependencies
 | 
				
			||||||
 | 
					import org.gradle.kotlin.dsl.getByType
 | 
				
			||||||
 | 
					import org.gradle.kotlin.dsl.withType
 | 
				
			||||||
 | 
					import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					open class PorkModulePlugin : Plugin<Project> {
 | 
				
			||||||
 | 
					  override fun apply(target: Project) {
 | 
				
			||||||
 | 
					    target.apply(plugin = "org.jetbrains.kotlin.jvm")
 | 
				
			||||||
 | 
					    target.apply(plugin = "org.jetbrains.kotlin.plugin.serialization")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    target.repositories.mavenCentral()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    target.extensions.getByType<JavaPluginExtension>().apply {
 | 
				
			||||||
 | 
					      val javaVersion = JavaVersion.toVersion(17)
 | 
				
			||||||
 | 
					      sourceCompatibility = javaVersion
 | 
				
			||||||
 | 
					      targetCompatibility = javaVersion
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    target.tasks.withType<KotlinCompile> {
 | 
				
			||||||
 | 
					      kotlinOptions.jvmTarget = "17"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    target.dependencies {
 | 
				
			||||||
 | 
					      add("implementation", "org.jetbrains.kotlin:kotlin-bom")
 | 
				
			||||||
 | 
					      add("implementation", "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,370 @@
 | 
				
			|||||||
 | 
					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
 | 
				
			||||||
 | 
					import kotlin.io.path.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld) {
 | 
				
			||||||
 | 
					  private fun deleteAllContents() {
 | 
				
			||||||
 | 
					    for (child in outputDirectory.listDirectoryEntries("*.kt")) {
 | 
				
			||||||
 | 
					      child.deleteExisting()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun generate() {
 | 
				
			||||||
 | 
					    deleteAllContents()
 | 
				
			||||||
 | 
					    for (type in world.typeRegistry.types) {
 | 
				
			||||||
 | 
					      writeAstType(type)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    writeNodeType()
 | 
				
			||||||
 | 
					    writeNodeVisitor()
 | 
				
			||||||
 | 
					    writeNodeCoalescer()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun writeNodeType() {
 | 
				
			||||||
 | 
					    val enumClass = KotlinEnum(pkg, "NodeType")
 | 
				
			||||||
 | 
					    val parentMember = KotlinMember("parent", "NodeType?", value = "null")
 | 
				
			||||||
 | 
					    enumClass.members.add(parentMember)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (type in world.typesInDependencyOrder()) {
 | 
				
			||||||
 | 
					      val role = world.typeRegistry.roleOfType(type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (role == AstTypeRole.ValueHolder || role == AstTypeRole.Enum) {
 | 
				
			||||||
 | 
					        continue
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val entry = KotlinEnumEntry(type.name)
 | 
				
			||||||
 | 
					      if (type.parent != null) {
 | 
				
			||||||
 | 
					        entry.parameters.add(type.parent!!.name)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      enumClass.entries.add(entry)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    write("NodeType.kt", KotlinWriter(enumClass))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun writeNodeVisitor() {
 | 
				
			||||||
 | 
					    val visitorInterface = KotlinClass(
 | 
				
			||||||
 | 
					      pkg,
 | 
				
			||||||
 | 
					      "NodeVisitor",
 | 
				
			||||||
 | 
					      typeParameters = mutableListOf("T"),
 | 
				
			||||||
 | 
					      isInterface = true
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (type in world.typesInDependencyOrder()) {
 | 
				
			||||||
 | 
					      val role = world.typeRegistry.roleOfType(type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (role != AstTypeRole.AstNode) {
 | 
				
			||||||
 | 
					        continue
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val visitFunction = KotlinFunction(
 | 
				
			||||||
 | 
					        "visit${type.name}",
 | 
				
			||||||
 | 
					        returnType = "T",
 | 
				
			||||||
 | 
					        parameters = mutableListOf(
 | 
				
			||||||
 | 
					          KotlinParameter("node", type.name)
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        isInterfaceMethod = true
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      visitorInterface.functions.add(visitFunction)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val visitNodesFunction = KotlinFunction(
 | 
				
			||||||
 | 
					      "visitNodes",
 | 
				
			||||||
 | 
					      returnType = "List<T>",
 | 
				
			||||||
 | 
					      parameters = mutableListOf(
 | 
				
			||||||
 | 
					        KotlinParameter("nodes", type = "Node?", vararg = true)
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      isImmediateExpression = true
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    visitNodesFunction.body.add("nodes.asSequence().filterNotNull().map { visit(it) }.toList()")
 | 
				
			||||||
 | 
					    visitorInterface.functions.add(visitNodesFunction)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val visitAllFunction = KotlinFunction(
 | 
				
			||||||
 | 
					      "visitAll",
 | 
				
			||||||
 | 
					      returnType = "List<T>",
 | 
				
			||||||
 | 
					      parameters = mutableListOf(
 | 
				
			||||||
 | 
					        KotlinParameter("nodeLists", type = "List<Node>", vararg = true)
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      isImmediateExpression = true
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    visitAllFunction.body.add("nodeLists.asSequence().flatten().map { visit(it) }.toList()")
 | 
				
			||||||
 | 
					    visitorInterface.functions.add(visitAllFunction)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val visitFunction = KotlinFunction(
 | 
				
			||||||
 | 
					      "visit",
 | 
				
			||||||
 | 
					      returnType = "T",
 | 
				
			||||||
 | 
					      parameters = mutableListOf(
 | 
				
			||||||
 | 
					        KotlinParameter("node", type = "Node")
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      isImmediateExpression = true
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    visitFunction.body.add("when (node) {")
 | 
				
			||||||
 | 
					    for (type in world.typeRegistry.types.filter { world.typeRegistry.roleOfType(it) == AstTypeRole.AstNode }) {
 | 
				
			||||||
 | 
					      visitFunction.body.add("  is ${type.name} -> visit${type.name}(node)")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    visitFunction.body.add("}")
 | 
				
			||||||
 | 
					    visitorInterface.functions.add(visitFunction)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    write("NodeVisitor.kt", KotlinWriter(visitorInterface))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun writeNodeCoalescer() {
 | 
				
			||||||
 | 
					    val coalescerClass = KotlinClass(
 | 
				
			||||||
 | 
					      pkg,
 | 
				
			||||||
 | 
					      "NodeCoalescer",
 | 
				
			||||||
 | 
					      inherits = mutableListOf("NodeVisitor<Unit>"),
 | 
				
			||||||
 | 
					      members = mutableListOf(
 | 
				
			||||||
 | 
					        KotlinMember(
 | 
				
			||||||
 | 
					          "handler",
 | 
				
			||||||
 | 
					          "(Node) -> Unit"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (type in world.typesInDependencyOrder()) {
 | 
				
			||||||
 | 
					      val role = world.typeRegistry.roleOfType(type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (role != AstTypeRole.AstNode) {
 | 
				
			||||||
 | 
					        continue
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val function = KotlinFunction(
 | 
				
			||||||
 | 
					        "visit${type.name}",
 | 
				
			||||||
 | 
					        returnType = "Unit",
 | 
				
			||||||
 | 
					        parameters = mutableListOf(
 | 
				
			||||||
 | 
					          KotlinParameter("node", type.name)
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        isImmediateExpression = true,
 | 
				
			||||||
 | 
					        overridden = true
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      function.body.add("handle(node)")
 | 
				
			||||||
 | 
					      coalescerClass.functions.add(function)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val handleFunction = KotlinFunction(
 | 
				
			||||||
 | 
					      "handle",
 | 
				
			||||||
 | 
					      parameters = mutableListOf(
 | 
				
			||||||
 | 
					        KotlinParameter("node", "Node")
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    handleFunction.body.add("handler(node)")
 | 
				
			||||||
 | 
					    handleFunction.body.add("node.visitChildren(this)")
 | 
				
			||||||
 | 
					    coalescerClass.functions.add(handleFunction)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    write("NodeCoalescer.kt", KotlinWriter(coalescerClass))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun writeAstType(type: AstType) {
 | 
				
			||||||
 | 
					    val role = world.typeRegistry.roleOfType(type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val kotlinClassLike: KotlinClassLike
 | 
				
			||||||
 | 
					    if (role == AstTypeRole.Enum) {
 | 
				
			||||||
 | 
					      val kotlinEnum = KotlinEnum(pkg, type.name)
 | 
				
			||||||
 | 
					      kotlinClassLike = kotlinEnum
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      val kotlinClass = KotlinClass(pkg, type.name)
 | 
				
			||||||
 | 
					      kotlinClassLike = kotlinClass
 | 
				
			||||||
 | 
					      if (role == AstTypeRole.RootNode || role == AstTypeRole.HierarchyNode) {
 | 
				
			||||||
 | 
					        kotlinClass.sealed = true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (role == AstTypeRole.RootNode) {
 | 
				
			||||||
 | 
					      val typeMember = KotlinMember(
 | 
				
			||||||
 | 
					        "type",
 | 
				
			||||||
 | 
					        "NodeType",
 | 
				
			||||||
 | 
					        abstract = true
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      kotlinClassLike.members.add(typeMember)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val abstractVisitChildrenFunction = KotlinFunction(
 | 
				
			||||||
 | 
					        "visitChildren",
 | 
				
			||||||
 | 
					        returnType = "List<T>",
 | 
				
			||||||
 | 
					        open = true,
 | 
				
			||||||
 | 
					        typeParameters = mutableListOf("T"),
 | 
				
			||||||
 | 
					        parameters = mutableListOf(
 | 
				
			||||||
 | 
					          KotlinParameter("visitor", "NodeVisitor<T>")
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        isImmediateExpression = true
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      abstractVisitChildrenFunction.body.add("emptyList()")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      kotlinClassLike.functions.add(abstractVisitChildrenFunction)
 | 
				
			||||||
 | 
					    } else if (role == AstTypeRole.AstNode) {
 | 
				
			||||||
 | 
					      val typeMember = KotlinMember(
 | 
				
			||||||
 | 
					        "type",
 | 
				
			||||||
 | 
					        "NodeType",
 | 
				
			||||||
 | 
					        overridden = true,
 | 
				
			||||||
 | 
					        value = "NodeType.${type.name}"
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      kotlinClassLike.members.add(typeMember)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (type.parent != null) {
 | 
				
			||||||
 | 
					      val parentName = type.parent!!.name
 | 
				
			||||||
 | 
					      kotlinClassLike.inherits.add("$parentName()")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (value in type.values) {
 | 
				
			||||||
 | 
					      val member = KotlinMember(value.name, toKotlinType(value.typeRef))
 | 
				
			||||||
 | 
					      member.abstract = value.abstract
 | 
				
			||||||
 | 
					      if (type.isParentAbstract(value)) {
 | 
				
			||||||
 | 
					        member.overridden = true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (role == AstTypeRole.ValueHolder) {
 | 
				
			||||||
 | 
					        member.mutable = true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      kotlinClassLike.members.add(member)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (role == AstTypeRole.Enum) {
 | 
				
			||||||
 | 
					      val kotlinEnum = kotlinClassLike as KotlinEnum
 | 
				
			||||||
 | 
					      for (entry in type.enums) {
 | 
				
			||||||
 | 
					        val orderOfKeys = entry.values.keys.sortedBy { key ->
 | 
				
			||||||
 | 
					          kotlinClassLike.members.indexOfFirst { it.name == key }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val parameters = mutableListOf<String>()
 | 
				
			||||||
 | 
					        for (key in orderOfKeys) {
 | 
				
			||||||
 | 
					          val value = entry.values[key] ?: continue
 | 
				
			||||||
 | 
					          parameters.add("\"${value}\"")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        val enumEntry = KotlinEnumEntry(entry.name, parameters)
 | 
				
			||||||
 | 
					        kotlinEnum.entries.add(enumEntry)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (role == AstTypeRole.AstNode) {
 | 
				
			||||||
 | 
					      val visitChildrenFunction = KotlinFunction(
 | 
				
			||||||
 | 
					        "visitChildren",
 | 
				
			||||||
 | 
					        returnType = "List<T>",
 | 
				
			||||||
 | 
					        typeParameters = mutableListOf("T")
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      visitChildrenFunction.overridden = true
 | 
				
			||||||
 | 
					      val visitorParameter = KotlinParameter("visitor", "NodeVisitor<T>")
 | 
				
			||||||
 | 
					      visitChildrenFunction.parameters.add(visitorParameter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      visitChildrenFunction.isImmediateExpression = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val anyListMembers = type.values.any { it.typeRef.form == AstTypeRefForm.List }
 | 
				
			||||||
 | 
					      val elideVisitChildren: Boolean
 | 
				
			||||||
 | 
					      if (anyListMembers) {
 | 
				
			||||||
 | 
					        val visitParameters = type.values.mapNotNull {
 | 
				
			||||||
 | 
					          if (it.typeRef.primitive != null) {
 | 
				
			||||||
 | 
					            null
 | 
				
			||||||
 | 
					          } else if (it.typeRef.type != null && !world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
 | 
				
			||||||
 | 
					            null
 | 
				
			||||||
 | 
					          } else if (it.typeRef.form == AstTypeRefForm.Single) {
 | 
				
			||||||
 | 
					            "listOf(${it.name})"
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            it.name
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }.joinToString(", ")
 | 
				
			||||||
 | 
					        elideVisitChildren = visitParameters.isEmpty()
 | 
				
			||||||
 | 
					        visitChildrenFunction.body.add("visitor.visitAll(${visitParameters})")
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        val visitParameters = type.values.mapNotNull {
 | 
				
			||||||
 | 
					          if (it.typeRef.primitive != null) {
 | 
				
			||||||
 | 
					            null
 | 
				
			||||||
 | 
					          } else if (it.typeRef.type != null && !world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
 | 
				
			||||||
 | 
					            null
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            it.name
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }.joinToString(", ")
 | 
				
			||||||
 | 
					        elideVisitChildren = visitParameters.isEmpty()
 | 
				
			||||||
 | 
					        visitChildrenFunction.body.add("visitor.visitNodes(${visitParameters})")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!elideVisitChildren) {
 | 
				
			||||||
 | 
					        kotlinClassLike.functions.add(visitChildrenFunction)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val equalsAndHashCodeMembers = kotlinClassLike.members.map { it.name }.sortedBy { it == "type" }
 | 
				
			||||||
 | 
					      val equalsFunction = KotlinFunction(
 | 
				
			||||||
 | 
					        "equals",
 | 
				
			||||||
 | 
					        returnType = "Boolean",
 | 
				
			||||||
 | 
					        overridden = true
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      equalsFunction.parameters.add(KotlinParameter(
 | 
				
			||||||
 | 
					        "other",
 | 
				
			||||||
 | 
					        "Any?"
 | 
				
			||||||
 | 
					      ))
 | 
				
			||||||
 | 
					      equalsFunction.body.add("if (other !is ${type.name}) return false")
 | 
				
			||||||
 | 
					      val predicate = equalsAndHashCodeMembers.mapNotNull {
 | 
				
			||||||
 | 
					        if (it == "type") null else "other.${it} == $it"
 | 
				
			||||||
 | 
					      }.joinToString(" && ")
 | 
				
			||||||
 | 
					      equalsFunction.body.add("return $predicate")
 | 
				
			||||||
 | 
					      kotlinClassLike.functions.add(equalsFunction)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      val hashCodeFunction = KotlinFunction(
 | 
				
			||||||
 | 
					        "hashCode",
 | 
				
			||||||
 | 
					        returnType = "Int",
 | 
				
			||||||
 | 
					        overridden = true
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (equalsAndHashCodeMembers.size == 1) {
 | 
				
			||||||
 | 
					        val member = equalsAndHashCodeMembers.single()
 | 
				
			||||||
 | 
					        hashCodeFunction.isImmediateExpression = true
 | 
				
			||||||
 | 
					        hashCodeFunction.body.add("31 * ${member}.hashCode()")
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        for ((index, value) in equalsAndHashCodeMembers.withIndex()) {
 | 
				
			||||||
 | 
					          if (index == 0) {
 | 
				
			||||||
 | 
					            hashCodeFunction.body.add("var result = ${value}.hashCode()")
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            hashCodeFunction.body.add("result = 31 * result + ${value}.hashCode()")
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        hashCodeFunction.body.add("return result")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      kotlinClassLike.functions.add(hashCodeFunction)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val serialName = kotlinClassLike.name[0].lowercase() +
 | 
				
			||||||
 | 
					      kotlinClassLike.name.substring(1)
 | 
				
			||||||
 | 
					    kotlinClassLike.imports.add("kotlinx.serialization.SerialName")
 | 
				
			||||||
 | 
					    kotlinClassLike.imports.add("kotlinx.serialization.Serializable")
 | 
				
			||||||
 | 
					    kotlinClassLike.annotations.add("Serializable")
 | 
				
			||||||
 | 
					    kotlinClassLike.annotations.add("SerialName(\"$serialName\")")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    write("${type.name}.kt", KotlinWriter(kotlinClassLike))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun toKotlinType(typeRef: AstTypeRef): String {
 | 
				
			||||||
 | 
					    val baseType = typeRef.type?.name ?: typeRef.primitive?.id
 | 
				
			||||||
 | 
					      ?: throw RuntimeException("Unable to determine base type.")
 | 
				
			||||||
 | 
					    return when (typeRef.form) {
 | 
				
			||||||
 | 
					      AstTypeRefForm.Single -> baseType
 | 
				
			||||||
 | 
					      AstTypeRefForm.Nullable -> "${baseType}?"
 | 
				
			||||||
 | 
					      AstTypeRefForm.List -> "List<${baseType}>"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private fun write(fileName: String, writer: KotlinWriter) {
 | 
				
			||||||
 | 
					    val path = outputDirectory.resolve(fileName)
 | 
				
			||||||
 | 
					    path.deleteIfExists()
 | 
				
			||||||
 | 
					    path.writeText(writer.toString(), StandardCharsets.UTF_8)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  companion object {
 | 
				
			||||||
 | 
					    fun run(pkg: String, astDescriptionFile: Path, 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()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
data class AstDescription(
 | 
					data class AstDescription(
 | 
				
			||||||
  val root: String,
 | 
					  val root: String,
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AstEnum(
 | 
					class AstEnum(
 | 
				
			||||||
  val name: String,
 | 
					  val name: String,
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AstEnumDescription(
 | 
					class AstEnumDescription(
 | 
				
			||||||
  val name: String,
 | 
					  val name: String,
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class AstPrimitive(val id: kotlin.String) {
 | 
					enum class AstPrimitive(val id: kotlin.String) {
 | 
				
			||||||
  Boolean("Boolean"),
 | 
					  Boolean("Boolean"),
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AstType(val name: String, var parent: AstType? = null) {
 | 
					class AstType(val name: String, var parent: AstType? = null) {
 | 
				
			||||||
  private val internalValues = mutableListOf<AstValue>()
 | 
					  private val internalValues = mutableListOf<AstValue>()
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
data class AstTypeDescription(
 | 
					data class AstTypeDescription(
 | 
				
			||||||
  val parent: String? = null,
 | 
					  val parent: String? = null,
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AstTypeRef(
 | 
					class AstTypeRef(
 | 
				
			||||||
  val type: AstType? = null,
 | 
					  val type: AstType? = null,
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class AstTypeRefForm {
 | 
					enum class AstTypeRefForm {
 | 
				
			||||||
  Single,
 | 
					  Single,
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AstTypeRegistry {
 | 
					class AstTypeRegistry {
 | 
				
			||||||
  private val internalTypes = mutableSetOf<AstType>()
 | 
					  private val internalTypes = mutableSetOf<AstType>()
 | 
				
			||||||
@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class AstTypeRole {
 | 
				
			||||||
 | 
					  RootNode,
 | 
				
			||||||
 | 
					  HierarchyNode,
 | 
				
			||||||
 | 
					  AstNode,
 | 
				
			||||||
 | 
					  ValueHolder,
 | 
				
			||||||
 | 
					  Enum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun isNodeInherited(): Boolean = when (this) {
 | 
				
			||||||
 | 
					    RootNode -> true
 | 
				
			||||||
 | 
					    HierarchyNode -> true
 | 
				
			||||||
 | 
					    AstNode -> true
 | 
				
			||||||
 | 
					    else -> false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AstValue(
 | 
					class AstValue(
 | 
				
			||||||
  val name: String,
 | 
					  val name: String,
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
data class AstValueDescription(
 | 
					data class AstValueDescription(
 | 
				
			||||||
  val name: String,
 | 
					  val name: String,
 | 
				
			||||||
@ -1,8 +1,25 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AstWorld {
 | 
					class AstWorld {
 | 
				
			||||||
  val typeRegistry: AstTypeRegistry = AstTypeRegistry()
 | 
					  val typeRegistry: AstTypeRegistry = AstTypeRegistry()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun typesInDependencyOrder(): List<AstType> {
 | 
				
			||||||
 | 
					    val typesInNameOrder = typeRegistry.types.sortedBy { it.name }
 | 
				
			||||||
 | 
					    val typesInDependencyOrder = mutableListOf<AstType>()
 | 
				
			||||||
 | 
					    for (type in typesInNameOrder) {
 | 
				
			||||||
 | 
					      if (type.parent != null) {
 | 
				
			||||||
 | 
					        if (!typesInDependencyOrder.contains(type.parent)) {
 | 
				
			||||||
 | 
					          typesInDependencyOrder.add(type.parent!!)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!typesInDependencyOrder.contains(type)) {
 | 
				
			||||||
 | 
					        typesInDependencyOrder.add(type)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return typesInDependencyOrder
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  companion object {
 | 
					  companion object {
 | 
				
			||||||
    fun build(description: AstDescription): AstWorld {
 | 
					    fun build(description: AstDescription): AstWorld {
 | 
				
			||||||
      val world = AstWorld()
 | 
					      val world = AstWorld()
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.ast
 | 
					package gay.pizza.pork.buildext.ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import kotlin.io.path.Path
 | 
					import kotlin.io.path.Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -6,9 +6,9 @@ object RunCodegenIde {
 | 
				
			|||||||
  @JvmStatic
 | 
					  @JvmStatic
 | 
				
			||||||
  fun main(args: Array<String>) {
 | 
					  fun main(args: Array<String>) {
 | 
				
			||||||
    AstCodegen.run(
 | 
					    AstCodegen.run(
 | 
				
			||||||
      pkg = "gay.pizza.pork.gen",
 | 
					      pkg = "gay.pizza.pork.ast",
 | 
				
			||||||
      astDescriptionFile = Path("src/main/ast/pork.yml"),
 | 
					      astDescriptionFile = Path("src/main/ast/pork.yml"),
 | 
				
			||||||
      outputDirectory = Path("src/main/kotlin/gay/pizza/pork/gen")
 | 
					      outputDirectory = Path("src/main/kotlin/gay/pizza/pork/ast")
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,12 +1,14 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.codegen
 | 
					package gay.pizza.pork.buildext.codegen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class KotlinClass(
 | 
					class KotlinClass(
 | 
				
			||||||
  override val pkg: String,
 | 
					  override val pkg: String,
 | 
				
			||||||
  override var name: String,
 | 
					  override var name: String,
 | 
				
			||||||
  var sealed: Boolean = false,
 | 
					  var sealed: Boolean = false,
 | 
				
			||||||
  override var inherits: MutableList<String> = mutableListOf(),
 | 
					  var isInterface: Boolean = false,
 | 
				
			||||||
  override var imports: MutableList<String> = mutableListOf(),
 | 
					  override var imports: MutableList<String> = mutableListOf(),
 | 
				
			||||||
  override var members: MutableList<KotlinMember> = mutableListOf(),
 | 
					 | 
				
			||||||
  override var annotations: MutableList<String> = mutableListOf(),
 | 
					  override var annotations: MutableList<String> = mutableListOf(),
 | 
				
			||||||
 | 
					  override var typeParameters: MutableList<String> = mutableListOf(),
 | 
				
			||||||
 | 
					  override var inherits: MutableList<String> = mutableListOf(),
 | 
				
			||||||
 | 
					  override var members: MutableList<KotlinMember> = mutableListOf(),
 | 
				
			||||||
  override var functions: MutableList<KotlinFunction> = mutableListOf()
 | 
					  override var functions: MutableList<KotlinFunction> = mutableListOf()
 | 
				
			||||||
) : KotlinClassLike()
 | 
					) : KotlinClassLike()
 | 
				
			||||||
@ -1,11 +1,12 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.codegen
 | 
					package gay.pizza.pork.buildext.codegen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class KotlinClassLike {
 | 
					abstract class KotlinClassLike {
 | 
				
			||||||
  abstract val pkg: String
 | 
					  abstract val pkg: String
 | 
				
			||||||
  abstract val name: String
 | 
					  abstract val name: String
 | 
				
			||||||
  abstract var imports: MutableList<String>
 | 
					  abstract var imports: MutableList<String>
 | 
				
			||||||
  abstract var inherits: MutableList<String>
 | 
					 | 
				
			||||||
  abstract var annotations: MutableList<String>
 | 
					  abstract var annotations: MutableList<String>
 | 
				
			||||||
 | 
					  abstract var typeParameters: MutableList<String>
 | 
				
			||||||
 | 
					  abstract var inherits: MutableList<String>
 | 
				
			||||||
  abstract var members: MutableList<KotlinMember>
 | 
					  abstract var members: MutableList<KotlinMember>
 | 
				
			||||||
  abstract var functions: MutableList<KotlinFunction>
 | 
					  abstract var functions: MutableList<KotlinFunction>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,12 +1,13 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.codegen
 | 
					package gay.pizza.pork.buildext.codegen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class KotlinEnum(
 | 
					class KotlinEnum(
 | 
				
			||||||
  override val pkg: String,
 | 
					  override val pkg: String,
 | 
				
			||||||
  override val name: String,
 | 
					  override val name: String,
 | 
				
			||||||
  override var imports: MutableList<String> = mutableListOf(),
 | 
					  override var imports: MutableList<String> = mutableListOf(),
 | 
				
			||||||
  override var inherits: MutableList<String> = mutableListOf(),
 | 
					 | 
				
			||||||
  override var annotations: MutableList<String> = mutableListOf(),
 | 
					  override var annotations: MutableList<String> = mutableListOf(),
 | 
				
			||||||
 | 
					  override var typeParameters: MutableList<String> = mutableListOf(),
 | 
				
			||||||
 | 
					  override var inherits: MutableList<String> = mutableListOf(),
 | 
				
			||||||
  override var members: MutableList<KotlinMember> = mutableListOf(),
 | 
					  override var members: MutableList<KotlinMember> = mutableListOf(),
 | 
				
			||||||
  override var functions: MutableList<KotlinFunction> = mutableListOf(),
 | 
					  override var functions: MutableList<KotlinFunction> = mutableListOf(),
 | 
				
			||||||
  var entries: MutableList<KotlinEnumEntry> = mutableListOf(),
 | 
					  var entries: MutableList<KotlinEnumEntry> = mutableListOf()
 | 
				
			||||||
) : KotlinClassLike()
 | 
					) : KotlinClassLike()
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.codegen
 | 
					package gay.pizza.pork.buildext.codegen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class KotlinEnumEntry(
 | 
					class KotlinEnumEntry(
 | 
				
			||||||
  val name: String,
 | 
					  val name: String,
 | 
				
			||||||
@ -1,11 +1,14 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.codegen
 | 
					package gay.pizza.pork.buildext.codegen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class KotlinFunction(
 | 
					class KotlinFunction(
 | 
				
			||||||
  val name: String,
 | 
					  val name: String,
 | 
				
			||||||
 | 
					  var typeParameters: MutableList<String> = mutableListOf(),
 | 
				
			||||||
  var parameters: MutableList<KotlinParameter> = mutableListOf(),
 | 
					  var parameters: MutableList<KotlinParameter> = mutableListOf(),
 | 
				
			||||||
  var returnType: String? = null,
 | 
					  var returnType: String? = null,
 | 
				
			||||||
  var abstract: Boolean = false,
 | 
					  var abstract: Boolean = false,
 | 
				
			||||||
 | 
					  var open: Boolean = false,
 | 
				
			||||||
  var overridden: Boolean = false,
 | 
					  var overridden: Boolean = false,
 | 
				
			||||||
  var isImmediateExpression: Boolean = false,
 | 
					  var isImmediateExpression: Boolean = false,
 | 
				
			||||||
  var body: MutableList<String> = mutableListOf()
 | 
					  var body: MutableList<String> = mutableListOf(),
 | 
				
			||||||
 | 
					  var isInterfaceMethod: Boolean = false
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -1,9 +1,10 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.codegen
 | 
					package gay.pizza.pork.buildext.codegen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class KotlinMember(
 | 
					class KotlinMember(
 | 
				
			||||||
  var name: String,
 | 
					  var name: String,
 | 
				
			||||||
  var type: String,
 | 
					  var type: String,
 | 
				
			||||||
  var abstract: Boolean = false,
 | 
					  var abstract: Boolean = false,
 | 
				
			||||||
  var overridden: Boolean = false,
 | 
					  var overridden: Boolean = false,
 | 
				
			||||||
  var value: String? = null
 | 
					  var value: String? = null,
 | 
				
			||||||
 | 
					  var mutable: Boolean = false
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					package gay.pizza.pork.buildext.codegen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class KotlinParameter(
 | 
				
			||||||
 | 
					  val name: String,
 | 
				
			||||||
 | 
					  var type: String,
 | 
				
			||||||
 | 
					  var defaultValue: String? = null,
 | 
				
			||||||
 | 
					  var vararg: Boolean = false
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -1,14 +1,18 @@
 | 
				
			|||||||
package gay.pizza.pork.gradle.codegen
 | 
					package gay.pizza.pork.buildext.codegen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class KotlinWriter {
 | 
					class KotlinWriter() {
 | 
				
			||||||
  private val buffer = StringBuilder()
 | 
					  private val buffer = StringBuilder()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(kotlinClassLike: KotlinClassLike) {
 | 
					  constructor(kotlinClassLike: KotlinClassLike) : this() {
 | 
				
			||||||
    write(kotlinClassLike)
 | 
					    write(kotlinClassLike)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun writeClass(kotlinClass: KotlinClass): Unit = buffer.run {
 | 
					  fun writeClass(kotlinClass: KotlinClass): Unit = buffer.run {
 | 
				
			||||||
    val classType = if (kotlinClass.sealed) "sealed class" else "class"
 | 
					    val classType = when {
 | 
				
			||||||
 | 
					      kotlinClass.sealed -> "sealed class"
 | 
				
			||||||
 | 
					      kotlinClass.isInterface -> "interface"
 | 
				
			||||||
 | 
					      else -> "class"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    writeClassLike(classType, kotlinClass)
 | 
					    writeClassLike(classType, kotlinClass)
 | 
				
			||||||
    val members = kotlinClass.members.filter {
 | 
					    val members = kotlinClass.members.filter {
 | 
				
			||||||
      it.abstract || (it.overridden && it.value != null)
 | 
					      it.abstract || (it.overridden && it.value != null)
 | 
				
			||||||
@ -20,13 +24,14 @@ class KotlinWriter {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (member in members) {
 | 
					    for (member in members) {
 | 
				
			||||||
 | 
					      val form = if (member.mutable) "var" else "val"
 | 
				
			||||||
      if (member.abstract) {
 | 
					      if (member.abstract) {
 | 
				
			||||||
        appendLine("  abstract val ${member.name}: ${member.type}")
 | 
					        appendLine("  abstract $form ${member.name}: ${member.type}")
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        if (member.overridden) {
 | 
					        if (member.overridden) {
 | 
				
			||||||
          append("  override ")
 | 
					          append("  override ")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        append("val ${member.name}: ${member.type}")
 | 
					        append("$form ${member.name}: ${member.type}")
 | 
				
			||||||
        if (member.value != null) {
 | 
					        if (member.value != null) {
 | 
				
			||||||
          append(" = ")
 | 
					          append(" = ")
 | 
				
			||||||
          append(member.value)
 | 
					          append(member.value)
 | 
				
			||||||
@ -107,6 +112,10 @@ class KotlinWriter {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    append("$classType ${kotlinClass.name}")
 | 
					    append("$classType ${kotlinClass.name}")
 | 
				
			||||||
 | 
					    if (kotlinClass.typeParameters.isNotEmpty()) {
 | 
				
			||||||
 | 
					      val typeParameters = kotlinClass.typeParameters.joinToString(", ")
 | 
				
			||||||
 | 
					      append("<${typeParameters}>")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val contructedMembers = kotlinClass.members.filter {
 | 
					    val contructedMembers = kotlinClass.members.filter {
 | 
				
			||||||
      !it.abstract && !(it.overridden && it.value != null)
 | 
					      !it.abstract && !(it.overridden && it.value != null)
 | 
				
			||||||
@ -115,7 +124,8 @@ class KotlinWriter {
 | 
				
			|||||||
    if (contructedMembers.isNotEmpty()) {
 | 
					    if (contructedMembers.isNotEmpty()) {
 | 
				
			||||||
      val constructor = contructedMembers.joinToString(", ") {
 | 
					      val constructor = contructedMembers.joinToString(", ") {
 | 
				
			||||||
        val prefix = if (it.overridden) "override " else ""
 | 
					        val prefix = if (it.overridden) "override " else ""
 | 
				
			||||||
        val start = "${prefix}val ${it.name}: ${it.type}"
 | 
					        val form = if (it.mutable) "var" else "val"
 | 
				
			||||||
 | 
					        val start = "${prefix}$form ${it.name}: ${it.type}"
 | 
				
			||||||
        if (it.value != null) {
 | 
					        if (it.value != null) {
 | 
				
			||||||
          "$start = ${it.value}"
 | 
					          "$start = ${it.value}"
 | 
				
			||||||
        } else start
 | 
					        } else start
 | 
				
			||||||
@ -129,7 +139,7 @@ class KotlinWriter {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun writeFunctions(kotlinClassLike: KotlinClassLike): Unit = buffer.run {
 | 
					  private fun writeFunctions(kotlinClassLike: KotlinClassLike): Unit = buffer.run {
 | 
				
			||||||
    for (function in kotlinClassLike.functions) {
 | 
					    for ((index, function) in kotlinClassLike.functions.withIndex()) {
 | 
				
			||||||
      append("  ")
 | 
					      append("  ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (function.overridden) {
 | 
					      if (function.overridden) {
 | 
				
			||||||
@ -140,9 +150,20 @@ class KotlinWriter {
 | 
				
			|||||||
        append("abstract ")
 | 
					        append("abstract ")
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      append("fun ${function.name}(")
 | 
					      if (function.open) {
 | 
				
			||||||
 | 
					        append("open ")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      append("fun ")
 | 
				
			||||||
 | 
					      if (function.typeParameters.isNotEmpty()) {
 | 
				
			||||||
 | 
					        append("<${function.typeParameters.joinToString(", ")}> ")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      append("${function.name}(")
 | 
				
			||||||
      append(function.parameters.joinToString(", ") {
 | 
					      append(function.parameters.joinToString(", ") {
 | 
				
			||||||
        val start = "${it.name}: ${it.type}"
 | 
					        var start = "${it.name}: ${it.type}"
 | 
				
			||||||
 | 
					        if (it.vararg) {
 | 
				
			||||||
 | 
					          start = "vararg $start"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        if (it.defaultValue != null) {
 | 
					        if (it.defaultValue != null) {
 | 
				
			||||||
          start + " = ${it.defaultValue}"
 | 
					          start + " = ${it.defaultValue}"
 | 
				
			||||||
        } else start
 | 
					        } else start
 | 
				
			||||||
@ -152,10 +173,10 @@ class KotlinWriter {
 | 
				
			|||||||
        append(": ${function.returnType}")
 | 
					        append(": ${function.returnType}")
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!function.isImmediateExpression) {
 | 
					      if (!function.isImmediateExpression && !function.abstract && !function.isInterfaceMethod) {
 | 
				
			||||||
        append(" {")
 | 
					        append(" {")
 | 
				
			||||||
      } else {
 | 
					      } else if (!function.abstract && !function.isInterfaceMethod) {
 | 
				
			||||||
        appendLine(" =")
 | 
					        append(" =")
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (function.body.isNotEmpty()) {
 | 
					      if (function.body.isNotEmpty()) {
 | 
				
			||||||
@ -166,8 +187,19 @@ class KotlinWriter {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!function.isImmediateExpression) {
 | 
					      if (!function.isImmediateExpression && !function.abstract && !function.isInterfaceMethod) {
 | 
				
			||||||
        appendLine("  }")
 | 
					        if (function.body.isNotEmpty()) {
 | 
				
			||||||
 | 
					          append("  ")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        appendLine("}")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (function.abstract || function.isInterfaceMethod) {
 | 
				
			||||||
 | 
					        appendLine()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (index < kotlinClassLike.functions.size - 1) {
 | 
				
			||||||
 | 
					        appendLine()
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -1,3 +1,3 @@
 | 
				
			|||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
  pork_module
 | 
					  id("gay.pizza.pork.module")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
  pork_module
 | 
					  id("gay.pizza.pork.module")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
 | 
				
			|||||||
@ -101,7 +101,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitFunctionDeclaration(node: FunctionDefinition): Any {
 | 
					  override fun visitFunctionDefinition(node: FunctionDefinition): Any {
 | 
				
			||||||
    val blockFunction = visitBlock(node.block) as BlockFunction
 | 
					    val blockFunction = visitBlock(node.block) as BlockFunction
 | 
				
			||||||
    val function = CallableFunction { arguments ->
 | 
					    val function = CallableFunction { arguments ->
 | 
				
			||||||
      currentScope = currentScope.fork()
 | 
					      currentScope = currentScope.fork()
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
  pork_module
 | 
					  id("gay.pizza.pork.module")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								gradle.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								gradle.properties
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					org.gradle.warning.mode=none
 | 
				
			||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
  pork_module
 | 
					  id("gay.pizza.pork.module")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
 | 
				
			|||||||
@ -147,7 +147,7 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
 | 
				
			|||||||
    visit(node.right)
 | 
					    visit(node.right)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun visitFunctionDeclaration(node: FunctionDefinition) {
 | 
					  override fun visitFunctionDefinition(node: FunctionDefinition) {
 | 
				
			||||||
    append("fn ")
 | 
					    append("fn ")
 | 
				
			||||||
    visit(node.symbol)
 | 
					    visit(node.symbol)
 | 
				
			||||||
    append("(")
 | 
					    append("(")
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
rootProject.name = "pork"
 | 
					rootProject.name = "pork"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					includeBuild("buildext")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include(
 | 
					include(
 | 
				
			||||||
  ":common",
 | 
					  ":common",
 | 
				
			||||||
  ":ast",
 | 
					  ":ast",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
  application
 | 
					  application
 | 
				
			||||||
  pork_module
 | 
					  id("gay.pizza.pork.module")
 | 
				
			||||||
  id("com.github.johnrengelman.shadow") version "8.1.1"
 | 
					  id("com.github.johnrengelman.shadow") version "8.1.1"
 | 
				
			||||||
  id("org.graalvm.buildtools.native") version "0.9.25"
 | 
					  id("org.graalvm.buildtools.native") version "0.9.25"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -15,9 +15,19 @@ dependencies {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
application {
 | 
					application {
 | 
				
			||||||
 | 
					  applicationName = "pork"
 | 
				
			||||||
  mainClass.set("gay.pizza.pork.tool.MainKt")
 | 
					  mainClass.set("gay.pizza.pork.tool.MainKt")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					for (task in arrayOf(tasks.shadowDistTar, tasks.shadowDistZip, tasks.shadowJar)) {
 | 
				
			||||||
 | 
					  val suffix = when {
 | 
				
			||||||
 | 
					    task == tasks.shadowJar -> ""
 | 
				
			||||||
 | 
					    task.name.startsWith("shadow") -> "-shadow"
 | 
				
			||||||
 | 
					    else -> ""
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  task.get().archiveBaseName.set("pork${suffix}")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
graalvmNative {
 | 
					graalvmNative {
 | 
				
			||||||
  binaries {
 | 
					  binaries {
 | 
				
			||||||
    named("main") {
 | 
					    named("main") {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user