|
| 1 | +# Parsing |
| 2 | + |
| 3 | +Formality's `#[term]` and `#[grammar]` attributes let you specify the grammar that will be used to parse your structs/enums. |
| 4 | + |
| 5 | +For structs, there is a single grammar, specified as part of the term: |
| 6 | + |
| 7 | +```rust |
| 8 | +#[term( /* grammar here */ )] |
| 9 | +struct MyStruct { } |
| 10 | +``` |
| 11 | + |
| 12 | +For enums, the grammar is placed in `#[grammar]` attributes on each variant: |
| 13 | + |
| 14 | +```rust |
| 15 | +#[term] |
| 16 | +struct MyEnum { |
| 17 | + #[grammar( /* grammar here */ )] |
| 18 | + Foo(...), |
| 19 | +} |
| 20 | +``` |
| 21 | + |
| 22 | +### Ambiguity, |
| 23 | + |
| 24 | +When parsing an enum there will be multiple possibilities. We will attempt to parse them all. If more than one succeeds, the parse is deemed ambiguous and an error is reported. If zero succeed, we will report back a parsing error, attempting to localize the problem as best we can. |
| 25 | + |
| 26 | +### Symbols |
| 27 | + |
| 28 | +A grammar consists of a series of *symbols*. Each symbol matches some text in the input string. Symbols come in two varieties: |
| 29 | + |
| 30 | +* Most things are *terminals* or *tokens*: this means they just match themselves: |
| 31 | + * For example, the `*` in `#[grammar($v0 * $v1)]` is a terminal, and it means to parse a `*` from the input. |
| 32 | + * Delimeters are accepted but must be matched, e.g., `( /* tokens */ )` or `[ /* tokens */ ]`. |
| 33 | +* Things beginning with `$` are *nonterminals* -- they parse the contents of a field. The grammar for a field is generally determined from its type. |
| 34 | + * If fields have names, then `$field` should name the field. |
| 35 | + * For position fields (e.g., the T and U in `Mul(Expr, Expr)`), use `$v0`, `$v1`, etc. |
| 36 | + * Exception: `$$` is treated as the terminal `'$'`. |
| 37 | +* Nonterminals can also accept modes: |
| 38 | + * `$field` -- just parse the field's type |
| 39 | + * `$*field` -- the field must be a `Vec<T>` -- parse any number of `T` instances. Something like `[ $*field ]` would parse `[f1 f2 f3]`, assuming `f1`, `f2`, and `f3` are valid values for `field`. |
| 40 | + * If the next token after `$*field` is a terminal, `$*` uses it as lookahead. The grammar `[ $*field ]`, for example, would stop parsing once a `]` is observed. |
| 41 | + * If the `$*field` appears at the end of the grammar or the next symbol is a nonterminal, then the type of `field` must define a grammar that begins with some terminal or else your parsing will likely be ambiguous or infinite. |
| 42 | + * `$,field` -- similar to the above, but uses a comma separated list (with optional trailing comma). So `[ $,field ]` will parse something like `[f1, f2, f3]`. |
| 43 | + * Lookahead is required for `$,field` (this could be changed). |
| 44 | + * `$?field` -- will parse `field` and use `Default::default()` value if not present. |
| 45 | + |
| 46 | +### Greediness |
| 47 | + |
| 48 | +Parsing is generally greedy. So `$*x` and `$,x`, for example, consume as many entries as they can, subject to lookahead. In a case like `$*f $*g`, the parser would parse as many `f` values as it could before parsing `g`. If some entry can be parsed as either `f` or `g`, the parser will not explore all possibilities. The caveat here is lookahead: given `$*f #`, for example, parsing will stop when `#` is observed, even if `f` could parse `#`. |
| 49 | + |
| 50 | +### Default grammar |
| 51 | + |
| 52 | +If no grammar is supplied, the default grammar is determined as follows: |
| 53 | + |
| 54 | +* If a `#[cast]` or `#[variable]` annotation is present, then the default grammar is just `$v0`. |
| 55 | +* Otherwise, the default grammar is the name of the type (for structs) or variant (for enums), followed by `()`, with the values for the fields in order. So `Mul(Expr, Expr)` would have a default grammar `mul($v0, $v1)`. |
0 commit comments