diff --git a/api/src/main/kotlin/io/smnp/callable/function/Function.kt b/api/src/main/kotlin/io/smnp/callable/function/Function.kt index c406a98..4d3b12c 100644 --- a/api/src/main/kotlin/io/smnp/callable/function/Function.kt +++ b/api/src/main/kotlin/io/smnp/callable/function/Function.kt @@ -2,7 +2,6 @@ package io.smnp.callable.function import io.smnp.environment.Environment import io.smnp.error.FunctionInvocationException -import io.smnp.error.RuntimeException import io.smnp.type.model.Value import io.smnp.type.module.Module @@ -25,7 +24,7 @@ abstract class Function(val name: String) { val (definition, args) = definitions .map { Pair(it, it.signature.parse(arguments.toList())) } .firstOrNull { (_, args) -> args.signatureMatched } - ?: throw FunctionInvocationException(this, arguments) + ?: throw FunctionInvocationException(this, arguments, environment) return definition.body(environment, args.arguments) } diff --git a/api/src/main/kotlin/io/smnp/callable/method/Method.kt b/api/src/main/kotlin/io/smnp/callable/method/Method.kt index 6e29f01..067fbe0 100644 --- a/api/src/main/kotlin/io/smnp/callable/method/Method.kt +++ b/api/src/main/kotlin/io/smnp/callable/method/Method.kt @@ -2,7 +2,6 @@ package io.smnp.callable.method import io.smnp.environment.Environment import io.smnp.error.MethodInvocationException -import io.smnp.error.RuntimeException import io.smnp.type.matcher.Matcher import io.smnp.type.model.Value import io.smnp.type.module.Module @@ -28,7 +27,7 @@ abstract class Method(val typeMatcher: Matcher, val name: String) { val (definition, args) = definitions .map { Pair(it, it.signature.parse(arguments.toList())) } .firstOrNull { (_, args) -> args.signatureMatched } - ?: throw MethodInvocationException(this, obj, arguments) + ?: throw MethodInvocationException(this, obj, arguments, environment) return definition.body(environment, obj, args.arguments) } diff --git a/api/src/main/kotlin/io/smnp/environment/Environment.kt b/api/src/main/kotlin/io/smnp/environment/Environment.kt index aaed5f4..c07186d 100644 --- a/api/src/main/kotlin/io/smnp/environment/Environment.kt +++ b/api/src/main/kotlin/io/smnp/environment/Environment.kt @@ -11,6 +11,7 @@ interface Environment { fun invokeFunction(name: String, arguments: List): Value fun invokeMethod(obj: Value, name: String, arguments: List): Value fun printCallStack() + fun stackTrace(): String fun defineFunction(function: Function) fun defineMethod(method: Method) fun pushScope(scope: MutableMap = mutableMapOf()) diff --git a/api/src/main/kotlin/io/smnp/error/CustomException.kt b/api/src/main/kotlin/io/smnp/error/CustomException.kt index 5ae9ca3..b491388 100644 --- a/api/src/main/kotlin/io/smnp/error/CustomException.kt +++ b/api/src/main/kotlin/io/smnp/error/CustomException.kt @@ -1,3 +1,3 @@ package io.smnp.error -class CustomException(message: String?) : Exception(message) \ No newline at end of file +class CustomException(message: String?) : SmnpException("Error", message) \ No newline at end of file diff --git a/api/src/main/kotlin/io/smnp/error/EnvironmentException.kt b/api/src/main/kotlin/io/smnp/error/EnvironmentException.kt new file mode 100644 index 0000000..b868c9d --- /dev/null +++ b/api/src/main/kotlin/io/smnp/error/EnvironmentException.kt @@ -0,0 +1,8 @@ +package io.smnp.error + +import io.smnp.environment.Environment + +class EnvironmentException(exception: SmnpException, val environment: Environment) : SmnpException( + exception.friendlyName, + "${exception.message}\n\nStack trace:\n${environment.stackTrace()}" +) \ No newline at end of file diff --git a/api/src/main/kotlin/io/smnp/error/EvaluationException.kt b/api/src/main/kotlin/io/smnp/error/EvaluationException.kt new file mode 100644 index 0000000..9355a4b --- /dev/null +++ b/api/src/main/kotlin/io/smnp/error/EvaluationException.kt @@ -0,0 +1,3 @@ +package io.smnp.error + +class EvaluationException(message: String?) : SmnpException("Runtime error", message) \ No newline at end of file diff --git a/api/src/main/kotlin/io/smnp/error/FunctionInvocationException.kt b/api/src/main/kotlin/io/smnp/error/FunctionInvocationException.kt index 4f52c71..0db1efe 100644 --- a/api/src/main/kotlin/io/smnp/error/FunctionInvocationException.kt +++ b/api/src/main/kotlin/io/smnp/error/FunctionInvocationException.kt @@ -2,8 +2,14 @@ package io.smnp.error import io.smnp.callable.function.Function import io.smnp.callable.signature.ActualSignatureFormatter.format +import io.smnp.environment.Environment import io.smnp.type.model.Value -class FunctionInvocationException(private val function: Function, private val passedArguments: Array) : Exception() { - override fun toString() = "Invalid signature: ${function.name}${format(passedArguments)}\nAllowed signatures:\n${function.signature}" -} \ No newline at end of file +class FunctionInvocationException( + function: Function, + passedArguments: Array, + val environment: Environment +) : SmnpException( + "Function invocation error", + "Invalid signature: ${function.name}${format(passedArguments)}\nAllowed signatures:\n${function.signature}" +) \ No newline at end of file diff --git a/api/src/main/kotlin/io/smnp/error/MethodInvocationException.kt b/api/src/main/kotlin/io/smnp/error/MethodInvocationException.kt index dc84642..b1c33f9 100644 --- a/api/src/main/kotlin/io/smnp/error/MethodInvocationException.kt +++ b/api/src/main/kotlin/io/smnp/error/MethodInvocationException.kt @@ -2,8 +2,15 @@ package io.smnp.error import io.smnp.callable.method.Method import io.smnp.callable.signature.ActualSignatureFormatter.format +import io.smnp.environment.Environment import io.smnp.type.model.Value -class MethodInvocationException(private val method: Method, private val obj: Value, private val passedArguments: Array) : Exception() { - override fun toString() = "Invalid signature: $obj.${method.name}${format(passedArguments)}\nAllowed signatures:\n${method.signature}" -} \ No newline at end of file +class MethodInvocationException( + method: Method, + obj: Value, + passedArguments: Array, + val environment: Environment +) : SmnpException( + "Method invocation error", + "Invalid signature: $obj.${method.name}${format(passedArguments)}\nAllowed signatures:\n${method.signature}" +) \ No newline at end of file diff --git a/api/src/main/kotlin/io/smnp/error/RuntimeException.kt b/api/src/main/kotlin/io/smnp/error/RuntimeException.kt deleted file mode 100644 index 914f6aa..0000000 --- a/api/src/main/kotlin/io/smnp/error/RuntimeException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.smnp.error - -class RuntimeException(message: String?) : Exception(message) \ No newline at end of file diff --git a/api/src/main/kotlin/io/smnp/error/SmnpException.kt b/api/src/main/kotlin/io/smnp/error/SmnpException.kt new file mode 100644 index 0000000..5556203 --- /dev/null +++ b/api/src/main/kotlin/io/smnp/error/SmnpException.kt @@ -0,0 +1,3 @@ +package io.smnp.error + +abstract class SmnpException(val friendlyName: String, message: String? = null) : Exception(message) \ No newline at end of file diff --git a/api/src/main/kotlin/io/smnp/runtime/model/CallStack.kt b/api/src/main/kotlin/io/smnp/runtime/model/CallStack.kt index 9e28b5c..bc45649 100644 --- a/api/src/main/kotlin/io/smnp/runtime/model/CallStack.kt +++ b/api/src/main/kotlin/io/smnp/runtime/model/CallStack.kt @@ -21,4 +21,6 @@ class CallStack { fun pretty() { items.asReversed().forEachIndexed { index, item -> println("[${items.size - index - 1}] $item") } } + + fun stackTrace() = items.asReversed().mapIndexed { index, item -> "[${items.size - index - 1}] $item" }.joinToString("\n") } \ No newline at end of file diff --git a/api/src/main/kotlin/io/smnp/runtime/model/CallStackFrame.kt b/api/src/main/kotlin/io/smnp/runtime/model/CallStackFrame.kt index a65302c..314b27b 100644 --- a/api/src/main/kotlin/io/smnp/runtime/model/CallStackFrame.kt +++ b/api/src/main/kotlin/io/smnp/runtime/model/CallStackFrame.kt @@ -2,6 +2,7 @@ package io.smnp.runtime.model import io.smnp.callable.signature.ActualSignatureFormatter import io.smnp.collection.Stack +import io.smnp.error.EvaluationException import io.smnp.type.model.Value import io.smnp.type.module.Module @@ -24,7 +25,7 @@ data class CallStackFrame( } fun getVariable(name: String): Value { - return scopes.lastOrNull { it.containsKey(name) }?.get(name) ?: throw RuntimeException("Undefined variable `$name`") + return scopes.lastOrNull { it.containsKey(name) }?.get(name) ?: throw EvaluationException("Undefined variable `$name`") } fun prettyScope() { diff --git a/app/src/main/kotlin/io/smnp/SMNP.kt b/app/src/main/kotlin/io/smnp/SMNP.kt index e81605c..8d7f4a0 100644 --- a/app/src/main/kotlin/io/smnp/SMNP.kt +++ b/app/src/main/kotlin/io/smnp/SMNP.kt @@ -1,5 +1,9 @@ package io.smnp -fun main(args: Array) { +import io.smnp.interpreter.DefaultInterpreter +import java.io.File; +fun main(args: Array) { + val interpreter = DefaultInterpreter() + interpreter.run(File("/home/bartek/Developent/SMNP-Kotlin/examples/scratchpad.mus")) } \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/callable/util/FunctionSignatureParser.kt b/app/src/main/kotlin/io/smnp/callable/util/FunctionSignatureParser.kt index 017afde..8d568ba 100644 --- a/app/src/main/kotlin/io/smnp/callable/util/FunctionSignatureParser.kt +++ b/app/src/main/kotlin/io/smnp/callable/util/FunctionSignatureParser.kt @@ -2,6 +2,7 @@ package io.smnp.callable.util import io.smnp.callable.signature.Signature import io.smnp.dsl.ast.model.node.* +import io.smnp.error.InvalidSignatureException import io.smnp.error.ShouldNeverReachThisLineException import io.smnp.type.enumeration.DataType import io.smnp.type.matcher.Matcher @@ -42,7 +43,7 @@ object FunctionSignatureParser { } }.eachCount().forEach { if (it.value > 1) { - throw RuntimeException("Duplicated argument name of '${it.key}'") + throw InvalidSignatureException("Duplicated argument name of '${it.key}'") } } } @@ -61,15 +62,15 @@ object FunctionSignatureParser { ) if (metadata.hasVararg && metadata.hasOptional) { - throw RuntimeException("Optional arguments and vararg cannot be mixed in same signature") + throw InvalidSignatureException("Optional arguments and vararg cannot be mixed in same signature") } if (metadata.hasRegular && metadata.hasOptional && firstOptional < lastRegular) { - throw RuntimeException("Optional arguments should be at the very end of arguments list") + throw InvalidSignatureException("Optional arguments should be at the very end of arguments list") } if (metadata.hasVararg && vararg != signature.items.size - 1) { - throw RuntimeException("Vararg arguments should be at the very end of arguments list") + throw InvalidSignatureException("Vararg arguments should be at the very end of arguments list") } return metadata @@ -107,7 +108,7 @@ object FunctionSignatureParser { ) } - throw RuntimeException("Unknown type") + throw ShouldNeverReachThisLineException() } private fun listSpecifier(listSpecifierNode: TypeSpecifierNode): Matcher { diff --git a/app/src/main/kotlin/io/smnp/dsl/ast/parser/ConditionParser.kt b/app/src/main/kotlin/io/smnp/dsl/ast/parser/ConditionParser.kt index 44e4227..b3123c6 100644 --- a/app/src/main/kotlin/io/smnp/dsl/ast/parser/ConditionParser.kt +++ b/app/src/main/kotlin/io/smnp/dsl/ast/parser/ConditionParser.kt @@ -14,7 +14,7 @@ class ConditionParser : Parser() { assert(SubexpressionParser(), "expression"), terminal(TokenType.CLOSE_PAREN), assert(StatementParser(), "statement") - ) { (ifToken, condition, trueBranch) -> + ) { (ifToken, _, condition, _, trueBranch) -> ConditionNode(ifToken, condition, trueBranch, Node.NONE, Node.NONE) } @@ -26,7 +26,7 @@ class ConditionParser : Parser() { assert(StatementParser(), "statement"), terminal(TokenType.ELSE), assert(StatementParser(), "statement") - ) { (ifToken, condition, trueBranch, elseToken, falseBranch) -> + ) { (ifToken, _, condition, _, trueBranch, elseToken, falseBranch) -> ConditionNode(ifToken, condition, trueBranch, elseToken, falseBranch) } @@ -35,4 +35,8 @@ class ConditionParser : Parser() { ifStatementParser ).parse(input) } -} \ No newline at end of file +} + +// It is required for destructing list of nodes in ifElseStatementParser object +private operator fun List.component6() = this[5]; +private operator fun List.component7() = this[6]; diff --git a/app/src/main/kotlin/io/smnp/dsl/ast/parser/ExtendParser.kt b/app/src/main/kotlin/io/smnp/dsl/ast/parser/ExtendParser.kt index 8fc533b..1b37f17 100644 --- a/app/src/main/kotlin/io/smnp/dsl/ast/parser/ExtendParser.kt +++ b/app/src/main/kotlin/io/smnp/dsl/ast/parser/ExtendParser.kt @@ -28,7 +28,7 @@ ExtendNode(targetType, identifier, method, extendToken.position) assert(loop(terminal(TokenType.OPEN_CURLY), assert(FunctionDefinitionParser(), "method definition or }"), terminal(TokenType.CLOSE_CURLY)) { begin, methods, end -> BlockNode(begin, methods, end) }, "block with methods' definitions or 'with' keyword with single method definition") - ) { (extendToken, targetType, identifier, methods) -> + ) { (extendToken, targetType, _, identifier, methods) -> ExtendNode(targetType, identifier, methods, extendToken.position) } diff --git a/app/src/main/kotlin/io/smnp/dsl/ast/parser/Parser.kt b/app/src/main/kotlin/io/smnp/dsl/ast/parser/Parser.kt index 5ac504d..e37b3e1 100644 --- a/app/src/main/kotlin/io/smnp/dsl/ast/parser/Parser.kt +++ b/app/src/main/kotlin/io/smnp/dsl/ast/parser/Parser.kt @@ -9,6 +9,7 @@ import io.smnp.dsl.token.model.entity.TokenList import io.smnp.dsl.token.model.entity.TokenPosition import io.smnp.dsl.token.model.enumeration.TokenType import io.smnp.error.InvalidSyntaxException +import io.smnp.error.PositionException abstract class Parser { fun parse(input: TokenList): ParserOutput { @@ -178,7 +179,7 @@ abstract class Parser { val output = parser.parse(input) if (output.result == ParsingResult.FAILED) { - throw InvalidSyntaxException("Expected $expected, got '${input.current.rawValue}'", input.currentPos()) + throw PositionException(InvalidSyntaxException("Expected $expected, got '${input.current.rawValue}'"), input.currentPos()) } return output diff --git a/app/src/main/kotlin/io/smnp/dsl/token/model/entity/TokenPosition.kt b/app/src/main/kotlin/io/smnp/dsl/token/model/entity/TokenPosition.kt index 2798554..153dfa4 100644 --- a/app/src/main/kotlin/io/smnp/dsl/token/model/entity/TokenPosition.kt +++ b/app/src/main/kotlin/io/smnp/dsl/token/model/entity/TokenPosition.kt @@ -6,10 +6,10 @@ data class TokenPosition(val line: Int, val beginCol: Int, val endCol: Int) { } override fun toString(): String { - return "[line ${line+1}, col ${beginCol}]" + return "[line ${line+1}, col ${beginCol+1}]" } fun short(): String { - return "${line+1}:${beginCol}" + return "${line+1}:${beginCol+1}" } } \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/dsl/token/tokenizer/DefaultTokenizer.kt b/app/src/main/kotlin/io/smnp/dsl/token/tokenizer/DefaultTokenizer.kt index 55bd77c..5194a1e 100644 --- a/app/src/main/kotlin/io/smnp/dsl/token/tokenizer/DefaultTokenizer.kt +++ b/app/src/main/kotlin/io/smnp/dsl/token/tokenizer/DefaultTokenizer.kt @@ -11,6 +11,7 @@ import io.smnp.dsl.token.tokenizer.Tokenizer.Companion.mapValue import io.smnp.dsl.token.tokenizer.Tokenizer.Companion.regex import io.smnp.dsl.token.tokenizer.Tokenizer.Companion.separated import io.smnp.error.InvalidSyntaxException +import io.smnp.error.PositionException class DefaultTokenizer : Tokenizer { private val tokenizers = listOf( @@ -91,7 +92,7 @@ class DefaultTokenizer : Tokenizer { val output = tokenize(line, current, index) if (!output.consumed()) { - throw InvalidSyntaxException("Unknown symbol ${line[current]}", TokenPosition(index, current, -1)) + throw PositionException(InvalidSyntaxException("Unknown symbol ${line[current]}"), TokenPosition(index, current, -1)) } current += output.consumedChars diff --git a/app/src/main/kotlin/io/smnp/environment/DefaultEnvironment.kt b/app/src/main/kotlin/io/smnp/environment/DefaultEnvironment.kt index 98224d8..b09011c 100644 --- a/app/src/main/kotlin/io/smnp/environment/DefaultEnvironment.kt +++ b/app/src/main/kotlin/io/smnp/environment/DefaultEnvironment.kt @@ -3,6 +3,7 @@ package io.smnp.environment import io.smnp.callable.function.Function import io.smnp.callable.method.Method import io.smnp.callable.signature.ActualSignatureFormatter.format +import io.smnp.error.EvaluationException import io.smnp.ext.DefaultModuleRegistry.requestModuleProviderForPath import io.smnp.ext.ModuleProvider import io.smnp.interpreter.LanguageModuleInterpreter @@ -49,11 +50,11 @@ class DefaultEnvironment : Environment { override fun invokeFunction(name: String, arguments: List): Value { val foundFunctions = rootModule.findFunction(name) if (foundFunctions.isEmpty()) { - throw RuntimeException("No function found with name of '$name'") + throw EvaluationException("No function found with name of '$name'") } if (foundFunctions.size > 1) { - throw RuntimeException("Found ${foundFunctions.size} functions with name of $name: [${foundFunctions.map { it.module.canonicalName }.joinToString()}]") + throw EvaluationException("Found ${foundFunctions.size} functions with name of $name: [${foundFunctions.map { it.module.canonicalName }.joinToString()}]") } @@ -69,11 +70,19 @@ class DefaultEnvironment : Environment { override fun invokeMethod(obj: Value, name: String, arguments: List): Value { val foundMethods = rootModule.findMethod(obj, name) if (foundMethods.isEmpty()) { - throw RuntimeException("No method found with name of '$name' for ${format(obj)}") + throw EvaluationException( + "No method found with name of '$name' for ${format( + obj + )}" + ) } if (foundMethods.size > 1) { - throw RuntimeException("Found ${foundMethods.size} methods with name of $name for ${format(obj)}: [${foundMethods.map { it.module.canonicalName }.joinToString()}]") + throw EvaluationException( + "Found ${foundMethods.size} methods with name of $name for ${format( + obj + )}: [${foundMethods.map { it.module.canonicalName }.joinToString()}]" + ) } val method = foundMethods[0] @@ -89,6 +98,10 @@ class DefaultEnvironment : Environment { callStack.pretty() } + override fun stackTrace(): String { + return callStack.stackTrace(); + } + override fun defineFunction(function: Function) { rootModule.addFunction(function) } diff --git a/app/src/main/kotlin/io/smnp/error/EvaluationException.kt b/app/src/main/kotlin/io/smnp/error/EvaluationException.kt deleted file mode 100644 index 94965b6..0000000 --- a/app/src/main/kotlin/io/smnp/error/EvaluationException.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.smnp.error - -import io.smnp.dsl.token.model.entity.TokenPosition - -class EvaluationException(message: String?, val position: TokenPosition?) : Exception(message) { - override val message: String? - get() = super.message + if(position != null) " $position" else "" -} \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/error/InvalidSignatureException.kt b/app/src/main/kotlin/io/smnp/error/InvalidSignatureException.kt new file mode 100644 index 0000000..5bfc88e --- /dev/null +++ b/app/src/main/kotlin/io/smnp/error/InvalidSignatureException.kt @@ -0,0 +1,3 @@ +package io.smnp.error + +class InvalidSignatureException(message: String?) : SmnpException("Invalid signature", message) \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/error/InvalidSyntaxException.kt b/app/src/main/kotlin/io/smnp/error/InvalidSyntaxException.kt index 5fc48b4..2479ef2 100644 --- a/app/src/main/kotlin/io/smnp/error/InvalidSyntaxException.kt +++ b/app/src/main/kotlin/io/smnp/error/InvalidSyntaxException.kt @@ -1,8 +1,3 @@ package io.smnp.error -import io.smnp.dsl.token.model.entity.TokenPosition - -class InvalidSyntaxException(message: String?, val position: TokenPosition?) : Exception(message) { - override val message: String? - get() = super.message + if(position != null) " $position" else "" -} \ No newline at end of file +class InvalidSyntaxException(message: String?) : SmnpException("Syntax error", message) \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/error/ModuleException.kt b/app/src/main/kotlin/io/smnp/error/ModuleException.kt new file mode 100644 index 0000000..a8a2c80 --- /dev/null +++ b/app/src/main/kotlin/io/smnp/error/ModuleException.kt @@ -0,0 +1,3 @@ +package io.smnp.error + +class ModuleException(message: String?) : SmnpException("Module error", message) \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/error/PositionException.kt b/app/src/main/kotlin/io/smnp/error/PositionException.kt new file mode 100644 index 0000000..0dee42f --- /dev/null +++ b/app/src/main/kotlin/io/smnp/error/PositionException.kt @@ -0,0 +1,8 @@ +package io.smnp.error + +import io.smnp.dsl.token.model.entity.TokenPosition + +class PositionException(exception: SmnpException, val position: TokenPosition) : SmnpException( + "${exception.friendlyName} $position", + exception.message +) \ 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 03eb8d6..1c8ea4e 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/AccessOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/AccessOperatorEvaluator.kt @@ -2,31 +2,54 @@ 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.MethodInvocationException +import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput class AccessOperatorEvaluator : Evaluator() { - override fun supportedNodes() = listOf(AccessOperatorNode::class) + override fun supportedNodes() = listOf(AccessOperatorNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val evaluator = ExpressionEvaluator() - val (lhsNode, _, rhsNode) = (node as AccessOperatorNode) - val lhs = evaluator.evaluate(lhsNode, environment).value!! + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val evaluator = ExpressionEvaluator() + val (lhsNode, _, rhsNode) = (node as AccessOperatorNode) + val lhs = evaluator.evaluate(lhsNode, environment).value!! - return when (rhsNode) { - is IdentifierNode -> { - val rhs = rhsNode.token.rawValue - EvaluatorOutput.value(lhs.properties[rhs] ?: throw EvaluationException("Unknown property $rhs of type ${lhs.type.name.toLowerCase()}", rhsNode.position)) + return when (rhsNode) { + is IdentifierNode -> { + val rhs = rhsNode.token.rawValue + EvaluatorOutput.value( + lhs.properties[rhs] ?: throw PositionException( + EnvironmentException( + EvaluationException("Unknown property $rhs of type ${lhs.type.name.toLowerCase()}"), + environment + ), + rhsNode.position + ) + ) + } + is FunctionCallNode -> { + val (identifierNode, argsNode) = rhsNode + val identifier = (identifierNode as IdentifierNode).token.rawValue + val arguments = + (argsNode as FunctionCallArgumentsNode).items.map { evaluator.evaluate(it, environment).value!! } + try { + return EvaluatorOutput.value(environment.invokeMethod(lhs, identifier, arguments)) + } catch(e: MethodInvocationException) { + throw PositionException(EnvironmentException(e, environment), identifierNode.position) + } catch(e: EvaluationException) { + throw PositionException(EnvironmentException(e, environment), identifierNode.position) } - is FunctionCallNode -> { - val (identifierNode, argsNode) = rhsNode - val identifier = (identifierNode as IdentifierNode).token.rawValue - val arguments = (argsNode as FunctionCallArgumentsNode).items.map { evaluator.evaluate(it, environment).value!! } - return EvaluatorOutput.value(environment.invokeMethod(lhs, identifier, arguments)) - } - else -> { - throw EvaluationException("Invalid property access type - only property name and method call are allowed", rhsNode.position) - } - } - } + } + else -> { + throw PositionException( + EnvironmentException( + EvaluationException("Invalid property access type - only property name and method call are allowed"), + environment + ), rhsNode.position + ) + } + } + } } \ No newline at end of file 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 1e12906..dee8e2d 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/AssignmentOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/AssignmentOperatorEvaluator.kt @@ -4,7 +4,9 @@ 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.type.enumeration.DataType @@ -19,8 +21,11 @@ class AssignmentOperatorEvaluator : Evaluator() { val value = evaluator.evaluate(valueNode, environment).value!! if (value.type == DataType.VOID) { - throw EvaluationException( - "Right hand side expression of assignment operation has returned nothing", + throw PositionException( + EnvironmentException( + EvaluationException("Right hand side expression of assignment operation has returned nothing"), + environment + ), valueNode.position ) } 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 1615d8d..e1d4da5 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ConditionEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ConditionEvaluator.kt @@ -4,29 +4,38 @@ 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.type.enumeration.DataType class ConditionEvaluator : Evaluator() { - override fun supportedNodes() = listOf(ConditionNode::class) + private val expressionEvaluator = ExpressionEvaluator() + private val defaultEvaluator = DefaultEvaluator() - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val expressionEvaluator = ExpressionEvaluator() - val defaultEvaluator = DefaultEvaluator() - val (conditionNode, trueBranchNode, falseBranchNode) = (node as ConditionNode) - val condition = expressionEvaluator.evaluate(conditionNode, environment).value!! + override fun supportedNodes() = listOf(ConditionNode::class) - if(condition.type != DataType.BOOL) { - throw EvaluationException("Condition should be of bool type, found '${condition.value}'", conditionNode.position) - } + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val (conditionNode, trueBranchNode, falseBranchNode) = (node as ConditionNode) + val condition = expressionEvaluator.evaluate(conditionNode, environment).value!! - if(condition.value!! as Boolean) { - return defaultEvaluator.evaluate(trueBranchNode, environment) - } else if(falseBranchNode !is NoneNode) { - return defaultEvaluator.evaluate(falseBranchNode, environment) - } + if (condition.type != DataType.BOOL) { + throw PositionException( + EnvironmentException( + EvaluationException("Condition should be of bool type, found '${condition.value}'"), + environment + ), + conditionNode.position + ) + } - return EvaluatorOutput.ok() - } + if (condition.value!! as Boolean) { + return defaultEvaluator.evaluate(trueBranchNode, environment) + } else if (falseBranchNode !is NoneNode) { + return defaultEvaluator.evaluate(falseBranchNode, environment) + } + + return EvaluatorOutput.ok() + } } \ No newline at end of file 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 9d231b3..393161c 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/Evaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/Evaluator.kt @@ -2,7 +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 kotlin.reflect.KClass @@ -62,7 +64,10 @@ abstract class Evaluator { val output = evaluator.evaluate(node, environment) if (output.result == EvaluationResult.FAILED) { - throw EvaluationException("Expected $expected", node.position) + throw PositionException( + EnvironmentException(EvaluationException("Expected $expected"), environment), + node.position + ) } 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 cb7eb0e..0721b16 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ExtendEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ExtendEvaluator.kt @@ -4,20 +4,29 @@ import io.smnp.callable.method.CustomMethod import io.smnp.callable.util.FunctionSignatureParser import io.smnp.dsl.ast.model.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 class ExtendEvaluator : Evaluator() { - override fun supportedNodes() = listOf(ExtendNode::class) + override fun supportedNodes() = listOf(ExtendNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val (typeNode, identifierNode, methodsNode) = node as ExtendNode - val type = FunctionSignatureParser.matcherForSingleTypeNode(typeNode as SingleTypeNode) - val identifier = (identifierNode as IdentifierNode).token.rawValue + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val (typeNode, identifierNode, methodsNode) = node as ExtendNode + val type = FunctionSignatureParser.matcherForSingleTypeNode(typeNode as SingleTypeNode) + val identifier = (identifierNode as IdentifierNode).token.rawValue - methodsNode.children - .map { CustomMethod.create(type, identifier, it as FunctionDefinitionNode) } - .forEach { environment.defineMethod(it) } + methodsNode.children + .map { it to CustomMethod.create(type, identifier, it as FunctionDefinitionNode) } + .forEach { + try { + environment.defineMethod(it.second) + } catch (e: SmnpException) { + throw PositionException(EnvironmentException(e, environment), it.first.position) + } + } - return EvaluatorOutput.ok() - } + return EvaluatorOutput.ok() + } } \ No newline at end of file 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 51ca64a..bd89988 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionCallEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionCallEvaluator.kt @@ -5,6 +5,10 @@ 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.EvaluationException +import io.smnp.error.FunctionInvocationException +import io.smnp.error.PositionException import io.smnp.evaluation.model.entity.EvaluatorOutput class FunctionCallEvaluator : Evaluator() { @@ -16,6 +20,12 @@ class FunctionCallEvaluator : Evaluator() { val identifier = (identifierNode as IdentifierNode).token.rawValue val arguments = (argsNode as FunctionCallArgumentsNode).items.map { evaluator.evaluate(it, environment).value!! } - return EvaluatorOutput.value(environment.invokeFunction(identifier, arguments)) + try { + return EvaluatorOutput.value(environment.invokeFunction(identifier, arguments)) + } catch(e: FunctionInvocationException) { + throw PositionException(EnvironmentException(e, environment), node.position) + } catch(e: EvaluationException) { + throw PositionException(EnvironmentException(e, environment), node.position) + } } } \ 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 5b427ef..0cba796 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionDefinitionEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/FunctionDefinitionEvaluator.kt @@ -4,6 +4,9 @@ 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 class FunctionDefinitionEvaluator : Evaluator() { @@ -11,7 +14,13 @@ class FunctionDefinitionEvaluator : Evaluator() { override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { val function = CustomFunction.create(node as FunctionDefinitionNode) - environment.defineFunction(function) + + try { + environment.defineFunction(function) + } catch(e: SmnpException) { + throw PositionException(EnvironmentException(e, environment), node.position) + } + 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 ba7d82c..77add36 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/IdentifierEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/IdentifierEvaluator.kt @@ -3,6 +3,9 @@ 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 class IdentifierEvaluator : Evaluator() { @@ -10,6 +13,11 @@ class IdentifierEvaluator : Evaluator() { override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { val identifier = (node as IdentifierNode).token.rawValue - return EvaluatorOutput.value(environment.getVariable(identifier)) + + try { + return EvaluatorOutput.value(environment.getVariable(identifier)) + } catch (e: EvaluationException) { + throw PositionException(EnvironmentException(e, environment), node.position) + } } } \ 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 cd9bda7..64b4601 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ImportEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ImportEvaluator.kt @@ -4,6 +4,9 @@ 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 class ImportEvaluator : Evaluator() { @@ -11,7 +14,12 @@ class ImportEvaluator : Evaluator() { override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { val path = (node as ImportNode).path.joinToString(".") { (it as IdentifierNode).token.rawValue } - environment.loadModule(path) + + try { + environment.loadModule(path) + } catch(e: SmnpException) { + throw PositionException(EnvironmentException(e, environment), node.position) + } return EvaluatorOutput.ok() } 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 dbf1d0d..c6a020c 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/LogicOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/LogicOperatorEvaluator.kt @@ -5,34 +5,50 @@ 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.type.enumeration.DataType import io.smnp.type.model.Value class LogicOperatorEvaluator : Evaluator() { - override fun supportedNodes() = listOf(LogicOperatorNode::class) + override fun supportedNodes() = listOf(LogicOperatorNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val evaluator = ExpressionEvaluator() - val (lhsNode, opNode, rhsNode) = (node as LogicOperatorNode) - val lhs = evaluator.evaluate(lhsNode, environment).value!! - val rhs = evaluator.evaluate(rhsNode, environment).value!! - val operator = (opNode as TokenNode).token.type + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val evaluator = ExpressionEvaluator() + val (lhsNode, opNode, rhsNode) = (node as LogicOperatorNode) + val lhs = evaluator.evaluate(lhsNode, environment).value!! + val rhs = evaluator.evaluate(rhsNode, environment).value!! + val operator = (opNode as TokenNode).token.type - if(lhs.type != DataType.BOOL) { - throw EvaluationException("Operator '${operator.token}' supports only bool types", lhsNode.position) - } + if (lhs.type != DataType.BOOL) { + throw PositionException( + EnvironmentException( + EvaluationException("Operator '${operator.token}' supports only bool types"), + environment + ), + lhsNode.position + ) + } - if(rhs.type != DataType.BOOL) { - throw EvaluationException("Operator '${operator.token}' supports only bool types", rhsNode.position) - } + if (rhs.type != DataType.BOOL) { + throw PositionException( + EnvironmentException( + EvaluationException("Operator '${operator.token}' supports only bool types"), + environment + ), + rhsNode.position + ) + } - return EvaluatorOutput.value(when(operator) { + return EvaluatorOutput.value( + when (operator) { TokenType.AND -> Value.bool((lhs.value as Boolean) && (rhs.value as Boolean)) TokenType.OR -> Value.bool((lhs.value as Boolean) || (rhs.value as Boolean)) else -> throw ShouldNeverReachThisLineException() - }) - } + } + ) + } } \ No newline at end of file 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 583b308..570368a 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/LoopEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/LoopEvaluator.kt @@ -4,7 +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.type.enumeration.DataType.* @@ -26,9 +28,13 @@ 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 EvaluationException( - "Expected for-loop with int iterator or foreach-loop with string, list or map iterator or while-loop with bool iterator, found ${iterator.type.name.toLowerCase()}", - iteratorNode.position + 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.type.name.toLowerCase()}" + ), + environment + ), iteratorNode.position ) } environment.popScope() @@ -71,7 +77,7 @@ class LoopEvaluator : Evaluator() { { id -> environment.setVariable(id, Value.int(index)) } ) - if(filter(filterNode, environment)) { + if (filter(filterNode, environment)) { outputs.add(defaultEvaluator.evaluate(statementNode, environment)) index++ } @@ -134,11 +140,22 @@ class LoopEvaluator : Evaluator() { environment: Environment ): EvaluatorOutput { if (parametersNode != Node.NONE) { - throw EvaluationException("Parameters are not supported in the while-loop", parametersNode.position) + throw PositionException( + EnvironmentException( + EvaluationException("Parameters are not supported in the while-loop"), + environment + ), + parametersNode.position + ) } if (filterNode != Node.NONE) { - throw EvaluationException("Filter is not supported in the while-loop", filterNode.position) + throw PositionException( + EnvironmentException( + EvaluationException("Filter is not supported in the while-loop"), + environment + ), filterNode.position + ) } return output { outputs -> @@ -162,7 +179,15 @@ class LoopEvaluator : Evaluator() { if (filterNode != Node.NONE) { val condition = expressionEvaluator.evaluate(filterNode, environment).value!! if (condition.type != BOOL) { - throw EvaluationException("Filter condition should be evaluated to bool type", filterNode.position) + throw PositionException( + EnvironmentException( + EvaluationException( + "Filter condition should be evaluated to bool type" + ), + environment + ), + filterNode.position + ) } 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 91025ed..2a14f3b 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/MapEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/MapEvaluator.kt @@ -5,35 +5,43 @@ 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.type.enumeration.DataType.* import io.smnp.type.model.Value class MapEvaluator : Evaluator() { - private val evaluator = ExpressionEvaluator() + private val evaluator = ExpressionEvaluator() - override fun supportedNodes() = listOf(MapNode::class) + override fun supportedNodes() = listOf(MapNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val value = (node as MapNode).items - .map { it as MapEntryNode } - .map { getKey(it.key, environment) to evaluator.evaluate(it.value, environment).value!! } - .toMap() + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val value = (node as MapNode).items + .map { it as MapEntryNode } + .map { getKey(it.key, environment) to evaluator.evaluate(it.value, environment).value!! } + .toMap() - return EvaluatorOutput.value(Value.map(value)) - } + return EvaluatorOutput.value(Value.map(value)) + } - private fun getKey(keyNode: Node, environment: Environment): Value { - val key = when(keyNode) { - is IdentifierNode -> Value.string(keyNode.token.rawValue) - else -> evaluator.evaluate(keyNode, environment).value!! - } + private fun getKey(keyNode: Node, environment: Environment): Value { + val key = when (keyNode) { + is IdentifierNode -> Value.string(keyNode.token.rawValue) + else -> evaluator.evaluate(keyNode, environment).value!! + } - if(key.type !in listOf(BOOL, INT, NOTE, STRING)) { - throw EvaluationException("Invalid map key's type ${key.type.name.toLowerCase()}", keyNode.position) - } + if (key.type !in listOf(BOOL, INT, NOTE, STRING)) { + throw PositionException( + EnvironmentException( + EvaluationException("Invalid map key's type ${key.type.name.toLowerCase()}"), + environment + ), + keyNode.position + ) + } - return key - } + return key + } } \ No newline at end of file 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 f294911..e988586 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/MinusOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/MinusOperatorEvaluator.kt @@ -3,25 +3,35 @@ 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.type.enumeration.DataType import io.smnp.type.model.Value class MinusOperatorEvaluator : Evaluator() { - override fun supportedNodes() = listOf(MinusOperatorNode::class) + override fun supportedNodes() = listOf(MinusOperatorNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val evaluator = ExpressionEvaluator() - val (_, operandNode) = (node as MinusOperatorNode) - val operand = evaluator.evaluate(operandNode, environment) + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val evaluator = ExpressionEvaluator() + val (_, operandNode) = (node as MinusOperatorNode) + val operand = evaluator.evaluate(operandNode, environment) - return EvaluatorOutput.value(when(operand.value!!.type) { + return EvaluatorOutput.value( + when (operand.value!!.type) { DataType.INT -> Value.int(-1 * operand.value.value as Int) 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 EvaluationException("Type ${operand.value.type.name.toLowerCase()} does not support minus operator", node.position) - }) - } + else -> throw PositionException( + EnvironmentException( + EvaluationException("Type ${operand.value.type.name.toLowerCase()} does not support minus operator"), + environment + ), + node.position + ) + } + ) + } } \ No newline at end of file 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 e299745..6324209 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/NotOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/NotOperatorEvaluator.kt @@ -3,23 +3,31 @@ 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.type.enumeration.DataType import io.smnp.type.model.Value class NotOperatorEvaluator : Evaluator() { - val evaluator = assert(ExpressionEvaluator(), "expression") - override fun supportedNodes() = listOf(NotOperatorNode::class) + val evaluator = assert(ExpressionEvaluator(), "expression") + override fun supportedNodes() = listOf(NotOperatorNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val (_, operandNode) = (node as NotOperatorNode) - val operand = evaluator.evaluate(operandNode, environment).value!! + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val (_, operandNode) = (node as NotOperatorNode) + val operand = evaluator.evaluate(operandNode, environment).value!! - if(operand.type != DataType.BOOL) { - throw EvaluationException("Only bool types can be negated", operandNode.position) - } + if (operand.type != DataType.BOOL) { + throw PositionException( + EnvironmentException( + EvaluationException("Only bool types can be negated"), + environment + ), + operandNode.position + ) + } - return EvaluatorOutput.value(Value.bool(!(operand.value as Boolean))) - } + return EvaluatorOutput.value(Value.bool(!(operand.value as Boolean))) + } } \ No newline at end of file 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 0e64f76..70575d1 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/PowerOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/PowerOperatorEvaluator.kt @@ -3,24 +3,32 @@ 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.type.model.Value import kotlin.math.pow class PowerOperatorEvaluator : Evaluator() { - override fun supportedNodes() = listOf(PowerOperatorNode::class) + override fun supportedNodes() = listOf(PowerOperatorNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val (lhsNode, _, rhsNode) = (node as PowerOperatorNode) - val evaluator = ExpressionEvaluator() - val lhs = evaluator.evaluate(lhsNode, environment).value!! - val rhs = evaluator.evaluate(rhsNode, environment).value!! + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val (lhsNode, _, rhsNode) = (node as PowerOperatorNode) + val evaluator = ExpressionEvaluator() + val lhs = evaluator.evaluate(lhsNode, environment).value!! + val rhs = evaluator.evaluate(rhsNode, environment).value!! - if(!lhs.type.isNumeric() || !rhs.type.isNumeric()) { - throw EvaluationException("Operator ** supports only numeric types", node.position) - } + if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { + throw PositionException( + EnvironmentException( + EvaluationException("Operator ** supports only numeric types"), + environment + ), + node.position + ) + } - return EvaluatorOutput.value(Value.float((lhs.value as Number).toFloat().pow((rhs.value as Number).toFloat()))) - } + return EvaluatorOutput.value(Value.float((lhs.value as Number).toFloat().pow((rhs.value as Number).toFloat()))) + } } \ No newline at end of file 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 9828085..c78395d 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ProductOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ProductOperatorEvaluator.kt @@ -5,32 +5,48 @@ 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.NumberUnification.unify import io.smnp.type.model.Value class ProductOperatorEvaluator : Evaluator() { - override fun supportedNodes() = listOf(ProductOperatorNode::class) + override fun supportedNodes() = listOf(ProductOperatorNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val evaluator = ExpressionEvaluator() - 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 + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val evaluator = ExpressionEvaluator() + 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.token} supports only numeric types", node.position) - } + if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { + throw PositionException( + EnvironmentException( + EvaluationException("Operator ${operator.token} supports only numeric types"), + environment + ), + node.position + ) + } - return EvaluatorOutput.value( - when (operator) { - TokenType.ASTERISK -> unify(lhs, rhs, int = { (l, r) -> Value.int(l * r) }, float = { (l, r) -> Value.float(l * r) }) - TokenType.SLASH -> unify(lhs, rhs, int = { (l, r) -> Value.int(l / r) }, float = { (l, r) -> Value.float(l / r) }) - else -> throw ShouldNeverReachThisLineException() - } - ) - } + return EvaluatorOutput.value( + when (operator) { + TokenType.ASTERISK -> unify( + lhs, + rhs, + int = { (l, r) -> Value.int(l * r) }, + float = { (l, r) -> Value.float(l * r) }) + TokenType.SLASH -> unify( + lhs, + rhs, + int = { (l, r) -> Value.int(l / r) }, + float = { (l, r) -> Value.float(l / r) }) + else -> throw ShouldNeverReachThisLineException() + } + ) + } } \ No newline at end of file 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 269136c..336034c 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/RelationOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/RelationOperatorEvaluator.kt @@ -4,43 +4,51 @@ 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.NumberUnification.unify import io.smnp.type.model.Value class RelationOperatorEvaluator : Evaluator() { - override fun supportedNodes() = listOf(RelationOperatorNode::class) + override fun supportedNodes() = listOf(RelationOperatorNode::class) - override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { - val evaluator = ExpressionEvaluator() - val (lhsNode, opNode, rhsNode) = (node as RelationOperatorNode) - val lhs = evaluator.evaluate(lhsNode, environment).value!! - val rhs = evaluator.evaluate(rhsNode, environment).value!! - val operator = (opNode as TokenNode).token.rawValue + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val evaluator = ExpressionEvaluator() + val (lhsNode, opNode, rhsNode) = (node as RelationOperatorNode) + val lhs = evaluator.evaluate(lhsNode, environment).value!! + val rhs = evaluator.evaluate(rhsNode, environment).value!! + val operator = (opNode as TokenNode).token.rawValue - if (operator in listOf("==", "!=")) { - return EvaluatorOutput.value( - Value.bool( - if (operator == "==") lhs.value == rhs.value - else lhs.value != rhs.value - ) + if (operator in listOf("==", "!=")) { + return EvaluatorOutput.value( + Value.bool( + if (operator == "==") lhs.value == rhs.value + else lhs.value != rhs.value ) - } + ) + } - if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { - throw EvaluationException("Operator $operator supports only numeric types", node.position) - } + if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { + throw PositionException( + EnvironmentException( + EvaluationException("Operator $operator supports only numeric types"), + environment + ), + node.position + ) + } - return EvaluatorOutput.value( - when(operator) { - ">" -> unify(lhs, rhs, int = { (l, r) -> Value.bool(l > r) }, float = { (l, r) -> Value.bool(l > r) }) - "<" -> unify(lhs, rhs, int = { (l, r) -> Value.bool(l < r) }, float = { (l, r) -> Value.bool(l < r) }) - ">=" -> unify(lhs, rhs, int = { (l, r) -> Value.bool(l >= r) }, float = { (l, r) -> Value.bool(l >= r) }) - "<=" -> unify(lhs, rhs, int = { (l, r) -> Value.bool(l <= r) }, float = { (l, r) -> Value.bool(l <= r) }) - else -> throw ShouldNeverReachThisLineException() - } - ) - } + return EvaluatorOutput.value( + when (operator) { + ">" -> unify(lhs, rhs, int = { (l, r) -> Value.bool(l > r) }, float = { (l, r) -> Value.bool(l > r) }) + "<" -> unify(lhs, rhs, int = { (l, r) -> Value.bool(l < r) }, float = { (l, r) -> Value.bool(l < r) }) + ">=" -> unify(lhs, rhs, int = { (l, r) -> Value.bool(l >= r) }, float = { (l, r) -> Value.bool(l >= r) }) + "<=" -> unify(lhs, rhs, int = { (l, r) -> Value.bool(l <= r) }, float = { (l, r) -> Value.bool(l <= r) }) + else -> throw ShouldNeverReachThisLineException() + } + ) + } } \ No newline at end of file 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 75e27d7..0915745 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/SumOperatorEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/SumOperatorEvaluator.kt @@ -5,7 +5,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.NumberUnification.unify @@ -24,27 +26,31 @@ class SumOperatorEvaluator : Evaluator() { return EvaluatorOutput.value( when (operator) { - TokenType.PLUS -> plus(lhs, opNode, rhs) - TokenType.MINUS -> minus(lhs, opNode, rhs) + TokenType.PLUS -> plus(lhs, opNode, rhs, environment) + TokenType.MINUS -> minus(lhs, opNode, rhs, environment) else -> throw ShouldNeverReachThisLineException() } ) } - private fun plus(lhs: Value, plusNode: Node, rhs: Value): Value { + private fun plus(lhs: Value, plusNode: Node, rhs: Value, environment: Environment): Value { return if (areNumeric(lhs, rhs)) unify(lhs, rhs, int = { (l, r) -> Value.int(l + r) }, float = { (l, r) -> Value.float(l + r) }) else if (lhs.type == DataType.STRING) Value.string(lhs.value!! as String + rhs.value.toString()) else if (areLists(lhs, rhs)) Value.list(lhs.value!! as List + rhs.value!! as List) - else throw EvaluationException( - "The ${lhs.type.name.toLowerCase()} and ${rhs.type.name.toLowerCase()} are not supported by + operator", - plusNode.position + else throw PositionException( + EnvironmentException( + EvaluationException( + "The ${lhs.type.name.toLowerCase()} and ${rhs.type.name.toLowerCase()} are not supported by + operator" + ), + environment + ), plusNode.position ) } - private fun minus(lhs: Value, minusNode: Node, rhs: Value): Value { + private fun minus(lhs: Value, minusNode: Node, rhs: Value, environment: Environment): Value { return if (areNumeric(lhs, rhs)) unify( lhs, @@ -52,7 +58,13 @@ class SumOperatorEvaluator : Evaluator() { int = { (l, r) -> Value.int(l - r) }, float = { (l, r) -> Value.float(l - r) } ) - else throw EvaluationException("The - operator supports only numeric values", minusNode.position) + else throw PositionException( + EnvironmentException( + EvaluationException("The - operator supports only numeric values"), + environment + ), + minusNode.position + ) } private fun areNumeric(lhs: Value, rhs: Value) = lhs.type.isNumeric() && rhs.type.isNumeric() diff --git a/app/src/main/kotlin/io/smnp/ext/DefaultModuleRegistry.kt b/app/src/main/kotlin/io/smnp/ext/DefaultModuleRegistry.kt index 945d1a4..730fc32 100644 --- a/app/src/main/kotlin/io/smnp/ext/DefaultModuleRegistry.kt +++ b/app/src/main/kotlin/io/smnp/ext/DefaultModuleRegistry.kt @@ -1,5 +1,6 @@ package io.smnp.ext +import io.smnp.error.ModuleException import org.pf4j.DefaultPluginManager object DefaultModuleRegistry : ModuleRegistry { @@ -15,7 +16,7 @@ object DefaultModuleRegistry : ModuleRegistry { } override fun requestModuleProviderForPath(path: String): ModuleProvider { - return modules[path] ?: throw RuntimeException("Module $path not found") + return modules[path] ?: throw ModuleException("Module $path not found") } override fun registeredModules() = modules.keys.toList() diff --git a/app/src/main/kotlin/io/smnp/interpreter/DefaultInterpreter.kt b/app/src/main/kotlin/io/smnp/interpreter/DefaultInterpreter.kt index 7871891..7a64545 100644 --- a/app/src/main/kotlin/io/smnp/interpreter/DefaultInterpreter.kt +++ b/app/src/main/kotlin/io/smnp/interpreter/DefaultInterpreter.kt @@ -4,50 +4,72 @@ import io.smnp.dsl.ast.parser.RootParser import io.smnp.dsl.token.tokenizer.DefaultTokenizer import io.smnp.environment.DefaultEnvironment import io.smnp.environment.Environment +import io.smnp.error.SmnpException import io.smnp.evaluation.evaluator.RootEvaluator import io.smnp.evaluation.model.enumeration.EvaluationResult import java.io.File +import java.lang.System.err +import kotlin.system.exitProcess class DefaultInterpreter : Interpreter { - private val tokenizer = DefaultTokenizer() - private val parser = RootParser() - private val evaluator = RootEvaluator() + private val tokenizer = DefaultTokenizer() + private val parser = RootParser() + private val evaluator = RootEvaluator() - fun run(code: String, printTokens: Boolean = false, printAst: Boolean = false, dryRun: Boolean = false): Environment { - val lines = code.split("\n") - return run(lines, printTokens, printAst, dryRun) - } + fun run( + code: String, + printTokens: Boolean = false, + printAst: Boolean = false, + dryRun: Boolean = false + ): Environment { + val lines = code.split("\n") + return run(lines, printTokens, printAst, dryRun) + } - private fun run(lines: List, printTokens: Boolean, printAst: Boolean, dryRun: Boolean): Environment { - val environment = createEnvironment() - val tokens = tokenizer.tokenize(lines) - val ast = parser.parse(tokens) + private fun run(lines: List, printTokens: Boolean, printAst: Boolean, dryRun: Boolean): Environment { + try { + return tryToRun(lines, printTokens, printAst, dryRun) + } catch (e: SmnpException) { + printError(e) + exitProcess(1) + } + } - if(printTokens) println(tokens) - if(printAst) ast.node.pretty() + private fun printError(e: SmnpException) { + err.println(e.friendlyName) + err.println(e.message) + } - if(!dryRun) { - val result = evaluator.evaluate(ast.node, environment) + private fun tryToRun(lines: List, printTokens: Boolean, printAst: Boolean, dryRun: Boolean): Environment { + val environment = createEnvironment() + val tokens = tokenizer.tokenize(lines) + val ast = parser.parse(tokens) - if(result.result == EvaluationResult.FAILED) { - throw RuntimeException("Evaluation failed") - } - } + if (printTokens) println(tokens) + if (printAst) ast.node.pretty() - return environment - } + if (!dryRun) { + val result = evaluator.evaluate(ast.node, environment) - private fun createEnvironment(): Environment { - val environment = DefaultEnvironment() - environment.loadModule("smnp.lang") + if (result.result == EvaluationResult.FAILED) { + throw RuntimeException("Evaluation failed") + } + } - return environment - } + return environment + } - fun run(file: File, printTokens: Boolean = false, printAst: Boolean = false, dryRun: Boolean = false): Environment { - val lines = file.readLines() - return run(lines, printTokens, printAst, dryRun) - } + private fun createEnvironment(): Environment { + val environment = DefaultEnvironment() + environment.loadModule("smnp.lang") - override fun run(code: String) = run(code, printTokens = false, printAst = false, dryRun = false) + return environment + } + + fun run(file: File, printTokens: Boolean = false, printAst: Boolean = false, dryRun: Boolean = false): Environment { + val lines = file.readLines() + return run(lines, printTokens, printAst, dryRun) + } + + override fun run(code: String) = run(code, printTokens = false, printAst = false, dryRun = false) } \ No newline at end of file diff --git a/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/CharAtMethod.kt b/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/CharAtMethod.kt index fd31f20..873e587 100644 --- a/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/CharAtMethod.kt +++ b/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/CharAtMethod.kt @@ -3,7 +3,7 @@ package io.smnp.ext.lang.method import io.smnp.callable.method.Method import io.smnp.callable.method.MethodDefinitionTool import io.smnp.callable.signature.Signature.Companion.simple -import io.smnp.error.RuntimeException +import io.smnp.error.EvaluationException import io.smnp.type.enumeration.DataType.INT import io.smnp.type.enumeration.DataType.STRING import io.smnp.type.matcher.Matcher.Companion.ofType @@ -12,7 +12,7 @@ import io.smnp.type.model.Value class CharAtMethod : Method(ofType(STRING),"charAt") { override fun define(new: MethodDefinitionTool) { new method simple(ofType(INT)) body { _, obj, (index) -> - Value.string((obj.value!! as String).getOrNull(index.value!! as Int)?.toString() ?: throw RuntimeException("Index '${index.value!!}' runs out of string bounds")) + Value.string((obj.value!! as String).getOrNull(index.value!! as Int)?.toString() ?: throw EvaluationException("Index '${index.value!!}' runs out of string bounds")) } } } \ No newline at end of file diff --git a/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/ListAccessMethod.kt b/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/ListAccessMethod.kt index af1fdce..3c9887e 100644 --- a/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/ListAccessMethod.kt +++ b/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/ListAccessMethod.kt @@ -3,7 +3,7 @@ package io.smnp.ext.lang.method import io.smnp.callable.method.Method import io.smnp.callable.method.MethodDefinitionTool import io.smnp.callable.signature.Signature.Companion.simple -import io.smnp.error.RuntimeException +import io.smnp.error.EvaluationException import io.smnp.type.enumeration.DataType.INT import io.smnp.type.enumeration.DataType.LIST import io.smnp.type.matcher.Matcher.Companion.ofType @@ -16,7 +16,7 @@ class ListAccessMethod : Method(ofType(LIST), "get") { val i = index.value!! as Int if(i >= list.size) { - throw RuntimeException("Index '$i' runs out of array bounds") + throw EvaluationException("Index '$i' runs out of array bounds") } list[i] diff --git a/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/MapAccessMethod.kt b/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/MapAccessMethod.kt index 1ed323b..f470646 100644 --- a/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/MapAccessMethod.kt +++ b/modules/lang/src/main/kotlin/io/smnp/ext/lang/method/MapAccessMethod.kt @@ -3,7 +3,7 @@ package io.smnp.ext.lang.method import io.smnp.callable.method.Method import io.smnp.callable.method.MethodDefinitionTool import io.smnp.callable.signature.Signature.Companion.simple -import io.smnp.error.RuntimeException +import io.smnp.error.EvaluationException import io.smnp.type.enumeration.DataType.MAP import io.smnp.type.matcher.Matcher.Companion.allTypes import io.smnp.type.matcher.Matcher.Companion.ofType @@ -13,7 +13,7 @@ class MapAccessMethod : Method(ofType(MAP), "get") { override fun define(new: MethodDefinitionTool) { new method simple(allTypes()) body { _, obj, (key) -> val map = (obj.value!! as Map) - map[key] ?: throw RuntimeException("Key '${key.value!!}' not found") + map[key] ?: throw EvaluationException("Key '${key.value!!}' not found") } } } \ No newline at end of file