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
|
||||
|
||||
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.
|
||||
*/
|
||||
sealed class Expr {
|
||||
abstract fun <R> accept(visitor: ExprVisitor<R>): R
|
||||
}
|
||||
|
||||
data class Binary(
|
||||
val left: Expr,
|
||||
val operator: Token,
|
||||
val right: Expr
|
||||
) : Expr()
|
||||
val left: Expr, val operator: Token, val right: Expr
|
||||
) : Expr() {
|
||||
override fun <R> accept(visitor: ExprVisitor<R>): R {
|
||||
return visitor.visitBinary(this)
|
||||
}
|
||||
}
|
||||
|
||||
data class Grouping(
|
||||
val expression: Expr
|
||||
) : Expr()
|
||||
) : Expr() {
|
||||
override fun <R> accept(visitor: ExprVisitor<R>): R {
|
||||
return visitor.visitGrouping(this)
|
||||
}
|
||||
}
|
||||
|
||||
data class Literal(
|
||||
val value: Any
|
||||
) : Expr()
|
||||
) : Expr() {
|
||||
override fun <R> accept(visitor: ExprVisitor<R>): R {
|
||||
return visitor.visitLiteral(this)
|
||||
}
|
||||
}
|
||||
|
||||
data class Unary(
|
||||
val operator: Token,
|
||||
val right: Expr
|
||||
) : Expr()
|
||||
val operator: Token, val right: 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