diff --git a/src/main/kotlin/io/smnp/data/model/Value.kt b/src/main/kotlin/io/smnp/data/model/Value.kt index 1784637..33948fd 100644 --- a/src/main/kotlin/io/smnp/data/model/Value.kt +++ b/src/main/kotlin/io/smnp/data/model/Value.kt @@ -2,6 +2,7 @@ package io.smnp.data.model import io.smnp.data.entity.Note import io.smnp.data.enumeration.DataType +import io.smnp.error.ShouldNeverReachThisLineException class Value private constructor(val type: DataType, val value: Any?, val properties: Map = emptyMap()) { init { @@ -23,6 +24,14 @@ class Value private constructor(val type: DataType, val value: Any?, val propert return Value(DataType.FLOAT, value) } + fun numeric(value: Number): Value { + return when(value::class) { + Int::class -> int(value.toInt()) + Float::class -> float(value.toFloat()) + else -> throw ShouldNeverReachThisLineException() + } + } + fun string(value: String): Value { return Value(DataType.STRING, value, hashMapOf( Pair("length", int(value.length)) diff --git a/src/main/kotlin/io/smnp/error/ShouldNeverReachThisLineException.kt b/src/main/kotlin/io/smnp/error/ShouldNeverReachThisLineException.kt new file mode 100644 index 0000000..9310958 --- /dev/null +++ b/src/main/kotlin/io/smnp/error/ShouldNeverReachThisLineException.kt @@ -0,0 +1,5 @@ +package io.smnp.error + +class ShouldNeverReachThisLineException : Exception( + "This exception should never be thrown. Please check stack trace and investigate the source of error." +) \ No newline at end of file diff --git a/src/main/kotlin/io/smnp/evaluation/evaluator/DefaultEvaluator.kt b/src/main/kotlin/io/smnp/evaluation/evaluator/DefaultEvaluator.kt index e2836d4..389991c 100644 --- a/src/main/kotlin/io/smnp/evaluation/evaluator/DefaultEvaluator.kt +++ b/src/main/kotlin/io/smnp/evaluation/evaluator/DefaultEvaluator.kt @@ -19,7 +19,8 @@ class DefaultEvaluator : Evaluator() { MinusOperatorEvaluator(), NotOperatorEvaluator(), - PowerOperatorEvaluator() + PowerOperatorEvaluator(), + ProductOperatorEvaluator() ).evaluate(node, environment) } } \ No newline at end of file diff --git a/src/main/kotlin/io/smnp/evaluation/evaluator/ProductOperatorEvaluator.kt b/src/main/kotlin/io/smnp/evaluation/evaluator/ProductOperatorEvaluator.kt new file mode 100644 index 0000000..7756f05 --- /dev/null +++ b/src/main/kotlin/io/smnp/evaluation/evaluator/ProductOperatorEvaluator.kt @@ -0,0 +1,52 @@ +package io.smnp.evaluation.evaluator + +import io.smnp.data.enumeration.DataType +import io.smnp.data.model.Value +import io.smnp.dsl.ast.model.node.Node +import io.smnp.dsl.ast.model.node.ProductOperatorNode +import io.smnp.dsl.ast.model.node.TokenNode +import io.smnp.dsl.token.model.enumeration.TokenType +import io.smnp.error.EvaluationException +import io.smnp.error.ShouldNeverReachThisLineException +import io.smnp.evaluation.environment.Environment +import io.smnp.evaluation.model.entity.EvaluatorOutput + +class ProductOperatorEvaluator : Evaluator() { + override fun supportedNodes() = listOf(ProductOperatorNode::class) + + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val evaluator = DefaultEvaluator() + val (lhsNode, opNode, rhsNode) = (node as ProductOperatorNode) + val lhs = evaluator.evaluate(lhsNode, environment).value!! + val rhs = evaluator.evaluate(rhsNode, environment).value!! + val operator = (opNode as TokenNode).token.type + + if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { + throw EvaluationException("Operator $operator supports only numeric types", node.position) + } + + return EvaluatorOutput.value( + when (operator) { + TokenType.ASTERISK -> product(lhs, rhs) + TokenType.SLASH -> quotient(lhs, rhs) + else -> throw ShouldNeverReachThisLineException() + } + ) + } + + private fun product(lhs: Value, rhs: Value): Value { + if(listOf(lhs.type, rhs.type).contains(DataType.FLOAT)) { + return Value.float((lhs.value as Number).toFloat() * (rhs.value as Number).toFloat()) + } + + return Value.int((lhs.value as Int) * (rhs.value as Int)) + } + + private fun quotient(lhs: Value, rhs: Value): Value { + if(listOf(lhs.type, rhs.type).contains(DataType.FLOAT)) { + return Value.float((lhs.value as Number).toFloat() / (rhs.value as Number).toFloat()) + } + + return Value.int((lhs.value as Int) / (rhs.value as Int)) + } +} \ No newline at end of file