Added simple Expr visitor
parent
076e5fce4e
commit
b52de314f0
@ -0,0 +1,34 @@
|
|||||||
|
package fr.celticinfo.lox
|
||||||
|
|
||||||
|
class AstPrinter : ExprVisitor<String> {
|
||||||
|
fun print(expr: Expr): String {
|
||||||
|
return expr.accept(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBinary(binary: Binary): String {
|
||||||
|
return parenthesize(binary.operator.lexeme, binary.left, binary.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGrouping(grouping: Grouping): String {
|
||||||
|
return parenthesize("group", grouping.expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLiteral(literal: Literal): String {
|
||||||
|
return literal.value?.toString() ?: "nil"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitUnary(unary: Unary): String {
|
||||||
|
return parenthesize(unary.operator.lexeme, unary.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parenthesize(name: String, vararg exprs: Expr): String {
|
||||||
|
val builder = StringBuilder()
|
||||||
|
builder.append("(").append(name)
|
||||||
|
for (expr in exprs) {
|
||||||
|
builder.append(" ")
|
||||||
|
builder.append(expr.accept(this))
|
||||||
|
}
|
||||||
|
builder.append(")")
|
||||||
|
return builder.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,26 +1,48 @@
|
|||||||
package fr.celticinfo.lox
|
package fr.celticinfo.lox
|
||||||
|
|
||||||
|
interface ExprVisitor<R> {
|
||||||
|
fun visitBinary(binary: Binary): R
|
||||||
|
fun visitGrouping(grouping: Grouping): R
|
||||||
|
fun visitLiteral(literal: Literal): R
|
||||||
|
fun visitUnary(unary: Unary): R
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Expr class represents the different types of expressions that can be parsed by the Parser.
|
* The Expr class represents the different types of expressions that can be parsed by the Parser.
|
||||||
*/
|
*/
|
||||||
sealed class Expr {
|
sealed class Expr {
|
||||||
|
abstract fun <R> accept(visitor: ExprVisitor<R>): R
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Binary(
|
data class Binary(
|
||||||
val left: Expr,
|
val left: Expr, val operator: Token, val right: Expr
|
||||||
val operator: Token,
|
) : Expr() {
|
||||||
val right: Expr
|
override fun <R> accept(visitor: ExprVisitor<R>): R {
|
||||||
) : Expr()
|
return visitor.visitBinary(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class Grouping(
|
data class Grouping(
|
||||||
val expression: Expr
|
val expression: Expr
|
||||||
) : Expr()
|
) : Expr() {
|
||||||
|
override fun <R> accept(visitor: ExprVisitor<R>): R {
|
||||||
|
return visitor.visitGrouping(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class Literal(
|
data class Literal(
|
||||||
val value: Any
|
val value: Any
|
||||||
) : Expr()
|
) : Expr() {
|
||||||
|
override fun <R> accept(visitor: ExprVisitor<R>): R {
|
||||||
|
return visitor.visitLiteral(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class Unary(
|
data class Unary(
|
||||||
val operator: Token,
|
val operator: Token, val right: Expr
|
||||||
val right: Expr
|
) : Expr() {
|
||||||
) : Expr()
|
override fun <R> accept(visitor: ExprVisitor<R>): R {
|
||||||
|
return visitor.visitUnary(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package fr.celticinfo.loxext
|
||||||
|
|
||||||
|
import fr.celticinfo.lox.*
|
||||||
|
|
||||||
|
class RpnPrinter : ExprVisitor<String> {
|
||||||
|
fun print(expr: Expr): String {
|
||||||
|
return expr.accept(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBinary(binary: Binary): String {
|
||||||
|
return stack(binary.operator.lexeme, binary.left, binary.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGrouping(grouping: Grouping): String {
|
||||||
|
return stack("", grouping.expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLiteral(literal: Literal): String {
|
||||||
|
return literal.value?.toString() ?: "nil"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitUnary(unary: Unary): String {
|
||||||
|
return stack(unary.operator.lexeme, unary.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stack(name: String, vararg exprs: Expr): String {
|
||||||
|
val builder = StringBuilder()
|
||||||
|
for (expr in exprs) {
|
||||||
|
builder.append(expr.accept(this))
|
||||||
|
if (name.isNotEmpty()) builder.append(" ")
|
||||||
|
}
|
||||||
|
builder.append(name)
|
||||||
|
return builder.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package fr.celticinfo.lox
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class AstPrinterTest {
|
||||||
|
private val astPrinter = AstPrinter()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun print() {
|
||||||
|
val expression: Expr = Binary(
|
||||||
|
Unary(
|
||||||
|
Token(TokenType.MINUS, "-", null, 1), Literal(123)
|
||||||
|
), Token(TokenType.STAR, "*", null, 1), Grouping(
|
||||||
|
Literal(45.67)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertEquals("(* (- 123) (group 45.67))", astPrinter.print(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun visitBinary() {
|
||||||
|
val expression: Expr = Binary(
|
||||||
|
Literal(1), Token(TokenType.PLUS, "+", null, 1), Literal(2)
|
||||||
|
)
|
||||||
|
assertEquals("(+ 1 2)", astPrinter.print(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun visitGrouping() {
|
||||||
|
val expression: Expr = Grouping(
|
||||||
|
Literal(123)
|
||||||
|
)
|
||||||
|
assertEquals("(group 123)", astPrinter.print(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun visitLiteral() {
|
||||||
|
val expression: Expr = Literal(123)
|
||||||
|
assertEquals("123", astPrinter.print(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun visitUnary() {
|
||||||
|
val expression: Expr = Unary(
|
||||||
|
Token(TokenType.MINUS, "-", null, 1), Literal(123)
|
||||||
|
)
|
||||||
|
assertEquals("(- 123)", astPrinter.print(expression))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
package fr.celticinfo.loxext
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
import fr.celticinfo.lox.*
|
||||||
|
|
||||||
|
class RpnPrinterTest {
|
||||||
|
private val rpnPrinter = RpnPrinter()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun print() {
|
||||||
|
val expression: Expr = Binary(
|
||||||
|
Unary(
|
||||||
|
Token(TokenType.MINUS, "-", null, 1), Literal(123)
|
||||||
|
), Token(TokenType.STAR, "*", null, 1), Grouping(
|
||||||
|
Literal(45.67)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertEquals("123 - 45.67 *", rpnPrinter.print(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testComplexExpr() {
|
||||||
|
val expression: Expr = Binary(
|
||||||
|
Grouping(
|
||||||
|
Binary(
|
||||||
|
Literal(1), Token(TokenType.PLUS, "+", null, 1), Literal(2)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Token(TokenType.STAR, "*", null, 1),
|
||||||
|
Grouping(
|
||||||
|
Binary(
|
||||||
|
Literal(4), Token(TokenType.MINUS, "-", null, 1), Literal(3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertEquals("1 2 + 4 3 - *", rpnPrinter.print(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun visitBinary() {
|
||||||
|
val expression: Expr = Binary(
|
||||||
|
Literal(1), Token(TokenType.PLUS, "+", null, 1), Literal(2)
|
||||||
|
)
|
||||||
|
assertEquals("1 2 +", rpnPrinter.print(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun visitGrouping() {
|
||||||
|
val expression: Expr = Grouping(
|
||||||
|
Literal(123)
|
||||||
|
)
|
||||||
|
assertEquals("123", rpnPrinter.print(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun visitLiteral() {
|
||||||
|
val expression: Expr = Literal(123)
|
||||||
|
assertEquals("123", rpnPrinter.print(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun visitUnary() {
|
||||||
|
val expression: Expr = Unary(
|
||||||
|
Token(TokenType.MINUS, "-", null, 1), Literal(123)
|
||||||
|
)
|
||||||
|
assertEquals("123 -", rpnPrinter.print(expression))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue