Skip to content

Commit 4a7f42a

Browse files
committed
Doc updates
1 parent 745eb59 commit 4a7f42a

File tree

8 files changed

+175
-184
lines changed

8 files changed

+175
-184
lines changed

Docs/FexElementsRef.md

Lines changed: 131 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
2-
3-
<a id="id-toc"></a>
41
# Fex Element Reference
52

63
Flow Expressions are defined by a structure of *FexElements* built via a Fluent API. This defines the logical flow and operations of the flow expression in a very readable format closely resembling a flow *grammar*:
@@ -39,47 +36,58 @@ mechanism with methods of the following basic form:
3936
> - The details of each element type are documented below.
4037
> - **Note:** Only elements marked with an Astrix * may be constructed via the FlowExpression factory.
4138
39+
40+
<a id="id-toc"></a>
41+
4242
| Fex Element | Brief |
4343
| :---------- | :---- |
4444
| [`Seq(s => s...)*`](#id-seq) | **Sequence:** Series of steps that must complete in full in order to pass. |
45+
| **Operators:** | *Perform an operation on the context producing a boolean result.<br> (see also [FexScanner operator extensions](Docs/FexScannerExt.md) when using FexScanner as the context)* |
4546
| [`Op(Func<Ctx, bool> op)`](#id-op) | **Operator:** Perform an operation on the Context returning a boolean result. |
4647
| [`ValidOp(Action<Ctx> action)`](#id-validop) | **Always valid operator:** Perform and operation on the Context and always returns true. |
47-
| [`ActValue<V>(Action<V> valueAction)`](#id-value) | **Value Action:** Bind and action to an operator that records a value. |
48+
| [`GlobalPreOp(Action<Ctx> preOp)`<br/>`PreOp(Action<T> preOp)`](#id-preop) | **Pre-Operators:** Attach pre-operations to operators. |
49+
| **Flow Control:** | *These elements control the flow of an expression.* |
4850
| [`Opt(o => o...)*` ](#id-opt) | **Optional:** Optional sequence. |
4951
| [`OneOf(o => o...)*`](#id-oneof) | **One Of:** Set of sequences that are *Or'd* together and one of them must succeed to pass. |
5052
| [`OptOneOf(o => o...)`*](#id-optoneof) | **Optional One Of:** Optionally perform a OneOf. |
5153
| [`NotOneOf(o => o...)*`](#id-notoneof) | **Not One Of:** Inverse of OneOf. |
5254
| [`BreakOn(o => o...)`](#id-notoneof) | **Alias for NotOneOf:** Reads better in loops. |
5355
| [`Rep(repMin, repMax, r => r...)*`<br/>`Rep(count, r => r...)*`<br/>`Rep0N(r => r...)*`<br/>`Rep1N(r => r...)`*](#id-rep) | **Repeat:** Repeated sequences. |
5456
| [`RepOneOf(repMin, repMax, r => r...)`*](#id-reponeof) | **Repeat One Of:** Repeated a OneOf expression. |
55-
| [`Fex(FexElement1, FexElement2, ...)`](#id-fex) | **Include FexElements:** Include a set of previously defined FexElements. |
57+
| **Actions:** | *Perform actions based on the current state of a production.<br> (see also [FexScanner action extensions](Docs/FexScannerExt.md) when using FexScanner as the context)* |
5658
| [`Act(Action<Ctx> action)`](#id-act) | **Action:** Perform any external Action based on the current state of the production. |
59+
| [`ActValue<V>(Action<V> valueAction)`](#id-value) | **Value Action:** Bind and action to an operator that records a value. |
5760
| [`RepAct(int repeat, Action<Ctx, int> action)`](#id-repact) | **Repeat Action:** Perform any external repeated Action based on the current state of the production. |
61+
| **Error Handling:** | |
5862
| [`OnFail(Action<Ctx> failAction)`](#id-onfail) | **Fail Action:** Perform an Action if the last operator or production failed. |
5963
| [`Fail(Action<Ctx> failAction)`](#id-fail) | **Force Fail Action:** Force a failure and perform an Action. |
6064
| [`Assert(Func<Ctx, bool> assert, Action<Ctx> failAction)`](#id-assert) | **Assert** if a condition is true else performs failAction. |
65+
| **Inclusion, Forward referencing and Recursion:** | |
66+
| [`Fex(FexElement1, FexElement2, ...)`](#id-fex) | **Include FexElements:** Include a set of previously defined FexElements. |
6167
| [`RefName(string name), Ref(string refName)`](#id-ref) | Forward Referencing and inclusion.|
6268
| [`OptSelf()`](#id-optself) | Optional recursive inclusion of the current production sequence within itself. |
63-
| [`GlobalPreOp(Action<Ctx> preOp)`<br/>`PreOp(Action<T> preOp)`](#id-preop) | **Pre-Operators:** Attach pre-operations to operators. |
69+
| **Tracing:** | *Debugging aid.* |
6470
| [`Trace(Func<Ctx, string> traceMessage, int level = 0)`<br/>`TraceOp(Func<Ctx, string> traceMessage, int level = 0)`<br/>`TraceOp(Func<Ctx, object, string> traceMessage, int level)`](#id-trace) | Tracing utilities. |
6571

6672
---
6773
<a id="id-seq"></a>
6874
### `Sequence: Seq(s => s...)`
69-
```mermaid
70-
graph LR
71-
subgraph "Seq (Sequence)"
72-
direction LR
73-
A[FexElement 1] --> B[FexElement 2] -.-> C[FexElement n];
74-
end
75-
```
75+
7676
A Sequence defines a series of steps that must complete in full in order to pass. Sequences are the primary building structures of flow expressions:
7777

7878
- A sequence consists of one or more FexElements.
7979
- All steps in a sequence must succeed for the sequence to pass.
8080
- *Action* FexElements don't affect the validity of a sequence.
8181
- Steps in the sequence may be optional (see Opt...) and these also don't affect the validity of a sequence.
8282

83+
```mermaid
84+
graph LR
85+
subgraph "Seq"
86+
direction LR
87+
A[FexElement 1] --> B[FexElement 2] -.-> C[FexElement n];
88+
end
89+
```
90+
8391
The following is a simple example of sequences.
8492

8593
```csharp
@@ -158,26 +166,27 @@ OneOf(o => o
158166
[`TOC`](#id-toc)
159167

160168
---
161-
<a id="id-value"></a>
162-
### `Value Action: ActValue<V>(Action<V> valueAction)`
169+
<a id="id-preop"></a>
170+
### Pre-Operators:
163171

164-
This binds an Action to an operator (Op) that recorded a value, and should follow directly after the Op:
172+
Pre-operators execute before an Op (operator) as and Action on the context:
173+
- Typically used to skip spaces, comments and newlines etc. before tokens when parsing scripts.
174+
- Pre-operators are efficient an only execute once while trying several lookahead operations.
165175

166-
- If the Op succeeds, and has a non-null value, then valueAction is invoked.
167-
- The value is recorded as an object and must be cast to the actual type before use (via V, or it may be inferred from the action).
168-
- Note that there a several other ways to do this:
169-
- The Op could directly perform an operation on a value it produces.
170-
- Context operator extensions may include a valueAction as part of the operator.
176+
<br/>
171177

172-
```csharp
173-
var digits = "";
178+
> **`GlobalPreOp(Action<Ctx> preOp)`**
179+
> - Binds a pre-operator to all subsequent operators.
174180
175-
// Basic form where Digit() records the digit character just read
176-
Rep(3, r => r.Digit().ActValue<char>(v => digits += v))
181+
<br/>
182+
183+
> **`PreOp(Action<Ctx> preOp)`**
184+
> - Use directly after an operator to bind a pre-operator to the preceding operator:
185+
> - The preOp may be null if no PreOp should be executed.
186+
> - The above mechanism could be used to *switch off* the GlobalPreOp's for selected Op's.
187+
188+
See the Expression example which uses a GlobalPreOp to skip all spaces before the *tokens*.
177189

178-
// Context Operator Extension configured to operate on the value directly
179-
Rep(3, r => r.Digit(v => digits += v))
180-
```
181190
[`TOC`](#id-toc)
182191

183192
---
@@ -192,6 +201,13 @@ Opt defines and optional sequence and the following rules apply:
192201
- If any of the leading optional steps or first non-optional step passes then the remainder must complete.
193202
- If the leading optional step(s) and the first non-optional fail then the sequence is aborted.
194203

204+
```mermaid
205+
graph LR
206+
subgraph "Opt"
207+
A[Seq]
208+
end
209+
```
210+
195211
```csharp
196212
// Parses: (ab)? (c)? d
197213
Seq(s => s
@@ -210,6 +226,14 @@ OneOf defines a set of sequences, where one of the sequences must succeed:
210226

211227
- Execution *breaks out* at the point where it succeeds.
212228
- If none of the sequences pass then the production fails.
229+
230+
```mermaid
231+
graph LR
232+
subgraph OneOf
233+
direction LR
234+
A[Seq 1] -->|or| B[Seq 2] -.->|or| C[Seq 3];
235+
end
236+
```
213237

214238
Some examples from the *expression parser* below:
215239

@@ -238,6 +262,14 @@ Define an optional set of sequences where one of them may pass:
238262
- Same as OneOf but does not fail if no sequence passes.
239263
- Execution *breaks out* at the point where it does succeeds.
240264

265+
```mermaid
266+
graph LR
267+
subgraph OptOneOf
268+
direction LR
269+
A[Seq 1] -->|or| B[Seq 2] -.->|or| C[Seq 3];
270+
end
271+
```
272+
241273
```csharp
242274
OptOneOf(o => o
243275
.Seq(s => s.Ch('+').Ref("factor").Act(c => Calc((n1, n2) => n1 + n2)))
@@ -257,6 +289,16 @@ Define a set of Sequences, where it fails if any sequence passes (inverse of One
257289
- If any of the sequences pass then the production fails.
258290
- `BreakOn(o => o...)` is an alias for NotOneOf that reads better in loops.
259291

292+
```mermaid
293+
graph LR
294+
subgraph NotOneOf
295+
subgraph "Not!"
296+
direction LR
297+
A[Seq 1] -->|or| B[Seq 2] -.->|or| C[Seq 3];
298+
end
299+
end
300+
```
301+
260302
In the example below if any of the steps in the BreakOn sequence passes, then BreakOn/NotOneOf fails and the loop is terminated because it was the first step in the Rep inner-sequence (see Rep rules).
261303

262304
```csharp
@@ -290,6 +332,14 @@ For convenience, several Repeat configurations are available:
290332
- `Rep0N(r => r...) -> Rep(0, -1, r => r...)`
291333
- `Rep1N(r => r...) -> Rep(1, -1, r => r...)`
292334

335+
```mermaid
336+
graph LR
337+
subgraph "Rep (min, max)"
338+
direction LR
339+
A[Seq];
340+
end
341+
```
342+
293343
```csharp
294344
Rep(3, -1, r => r.Ch('a').Ch('b'));
295345
Rep(3, 9, r => r.Ch('a').Ch('b');)
@@ -311,6 +361,14 @@ Repeat a OneOf construct and the following rules apply:
311361
- repMax = -1: Repeat repMin to N times.Treats the OneOf, after repMin, as an optional (see Opt rules).<br/>
312362
- repMax > 0: Repeat repMin to repMax times and then terminates the loop.
313363

364+
```mermaid
365+
graph LR
366+
subgraph "RepOneOf (min, max)"
367+
direction LR
368+
A[Seq 1] -->|or| B[Seq 2] -.->|or| C[Seq 3];
369+
end
370+
```
371+
314372
```csharp
315373
RepOneOf(0, -1, r => r
316374
.Seq(s => s.Ch('+').Ref("factor").Act(c => Calc((n1, n2) => n1 + n2)))
@@ -319,24 +377,6 @@ RepOneOf(0, -1, r => r
319377
```
320378
[`TOC`](#id-toc)
321379

322-
---
323-
<a id="id-fex"></a>
324-
### `Include FexElements: Fex(FexElement1, FexElement2, ...)`
325-
326-
Include a set of previously defined FexElements (sub-expressions):
327-
328-
- For complex expressions it may be easier to factorize out smaller sub-expressions which are then included to form the whole.
329-
- A common sub-expressions may also be reused in several places using Fex(...).
330-
- In either case it makes the overall expression easier to read and maintain.
331-
332-
```csharp
333-
var abSequence = fex.Seq(s => s.Ch('(') .Rep(3, r => r.Ch('a').Ch('b')) .Ch(')'));
334-
var cdSequence = fex.Seq(s => s.Ch('[') .Rep(3, r => r.Ch('c').Ch('d')) .Ch(']'));
335-
336-
var fullSequence = fex.Seq(s => s.Ch('{').Fex(abSequence, cdSequence).Ch('}'));
337-
```
338-
[`toc`)](#id-toc)
339-
340380
---
341381
<a id="id-act"></a>
342382
### `Action: Act(Action<Ctx> action)`
@@ -356,6 +396,29 @@ Seq(s => s.Ch('-').Ref("unary").Act(a => numStack.Push(-numStack.Pop())))
356396
```
357397
[`TOC`](#id-toc)
358398

399+
---
400+
<a id="id-value"></a>
401+
### `Value Action: ActValue<V>(Action<V> valueAction)`
402+
403+
This binds an Action to an operator (Op) that recorded a value, and should follow directly after the Op:
404+
405+
- If the Op succeeds, and has a non-null value, then valueAction is invoked.
406+
- The value is recorded as an object and must be cast to the actual type before use (via V, or it may be inferred from the action).
407+
- Note that there a several other ways to do this:
408+
- The Op could directly perform an operation on a value it produces.
409+
- Context operator extensions may include a valueAction as part of the operator.
410+
411+
```csharp
412+
var digits = "";
413+
414+
// Basic form where Digit() records the digit character just read
415+
Rep(3, r => r.Digit().ActValue<char>(v => digits += v))
416+
417+
// Context Operator Extension configured to operate on the value directly
418+
Rep(3, r => r.Digit(v => digits += v))
419+
```
420+
[`TOC`](#id-toc)
421+
359422
---
360423
<a id="id-repact"></a>
361424
### `Repeat Action: RepAct(int repeat, Action<Ctx, int> action)`
@@ -425,6 +488,24 @@ Seq(s => s.Ch('/').Ref("unary")
425488
```
426489
[`TOC`](#id-toc)
427490

491+
---
492+
<a id="id-fex"></a>
493+
### `Include FexElements: Fex(FexElement1, FexElement2, ...)`
494+
495+
Include a set of previously defined FexElements (sub-expressions):
496+
497+
- For complex expressions it may be easier to factorize out smaller sub-expressions which are then included to form the whole.
498+
- A common sub-expressions may also be reused in several places using Fex(...).
499+
- In either case it makes the overall expression easier to read and maintain.
500+
501+
```csharp
502+
var abSequence = fex.Seq(s => s.Ch('(') .Rep(3, r => r.Ch('a').Ch('b')) .Ch(')'));
503+
var cdSequence = fex.Seq(s => s.Ch('[') .Rep(3, r => r.Ch('c').Ch('d')) .Ch(']'));
504+
505+
var fullSequence = fex.Seq(s => s.Ch('{').Fex(abSequence, cdSequence).Ch('}'));
506+
```
507+
[`toc`)](#id-toc)
508+
428509
---
429510
<a id="id-ref"></a>
430511
### `Forward Reference: RefName(string name), Ref(string refName)`
@@ -466,33 +547,9 @@ Seq(s => s.Digit().OptSelf().IsEos());
466547

467548
A Flow expressions implement recursion via Forward Referencing, OptSelf or Fex inclusion.
468549

469-
> **Note** Flow Expressions do not support [*Left Recursion*](https://en.wikipedia.org/wiki/Left_recursion) (which will cause an endless loop and possibly a stack overflow)
550+
> **Note:** Flow Expressions do not support [*Left Recursion*](https://en.wikipedia.org/wiki/Left_recursion) (which will cause an endless loop and possibly a stack overflow)
470551
471552

472-
[`TOC`](#id-toc)
473-
474-
---
475-
<a id="id-preop"></a>
476-
### Pre-Operators:
477-
478-
Pre-operators execute before an Op (operator) as and Action on the context:
479-
- Typically used to skip spaces, comments and newlines etc. before tokens when parsing scripts.
480-
- Pre-operators are efficient an only execute once while trying several lookahead operations.
481-
482-
<br/>
483-
484-
> **`GlobalPreOp(Action<Ctx> preOp)`**
485-
> - Binds a pre-operator to all subsequent operators.
486-
487-
<br/>
488-
489-
> **`PreOp(Action<Ctx> preOp)`**
490-
> - Use directly after an operator to bind a pre-operator to the preceding operator:
491-
> - The preOp may be null if no PreOp should be executed.
492-
> - The above mechanism could be used to *switch off* the GlobalPreOp's for selected Op's.
493-
494-
See the Expression example which uses a GlobalPreOp to skip all spaces before the *tokens*.
495-
496553
[`TOC`](#id-toc)
497554

498555
---
@@ -561,7 +618,6 @@ public class ConsoleTracer : IFexTracer
561618

562619
**Example usage of the above:**
563620
```csharp
564-
565621
// Enable tracing via an IFexTracer in the FlowExpression constructor.
566622
var fex = new FlowExpression<FexScanner>(new ConsoleTracer());
567623

@@ -571,17 +627,17 @@ var after = fex.Seq(s => s.Trace(c => "try after sequence.")
571627
.Ch('c').OnFail("c expected")
572628
);
573629

574-
// Example output: try after sequence.
630+
// Output: try after sequence.
575631
576632
// Trace Op without value (since value is known):
577633
Ch('+').TraceOp(c => "Check for +")
578634

579-
// Example output: Check for + [False]
635+
// Output: Check for + [False]
580636
581637
// Trace Op with value:
582638
AnyCh("+-", v => opStack.Push(v)).TraceOp((c, v) => $"AnyCh val: {v}")
583639

584-
// Example output: AnyCh val: + [True]
640+
// Output: AnyCh val: + [True]
585641
```
586642

587643
[`TOC`](#id-toc)

0 commit comments

Comments
 (0)