Restructure AST to make roles more clear.

This commit is contained in:
Alex Zenla 2023-08-21 00:47:14 -07:00
parent 624b05605a
commit d92dc8d904
Signed by: alex
GPG Key ID: C0780728420EBFE5
30 changed files with 141 additions and 70 deletions

View File

@ -1,8 +0,0 @@
package gay.pizza.pork.ast
class Define(val symbol: Symbol, val value: Expression) : Expression() {
override val type: NodeType = NodeType.Define
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
visitor.visitNodes(symbol, value)
}

View File

@ -1,8 +0,0 @@
package gay.pizza.pork.ast
class ListLiteral(val items: List<Expression>) : Expression() {
override val type: NodeType = NodeType.ListLiteral
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
visitor.visitAll(items)
}

View File

@ -1,8 +0,0 @@
package gay.pizza.pork.ast
abstract class Node {
abstract val type: NodeType
open fun <T> visitChildren(visitor: Visitor<T>): List<T> = emptyList()
override fun toString(): String = let { node -> buildString { Printer(this).visit(node) } }
}

View File

@ -0,0 +1,19 @@
package gay.pizza.pork.ast
import gay.pizza.pork.ast.nodes.*
class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
override fun visitDefine(node: Define) = handler(node)
override fun visitFunctionCall(node: FunctionCall) = handler(node)
override fun visitReference(node: SymbolReference) = handler(node)
override fun visitIf(node: If) = handler(node)
override fun visitSymbol(node: Symbol) = handler(node)
override fun visitLambda(node: Lambda) = handler(node)
override fun visitIntLiteral(node: IntLiteral) = handler(node)
override fun visitBooleanLiteral(node: BooleanLiteral) = handler(node)
override fun visitListLiteral(node: ListLiteral) = handler(node)
override fun visitParentheses(node: Parentheses) = handler(node)
override fun visitPrefixOperation(node: PrefixOperation) = handler(node)
override fun visitInfixOperation(node: InfixOperation) = handler(node)
override fun visitProgram(node: Program) = handler(node)
}

View File

