From 2ab32b48fa3d165447cb00bd618268c3b7c06388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Thu, 19 Mar 2020 15:10:08 +0100 Subject: [PATCH] Create staff evaluator and rewrite adeste.mus to use new staff notation --- .../evaluator/ExpressionEvaluator.kt | 3 +- .../evaluation/evaluator/StaffEvaluator.kt | 70 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 app/src/main/kotlin/io/smnp/evaluation/evaluator/StaffEvaluator.kt diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ExpressionEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ExpressionEvaluator.kt index a4b89da..bdbcb31 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ExpressionEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ExpressionEvaluator.kt @@ -14,7 +14,8 @@ class ExpressionEvaluator : Evaluator() { FloatLiteralEvaluator(), StringLiteralEvaluator(), BoolLiteralEvaluator(), - NoteLiteralEvaluator(), + NoteLiteralEvaluator(), + StaffEvaluator(), ListEvaluator(), MapEvaluator(), IdentifierEvaluator(), diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/StaffEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/StaffEvaluator.kt new file mode 100644 index 0000000..4142a5b --- /dev/null +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/StaffEvaluator.kt @@ -0,0 +1,70 @@ +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.math.Fraction +import io.smnp.type.enumeration.DataType +import io.smnp.type.model.Value + +class StaffEvaluator : Evaluator() { + private val evaluator = ExpressionEvaluator() + + override fun supportedNodes() = listOf(StaffNode::class) + + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val measures = (node as StaffNode).items + var currentSignature: Fraction? = null + + val list = measures.map { it as MeasureNode }.flatMap { measure -> + val evaluatedMeasure = measure.items.mapNotNull { + when (it) { + is TimeSignatureNode -> { + currentSignature = Fraction( + (it.numerator as IntegerLiteralNode).token.value as Int, + (it.denominator as IntegerLiteralNode).token.value as Int + ) + + null + } + + else -> evaluator.evaluate(it, environment).value + } + } + + val evaluatedSignature = calculateTimeSignature(evaluatedMeasure) + + 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 + ) + } + } + + evaluatedMeasure + } + + return EvaluatorOutput.value(Value.list(list)) + } + + private fun calculateTimeSignature(values: List): Fraction { + return values.fold(Fraction(0, 1)) { acc, value -> + acc + when (value.type) { + DataType.NOTE -> (value.value as Note).duration + DataType.INT -> Fraction(1, value.value as Int) + DataType.LIST -> calculateTimeSignature(value.value as List) + else -> Fraction(0, 1) + } + } + } + +} \ No newline at end of file