diff --git a/app/src/main/kotlin/io/smnp/SMNP.kt b/app/src/main/kotlin/io/smnp/SMNP.kt index 018de90..954c86a 100644 --- a/app/src/main/kotlin/io/smnp/SMNP.kt +++ b/app/src/main/kotlin/io/smnp/SMNP.kt @@ -16,10 +16,10 @@ import kotlin.system.exitProcess fun main(args: Array): Unit = mainBody { ArgParser(args).parseInto(::Arguments).run { - try { - val interpreter = DefaultInterpreter() - val environment = DefaultEnvironment() + val interpreter = DefaultInterpreter() + val environment = DefaultEnvironment() + try { environment.setVariable("__param__", Value.wrap(parameters.toMap())) when { @@ -51,6 +51,10 @@ fun main(args: Array): Unit = mainBody { System.err.println("\nStack trace:\n${it.environment.stackTrace()}") } exitProcess(1) + } finally { + if(!environment.disposed) { + environment.dispose() + } } } } \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/AccessOperatorEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/AccessOperatorEvaluator.kt index 522a13d..c7e2b25 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/AccessOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/AccessOperatorEvaluator.kt @@ -2,11 +2,10 @@ package io.smnp.evaluation.evaluator import io.smnp.dsl.ast.model.node.* import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.error.SmnpException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException class AccessOperatorEvaluator : Evaluator() { override fun supportedNodes() = listOf(AccessOperatorNode::class) @@ -20,12 +19,10 @@ class AccessOperatorEvaluator : Evaluator() { is IdentifierNode -> { val rhs = rhsNode.token.rawValue EvaluatorOutput.value( - lhs.properties[rhs] ?: throw PositionException( - EnvironmentException( - EvaluationException("Unknown property $rhs of type ${lhs.typeName}"), - environment - ), - rhsNode.position + lhs.properties[rhs] ?: throw contextEvaluationException( + "Unknown property $rhs of type ${lhs.typeName}", + rhsNode.position, + environment ) ) } @@ -36,16 +33,15 @@ class AccessOperatorEvaluator : Evaluator() { (argsNode as FunctionCallArgumentsNode).items.map { evaluator.evaluate(it, environment).value } try { return EvaluatorOutput.value(environment.invokeMethod(lhs, identifier, arguments)) - } catch(e: SmnpException) { - throw PositionException(EnvironmentException(e, environment), identifierNode.position) + } catch (e: SmnpException) { + throw ContextExceptionFactory.wrapWithContext(e, identifierNode.position, environment) } } else -> { - throw PositionException( - EnvironmentException( - EvaluationException("Invalid property access type - only property name and method call are allowed"), - environment - ), rhsNode.position + throw contextEvaluationException( + "Invalid property access type - only property name and method call are allowed", + rhsNode.position, + environment ) } } diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/AssignmentOperatorEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/AssignmentOperatorEvaluator.kt index a1a8e31..495306a 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/AssignmentOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/AssignmentOperatorEvaluator.kt @@ -4,10 +4,8 @@ import io.smnp.dsl.ast.model.node.AssignmentOperatorNode import io.smnp.dsl.ast.model.node.IdentifierNode import io.smnp.dsl.ast.model.node.Node import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.type.enumeration.DataType class AssignmentOperatorEvaluator : Evaluator() { @@ -21,12 +19,10 @@ class AssignmentOperatorEvaluator : Evaluator() { val value = evaluator.evaluate(valueNode, environment).value if (value.type == DataType.VOID) { - throw PositionException( - EnvironmentException( - EvaluationException("Right hand side expression of assignment operation has returned nothing"), - environment - ), - valueNode.position + throw contextEvaluationException( + "Right hand side expression of assignment operation has returned nothing", + valueNode.position, + environment ) } diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ConditionEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ConditionEvaluator.kt index 73a82a5..a8d7a95 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ConditionEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ConditionEvaluator.kt @@ -4,10 +4,8 @@ import io.smnp.dsl.ast.model.node.ConditionNode import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.NoneNode import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.type.enumeration.DataType class ConditionEvaluator : Evaluator() { @@ -21,12 +19,10 @@ class ConditionEvaluator : Evaluator() { val condition = expressionEvaluator.evaluate(conditionNode, environment).value if (condition.type != DataType.BOOL) { - throw PositionException( - EnvironmentException( - EvaluationException("Condition should be of bool type, found '${condition.value}'"), - environment - ), - conditionNode.position + throw contextEvaluationException( + "Condition should be of bool type, found '${condition.value}'", + conditionNode.position, + environment ) } diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/Evaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/Evaluator.kt index 393161c..eacab1f 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/Evaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/Evaluator.kt @@ -2,11 +2,9 @@ package io.smnp.evaluation.evaluator import io.smnp.dsl.ast.model.node.Node import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.enumeration.EvaluationResult +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import kotlin.reflect.KClass abstract class Evaluator { @@ -64,10 +62,7 @@ abstract class Evaluator { val output = evaluator.evaluate(node, environment) if (output.result == EvaluationResult.FAILED) { - throw PositionException( - EnvironmentException(EvaluationException("Expected $expected"), environment), - node.position - ) + throw contextEvaluationException("Expected $expected", node.position, environment) } return output diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ExtendEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ExtendEvaluator.kt index 543ce2e..89d7231 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ExtendEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ExtendEvaluator.kt @@ -7,10 +7,9 @@ import io.smnp.dsl.ast.model.node.FunctionDefinitionNode import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.SingleTypeNode import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.PositionException import io.smnp.error.SmnpException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext class ExtendEvaluator : Evaluator() { override fun supportedNodes() = listOf(ExtendNode::class) @@ -25,7 +24,7 @@ class ExtendEvaluator : Evaluator() { try { environment.defineMethod(it.second) } catch (e: SmnpException) { - throw PositionException(EnvironmentException(e, environment), it.first.position) + throw wrapWithContext(e, it.first.position, environment) } } diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionCallEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionCallEvaluator.kt index 957a46c..8789664 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionCallEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionCallEvaluator.kt @@ -5,24 +5,23 @@ import io.smnp.dsl.ast.model.node.FunctionCallNode import io.smnp.dsl.ast.model.node.IdentifierNode import io.smnp.dsl.ast.model.node.Node import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.PositionException import io.smnp.error.SmnpException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext class FunctionCallEvaluator : Evaluator() { - override fun supportedNodes() = listOf(FunctionCallNode::class) + override fun supportedNodes() = listOf(FunctionCallNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val evaluator = assert(ExpressionEvaluator(), "expression") - val (identifierNode, argsNode) = node as FunctionCallNode - val identifier = (identifierNode as IdentifierNode).token.rawValue - val arguments = (argsNode as FunctionCallArgumentsNode).items.map { evaluator.evaluate(it, environment).value } + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val evaluator = assert(ExpressionEvaluator(), "expression") + val (identifierNode, argsNode) = node as FunctionCallNode + val identifier = (identifierNode as IdentifierNode).token.rawValue + val arguments = (argsNode as FunctionCallArgumentsNode).items.map { evaluator.evaluate(it, environment).value } - try { - return EvaluatorOutput.value(environment.invokeFunction(identifier, arguments)) - } catch(e: SmnpException) { - throw PositionException(EnvironmentException(e, environment), identifierNode.position) - } - } + try { + return EvaluatorOutput.value(environment.invokeFunction(identifier, arguments)) + } catch (e: SmnpException) { + throw wrapWithContext(e, identifierNode.position, environment) + } + } } \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionDefinitionEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionDefinitionEvaluator.kt index 0cba796..e55d28c 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionDefinitionEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionDefinitionEvaluator.kt @@ -4,23 +4,22 @@ import io.smnp.callable.function.CustomFunction import io.smnp.dsl.ast.model.node.FunctionDefinitionNode import io.smnp.dsl.ast.model.node.Node import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.PositionException import io.smnp.error.SmnpException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext class FunctionDefinitionEvaluator : Evaluator() { - override fun supportedNodes() = listOf(FunctionDefinitionNode::class) + override fun supportedNodes() = listOf(FunctionDefinitionNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val function = CustomFunction.create(node as FunctionDefinitionNode) + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val function = CustomFunction.create(node as FunctionDefinitionNode) - try { - environment.defineFunction(function) - } catch(e: SmnpException) { - throw PositionException(EnvironmentException(e, environment), node.position) - } + try { + environment.defineFunction(function) + } catch (e: SmnpException) { + throw wrapWithContext(e, node.position, environment) + } - return EvaluatorOutput.ok() - } + return EvaluatorOutput.ok() + } } \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/IdentifierEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/IdentifierEvaluator.kt index 77add36..5c9dc19 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/IdentifierEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/IdentifierEvaluator.kt @@ -3,21 +3,20 @@ package io.smnp.evaluation.evaluator import io.smnp.dsl.ast.model.node.IdentifierNode import io.smnp.dsl.ast.model.node.Node import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext class IdentifierEvaluator : Evaluator() { - override fun supportedNodes() = listOf(IdentifierNode::class) + override fun supportedNodes() = listOf(IdentifierNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val identifier = (node as IdentifierNode).token.rawValue + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val identifier = (node as IdentifierNode).token.rawValue - try { - return EvaluatorOutput.value(environment.getVariable(identifier)) - } catch (e: EvaluationException) { - throw PositionException(EnvironmentException(e, environment), node.position) - } - } + try { + return EvaluatorOutput.value(environment.getVariable(identifier)) + } catch (e: EvaluationException) { + throw wrapWithContext(e, node.position, environment) + } + } } \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ImportEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ImportEvaluator.kt index 64b4601..546a3f8 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ImportEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ImportEvaluator.kt @@ -4,23 +4,22 @@ import io.smnp.dsl.ast.model.node.IdentifierNode import io.smnp.dsl.ast.model.node.ImportNode import io.smnp.dsl.ast.model.node.Node import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.PositionException import io.smnp.error.SmnpException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext class ImportEvaluator : Evaluator() { - override fun supportedNodes() = listOf(ImportNode::class) + override fun supportedNodes() = listOf(ImportNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val path = (node as ImportNode).path.joinToString(".") { (it as IdentifierNode).token.rawValue } + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val path = (node as ImportNode).path.joinToString(".") { (it as IdentifierNode).token.rawValue } - try { - environment.loadModule(path) - } catch(e: SmnpException) { - throw PositionException(EnvironmentException(e, environment), node.position) - } + try { + environment.loadModule(path) + } catch (e: SmnpException) { + throw wrapWithContext(e, node.position, environment) + } - return EvaluatorOutput.ok() - } + return EvaluatorOutput.ok() + } } \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/LogicOperatorEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/LogicOperatorEvaluator.kt index 3035812..aeaf16c 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/LogicOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/LogicOperatorEvaluator.kt @@ -5,11 +5,9 @@ import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.TokenNode import io.smnp.dsl.token.model.enumeration.TokenType import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.error.ShouldNeverReachThisLineException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.type.enumeration.DataType import io.smnp.type.model.Value @@ -24,8 +22,16 @@ class LogicOperatorEvaluator : Evaluator() { return EvaluatorOutput.value( Value.bool( when (operator) { - TokenType.AND -> if(evalOperand(lhsNode, operator, environment)) evalOperand(rhsNode, operator, environment) else false - TokenType.OR -> if (evalOperand(lhsNode, operator, environment)) true else evalOperand(rhsNode, operator, environment) + TokenType.AND -> if (evalOperand(lhsNode, operator, environment)) evalOperand( + rhsNode, + operator, + environment + ) else false + TokenType.OR -> if (evalOperand(lhsNode, operator, environment)) true else evalOperand( + rhsNode, + operator, + environment + ) else -> throw ShouldNeverReachThisLineException() } ) @@ -36,12 +42,10 @@ class LogicOperatorEvaluator : Evaluator() { val value = evaluator.evaluate(operand, environment).value if (value.type != DataType.BOOL) { - throw PositionException( - EnvironmentException( - EvaluationException("Operator '${operator.token}' supports only bool types, found ${value.typeName}"), - environment - ), - operand.position + throw contextEvaluationException( + "Operator '${operator.token}' supports only bool types, found ${value.typeName}", + operand.position, + environment ) } diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/LoopEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/LoopEvaluator.kt index d86077b..f8b475d 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/LoopEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/LoopEvaluator.kt @@ -4,11 +4,9 @@ import io.smnp.dsl.ast.model.node.IdentifierNode import io.smnp.dsl.ast.model.node.LoopNode import io.smnp.dsl.ast.model.node.Node import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.enumeration.EvaluationResult +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.type.enumeration.DataType.* import io.smnp.type.model.Value @@ -28,13 +26,10 @@ class LoopEvaluator : Evaluator() { LIST -> evaluateForList(iterator, parametersNode, statementNode, filterNode, environment) MAP -> evaluateForMap(iterator, parametersNode, statementNode, filterNode, environment) BOOL -> evaluateForBool(iteratorNode, parametersNode, statementNode, filterNode, environment) - else -> throw PositionException( - EnvironmentException( - EvaluationException( - "Expected for-loop with int iterator or foreach-loop with string, list or map iterator or while-loop with bool iterator, found ${iterator.typeName}" - ), - environment - ), iteratorNode.position + else -> throw contextEvaluationException( + "Expected for-loop with int iterator or foreach-loop with string, list or map iterator or while-loop with bool iterator, found ${iterator.typeName}", + iteratorNode.position, + environment ) } environment.popScope() @@ -140,21 +135,18 @@ class LoopEvaluator : Evaluator() { environment: Environment ): EvaluatorOutput { if (parametersNode != Node.NONE) { - throw PositionException( - EnvironmentException( - EvaluationException("Parameters are not supported in the while-loop"), - environment - ), - parametersNode.position + throw contextEvaluationException( + "Parameters are not supported in the while-loop", + parametersNode.position, + environment ) } if (filterNode != Node.NONE) { - throw PositionException( - EnvironmentException( - EvaluationException("Filter is not supported in the while-loop"), - environment - ), filterNode.position + throw contextEvaluationException( + "Filter is not supported in the while-loop", + filterNode.position, + environment ) } @@ -179,14 +171,10 @@ class LoopEvaluator : Evaluator() { if (filterNode != Node.NONE) { val condition = expressionEvaluator.evaluate(filterNode, environment).value if (condition.type != BOOL) { - throw PositionException( - EnvironmentException( - EvaluationException( - "Filter condition should be evaluated to bool type" - ), - environment - ), - filterNode.position + throw contextEvaluationException( + "Filter condition should be evaluated to bool type", + filterNode.position, + environment ) } return condition.value as Boolean diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/MapEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/MapEvaluator.kt index c693d9b..2e9e7e0 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/MapEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/MapEvaluator.kt @@ -5,10 +5,8 @@ import io.smnp.dsl.ast.model.node.MapEntryNode import io.smnp.dsl.ast.model.node.MapNode import io.smnp.dsl.ast.model.node.Node import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.type.enumeration.DataType.* import io.smnp.type.model.Value @@ -33,13 +31,7 @@ class MapEvaluator : Evaluator() { } if (key.type !in listOf(BOOL, INT, NOTE, STRING)) { - throw PositionException( - EnvironmentException( - EvaluationException("Invalid map key's type ${key.typeName}"), - environment - ), - keyNode.position - ) + throw contextEvaluationException("Invalid map key's type ${key.typeName}", keyNode.position, environment) } return key diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/MinusOperatorEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/MinusOperatorEvaluator.kt index dd2ca98..41447f4 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/MinusOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/MinusOperatorEvaluator.kt @@ -3,10 +3,8 @@ package io.smnp.evaluation.evaluator import io.smnp.dsl.ast.model.node.MinusOperatorNode import io.smnp.dsl.ast.model.node.Node import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.type.enumeration.DataType import io.smnp.type.model.Value @@ -24,12 +22,10 @@ class MinusOperatorEvaluator : Evaluator() { DataType.FLOAT -> Value.float(-1.0f * operand.value.value as Float) DataType.STRING -> Value.string((operand.value.value as String).reversed()) DataType.LIST -> Value.list((operand.value.value as List).reversed()) - else -> throw PositionException( - EnvironmentException( - EvaluationException("Type ${operand.value.typeName} does not support minus operator"), - environment - ), - node.position + else -> throw contextEvaluationException( + "Type ${operand.value.typeName} does not support minus operator", + node.position, + environment ) } ) diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/NotOperatorEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/NotOperatorEvaluator.kt index dfc0666..11b836a 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/NotOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/NotOperatorEvaluator.kt @@ -3,10 +3,8 @@ package io.smnp.evaluation.evaluator import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.NotOperatorNode import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.type.enumeration.DataType import io.smnp.type.model.Value @@ -19,13 +17,7 @@ class NotOperatorEvaluator : Evaluator() { val operand = evaluator.evaluate(operandNode, environment).value if (operand.type != DataType.BOOL) { - throw PositionException( - EnvironmentException( - EvaluationException("Only bool types can be negated"), - environment - ), - operandNode.position - ) + throw contextEvaluationException("Only bool types can be negated", operandNode.position, environment) } return EvaluatorOutput.value(Value.bool(!(operand.value as Boolean))) diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/PowerOperatorEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/PowerOperatorEvaluator.kt index 6a94c08..3122cd1 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/PowerOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/PowerOperatorEvaluator.kt @@ -3,10 +3,8 @@ package io.smnp.evaluation.evaluator import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.PowerOperatorNode import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.type.model.Value import kotlin.math.pow @@ -20,13 +18,7 @@ class PowerOperatorEvaluator : Evaluator() { val rhs = evaluator.evaluate(rhsNode, environment).value if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { - throw PositionException( - EnvironmentException( - EvaluationException("Operator ** supports only numeric types"), - environment - ), - node.position - ) + throw contextEvaluationException("Operator ** supports only numeric types", node.position, environment) } return EvaluatorOutput.value(Value.float((lhs.value as Number).toFloat().pow((rhs.value as Number).toFloat()))) diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ProductOperatorEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ProductOperatorEvaluator.kt index fc52853..d532d98 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ProductOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ProductOperatorEvaluator.kt @@ -5,11 +5,9 @@ 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.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.error.ShouldNeverReachThisLineException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.evaluation.util.NumberUnification.unify import io.smnp.type.model.Value @@ -24,12 +22,10 @@ class ProductOperatorEvaluator : Evaluator() { val operator = (opNode as TokenNode).token.type if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { - throw PositionException( - EnvironmentException( - EvaluationException("Operator ${operator.token} supports only numeric types"), - environment - ), - node.position + throw contextEvaluationException( + "Operator ${operator.token} supports only numeric types", + node.position, + environment ) } diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/RelationOperatorEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/RelationOperatorEvaluator.kt index 57445d4..ffaeef0 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/RelationOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/RelationOperatorEvaluator.kt @@ -4,11 +4,9 @@ import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.RelationOperatorNode import io.smnp.dsl.ast.model.node.TokenNode import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.error.ShouldNeverReachThisLineException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.evaluation.util.NumberUnification.unify import io.smnp.type.model.Value @@ -32,13 +30,7 @@ class RelationOperatorEvaluator : Evaluator() { } if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { - throw PositionException( - EnvironmentException( - EvaluationException("Operator $operator supports only numeric types"), - environment - ), - node.position - ) + throw contextEvaluationException("Operator $operator supports only numeric types", node.position, environment) } return EvaluatorOutput.value( diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/StaffEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/StaffEvaluator.kt index 3a6e3a8..b72959b 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/StaffEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/StaffEvaluator.kt @@ -3,10 +3,8 @@ package io.smnp.evaluation.evaluator import io.smnp.data.entity.Note import io.smnp.dsl.ast.model.node.* import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.math.Fraction import io.smnp.type.enumeration.DataType import io.smnp.type.model.Value @@ -49,11 +47,10 @@ class StaffEvaluator : Evaluator() { it: Node ) { if (index != 0) { - throw PositionException( - EnvironmentException( - EvaluationException("Time signature can be placed only at the beginning of measure"), - environment - ), it.position + throw contextEvaluationException( + "Time signature can be placed only at the beginning of measure", + it.position, + environment ) } } @@ -69,11 +66,10 @@ class StaffEvaluator : Evaluator() { currentSignature?.let { if (evaluatedSignature != it) { val simplified = evaluatedSignature.simplified - throw PositionException( - EnvironmentException( - EvaluationException("Invalid time signature: expected ${it.numerator}/${it.denominator}, got ${simplified.numerator}/${simplified.denominator}"), - environment - ), measure.position + throw contextEvaluationException( + "Invalid time signature: expected ${it.numerator}/${it.denominator}, got ${simplified.numerator}/${simplified.denominator}", + measure.position, + environment ) } } diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/SumOperatorEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/SumOperatorEvaluator.kt index ebeb0ba..d282276 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/SumOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/SumOperatorEvaluator.kt @@ -6,11 +6,9 @@ import io.smnp.dsl.ast.model.node.SumOperatorNode import io.smnp.dsl.ast.model.node.TokenNode import io.smnp.dsl.token.model.enumeration.TokenType import io.smnp.environment.Environment -import io.smnp.error.EnvironmentException -import io.smnp.error.EvaluationException -import io.smnp.error.PositionException import io.smnp.error.ShouldNeverReachThisLineException import io.smnp.evaluation.model.entity.EvaluatorOutput +import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException import io.smnp.evaluation.util.NumberUnification.unify import io.smnp.math.Fraction import io.smnp.type.enumeration.DataType.* @@ -40,17 +38,18 @@ class SumOperatorEvaluator : Evaluator() { private fun plus(lhs: Value, plusNode: Node, rhs: Value, environment: Environment): Value { return when { - areNumeric(lhs, rhs) -> unify(lhs, rhs, int = { (l, r) -> Value.int(l + r) }, float = { (l, r) -> Value.float(l + r) }) + areNumeric(lhs, rhs) -> unify( + lhs, + rhs, + int = { (l, r) -> Value.int(l + r) }, + float = { (l, r) -> Value.float(l + r) }) lhs.type == STRING -> string(lhs.value as String + rhs.value.toString()) areLists(lhs, rhs) -> list(lhs.value as List + rhs.value as List) lhs.type == NOTE && rhs.type == INT -> note(lhs.value as Note + Fraction(1, rhs.value as Int)) - else -> throw PositionException( - EnvironmentException( - EvaluationException( - "The ${lhs.typeName} and ${rhs.typeName} are not supported by + operator" - ), - environment - ), plusNode.position + else -> throw contextEvaluationException( + "The ${lhs.typeName} and ${rhs.typeName} are not supported by + operator", + plusNode.position, + environment ) } } @@ -63,12 +62,10 @@ class SumOperatorEvaluator : Evaluator() { int = { (l, r) -> Value.int(l - r) }, float = { (l, r) -> Value.float(l - r) } ) - else throw PositionException( - EnvironmentException( - EvaluationException("The - operator supports only numeric values"), - environment - ), - minusNode.position + else throw contextEvaluationException( + "The - operator supports only numeric values", + minusNode.position, + environment ) } diff --git a/app/src/main/kotlin/io/smnp/evaluation/util/ContextExceptionFactory.kt b/app/src/main/kotlin/io/smnp/evaluation/util/ContextExceptionFactory.kt new file mode 100644 index 0000000..117364b --- /dev/null +++ b/app/src/main/kotlin/io/smnp/evaluation/util/ContextExceptionFactory.kt @@ -0,0 +1,27 @@ +package io.smnp.evaluation.util + +import io.smnp.dsl.token.model.entity.TokenPosition +import io.smnp.environment.Environment +import io.smnp.error.EnvironmentException +import io.smnp.error.EvaluationException +import io.smnp.error.PositionException +import io.smnp.error.SmnpException + +object ContextExceptionFactory { + fun contextEvaluationException(message: String, position: TokenPosition, environment: Environment): SmnpException { + return wrapWithContext( + EvaluationException( + message + ), position, environment + ) + } + + fun wrapWithContext(exception: SmnpException, position: TokenPosition, environment: Environment): SmnpException { + return PositionException( + EnvironmentException( + exception, + environment + ), position + ) + } +} \ No newline at end of file