From 35974645a4bd58041c7a462c556578bc9f384d71 Mon Sep 17 00:00:00 2001 From: oabrivard Date: Wed, 3 Jul 2024 12:19:02 +0200 Subject: [PATCH] Added the Interpreter class --- src/main/fr/celticinfo/lox/Interpreter.kt | 111 +++++++++++++++++++++ src/main/fr/celticinfo/lox/RuntimeError.kt | 5 + 2 files changed, 116 insertions(+) create mode 100644 src/main/fr/celticinfo/lox/Interpreter.kt create mode 100644 src/main/fr/celticinfo/lox/RuntimeError.kt diff --git a/src/main/fr/celticinfo/lox/Interpreter.kt b/src/main/fr/celticinfo/lox/Interpreter.kt new file mode 100644 index 0000000..6091077 --- /dev/null +++ b/src/main/fr/celticinfo/lox/Interpreter.kt @@ -0,0 +1,111 @@ +package fr.celticinfo.lox + +import fr.celticinfo.lox.TokenType.* + +class Interpreter: ExprVisitor{ + 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") + } + } +} \ No newline at end of file diff --git a/src/main/fr/celticinfo/lox/RuntimeError.kt b/src/main/fr/celticinfo/lox/RuntimeError.kt new file mode 100644 index 0000000..93adebe --- /dev/null +++ b/src/main/fr/celticinfo/lox/RuntimeError.kt @@ -0,0 +1,5 @@ +package fr.celticinfo.lox + +class RuntimeError(val token: Token, message: String) : RuntimeException(message) { + +}