mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 05:10: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
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
interface Visitor<T> {
|
import gay.pizza.pork.ast.nodes.*
|
||||||
|
|
||||||
|
interface NodeVisitor<T> {
|
||||||
fun visitDefine(node: Define): T
|
fun visitDefine(node: Define): T
|
||||||
fun visitFunctionCall(node: FunctionCall): T
|
fun visitFunctionCall(node: FunctionCall): T
|
||||||
fun visitReference(node: SymbolReference): 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
|
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 var indent = 0
|
||||||
|
|
||||||
private fun append(text: String) {
|
private fun append(text: String) {
|
||||||
@ -65,6 +67,8 @@ class Printer(private val buffer: StringBuilder) : Visitor<Unit> {
|
|||||||
}
|
}
|
||||||
append(" ")
|
append(" ")
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
append(" ")
|
||||||
}
|
}
|
||||||
append("in")
|
append("in")
|
||||||
indent++
|
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() {
|
class BooleanLiteral(val value: Boolean) : Expression() {
|
||||||
override val type: NodeType = NodeType.BooleanLiteral
|
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()
|
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() {
|
class FunctionCall(val symbol: Symbol, val arguments: List<Expression>) : Expression() {
|
||||||
override val type: NodeType = NodeType.FunctionCall
|
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)
|
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(
|
class If(
|
||||||
val condition: Expression,
|
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() {
|
class InfixOperation(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: Visitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitNodes(left, right)
|
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) {
|
enum class InfixOperator(val token: String) {
|
||||||
Plus("+"),
|
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() {
|
class IntLiteral(val value: Int) : Expression() {
|
||||||
override val type: NodeType = NodeType.IntLiteral
|
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() {
|
class Lambda(val arguments: List<Symbol>, val expressions: List<Expression>) : Expression() {
|
||||||
override val type: NodeType = NodeType.Lambda
|
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)
|
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() {
|
class PrefixOperation(val op: PrefixOperator, val expression: Expression) : Expression() {
|
||||||
override val type: NodeType = NodeType.PrefixOperation
|
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) {
|
enum class PrefixOperator(val token: String) {
|
||||||
Negate("!")
|
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() {
|
class Symbol(val id: String) : Node() {
|
||||||
override val type: NodeType = NodeType.Symbol
|
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
|
package gay.pizza.pork.compiler
|
||||||
|
|
||||||
import gay.pizza.pork.ast.*
|
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 =
|
override fun visitDefine(node: Define): String =
|
||||||
"val ${visit(node.symbol)} = ${visit(node.value)}"
|
"val ${visit(node.symbol)} = ${visit(node.value)}"
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package gay.pizza.pork.eval
|
package gay.pizza.pork.eval
|
||||||
|
|
||||||
import gay.pizza.pork.ast.*
|
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
|
private var currentScope: Scope = root
|
||||||
|
|
||||||
override fun visitDefine(node: Define): Any {
|
override fun visitDefine(node: Define): Any {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package gay.pizza.pork
|
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.Arguments
|
||||||
import gay.pizza.pork.eval.PorkEvaluator
|
import gay.pizza.pork.eval.PorkEvaluator
|
||||||
import gay.pizza.pork.eval.Scope
|
import gay.pizza.pork.eval.Scope
|
||||||
@ -39,9 +40,14 @@ fun main(args: Array<String>) {
|
|||||||
eval(program)
|
eval(program)
|
||||||
|
|
||||||
val exactCode = stream.tokens.joinToString("") { it.text }
|
val exactCode = stream.tokens.joinToString("") { it.text }
|
||||||
println(exactCode)
|
|
||||||
println(code == exactCode)
|
|
||||||
validateTokenSoundness(code, stream)
|
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 =
|
fun tokenize(input: String): TokenStream =
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package gay.pizza.pork.parse
|
package gay.pizza.pork.parse
|
||||||
|
|
||||||
import gay.pizza.pork.ast.*
|
import gay.pizza.pork.ast.nodes.*
|
||||||
|
|
||||||
class PorkParser(source: PeekableSource<Token>) {
|
class PorkParser(source: PeekableSource<Token>) {
|
||||||
private val whitespaceIncludedSource = source
|
private val whitespaceIncludedSource = source
|
||||||
|
Loading…
Reference in New Issue
Block a user