Define node visitor order based on parsing order.

This commit is contained in:
Alex Zenla 2023-09-02 15:11:25 -07:00
parent 900e3f1a1c
commit 941b201549
Signed by: alex
GPG Key ID: C0780728420EBFE5
8 changed files with 188 additions and 193 deletions

View File

@ -3,11 +3,11 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
application
kotlin("jvm") version "1.9.0"
kotlin("plugin.serialization") version "1.9.0"
kotlin("jvm") version "1.9.10"
kotlin("plugin.serialization") version "1.9.10"
id("com.github.johnrengelman.shadow") version "8.1.1"
id("org.graalvm.buildtools.native") version "0.9.23"
id("org.graalvm.buildtools.native") version "0.9.25"
}
repositories {
@ -22,9 +22,8 @@ java {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-bom")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("com.github.ajalt.clikt:clikt:4.2.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0-RC")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
}
tasks.withType<KotlinCompile> {

View File

@ -3,18 +3,18 @@ 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 visitStringLiteral(node: StringLiteral) = 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)
override fun visitIntLiteral(node: IntLiteral): Unit = handler(node)
override fun visitStringLiteral(node: StringLiteral): Unit = handler(node)
override fun visitBooleanLiteral(node: BooleanLiteral): Unit = handler(node)
override fun visitListLiteral(node: ListLiteral): Unit = handler(node)
override fun visitSymbol(node: Symbol): Unit = handler(node)
override fun visitFunctionCall(node: FunctionCall): Unit = handler(node)
override fun visitDefine(node: Define): Unit = handler(node)
override fun visitSymbolReference(node: SymbolReference): Unit = handler(node)
override fun visitLambda(node: Lambda): Unit = handler(node)
override fun visitParentheses(node: Parentheses): Unit = handler(node)
override fun visitPrefixOperation(node: PrefixOperation): Unit = handler(node)
override fun visitIf(node: If): Unit = handler(node)
override fun visitInfixOperation(node: InfixOperation): Unit = handler(node)
override fun visitProgram(node: Program): Unit = handler(node)
}

View File

