Simplify wrapping with decorator pattern evaluation exceptions

This commit is contained in:
2020-03-19 16:36:53 +01:00
parent 53b92150c4
commit c41a02f880
21 changed files with 178 additions and 224 deletions

View File

@@ -16,10 +16,10 @@ import kotlin.system.exitProcess
fun main(args: Array<String>): Unit = mainBody { fun main(args: Array<String>): Unit = mainBody {
ArgParser(args).parseInto(::Arguments).run { ArgParser(args).parseInto(::Arguments).run {
try {
val interpreter = DefaultInterpreter() val interpreter = DefaultInterpreter()
val environment = DefaultEnvironment() val environment = DefaultEnvironment()
try {
environment.setVariable("__param__", Value.wrap(parameters.toMap())) environment.setVariable("__param__", Value.wrap(parameters.toMap()))
when { when {
@@ -51,6 +51,10 @@ fun main(args: Array<String>): Unit = mainBody {
System.err.println("\nStack trace:\n${it.environment.stackTrace()}") System.err.println("\nStack trace:\n${it.environment.stackTrace()}")
} }
exitProcess(1) exitProcess(1)
} finally {
if(!environment.disposed) {
environment.dispose()
}
} }
} }
} }

View File

@@ -2,11 +2,10 @@ package io.smnp.evaluation.evaluator
import io.smnp.dsl.ast.model.node.* import io.smnp.dsl.ast.model.node.*
import io.smnp.environment.Environment 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.error.SmnpException
import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
class AccessOperatorEvaluator : Evaluator() { class AccessOperatorEvaluator : Evaluator() {
override fun supportedNodes() = listOf(AccessOperatorNode::class) override fun supportedNodes() = listOf(AccessOperatorNode::class)
@@ -20,12 +19,10 @@ class AccessOperatorEvaluator : Evaluator() {
is IdentifierNode -> { is IdentifierNode -> {
val rhs = rhsNode.token.rawValue val rhs = rhsNode.token.rawValue
EvaluatorOutput.value( EvaluatorOutput.value(
lhs.properties[rhs] ?: throw PositionException( lhs.properties[rhs] ?: throw contextEvaluationException(
EnvironmentException( "Unknown property $rhs of type ${lhs.typeName}",
EvaluationException("Unknown property $rhs of type ${lhs.typeName}"), rhsNode.position,
environment environment
),
rhsNode.position
) )
) )
} }
@@ -37,15 +34,14 @@ class AccessOperatorEvaluator : Evaluator() {
try { try {
return EvaluatorOutput.value(environment.invokeMethod(lhs, identifier, arguments)) return EvaluatorOutput.value(environment.invokeMethod(lhs, identifier, arguments))
} catch (e: SmnpException) { } catch (e: SmnpException) {
throw PositionException(EnvironmentException(e, environment), identifierNode.position) throw ContextExceptionFactory.wrapWithContext(e, identifierNode.position, environment)
} }
} }
else -> { else -> {
throw PositionException( throw contextEvaluationException(
EnvironmentException( "Invalid property access type - only property name and method call are allowed",
EvaluationException("Invalid property access type - only property name and method call are allowed"), rhsNode.position,
environment environment
), rhsNode.position
) )
} }
} }

View File

@@ -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.IdentifierNode
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment 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.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.type.enumeration.DataType import io.smnp.type.enumeration.DataType
class AssignmentOperatorEvaluator : Evaluator() { class AssignmentOperatorEvaluator : Evaluator() {
@@ -21,12 +19,10 @@ class AssignmentOperatorEvaluator : Evaluator() {
val value = evaluator.evaluate(valueNode, environment).value val value = evaluator.evaluate(valueNode, environment).value
if (value.type == DataType.VOID) { if (value.type == DataType.VOID) {
throw PositionException( throw contextEvaluationException(
EnvironmentException( "Right hand side expression of assignment operation has returned nothing",
EvaluationException("Right hand side expression of assignment operation has returned nothing"), valueNode.position,
environment environment
),
valueNode.position
) )
} }

View File

@@ -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.Node
import io.smnp.dsl.ast.model.node.NoneNode import io.smnp.dsl.ast.model.node.NoneNode
import io.smnp.environment.Environment 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.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.type.enumeration.DataType import io.smnp.type.enumeration.DataType
class ConditionEvaluator : Evaluator() { class ConditionEvaluator : Evaluator() {
@@ -21,12 +19,10 @@ class ConditionEvaluator : Evaluator() {
val condition = expressionEvaluator.evaluate(conditionNode, environment).value val condition = expressionEvaluator.evaluate(conditionNode, environment).value
if (condition.type != DataType.BOOL) { if (condition.type != DataType.BOOL) {
throw PositionException( throw contextEvaluationException(
EnvironmentException( "Condition should be of bool type, found '${condition.value}'",
EvaluationException("Condition should be of bool type, found '${condition.value}'"), conditionNode.position,
environment environment
),
conditionNode.position
) )
} }

View File

@@ -2,11 +2,9 @@ package io.smnp.evaluation.evaluator
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment 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.entity.EvaluatorOutput
import io.smnp.evaluation.model.enumeration.EvaluationResult import io.smnp.evaluation.model.enumeration.EvaluationResult
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import kotlin.reflect.KClass import kotlin.reflect.KClass
abstract class Evaluator { abstract class Evaluator {
@@ -64,10 +62,7 @@ abstract class Evaluator {
val output = evaluator.evaluate(node, environment) val output = evaluator.evaluate(node, environment)
if (output.result == EvaluationResult.FAILED) { if (output.result == EvaluationResult.FAILED) {
throw PositionException( throw contextEvaluationException("Expected $expected", node.position, environment)
EnvironmentException(EvaluationException("Expected $expected"), environment),
node.position
)
} }
return output return output

View File

@@ -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.Node
import io.smnp.dsl.ast.model.node.SingleTypeNode import io.smnp.dsl.ast.model.node.SingleTypeNode
import io.smnp.environment.Environment import io.smnp.environment.Environment
import io.smnp.error.EnvironmentException
import io.smnp.error.PositionException
import io.smnp.error.SmnpException import io.smnp.error.SmnpException
import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext
class ExtendEvaluator : Evaluator() { class ExtendEvaluator : Evaluator() {
override fun supportedNodes() = listOf(ExtendNode::class) override fun supportedNodes() = listOf(ExtendNode::class)
@@ -25,7 +24,7 @@ class ExtendEvaluator : Evaluator() {
try { try {
environment.defineMethod(it.second) environment.defineMethod(it.second)
} catch (e: SmnpException) { } catch (e: SmnpException) {
throw PositionException(EnvironmentException(e, environment), it.first.position) throw wrapWithContext(e, it.first.position, environment)
} }
} }

View File

@@ -5,10 +5,9 @@ import io.smnp.dsl.ast.model.node.FunctionCallNode
import io.smnp.dsl.ast.model.node.IdentifierNode import io.smnp.dsl.ast.model.node.IdentifierNode
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment import io.smnp.environment.Environment
import io.smnp.error.EnvironmentException
import io.smnp.error.PositionException
import io.smnp.error.SmnpException import io.smnp.error.SmnpException
import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext
class FunctionCallEvaluator : Evaluator() { class FunctionCallEvaluator : Evaluator() {
override fun supportedNodes() = listOf(FunctionCallNode::class) override fun supportedNodes() = listOf(FunctionCallNode::class)
@@ -22,7 +21,7 @@ class FunctionCallEvaluator : Evaluator() {
try { try {
return EvaluatorOutput.value(environment.invokeFunction(identifier, arguments)) return EvaluatorOutput.value(environment.invokeFunction(identifier, arguments))
} catch (e: SmnpException) { } catch (e: SmnpException) {
throw PositionException(EnvironmentException(e, environment), identifierNode.position) throw wrapWithContext(e, identifierNode.position, environment)
} }
} }
} }

View File

@@ -4,10 +4,9 @@ import io.smnp.callable.function.CustomFunction
import io.smnp.dsl.ast.model.node.FunctionDefinitionNode import io.smnp.dsl.ast.model.node.FunctionDefinitionNode
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment import io.smnp.environment.Environment
import io.smnp.error.EnvironmentException
import io.smnp.error.PositionException
import io.smnp.error.SmnpException import io.smnp.error.SmnpException
import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext
class FunctionDefinitionEvaluator : Evaluator() { class FunctionDefinitionEvaluator : Evaluator() {
override fun supportedNodes() = listOf(FunctionDefinitionNode::class) override fun supportedNodes() = listOf(FunctionDefinitionNode::class)
@@ -18,7 +17,7 @@ class FunctionDefinitionEvaluator : Evaluator() {
try { try {
environment.defineFunction(function) environment.defineFunction(function)
} catch (e: SmnpException) { } catch (e: SmnpException) {
throw PositionException(EnvironmentException(e, environment), node.position) throw wrapWithContext(e, node.position, environment)
} }
return EvaluatorOutput.ok() return EvaluatorOutput.ok()

View File

@@ -3,10 +3,9 @@ package io.smnp.evaluation.evaluator
import io.smnp.dsl.ast.model.node.IdentifierNode import io.smnp.dsl.ast.model.node.IdentifierNode
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment import io.smnp.environment.Environment
import io.smnp.error.EnvironmentException
import io.smnp.error.EvaluationException import io.smnp.error.EvaluationException
import io.smnp.error.PositionException
import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext
class IdentifierEvaluator : Evaluator() { class IdentifierEvaluator : Evaluator() {
override fun supportedNodes() = listOf(IdentifierNode::class) override fun supportedNodes() = listOf(IdentifierNode::class)
@@ -17,7 +16,7 @@ class IdentifierEvaluator : Evaluator() {
try { try {
return EvaluatorOutput.value(environment.getVariable(identifier)) return EvaluatorOutput.value(environment.getVariable(identifier))
} catch (e: EvaluationException) { } catch (e: EvaluationException) {
throw PositionException(EnvironmentException(e, environment), node.position) throw wrapWithContext(e, node.position, environment)
} }
} }
} }

View File

@@ -4,10 +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.ImportNode
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment import io.smnp.environment.Environment
import io.smnp.error.EnvironmentException
import io.smnp.error.PositionException
import io.smnp.error.SmnpException import io.smnp.error.SmnpException
import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext
class ImportEvaluator : Evaluator() { class ImportEvaluator : Evaluator() {
override fun supportedNodes() = listOf(ImportNode::class) override fun supportedNodes() = listOf(ImportNode::class)
@@ -18,7 +17,7 @@ class ImportEvaluator : Evaluator() {
try { try {
environment.loadModule(path) environment.loadModule(path)
} catch (e: SmnpException) { } catch (e: SmnpException) {
throw PositionException(EnvironmentException(e, environment), node.position) throw wrapWithContext(e, node.position, environment)
} }
return EvaluatorOutput.ok() return EvaluatorOutput.ok()

View File

@@ -5,11 +5,9 @@ import io.smnp.dsl.ast.model.node.Node
import io.smnp.dsl.ast.model.node.TokenNode import io.smnp.dsl.ast.model.node.TokenNode
import io.smnp.dsl.token.model.enumeration.TokenType import io.smnp.dsl.token.model.enumeration.TokenType
import io.smnp.environment.Environment 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.error.ShouldNeverReachThisLineException
import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.type.enumeration.DataType import io.smnp.type.enumeration.DataType
import io.smnp.type.model.Value import io.smnp.type.model.Value
@@ -24,8 +22,16 @@ class LogicOperatorEvaluator : Evaluator() {
return EvaluatorOutput.value( return EvaluatorOutput.value(
Value.bool( Value.bool(
when (operator) { when (operator) {
TokenType.AND -> if(evalOperand(lhsNode, operator, environment)) evalOperand(rhsNode, operator, environment) else false TokenType.AND -> if (evalOperand(lhsNode, operator, environment)) evalOperand(
TokenType.OR -> if (evalOperand(lhsNode, operator, environment)) true else evalOperand(rhsNode, operator, environment) rhsNode,
operator,
environment
) else false
TokenType.OR -> if (evalOperand(lhsNode, operator, environment)) true else evalOperand(
rhsNode,
operator,
environment
)
else -> throw ShouldNeverReachThisLineException() else -> throw ShouldNeverReachThisLineException()
} }
) )
@@ -36,12 +42,10 @@ class LogicOperatorEvaluator : Evaluator() {
val value = evaluator.evaluate(operand, environment).value val value = evaluator.evaluate(operand, environment).value
if (value.type != DataType.BOOL) { if (value.type != DataType.BOOL) {
throw PositionException( throw contextEvaluationException(
EnvironmentException( "Operator '${operator.token}' supports only bool types, found ${value.typeName}",
EvaluationException("Operator '${operator.token}' supports only bool types, found ${value.typeName}"), operand.position,
environment environment
),
operand.position
) )
} }

View File

@@ -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.LoopNode
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment 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.entity.EvaluatorOutput
import io.smnp.evaluation.model.enumeration.EvaluationResult import io.smnp.evaluation.model.enumeration.EvaluationResult
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.type.enumeration.DataType.* import io.smnp.type.enumeration.DataType.*
import io.smnp.type.model.Value import io.smnp.type.model.Value
@@ -28,13 +26,10 @@ class LoopEvaluator : Evaluator() {
LIST -> evaluateForList(iterator, parametersNode, statementNode, filterNode, environment) LIST -> evaluateForList(iterator, parametersNode, statementNode, filterNode, environment)
MAP -> evaluateForMap(iterator, parametersNode, statementNode, filterNode, environment) MAP -> evaluateForMap(iterator, parametersNode, statementNode, filterNode, environment)
BOOL -> evaluateForBool(iteratorNode, parametersNode, statementNode, filterNode, environment) BOOL -> evaluateForBool(iteratorNode, parametersNode, statementNode, filterNode, environment)
else -> throw PositionException( else -> throw contextEvaluationException(
EnvironmentException( "Expected for-loop with int iterator or foreach-loop with string, list or map iterator or while-loop with bool iterator, found ${iterator.typeName}",
EvaluationException( iteratorNode.position,
"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 environment
), iteratorNode.position
) )
} }
environment.popScope() environment.popScope()
@@ -140,21 +135,18 @@ class LoopEvaluator : Evaluator() {
environment: Environment environment: Environment
): EvaluatorOutput { ): EvaluatorOutput {
if (parametersNode != Node.NONE) { if (parametersNode != Node.NONE) {
throw PositionException( throw contextEvaluationException(
EnvironmentException( "Parameters are not supported in the while-loop",
EvaluationException("Parameters are not supported in the while-loop"), parametersNode.position,
environment environment
),
parametersNode.position
) )
} }
if (filterNode != Node.NONE) { if (filterNode != Node.NONE) {
throw PositionException( throw contextEvaluationException(
EnvironmentException( "Filter is not supported in the while-loop",
EvaluationException("Filter is not supported in the while-loop"), filterNode.position,
environment environment
), filterNode.position
) )
} }
@@ -179,14 +171,10 @@ class LoopEvaluator : Evaluator() {
if (filterNode != Node.NONE) { if (filterNode != Node.NONE) {
val condition = expressionEvaluator.evaluate(filterNode, environment).value val condition = expressionEvaluator.evaluate(filterNode, environment).value
if (condition.type != BOOL) { if (condition.type != BOOL) {
throw PositionException( throw contextEvaluationException(
EnvironmentException( "Filter condition should be evaluated to bool type",
EvaluationException( filterNode.position,
"Filter condition should be evaluated to bool type"
),
environment environment
),
filterNode.position
) )
} }
return condition.value as Boolean return condition.value as Boolean

View File

@@ -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.MapNode
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment 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.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.type.enumeration.DataType.* import io.smnp.type.enumeration.DataType.*
import io.smnp.type.model.Value import io.smnp.type.model.Value
@@ -33,13 +31,7 @@ class MapEvaluator : Evaluator() {
} }
if (key.type !in listOf(BOOL, INT, NOTE, STRING)) { if (key.type !in listOf(BOOL, INT, NOTE, STRING)) {
throw PositionException( throw contextEvaluationException("Invalid map key's type ${key.typeName}", keyNode.position, environment)
EnvironmentException(
EvaluationException("Invalid map key's type ${key.typeName}"),
environment
),
keyNode.position
)
} }
return key return key

View File

@@ -3,10 +3,8 @@ package io.smnp.evaluation.evaluator
import io.smnp.dsl.ast.model.node.MinusOperatorNode import io.smnp.dsl.ast.model.node.MinusOperatorNode
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment 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.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.type.enumeration.DataType import io.smnp.type.enumeration.DataType
import io.smnp.type.model.Value 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.FLOAT -> Value.float(-1.0f * operand.value.value as Float)
DataType.STRING -> Value.string((operand.value.value as String).reversed()) DataType.STRING -> Value.string((operand.value.value as String).reversed())
DataType.LIST -> Value.list((operand.value.value as List<Value>).reversed()) DataType.LIST -> Value.list((operand.value.value as List<Value>).reversed())
else -> throw PositionException( else -> throw contextEvaluationException(
EnvironmentException( "Type ${operand.value.typeName} does not support minus operator",
EvaluationException("Type ${operand.value.typeName} does not support minus operator"), node.position,
environment environment
),
node.position
) )
} }
) )

View File

@@ -3,10 +3,8 @@ package io.smnp.evaluation.evaluator
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.dsl.ast.model.node.NotOperatorNode import io.smnp.dsl.ast.model.node.NotOperatorNode
import io.smnp.environment.Environment 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.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.type.enumeration.DataType import io.smnp.type.enumeration.DataType
import io.smnp.type.model.Value import io.smnp.type.model.Value
@@ -19,13 +17,7 @@ class NotOperatorEvaluator : Evaluator() {
val operand = evaluator.evaluate(operandNode, environment).value val operand = evaluator.evaluate(operandNode, environment).value
if (operand.type != DataType.BOOL) { if (operand.type != DataType.BOOL) {
throw PositionException( throw contextEvaluationException("Only bool types can be negated", operandNode.position, environment)
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)))

View File

@@ -3,10 +3,8 @@ package io.smnp.evaluation.evaluator
import io.smnp.dsl.ast.model.node.Node import io.smnp.dsl.ast.model.node.Node
import io.smnp.dsl.ast.model.node.PowerOperatorNode import io.smnp.dsl.ast.model.node.PowerOperatorNode
import io.smnp.environment.Environment 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.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.type.model.Value import io.smnp.type.model.Value
import kotlin.math.pow import kotlin.math.pow
@@ -20,13 +18,7 @@ class PowerOperatorEvaluator : Evaluator() {
val rhs = evaluator.evaluate(rhsNode, environment).value val rhs = evaluator.evaluate(rhsNode, environment).value
if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) {
throw PositionException( throw contextEvaluationException("Operator ** supports only numeric types", node.position, environment)
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())))

View File

@@ -5,11 +5,9 @@ import io.smnp.dsl.ast.model.node.ProductOperatorNode
import io.smnp.dsl.ast.model.node.TokenNode import io.smnp.dsl.ast.model.node.TokenNode
import io.smnp.dsl.token.model.enumeration.TokenType import io.smnp.dsl.token.model.enumeration.TokenType
import io.smnp.environment.Environment 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.error.ShouldNeverReachThisLineException
import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.evaluation.util.NumberUnification.unify import io.smnp.evaluation.util.NumberUnification.unify
import io.smnp.type.model.Value import io.smnp.type.model.Value
@@ -24,12 +22,10 @@ class ProductOperatorEvaluator : Evaluator() {
val operator = (opNode as TokenNode).token.type val operator = (opNode as TokenNode).token.type
if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) {
throw PositionException( throw contextEvaluationException(
EnvironmentException( "Operator ${operator.token} supports only numeric types",
EvaluationException("Operator ${operator.token} supports only numeric types"), node.position,
environment environment
),
node.position
) )
} }

View File

@@ -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.RelationOperatorNode
import io.smnp.dsl.ast.model.node.TokenNode import io.smnp.dsl.ast.model.node.TokenNode
import io.smnp.environment.Environment 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.error.ShouldNeverReachThisLineException
import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.evaluation.util.NumberUnification.unify import io.smnp.evaluation.util.NumberUnification.unify
import io.smnp.type.model.Value import io.smnp.type.model.Value
@@ -32,13 +30,7 @@ class RelationOperatorEvaluator : Evaluator() {
} }
if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) { if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) {
throw PositionException( throw contextEvaluationException("Operator $operator supports only numeric types", node.position, environment)
EnvironmentException(
EvaluationException("Operator $operator supports only numeric types"),
environment
),
node.position
)
} }
return EvaluatorOutput.value( return EvaluatorOutput.value(

View File

@@ -3,10 +3,8 @@ package io.smnp.evaluation.evaluator
import io.smnp.data.entity.Note import io.smnp.data.entity.Note
import io.smnp.dsl.ast.model.node.* import io.smnp.dsl.ast.model.node.*
import io.smnp.environment.Environment 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.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.math.Fraction import io.smnp.math.Fraction
import io.smnp.type.enumeration.DataType import io.smnp.type.enumeration.DataType
import io.smnp.type.model.Value import io.smnp.type.model.Value
@@ -49,11 +47,10 @@ class StaffEvaluator : Evaluator() {
it: Node it: Node
) { ) {
if (index != 0) { if (index != 0) {
throw PositionException( throw contextEvaluationException(
EnvironmentException( "Time signature can be placed only at the beginning of measure",
EvaluationException("Time signature can be placed only at the beginning of measure"), it.position,
environment environment
), it.position
) )
} }
} }
@@ -69,11 +66,10 @@ class StaffEvaluator : Evaluator() {
currentSignature?.let { currentSignature?.let {
if (evaluatedSignature != it) { if (evaluatedSignature != it) {
val simplified = evaluatedSignature.simplified val simplified = evaluatedSignature.simplified
throw PositionException( throw contextEvaluationException(
EnvironmentException( "Invalid time signature: expected ${it.numerator}/${it.denominator}, got ${simplified.numerator}/${simplified.denominator}",
EvaluationException("Invalid time signature: expected ${it.numerator}/${it.denominator}, got ${simplified.numerator}/${simplified.denominator}"), measure.position,
environment environment
), measure.position
) )
} }
} }

View File

@@ -6,11 +6,9 @@ import io.smnp.dsl.ast.model.node.SumOperatorNode
import io.smnp.dsl.ast.model.node.TokenNode import io.smnp.dsl.ast.model.node.TokenNode
import io.smnp.dsl.token.model.enumeration.TokenType import io.smnp.dsl.token.model.enumeration.TokenType
import io.smnp.environment.Environment 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.error.ShouldNeverReachThisLineException
import io.smnp.evaluation.model.entity.EvaluatorOutput import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.evaluation.util.NumberUnification.unify import io.smnp.evaluation.util.NumberUnification.unify
import io.smnp.math.Fraction import io.smnp.math.Fraction
import io.smnp.type.enumeration.DataType.* 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 { private fun plus(lhs: Value, plusNode: Node, rhs: Value, environment: Environment): Value {
return when { 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()) lhs.type == STRING -> string(lhs.value as String + rhs.value.toString())
areLists(lhs, rhs) -> list(lhs.value as List<Value> + rhs.value as List<Value>) areLists(lhs, rhs) -> list(lhs.value as List<Value> + rhs.value as List<Value>)
lhs.type == NOTE && rhs.type == INT -> note(lhs.value as Note + Fraction(1, rhs.value as Int)) lhs.type == NOTE && rhs.type == INT -> note(lhs.value as Note + Fraction(1, rhs.value as Int))
else -> throw PositionException( else -> throw contextEvaluationException(
EnvironmentException( "The ${lhs.typeName} and ${rhs.typeName} are not supported by + operator",
EvaluationException( plusNode.position,
"The ${lhs.typeName} and ${rhs.typeName} are not supported by + operator"
),
environment environment
), plusNode.position
) )
} }
} }
@@ -63,12 +62,10 @@ class SumOperatorEvaluator : Evaluator() {
int = { (l, r) -> Value.int(l - r) }, int = { (l, r) -> Value.int(l - r) },
float = { (l, r) -> Value.float(l - r) } float = { (l, r) -> Value.float(l - r) }
) )
else throw PositionException( else throw contextEvaluationException(
EnvironmentException( "The - operator supports only numeric values",
EvaluationException("The - operator supports only numeric values"), minusNode.position,
environment environment
),
minusNode.position
) )
} }

View File

@@ -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
)
}
}