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 {
ArgParser(args).parseInto(::Arguments).run {
try {
val interpreter = DefaultInterpreter()
val environment = DefaultEnvironment()
val interpreter = DefaultInterpreter()
val environment = DefaultEnvironment()
try {
environment.setVariable("__param__", Value.wrap(parameters.toMap()))
when {
@@ -51,6 +51,10 @@ fun main(args: Array<String>): Unit = mainBody {
System.err.println("\nStack trace:\n${it.environment.stackTrace()}")
}
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.environment.Environment
import io.smnp.error.EnvironmentException
import io.smnp.error.EvaluationException
import io.smnp.error.PositionException
import io.smnp.error.SmnpException
import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
class AccessOperatorEvaluator : Evaluator() {
override fun supportedNodes() = listOf(AccessOperatorNode::class)
@@ -20,12 +19,10 @@ class AccessOperatorEvaluator : Evaluator() {
is IdentifierNode -> {
val rhs = rhsNode.token.rawValue
EvaluatorOutput.value(
lhs.properties[rhs] ?: throw PositionException(
EnvironmentException(
EvaluationException("Unknown property $rhs of type ${lhs.typeName}"),
environment
),
rhsNode.position
lhs.properties[rhs] ?: throw contextEvaluationException(
"Unknown property $rhs of type ${lhs.typeName}",
rhsNode.position,
environment
)
)
}
@@ -36,16 +33,15 @@ class AccessOperatorEvaluator : Evaluator() {
(argsNode as FunctionCallArgumentsNode).items.map { evaluator.evaluate(it, environment).value }
try {
return EvaluatorOutput.value(environment.invokeMethod(lhs, identifier, arguments))
} catch(e: SmnpException) {
throw PositionException(EnvironmentException(e, environment), identifierNode.position)
} catch (e: SmnpException) {
throw ContextExceptionFactory.wrapWithContext(e, identifierNode.position, environment)
}
}
else -> {
throw PositionException(
EnvironmentException(
EvaluationException("Invalid property access type - only property name and method call are allowed"),
environment
), rhsNode.position
throw contextEvaluationException(
"Invalid property access type - only property name and method call are allowed",
rhsNode.position,
environment
)
}
}

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

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

View File

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

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

View File

@@ -5,24 +5,23 @@ import io.smnp.dsl.ast.model.node.FunctionCallNode
import io.smnp.dsl.ast.model.node.IdentifierNode
import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment
import io.smnp.error.EnvironmentException
import io.smnp.error.PositionException
import io.smnp.error.SmnpException
import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext
class FunctionCallEvaluator : Evaluator() {
override fun supportedNodes() = listOf(FunctionCallNode::class)
override fun supportedNodes() = listOf(FunctionCallNode::class)
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
val evaluator = assert(ExpressionEvaluator(), "expression")
val (identifierNode, argsNode) = node as FunctionCallNode
val identifier = (identifierNode as IdentifierNode).token.rawValue
val arguments = (argsNode as FunctionCallArgumentsNode).items.map { evaluator.evaluate(it, environment).value }
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
val evaluator = assert(ExpressionEvaluator(), "expression")
val (identifierNode, argsNode) = node as FunctionCallNode
val identifier = (identifierNode as IdentifierNode).token.rawValue
val arguments = (argsNode as FunctionCallArgumentsNode).items.map { evaluator.evaluate(it, environment).value }
try {
return EvaluatorOutput.value(environment.invokeFunction(identifier, arguments))
} catch(e: SmnpException) {
throw PositionException(EnvironmentException(e, environment), identifierNode.position)
}
}
try {
return EvaluatorOutput.value(environment.invokeFunction(identifier, arguments))
} catch (e: SmnpException) {
throw wrapWithContext(e, identifierNode.position, environment)
}
}
}

View File

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

View File

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

View File

@@ -4,23 +4,22 @@ import io.smnp.dsl.ast.model.node.IdentifierNode
import io.smnp.dsl.ast.model.node.ImportNode
import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment
import io.smnp.error.EnvironmentException
import io.smnp.error.PositionException
import io.smnp.error.SmnpException
import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.wrapWithContext
class ImportEvaluator : Evaluator() {
override fun supportedNodes() = listOf(ImportNode::class)
override fun supportedNodes() = listOf(ImportNode::class)
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
val path = (node as ImportNode).path.joinToString(".") { (it as IdentifierNode).token.rawValue }
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
val path = (node as ImportNode).path.joinToString(".") { (it as IdentifierNode).token.rawValue }
try {
environment.loadModule(path)
} catch(e: SmnpException) {
throw PositionException(EnvironmentException(e, environment), node.position)
}
try {
environment.loadModule(path)
} catch (e: SmnpException) {
throw wrapWithContext(e, node.position, environment)
}
return EvaluatorOutput.ok()
}
return EvaluatorOutput.ok()
}
}

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

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

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

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

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.NotOperatorNode
import io.smnp.environment.Environment
import io.smnp.error.EnvironmentException
import io.smnp.error.EvaluationException
import io.smnp.error.PositionException
import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.type.enumeration.DataType
import io.smnp.type.model.Value
@@ -19,13 +17,7 @@ class NotOperatorEvaluator : Evaluator() {
val operand = evaluator.evaluate(operandNode, environment).value
if (operand.type != DataType.BOOL) {
throw PositionException(
EnvironmentException(
EvaluationException("Only bool types can be negated"),
environment
),
operandNode.position
)
throw contextEvaluationException("Only bool types can be negated", operandNode.position, environment)
}
return EvaluatorOutput.value(Value.bool(!(operand.value as Boolean)))

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.PowerOperatorNode
import io.smnp.environment.Environment
import io.smnp.error.EnvironmentException
import io.smnp.error.EvaluationException
import io.smnp.error.PositionException
import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.util.ContextExceptionFactory.contextEvaluationException
import io.smnp.type.model.Value
import kotlin.math.pow
@@ -20,13 +18,7 @@ class PowerOperatorEvaluator : Evaluator() {
val rhs = evaluator.evaluate(rhsNode, environment).value
if (!lhs.type.isNumeric() || !rhs.type.isNumeric()) {
throw PositionException(
EnvironmentException(
EvaluationException("Operator ** supports only numeric types"),
environment
),
node.position
)
throw contextEvaluationException("Operator ** supports only numeric types", node.position, environment)
}
return EvaluatorOutput.value(Value.float((lhs.value as Number).toFloat().pow((rhs.value as Number).toFloat())))

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

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

View File

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

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

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