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