Auto-generate the AST.

This commit is contained in:
2023-09-04 21:50:27 -07:00
parent f06ea93dc4
commit 174d51ca1c
58 changed files with 741 additions and 390 deletions

View File

@ -1,5 +1,4 @@
plugins {
pork_module
id("gay.pizza.pork.module")
id("gay.pizza.pork.ast")
}

View File

@ -33,7 +33,7 @@ types:
- name: declarations
type: List<Declaration>
- name: definitions
type: List<Declaration>
type: List<Definition>
LetAssignment:
parent: Expression
values:

View File

@ -9,15 +9,16 @@ class CompilationUnit(val declarations: List<Declaration>, val definitions: List
override val type: NodeType = NodeType.CompilationUnit
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
visitor.visitAll(declarations)
visitor.visitAll(declarations, definitions)
override fun equals(other: Any?): Boolean {
if (other !is CompilationUnit) return false
return other.declarations == declarations
return other.declarations == declarations && other.definitions == definitions
}
override fun hashCode(): Int {
var result = declarations.hashCode()
result = 31 * result + definitions.hashCode()
result = 31 * result + type.hashCode()
return result
}

View File

@ -1,6 +1,8 @@
package gay.pizza.pork.ast
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
@SerialName("declaration")
sealed class Declaration : Node()

View File

@ -1,8 +1,10 @@
package gay.pizza.pork.ast
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
@SerialName("definition")
sealed class Definition : Node() {
abstract val symbol: Symbol
abstract val modifiers: DefinitionModifiers

View File

@ -1,8 +1,8 @@
package gay.pizza.pork.ast
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
class DefinitionModifiers(
var export: Boolean
)
@SerialName("definitionModifiers")
class DefinitionModifiers(var export: Boolean)

View File

@ -1,6 +1,8 @@
package gay.pizza.pork.ast
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
@SerialName("expression")
sealed class Expression : Node()

View File

@ -5,24 +5,20 @@ import kotlinx.serialization.Serializable
@Serializable
@SerialName("functionDefinition")
class FunctionDefinition(
override val modifiers: DefinitionModifiers,
override val symbol: Symbol,
val arguments: List<Symbol>,
val block: Block
) : Definition() {
class FunctionDefinition(override val modifiers: DefinitionModifiers, override val symbol: Symbol, val arguments: List<Symbol>, val block: Block) : Definition() {
override val type: NodeType = NodeType.FunctionDefinition
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 {
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 {
var result = symbol.hashCode()
var result = modifiers.hashCode()
result = 31 * result + symbol.hashCode()
result = 31 * result + arguments.hashCode()
result = 31 * result + block.hashCode()
result = 31 * result + type.hashCode()

View File

@ -5,11 +5,7 @@ import kotlinx.serialization.Serializable
@Serializable
@SerialName("if")
class If(
val condition: Expression,
val thenExpression: Expression,
val elseExpression: Expression? = null
) : Expression() {
class If(val condition: Expression, val thenExpression: Expression, val elseExpression: Expression?) : Expression() {
override val type: NodeType = NodeType.If
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
@ -17,15 +13,13 @@ class If(
override fun equals(other: Any?): Boolean {
if (other !is If) return false
return other.condition == condition &&
other.thenExpression == thenExpression &&
other.elseExpression == elseExpression
return other.condition == condition && other.thenExpression == thenExpression && other.elseExpression == elseExpression
}
override fun hashCode(): Int {
var result = condition.hashCode()
result = 31 * result + thenExpression.hashCode()
result = 31 * result + (elseExpression?.hashCode() ?: 0)
result = 31 * result + elseExpression.hashCode()
result = 31 * result + type.hashCode()
return result
}

View File

@ -5,11 +5,7 @@ import kotlinx.serialization.Serializable
@Serializable
@SerialName("infixOperation")
class InfixOperation(
val left: Expression,
val op: InfixOperator,
val right: Expression
) : Expression() {
class InfixOperation(val left: Expression, val op: InfixOperator, val right: Expression) : Expression() {
override val type: NodeType = NodeType.InfixOperation
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
@ -17,9 +13,7 @@ class InfixOperation(
override fun equals(other: Any?): Boolean {
if (other !is InfixOperation) return false
return other.op == op &&
other.left == left &&
other.right == right
return other.left == left && other.op == op && other.right == right
}
override fun hashCode(): Int {

View File

@ -14,7 +14,7 @@ class IntLiteral(val value: Int) : Expression() {
}
override fun hashCode(): Int {
var result = value
var result = value.hashCode()
result = 31 * result + type.hashCode()
return result
}

View File

@ -1,9 +1,13 @@
package gay.pizza.pork.ast
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
@SerialName("node")
sealed class Node {
abstract val type: NodeType
open fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> = emptyList()
open fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
emptyList()
}

View File

@ -1,26 +1,58 @@
package gay.pizza.pork.ast
class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
override fun visitIntLiteral(node: IntLiteral): Unit = handle(node)
override fun visitStringLiteral(node: StringLiteral): Unit = 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 visitBlock(node: Block): 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)
node.visitChildren(this)
}

View File

@ -2,24 +2,24 @@ package gay.pizza.pork.ast
enum class NodeType(val parent: NodeType? = null) {
Node,
Symbol(Node),
Block(Node),
Expression(Node),
BooleanLiteral(Expression),
CompilationUnit(Node),
Declaration(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),
FunctionDefinition(Definition),
If(Expression),
ImportDeclaration(Declaration),
FunctionDefinition(Definition)
InfixOperation(Expression),
IntLiteral(Expression),
Lambda(Expression),
LetAssignment(Expression),
ListLiteral(Expression),
Parentheses(Expression),
PrefixOperation(Expression),
StringLiteral(Expression),
Symbol(Node),
SymbolReference(Expression)
}

View File

@ -1,60 +1,64 @@
package gay.pizza.pork.ast
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 visitImportDeclaration(node: ImportDeclaration): T
fun visitBooleanLiteral(node: BooleanLiteral): T
fun visitCompilationUnit(node: CompilationUnit): T
fun visitExpression(node: Expression): T = when (node) {
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 visitFunctionCall(node: FunctionCall): T
fun visitDeclaration(node: Declaration): T = when (node) {
is ImportDeclaration -> visitImportDeclaration(node)
}
fun visitFunctionDefinition(node: FunctionDefinition): T
fun visitDefinition(node: Definition): T = when (node) {
is FunctionDefinition -> visitFunctionDeclaration(node)
}
fun visitIf(node: If): T
fun visit(node: Node): T = when (node) {
is Symbol -> visitSymbol(node)
is Expression -> visitExpression(node)
is CompilationUnit -> visitCompilationUnit(node)
is Block -> visitBlock(node)
is Declaration -> visitDeclaration(node)
is Definition -> visitDefinition(node)
}
fun visitImportDeclaration(node: ImportDeclaration): T
fun visitInfixOperation(node: InfixOperation): T
fun visitIntLiteral(node: IntLiteral): T
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> =
nodes.asSequence().filterNotNull().map { visit(it) }.toList()
fun visitAll(vararg nodeLists: List<Node>): List<T> =
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)
}
}