diff --git a/Application-overview.md b/Application-overview.md index 8759c03..1badebe 100644 --- a/Application-overview.md +++ b/Application-overview.md @@ -223,4 +223,60 @@ RootNode 1:16 │ └ (not, »not«, 1:33) └─BoolLiteralNode 1:37 └ (bool, »false«, 1:37) -``` \ No newline at end of file +``` + +All parsers-related code is located in `io.smnp.dsl.ast` package. + +## Evaluator +Evaluator is the last stage of SMNP language processing pipeline and also is the heart +of entire SMNP tool, which takes AST as an input and performs programmed operations. +Similar to implemented parser, evaluator works *recursively* because of processing tree-like +structure. +Evaluator's architecture is similar to parser's one. Evaluator consists of +smaller evaluators which are able to evaluate small part of AST's node types. +Similar to parsers, the evaluators also uses a helper method (like `oneOf()`) to improve readability and decrease +the complexity along with the code repeatability. + +Because evaluator introduces as *runtime* term, it also works on special object +called *environment*. The *environment* object contains some runtime information, +like loaded modules (with included functions and methods), call stack with included scopes and some meta information. This object is passed through all evaluators along with AST and its +subtrees. + +Following listening shows the example evaluator which is `if` statement evaluator: +```kotlin +class ConditionEvaluator : Evaluator() { + private val expressionEvaluator = ExpressionEvaluator() + private val defaultEvaluator = DefaultEvaluator() + + override fun supportedNodes() = listOf(ConditionNode::class) + + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val (conditionNode, trueBranchNode, falseBranchNode) = (node as ConditionNode) + val condition = expressionEvaluator.evaluate(conditionNode, environment).value + + if (condition.type != DataType.BOOL) { + throw contextEvaluationException( + "Condition should be of bool type, found '${condition.value}'", + conditionNode.position, + environment + ) + } + + if (condition.value as Boolean) { + return defaultEvaluator.evaluate(trueBranchNode, environment) + } else if (falseBranchNode !is NoneNode) { + return defaultEvaluator.evaluate(falseBranchNode, environment) + } + + return EvaluatorOutput.ok() + } +} +``` +The code above defines list of supported node, which in this case is a list with single element: `ConditionNode`. The `ConditionNode` is product of `ConditionParser`'s work which handles the `if` statements. +The `tryToEvaluate()` method contains the actually logic of evaluation, and in this case it: +1. evaluates the condition using `ExpressionEvaluator` (it always returns a value) +2. asserts the value to be of `bool` type - if it's other than `bool`, an exception is begin thrown +3. evaluates the `trueBranchNode` if the value is evaluated to `true` +4. if the condition is evaluated to `false`, it checks if `falseBranchNode` (that comes from `else` clause) is present. If so, it's being evaluated. + +All evaluator-related code is located in `io.smnp.evaluation` package. \ No newline at end of file