mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
Restructure AST to make roles more clear.
This commit is contained in:
parent
624b05605a
commit
d92dc8d904
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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) } }
|
||||
}
|
19
src/main/kotlin/gay/pizza/pork/ast/NodeCoalescer.kt
Normal file
19
src/main/kotlin/gay/pizza/pork/ast/NodeCoalescer.kt
Normal 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)
|
||||
}
|
@ -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
|
@ -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)
|
||||
}
|
@ -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++
|
||||
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
11
src/main/kotlin/gay/pizza/pork/ast/nodes/Define.kt
Normal file
11
src/main/kotlin/gay/pizza/pork/ast/nodes/Define.kt
Normal 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)
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
package gay.pizza.pork.ast
|
||||
package gay.pizza.pork.ast.nodes
|
||||
|
||||
abstract class Expression : Node()
|
@ -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)
|
||||
}
|
@ -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,
|
@ -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)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.ast
|
||||
package gay.pizza.pork.ast.nodes
|
||||
|
||||
enum class InfixOperator(val token: String) {
|
||||
Plus("+"),
|
@ -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
|
@ -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)
|
||||
}
|
11
src/main/kotlin/gay/pizza/pork/ast/nodes/ListLiteral.kt
Normal file
11
src/main/kotlin/gay/pizza/pork/ast/nodes/ListLiteral.kt
Normal 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)
|
||||
}
|
12
src/main/kotlin/gay/pizza/pork/ast/nodes/Node.kt
Normal file
12
src/main/kotlin/gay/pizza/pork/ast/nodes/Node.kt
Normal 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) } }
|
||||
}
|
11
src/main/kotlin/gay/pizza/pork/ast/nodes/Parentheses.kt
Normal file
11
src/main/kotlin/gay/pizza/pork/ast/nodes/Parentheses.kt
Normal 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)
|
||||
}
|
@ -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
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.ast
|
||||
package gay.pizza.pork.ast.nodes
|
||||
|
||||
enum class PrefixOperator(val token: String) {
|
||||
Negate("!")
|
11
src/main/kotlin/gay/pizza/pork/ast/nodes/Program.kt
Normal file
11
src/main/kotlin/gay/pizza/pork/ast/nodes/Program.kt
Normal 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)
|
||||
}
|
@ -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
|
11
src/main/kotlin/gay/pizza/pork/ast/nodes/SymbolReference.kt
Normal file
11
src/main/kotlin/gay/pizza/pork/ast/nodes/SymbolReference.kt
Normal 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)
|
||||
}
|
@ -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)}"
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user