@ -3,47 +3,44 @@ package gay.pizza.pork.ast
import gay.pizza.pork.ast.nodes.*
interface NodeVisitor<T> {
fun visitDefine(node: Define): T
fun visitFunctionCall(node: FunctionCall): T
fun visitReference(node: SymbolReference): T
fun visitIf(node: If): T
fun visitSymbol(node: Symbol): T
fun visitLambda(node: Lambda): T
fun visitIntLiteral(node: IntLiteral): T
fun visitStringLiteral(node: StringLiteral): T
fun visitBooleanLiteral(node: BooleanLiteral): T
fun visitListLiteral(node: ListLiteral): T
fun visitStringLiteral(node: StringLiteral): T
fun visitSymbol(node: Symbol): T
fun visitFunctionCall(node: FunctionCall): T
fun visitDefine(node: Define): 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 visitProgram(node: Program): 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 StringLiteral -> visitStringLiteral(node)
is Parentheses -> visitParentheses(node)
is InfixOperation -> visitInfixOperation(node)
is PrefixOperation -> visitPrefixOperation(node)
is Define -> visitDefine(node)
is Lambda -> visitLambda(node)
is FunctionCall -> visitFunctionCall(node)
is SymbolReference -> visitReference(node)
is Define -> visitDefine(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 visit(node: Node): T = when (node) {
is Expression -> visitExpression(node)
is Symbol -> visitSymbol(node)
is Expression -> visitExpression(node)
is Program -> visitProgram(node)
}
fun visitNodes(vararg nodes: Node?): List<T> =
nodes.filterNotNull().map { visit(it) }
nodes.asSequence().filterNotNull().map { visit(it) }.toList()
fun visitAll(vararg nodeLists: List<Node>): List<T> =
nodeLists.asSequence().flatten().map { visit(it) }.toList()

View File

@ -20,10 +20,37 @@ class Printer(private val buffer: StringBuilder) : NodeVisitor<Unit> {
}
}
override fun visitDefine(node: Define) {
visit(node.symbol)
append(" = ")
visit(node.value)
override fun visitIntLiteral(node: IntLiteral) {
append(node.value.toString())
}
override fun visitStringLiteral(node: StringLiteral) {
append("\"")
append(StringEscape.escape(node.text))
append("\"")
}
override fun visitBooleanLiteral(node: BooleanLiteral) {
if (node.value) {
append("true")
} else {
append("false")
}
}
override fun visitListLiteral(node: ListLiteral) {
append("[")
for ((index, item) in node.items.withIndex()) {
visit(item)
if (index != node.items.size - 1) {
append(", ")
}
}
append("]")
}
override fun visitSymbol(node: Symbol) {
append(node.id)
}
override fun visitFunctionCall(node: FunctionCall) {
@ -38,24 +65,16 @@ class Printer(private val buffer: StringBuilder) : NodeVisitor<Unit> {
append(")")
}
override fun visitReference(node: SymbolReference) {
override fun visitDefine(node: Define) {
visit(node.symbol)
append(" = ")
visit(node.value)
}
override fun visitSymbolReference(node: SymbolReference) {
visit(node.symbol)
}
override fun visitIf(node: If) {
append("if ")
visit(node.condition)
append(" then ")
visit(node.thenExpression)
if (node.elseExpression != null) {
append(" else ")
visit(node.elseExpression)
}
}
override fun visitSymbol(node: Symbol) {
append(node.id)
}
override fun visitLambda(node: Lambda) {
append("{")
@ -87,35 +106,6 @@ class Printer(private val buffer: StringBuilder) : NodeVisitor<Unit> {
append("}")
}
override fun visitIntLiteral(node: IntLiteral) {
append(node.value.toString())
}
override fun visitBooleanLiteral(node: BooleanLiteral) {
if (node.value) {
append("true")
} else {
append("false")
}
}
override fun visitListLiteral(node: ListLiteral) {
append("[")
for ((index, item) in node.items.withIndex()) {
visit(item)
if (index != node.items.size - 1) {
append(", ")
}
}
append("]")
}
override fun visitStringLiteral(node: StringLiteral) {
append("\"")
append(StringEscape.escape(node.text))
append("\"")
}
override fun visitParentheses(node: Parentheses) {
append("(")
visit(node.expression)
@ -127,6 +117,17 @@ class Printer(private val buffer: StringBuilder) : NodeVisitor<Unit> {
visit(node.expression)
}
override fun visitIf(node: If) {
append("if ")
visit(node.condition)
append(" then ")
visit(node.thenExpression)
if (node.elseExpression != null) {
append(" else ")
visit(node.elseExpression)
}
}
override fun visitInfixOperation(node: InfixOperation) {
visit(node.left)
append(" ")

View File

@ -5,49 +5,12 @@ import gay.pizza.pork.ast.nodes.*
import gay.pizza.pork.util.StringEscape
class DartCompiler : NodeVisitor<String> {
override fun visitDefine(node: Define): String =
"final ${visit(node.symbol)} = ${visit(node.value)};"
override fun visitFunctionCall(node: FunctionCall): String =
"${visit(node.symbol)}(${node.arguments.joinToString(", ") { visit(it) }})"
override fun visitReference(node: SymbolReference): String =
visit(node.symbol)
override fun visitIf(node: If): String = buildString {
append("if (")
append(visit(node.condition))
append(") {")
append(visit(node.thenExpression))
append("}")
if (node.elseExpression != null) {
append(" else {")
append(visit(node.elseExpression))
append("}")
}
}
override fun visitSymbol(node: Symbol): String =
node.id
override fun visitLambda(node: Lambda): String = buildString {
append("(${node.arguments.joinToString(", ") { visit(it) }}) {")
appendLine()
for ((index, expression) in node.expressions.withIndex()) {
val code = visit(expression)
if (index == node.expressions.size - 1) {
append("return ");
}
append(code)
append(";")
}
appendLine()
append("}")
}
override fun visitIntLiteral(node: IntLiteral): String =
node.value.toString()
override fun visitStringLiteral(node: StringLiteral): String =
"\"" + StringEscape.escape(node.text) + "\""
override fun visitBooleanLiteral(node: BooleanLiteral): String =
node.value.toString()
@ -63,8 +26,32 @@ class DartCompiler : NodeVisitor<String> {
append("]")
}
override fun visitStringLiteral(node: StringLiteral): String =
"\"" + StringEscape.escape(node.text) + "\""
override fun visitSymbol(node: Symbol): String =
node.id
override fun visitFunctionCall(node: FunctionCall): String =
"${visit(node.symbol)}(${node.arguments.joinToString(", ") { visit(it) }})"
override fun visitDefine(node: Define): String =
"final ${visit(node.symbol)} = ${visit(node.value)};"
override fun visitSymbolReference(node: SymbolReference): String =
visit(node.symbol)
override fun visitLambda(node: Lambda): String = buildString {
append("(${node.arguments.joinToString(", ") { visit(it) }}) {")
appendLine()
for ((index, expression) in node.expressions.withIndex()) {
val code = visit(expression)
if (index == node.expressions.size - 1) {
append("return ");
}
append(code)
append(";")
}
appendLine()
append("}")
}
override fun visitParentheses(node: Parentheses): String =
"(${visit(node.expression)})"
@ -72,6 +59,19 @@ class DartCompiler : NodeVisitor<String> {
override fun visitPrefixOperation(node: PrefixOperation): String =
"${node.op.token}${visit(node.expression)}"
override fun visitIf(node: If): String = buildString {
append("if (")
append(visit(node.condition))
append(") {")
append(visit(node.thenExpression))
append("}")
if (node.elseExpression != null) {
append(" else {")
append(visit(node.elseExpression))
append("}")
}
}
override fun visitInfixOperation(node: InfixOperation): String =
"${visit(node.left)} ${node.op.token} ${visit(node.right)}"

View File

@ -5,42 +5,12 @@ import gay.pizza.pork.ast.nodes.*
import gay.pizza.pork.util.StringEscape
class KotlinCompiler : NodeVisitor<String> {
override fun visitDefine(node: Define): String =
"val ${visit(node.symbol)} = ${visit(node.value)}"
override fun visitFunctionCall(node: FunctionCall): String =
"${visit(node.symbol)}(${node.arguments.joinToString(", ") { visit(it) }})"
override fun visitReference(node: SymbolReference): String =
visit(node.symbol)
override fun visitIf(node: If): String = buildString {
append("if (")
append(visit(node.condition))
append(") {")
append(visit(node.thenExpression))
append("}")
if (node.elseExpression != null) {
append(" else {")
append(visit(node.elseExpression))
append("}")
}
}
override fun visitSymbol(node: Symbol): String =
node.id
override fun visitLambda(node: Lambda): String = buildString {
append("{ ${node.arguments.joinToString(", ") { visit(it) }} ->")
appendLine()
append(visitAll(node.expressions).joinToString("\n"))
appendLine()
append("}")
}
override fun visitIntLiteral(node: IntLiteral): String =
node.value.toString()
override fun visitStringLiteral(node: StringLiteral): String =
"\"" + StringEscape.escape(node.text) + "\""
override fun visitBooleanLiteral(node: BooleanLiteral): String =
node.value.toString()
@ -56,8 +26,25 @@ class KotlinCompiler : NodeVisitor<String> {
append(")")
}
override fun visitStringLiteral(node: StringLiteral): String =
"\"" + StringEscape.escape(node.text) + "\""
override fun visitSymbol(node: Symbol): String =
node.id
override fun visitFunctionCall(node: FunctionCall): String =
"${visit(node.symbol)}(${node.arguments.joinToString(", ") { visit(it) }})"
override fun visitDefine(node: Define): String =
"val ${visit(node.symbol)} = ${visit(node.value)}"
override fun visitSymbolReference(node: SymbolReference): String =
visit(node.symbol)
override fun visitLambda(node: Lambda): String = buildString {
append("{ ${node.arguments.joinToString(", ") { visit(it) }} ->")
appendLine()
append(visitAll(node.expressions).joinToString("\n"))
appendLine()
append("}")
}
override fun visitParentheses(node: Parentheses): String =
"(${visit(node.expression)})"
@ -65,6 +52,19 @@ class KotlinCompiler : NodeVisitor<String> {
override fun visitPrefixOperation(node: PrefixOperation): String =
"${node.op.token}${visit(node.expression)}"
override fun visitIf(node: If): String = buildString {
append("if (")
append(visit(node.condition))
append(") {")
append(visit(node.thenExpression))
append("}")
if (node.elseExpression != null) {
append(" else {")
append(visit(node.elseExpression))
append("}")
}
}
override fun visitInfixOperation(node: InfixOperation): String =
"${visit(node.left)} ${node.op.token} ${visit(node.right)}"

View File

@ -6,37 +6,27 @@ import gay.pizza.pork.ast.nodes.*
class Evaluator(root: Scope) : NodeVisitor<Any> {
private var currentScope: Scope = root
override fun visitDefine(node: Define): Any {
val value = visit(node.value)
currentScope.define(node.symbol.id, value)
return value
}
override fun visitIntLiteral(node: IntLiteral): Any = node.value
override fun visitStringLiteral(node: StringLiteral): Any = node.text
override fun visitBooleanLiteral(node: BooleanLiteral): Any = node.value
override fun visitListLiteral(node: ListLiteral): Any = node.items.map { visit(it) }
override fun visitSymbol(node: Symbol): Any = None
override fun visitFunctionCall(node: FunctionCall): Any {
val arguments = node.arguments.map { visit(it) }
return currentScope.call(node.symbol.id, Arguments(arguments))
}
override fun visitReference(node: SymbolReference): Any =
override fun visitDefine(node: Define): Any {
val value = visit(node.value)
currentScope.define(node.symbol.id, value)
return value
}
override fun visitSymbolReference(node: SymbolReference): Any =
currentScope.value(node.symbol.id)
override fun visitIf(node: If): Any {
val condition = visit(node.condition)
return if (condition == true) {
visit(node.thenExpression)
} else {
if (node.elseExpression != null) {
visit(node.elseExpression)
} else {
None
}
}
}
override fun visitSymbol(node: Symbol): Any {
return None
}
override fun visitLambda(node: Lambda): CallableFunction {
return CallableFunction { arguments ->
currentScope = currentScope.fork()
@ -55,11 +45,6 @@ class Evaluator(root: Scope) : NodeVisitor<Any> {
}
}
override fun visitIntLiteral(node: IntLiteral): Any = node.value
override fun visitBooleanLiteral(node: BooleanLiteral): Any = node.value
override fun visitListLiteral(node: ListLiteral): Any = node.items.map { visit(it) }
override fun visitStringLiteral(node: StringLiteral): Any = node.text
override fun visitParentheses(node: Parentheses): Any = visit(node.expression)
override fun visitPrefixOperation(node: PrefixOperation): Any {
@ -74,6 +59,19 @@ class Evaluator(root: Scope) : NodeVisitor<Any> {
}
}
override fun visitIf(node: If): Any {
val condition = visit(node.condition)
return if (condition == true) {
visit(node.thenExpression)
} else {
if (node.elseExpression != null) {
visit(node.elseExpression)
} else {
None
}
}
}
override fun visitInfixOperation(node: InfixOperation): Any {
val left = visit(node.left)
val right = visit(node.right)

View File

@ -77,7 +77,7 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
Parentheses(expression)
}
private fun readNegation(): PrefixOperation = within {
private fun readPrefixOperation(): PrefixOperation = within {
expect(TokenType.Negation) {
PrefixOperation(PrefixOperator.Negate, readExpression())
}
@ -127,7 +127,7 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
}
TokenType.Negation -> {
readNegation()
readPrefixOperation()
}
TokenType.If -> {