@ -1,6 +1,8 @@
package gay.pizza.pork.ast
interface Visitor<T> {
import gay.pizza.pork.ast.nodes.*
interface NodeVisitor<T> {
fun visitDefine(node: Define): T
fun visitFunctionCall(node: FunctionCall): T
fun visitReference(node: SymbolReference): T

View File

@ -1,8 +0,0 @@
package gay.pizza.pork.ast
class Parentheses(val expression: Expression) : Expression() {
override val type: NodeType = NodeType.Parentheses
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
visitor.visitNodes(expression)
}

View File

@ -1,6 +1,8 @@
package gay.pizza.pork.ast
class Printer(private val buffer: StringBuilder) : Visitor<Unit> {
import gay.pizza.pork.ast.nodes.*
class Printer(private val buffer: StringBuilder) : NodeVisitor<Unit> {
private var indent = 0
private fun append(text: String) {
@ -65,6 +67,8 @@ class Printer(private val buffer: StringBuilder) : Visitor<Unit> {
}
append(" ")
}
} else {
append(" ")
}
append("in")
indent++

View File

@ -1,8 +0,0 @@
package gay.pizza.pork.ast
class Program(val expressions: List<Expression>) : Node() {
override val type: NodeType = NodeType.Program
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
visitor.visitAll(expressions)
}

View File

@ -1,8 +0,0 @@
package gay.pizza.pork.ast
class SymbolReference(val symbol: Symbol) : Expression() {
override val type: NodeType = NodeType.SymbolReference
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
visitor.visitNodes(symbol)
}

View File

@ -1,4 +1,6 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
class BooleanLiteral(val value: Boolean) : Expression() {
override val type: NodeType = NodeType.BooleanLiteral

View File

@ -0,0 +1,11 @@
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
import gay.pizza.pork.ast.NodeVisitor
class Define(val symbol: Symbol, val value: Expression) : Expression() {
override val type: NodeType = NodeType.Define
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
visitor.visitNodes(symbol, value)
}

View File

@ -1,3 +1,3 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
abstract class Expression : Node()

View File

@ -1,8 +1,11 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
import gay.pizza.pork.ast.NodeVisitor
class FunctionCall(val symbol: Symbol, val arguments: List<Expression>) : Expression() {
override val type: NodeType = NodeType.FunctionCall
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
visitor.visitAll(listOf(symbol), arguments)
}

View File

@ -1,4 +1,6 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
class If(
val condition: Expression,

View File

@ -1,8 +1,11 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
import gay.pizza.pork.ast.NodeVisitor
class InfixOperation(val left: Expression, val op: InfixOperator, val right: Expression) : Expression() {
override val type: NodeType = NodeType.InfixOperation
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
visitor.visitNodes(left, right)
}

View File

@ -1,4 +1,4 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
enum class InfixOperator(val token: String) {
Plus("+"),

View File

@ -1,4 +1,6 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
class IntLiteral(val value: Int) : Expression() {
override val type: NodeType = NodeType.IntLiteral

View File

@ -1,8 +1,11 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
import gay.pizza.pork.ast.NodeVisitor
class Lambda(val arguments: List<Symbol>, val expressions: List<Expression>) : Expression() {
override val type: NodeType = NodeType.Lambda
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
visitor.visitAll(arguments, expressions)
}

View File

@ -0,0 +1,11 @@
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
import gay.pizza.pork.ast.NodeVisitor
class ListLiteral(val items: List<Expression>) : Expression() {
override val type: NodeType = NodeType.ListLiteral
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
visitor.visitAll(items)
}

View File

@ -0,0 +1,12 @@
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
import gay.pizza.pork.ast.Printer
import gay.pizza.pork.ast.NodeVisitor
abstract class Node {
abstract val type: NodeType
open fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> = emptyList()
override fun toString(): String = let { node -> buildString { Printer(this).visit(node) } }
}

View File

@ -0,0 +1,11 @@
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
import gay.pizza.pork.ast.NodeVisitor
class Parentheses(val expression: Expression) : Expression() {
override val type: NodeType = NodeType.Parentheses
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
visitor.visitNodes(expression)
}

View File

@ -1,4 +1,6 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
class PrefixOperation(val op: PrefixOperator, val expression: Expression) : Expression() {
override val type: NodeType = NodeType.PrefixOperation

View File

@ -1,4 +1,4 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
enum class PrefixOperator(val token: String) {
Negate("!")

View File

@ -0,0 +1,11 @@
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
import gay.pizza.pork.ast.NodeVisitor
class Program(val expressions: List<Expression>) : Node() {
override val type: NodeType = NodeType.Program
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
visitor.visitAll(expressions)
}

View File

@ -1,4 +1,6 @@
package gay.pizza.pork.ast
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
class Symbol(val id: String) : Node() {
override val type: NodeType = NodeType.Symbol

View File

@ -0,0 +1,11 @@
package gay.pizza.pork.ast.nodes
import gay.pizza.pork.ast.NodeType
import gay.pizza.pork.ast.NodeVisitor
class SymbolReference(val symbol: Symbol) : Expression() {
override val type: NodeType = NodeType.SymbolReference
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
visitor.visitNodes(symbol)
}

View File

@ -1,8 +1,9 @@
package gay.pizza.pork.compiler
import gay.pizza.pork.ast.*
import gay.pizza.pork.ast.nodes.*
class KotlinCompiler : Visitor<String> {
class KotlinCompiler : NodeVisitor<String> {
override fun visitDefine(node: Define): String =
"val ${visit(node.symbol)} = ${visit(node.value)}"

View File

@ -1,8 +1,9 @@
package gay.pizza.pork.eval
import gay.pizza.pork.ast.*
import gay.pizza.pork.ast.nodes.*
class PorkEvaluator(root: Scope) : Visitor<Any> {
class PorkEvaluator(root: Scope) : NodeVisitor<Any> {
private var currentScope: Scope = root
override fun visitDefine(node: Define): Any {

View File

@ -1,6 +1,7 @@
package gay.pizza.pork
import gay.pizza.pork.ast.Program
import gay.pizza.pork.ast.Printer
import gay.pizza.pork.ast.nodes.Program
import gay.pizza.pork.eval.Arguments
import gay.pizza.pork.eval.PorkEvaluator
import gay.pizza.pork.eval.Scope
@ -39,9 +40,14 @@ fun main(args: Array<String>) {
eval(program)
val exactCode = stream.tokens.joinToString("") { it.text }
println(exactCode)
println(code == exactCode)
validateTokenSoundness(code, stream)
if (exactCode != code) {
throw RuntimeException("Token reconstruction didn't succeed.")
}
val generated = buildString { Printer(this).visit(program) }
parse(tokenize(generated))
println(generated)
}
fun tokenize(input: String): TokenStream =

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.parse
import gay.pizza.pork.ast.*
import gay.pizza.pork.ast.nodes.*
class PorkParser(source: PeekableSource<Token>) {
private val whitespaceIncludedSource = source