Updated Application overview (markdown)
@@ -280,3 +280,75 @@ The `tryToEvaluate()` method contains the actually logic of evaluation, and in t
|
|||||||
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.
|
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.
|
All evaluator-related code is located in `io.smnp.evaluation` package.
|
||||||
|
|
||||||
|
## Interpreter
|
||||||
|
`Interpreter` actually isn't an another language processing
|
||||||
|
stage, rather it is a facade that composes each stage into single pipeline,
|
||||||
|
accepting a raw SMNP code as an input.
|
||||||
|
It also accepts additional parameters, like `printTokens`, `printAst` and `dryRun`.
|
||||||
|
|
||||||
|
So far, SMNP provides two types of interpreters:
|
||||||
|
* `LanguageModuleInterpreter` (with its implementation: `DefaultLanguageModuleInterpreter`) and is used only by _Language Module Providers_ and _Hybrid Module Providers_.
|
||||||
|
* `DefaultInterpreter` which is the standard interpreter that is used for user's input (in form of both scripts and inline code snippets).
|
||||||
|
|
||||||
|
The difference between these two interpreters is the `LanguageModuleInterpreter` does support only definitions of functions and methods at the top level of script (technically, in `RootNode`), whereas the `DefaultInterpreter` allows you to have each available statement at the top level of script.
|
||||||
|
|
||||||
|
Following snippets shows the code of `DefaultInterpreter`:
|
||||||
|
```kotlin
|
||||||
|
class DefaultInterpreter {
|
||||||
|
private val tokenizer = DefaultTokenizer()
|
||||||
|
private val parser = RootParser()
|
||||||
|
private val evaluator = RootEvaluator()
|
||||||
|
|
||||||
|
fun run(
|
||||||
|
code: String,
|
||||||
|
environment: Environment = DefaultEnvironment(),
|
||||||
|
printTokens: Boolean = false,
|
||||||
|
printAst: Boolean = false,
|
||||||
|
dryRun: Boolean = false
|
||||||
|
): Environment {
|
||||||
|
val lines = code.split("\n")
|
||||||
|
return run(lines, "<inline>", environment, printTokens, printAst, dryRun)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun run(
|
||||||
|
file: File,
|
||||||
|
environment: Environment = DefaultEnvironment(),
|
||||||
|
printTokens: Boolean = false,
|
||||||
|
printAst: Boolean = false,
|
||||||
|
dryRun: Boolean = false
|
||||||
|
): Environment {
|
||||||
|
val lines = file.readLines()
|
||||||
|
return run(lines, file.canonicalPath, environment, printTokens, printAst, dryRun)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun run(
|
||||||
|
lines: List<String>,
|
||||||
|
source: String,
|
||||||
|
environment: Environment,
|
||||||
|
printTokens: Boolean,
|
||||||
|
printAst: Boolean,
|
||||||
|
dryRun: Boolean
|
||||||
|
): Environment {
|
||||||
|
environment.loadModule("smnp.lang")
|
||||||
|
|
||||||
|
val tokens = tokenizer.tokenize(lines, source)
|
||||||
|
if (printTokens) println(tokens)
|
||||||
|
|
||||||
|
val ast = parser.parse(tokens)
|
||||||
|
if (printAst) ast.node.pretty()
|
||||||
|
|
||||||
|
if (!dryRun) {
|
||||||
|
val result = evaluator.evaluate(ast.node, environment)
|
||||||
|
|
||||||
|
if (result.result == EvaluationResult.FAILED) {
|
||||||
|
throw RuntimeException("Evaluation failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return environment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can think of `DefaultInterpreter` as an endpoint for `core` module that is ready to be used by `app` module or any other application willing to make use of SMNP.
|
||||||
Reference in New Issue
Block a user