Updated Application overview (markdown)

Bartłomiej Przemysław Pluta
2020-03-30 18:26:47 +02:00
parent 980880f7d1
commit 08e561a626

@@ -2,7 +2,7 @@
[[schemas/architecture.svg]] [[schemas/architecture.svg]]
The system is composed of following components (which are technically Gradle subprojects) : The system is composed of following components (which are technically Gradle subprojects) :
* `core` - the SMNP language engine consisting of interpreter (being actually a facade for tokenizer, parser and evaluator), as well as the modules management system * `core` - the SMNP language engine consisting of interpreter (being actually a facade for tokenizer, parser and evaluator), as well as the modules' management system
* `app` - the commandline-based frontend for `core` component * `app` - the commandline-based frontend for `core` component
* modules (`smnp.lang`, `smnp.io`, `smnp.audio.synth` etc.) - a set of external modules that extends the functionality of SMNP scripts * modules (`smnp.lang`, `smnp.io`, `smnp.audio.synth` etc.) - a set of external modules that extends the functionality of SMNP scripts
* `api` - component that provides shared interfaces and abstract classes common for both `core` and each module components. * `api` - component that provides shared interfaces and abstract classes common for both `core` and each module components.
@@ -149,10 +149,10 @@ parenthesesExpr ::= '(' expr ')' ;
atom ::= parenthesesExpr | identifier | staff | list | map ; atom ::= parenthesesExpr | identifier | staff | list | map ;
``` ```
Therefore `allOf(a, b, c) {...}` is equivalent of `a = a b c`, whereas `oneOf(a, b, c)` is equivalent of `a = a | b | c`. Therefore, `allOf(a, b, c) {...}` is equivalent of `a = a b c`, whereas `oneOf(a, b, c)` is equivalent of `a = a | b | c`.
### Parsers' cascade ### Parsers' cascade
Parsers are cascadingly composed and thanks to that, they are able to parse a one-dimensional tokens stream to tree structure. For example, the mentioned before `AtomParser` is used by `UnitParser` which is responsible for parsing minus operator and dot operator. In turn, the `UnitParser` is used by `FactorParser` that is responsible for parsing `not` operator and power operator. The `FactorParser` is used by `TermParser` which is responsible for parsing product operator. The `TermParser` is used by `SubexpressionParser` which provides production rules for logic operators, relation operators etc. The `SubexpressionParser` is used by `ExpressionParser` which technically is `oneOf`-based wrapper for `SubexpressionParser` and `LoopParser`. The `ExpressionParser represents all constructions that can product a value and is used by `StatementParser` which is eventually used by `RootParser`. Parsers are cascaded composed and thanks to that, they are able to parse a one-dimensional tokens' stream to tree structure. For example, the mentioned before `AtomParser` is used by `UnitParser` which is responsible for parsing minus operator and dot operator. In turn, the `UnitParser` is used by `FactorParser` that is responsible for parsing `not` operator and power operator. The `FactorParser` is used by `TermParser` which is responsible for parsing product operator. The `TermParser` is used by `SubexpressionParser` which provides production rules for logic operators, relation operators etc. The `SubexpressionParser` is used by `ExpressionParser` which technically is `oneOf`-based wrapper for `SubexpressionParser` and `LoopParser`. The `ExpressionParser represents all constructions that can product a value and is used by `StatementParser` which is eventually used by `RootParser`.
The order of each parser in the cascade determines the precedence of each operation and has influence on the The order of each parser in the cascade determines the precedence of each operation and has influence on the
AST's shape. Take look at the following example: AST's shape. Take look at the following example:
@@ -194,8 +194,33 @@ class SubexpressionParser : Parser() {
return expr4Parser.parse(input) return expr4Parser.parse(input)
} }
``` ```
This is a code of `SubexpressionParser` and it consists of 4 subparser cascadingly composed. Because of the `expr4Parser` (responsible for `or` operator) is defined using `expr3Parser` (responsible for `and` operator), the `or` operator has a higher precendee than `and` operator (please compare [[Operators#Operators precedence]]. This is a code of `SubexpressionParser` and it consists of 4 subparsers cascaded composed. Because of the `expr4Parser` (responsible for `or` operator) is defined using `expr3Parser` (responsible for `and` operator), the `or` operator has a higher precedence than `and` operator (please compare [[Operators#Operators precedence]]).
Take a look at the following AST:
Following listening features the composition of `and` and `or` operator nodes honoring their precedence:
``` ```
$ smnp --ast --dry-run -c "true and false or not false and not false;" $ smnp --ast --dry-run -c "true and false or not false and not false;"
RootNode 1:16
└─LogicOperatorNode 1:16
├─LogicOperatorNode 1:6
│ ├─BoolLiteralNode 1:1
│ │ └ (bool, »true«, 1:1)
│ ├─TokenNode 1:6
│ │ └ (and, »and«, 1:6)
│ └─BoolLiteralNode 1:10
│ └ (bool, »false«, 1:10)
├─TokenNode 1:16
│ └ (or, »or«, 1:16)
└─LogicOperatorNode 1:29
├─NotOperatorNode 1:19
│ ├─TokenNode 1:19
│ │ └ (not, »not«, 1:19)
│ └─BoolLiteralNode 1:23
│ └ (bool, »false«, 1:23)
├─TokenNode 1:29
│ └ (and, »and«, 1:29)
└─NotOperatorNode 1:33
├─TokenNode 1:33
│ └ (not, »not«, 1:33)
└─BoolLiteralNode 1:37
└ (bool, »false«, 1:37)
``` ```