Added the Interpreter class
parent
8aa86a34ce
commit
35974645a4
@ -0,0 +1,111 @@
|
||||
package fr.celticinfo.lox
|
||||
|
||||
import fr.celticinfo.lox.TokenType.*
|
||||
|
||||
class Interpreter: ExprVisitor<Any?>{
|
||||
override fun visitBinary(binary: Binary): Any? {
|
||||
val left = evaluate(binary.left)
|
||||
val right = evaluate(binary.right)
|
||||
|
||||
return when (binary.operator.type) {
|
||||
MINUS -> {
|
||||
checkNumberOperands(binary.operator, left, right)
|
||||
left as Double - right as Double
|
||||
}
|
||||
SLASH -> {
|
||||
checkNumberOperands(binary.operator, left, right)
|
||||
if (right == 0.0) {
|
||||
throw RuntimeError(binary.operator, "Division by zero")
|
||||
}
|
||||
left as Double / right as Double
|
||||
}
|
||||
STAR -> {
|
||||
checkNumberOperands(binary.operator, left, right)
|
||||
left as Double * right as Double
|
||||
}
|
||||
PLUS -> {
|
||||
if (left is Double && right is Double) {
|
||||
left + right
|
||||
} else if (left is String && right is String) {
|
||||
left + right
|
||||
} else {
|
||||
throw RuntimeError(binary.operator, "Operands must be two numbers or two strings")
|
||||
}
|
||||
}
|
||||
GREATER -> {
|
||||
checkNumberOperands(binary.operator, left, right)
|
||||
left as Double > right as Double
|
||||
}
|
||||
GREATER_EQUAL -> {
|
||||
checkNumberOperands(binary.operator, left, right)
|
||||
left as Double >= right as Double
|
||||
}
|
||||
LESS -> {
|
||||
checkNumberOperands(binary.operator, left, right)
|
||||
(left as Double) < right as Double
|
||||
}
|
||||
LESS_EQUAL -> {
|
||||
checkNumberOperands(binary.operator, left, right)
|
||||
left as Double <= right as Double
|
||||
}
|
||||
BANG_EQUAL -> return !isEqual(left, right)
|
||||
EQUAL_EQUAL -> return isEqual(left, right)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitGrouping(grouping: Grouping): Any? {
|
||||
return evaluate(grouping.expression)
|
||||
}
|
||||
|
||||
override fun visitLiteral(literal: Literal): Any? {
|
||||
return literal.value
|
||||
}
|
||||
|
||||
override fun visitUnary(unary: Unary): Any? {
|
||||
val right = evaluate(unary.right)
|
||||
|
||||
return when (unary.operator.type) {
|
||||
MINUS -> {
|
||||
checkNumberOperand(unary.operator, right)
|
||||
-(right as Double)
|
||||
}
|
||||
BANG -> !isTruthy(right)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun isTruthy(obj: Any?): Boolean {
|
||||
return when (obj) {
|
||||
null -> false
|
||||
is Boolean -> obj
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
private fun evaluate(expr: Expr): Any? {
|
||||
return expr.accept(this)
|
||||
}
|
||||
|
||||
private fun isEqual(left: Any?, right: Any?): Boolean {
|
||||
return if (left == null && right == null) {
|
||||
true
|
||||
} else if (left == null) {
|
||||
false
|
||||
} else {
|
||||
left == right
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkNumberOperand(operator: Token, right: Any?) {
|
||||
if (right !is Double) {
|
||||
throw RuntimeError(operator, "Operand must be a number")
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkNumberOperands(operator: Token, left: Any?, right: Any?) {
|
||||
if (left !is Double || right !is Double) {
|
||||
throw RuntimeError(operator, "Operands must be numbers")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package fr.celticinfo.lox
|
||||
|
||||
class RuntimeError(val token: Token, message: String) : RuntimeException(message) {
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue