From 941b201549d753ef4d7145b3d9273e75d35a9de7 Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Sat, 2 Sep 2023 15:11:25 -0700 Subject: [PATCH] Define node visitor order based on parsing order. --- build.gradle.kts | 9 +- .../gay/pizza/pork/ast/NodeCoalescer.kt | 28 +++--- .../kotlin/gay/pizza/pork/ast/NodeVisitor.kt | 35 +++---- src/main/kotlin/gay/pizza/pork/ast/Printer.kt | 97 ++++++++++--------- .../gay/pizza/pork/compiler/DartCompiler.kt | 84 ++++++++-------- .../gay/pizza/pork/compiler/KotlinCompiler.kt | 70 ++++++------- .../kotlin/gay/pizza/pork/eval/Evaluator.kt | 54 +++++------ .../kotlin/gay/pizza/pork/parse/Parser.kt | 4 +- 8 files changed, 188 insertions(+), 193 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 60f2fb9..08ca1d2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -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 { diff --git a/src/main/kotlin/gay/pizza/pork/ast/NodeCoalescer.kt b/src/main/kotlin/gay/pizza/pork/ast/NodeCoalescer.kt index 64ee30c..3c21c2c 100644 --- a/src/main/kotlin/gay/pizza/pork/ast/NodeCoalescer.kt +++ b/src/main/kotlin/gay/pizza/pork/ast/NodeCoalescer.kt @@ -3,18 +3,18 @@ package gay.pizza.pork.ast import gay.pizza.pork.ast.nodes.* class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor { - 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) } diff --git a/src/main/kotlin/gay/pizza/pork/ast/NodeVisitor.kt b/src/main/kotlin/gay/pizza/pork/ast/NodeVisitor.kt index 68e2cc8..27d712a 100644 --- a/src/main/kotlin/gay/pizza/pork/ast/NodeVisitor.kt +++ b/src/main/kotlin/gay/pizza/pork/ast/NodeVisitor.kt @@ -3,47 +3,44 @@ package gay.pizza.pork.ast import gay.pizza.pork.ast.nodes.* interface NodeVisitor { - 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 = - nodes.filterNotNull().map { visit(it) } + nodes.asSequence().filterNotNull().map { visit(it) }.toList() fun visitAll(vararg nodeLists: List): List = nodeLists.asSequence().flatten().map { visit(it) }.toList() diff --git a/src/main/kotlin/gay/pizza/pork/ast/Printer.kt b/src/main/kotlin/gay/pizza/pork/ast/Printer.kt index d979114..435ba53 100644 --- a/src/main/kotlin/gay/pizza/pork/ast/Printer.kt +++ b/src/main/kotlin/gay/pizza/pork/ast/Printer.kt @@ -20,10 +20,37 @@ class Printer(private val buffer: StringBuilder) : NodeVisitor { } } - 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 { 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 { 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 { 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(" ") diff --git a/src/main/kotlin/gay/pizza/pork/compiler/DartCompiler.kt b/src/main/kotlin/gay/pizza/pork/compiler/DartCompiler.kt index a5191be..2764ea0 100644 --- a/src/main/kotlin/gay/pizza/pork/compiler/DartCompiler.kt +++ b/src/main/kotlin/gay/pizza/pork/compiler/DartCompiler.kt @@ -5,49 +5,12 @@ import gay.pizza.pork.ast.nodes.* import gay.pizza.pork.util.StringEscape class DartCompiler : NodeVisitor { - 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 { 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 { 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)}" diff --git a/src/main/kotlin/gay/pizza/pork/compiler/KotlinCompiler.kt b/src/main/kotlin/gay/pizza/pork/compiler/KotlinCompiler.kt index d3fa4a6..dc6dcc3 100644 --- a/src/main/kotlin/gay/pizza/pork/compiler/KotlinCompiler.kt +++ b/src/main/kotlin/gay/pizza/pork/compiler/KotlinCompiler.kt @@ -5,42 +5,12 @@ import gay.pizza.pork.ast.nodes.* import gay.pizza.pork.util.StringEscape class KotlinCompiler : NodeVisitor { - 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 { 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 { 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)}" diff --git a/src/main/kotlin/gay/pizza/pork/eval/Evaluator.kt b/src/main/kotlin/gay/pizza/pork/eval/Evaluator.kt index bb4d126..a32c3e3 100644 --- a/src/main/kotlin/gay/pizza/pork/eval/Evaluator.kt +++ b/src/main/kotlin/gay/pizza/pork/eval/Evaluator.kt @@ -6,37 +6,27 @@ import gay.pizza.pork.ast.nodes.* class Evaluator(root: Scope) : NodeVisitor { 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 { } } - 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 { } } + 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) diff --git a/src/main/kotlin/gay/pizza/pork/parse/Parser.kt b/src/main/kotlin/gay/pizza/pork/parse/Parser.kt index 181d4db..d362178 100644 --- a/src/main/kotlin/gay/pizza/pork/parse/Parser.kt +++ b/src/main/kotlin/gay/pizza/pork/parse/Parser.kt @@ -77,7 +77,7 @@ class Parser(source: PeekableSource, 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, val attribution: NodeAttribution) { } TokenType.Negation -> { - readNegation() + readPrefixOperation() } TokenType.If -> {