|
| 1 | +//! Main points of this example: |
| 2 | +//! |
| 3 | +//! 1. [Expr], representing the AST of C-style expressions |
| 4 | +//! 2. [pratt_parser()], the core parser. |
| 5 | +//! 3. The [test]s, which demonstrate the expected input/outputs. |
| 6 | +//! |
| 7 | +//! # Errata: |
| 8 | +//! - There is a helper parser, [identifier()] |
| 9 | +//! - Two print implementations: [Expr::fmt_ast_with_indent()] and [Expr::fmt_delimited()] |
| 10 | +//! - For operator precedence, `1` has a low binding power while `13` has a high binding power. |
| 11 | +//! |
| 12 | +//! ## Printing |
| 13 | +//! |
| 14 | +//! `fmt_delimited()` is essentially prefix-notation. |
| 15 | +//! |
| 16 | +//! A short visual about the differences in printing, for parsing `1 + 1`: |
| 17 | +//! |
| 18 | +//! `fmt_ast_with_indent()` = |
| 19 | +//! ~~~text |
| 20 | +//! ADD |
| 21 | +//! VAL 1 |
| 22 | +//! VAL 1 |
| 23 | +//! ~~~ |
| 24 | +//! |
| 25 | +//! `fmt_delimited()` = |
| 26 | +//! ~~~text |
| 27 | +//! (+ 1 1) |
| 28 | +//! ~~~ |
| 29 | +//! |
| 30 | +//! ## Precedences |
| 31 | +//! |
| 32 | +//! Values uses an *inverted form* of the [C language operator precedence](c-precedence). |
| 33 | +//! |
| 34 | +//! In our implementation, a precedence of `1` is a very low precedence compared |
| 35 | +//! to a value of `13`. |
| 36 | +//! |
| 37 | +//! In the linked C operator page, the table shows precedence in *descending precedence order*, |
| 38 | +//! so `1` is the highest precedence, while `13` is a low precedence. |
| 39 | +//! |
| 40 | +//! The precedence levels you have to choose for your grammar depend on the language's |
| 41 | +//! semantics. |
| 42 | +//! |
| 43 | +//! [c-precedence]: https://en.cppreference.com/w/c/language/operator_precedence.html |
| 44 | +//! |
| 45 | +//! ### Precedence Table |
| 46 | +//! |
| 47 | +//! An overview of the different operators for this C-style expression language. |
| 48 | +//! |
| 49 | +//! Note: this does not include the operands themselves, such as literals or |
| 50 | +//! parenthesized expressions like: `(x)` |
| 51 | +//! |
| 52 | +//! Legend: |
| 53 | +//! - Kind: one of Prefix, Postfix, or Infix |
| 54 | +//! - Example: input text example |
| 55 | +//! - Name: the [Expr] variant it corresponds to |
| 56 | +//! - Power: the binding power/precedence of the operator |
| 57 | +//! - Assoc: infix-only, represents the left/right associativity of an operator |
| 58 | +//! - Recursive: only "TRUE" if parsing the operand invokes the parser again |
| 59 | +//! |
| 60 | +//! | Kind | Example | Name | Power | Assoc | Recursive | |
| 61 | +//! |---------|------------|------------------|-------|---------|-----------| |
| 62 | +//! | Prefix | `++x` | PreIncr | 18 | | | |
| 63 | +//! | Prefix | `+x` | Positive (no-op) | 18 | | | |
| 64 | +//! | Prefix | `--x` | PreDecr | 18 | | | |
| 65 | +//! | Prefix | `-x` | Neg | 18 | | | |
| 66 | +//! | Prefix | `&x` | Addr | 18 | | | |
| 67 | +//! | Prefix | `*x` | Deref | 18 | | | |
| 68 | +//! | Prefix | `!x` | Not | 18 | | | |
| 69 | +//! | Prefix | `~x` | BitwiseNot | 18 | | | |
| 70 | +//! | Postfix | `x!` | Fac | 19 | | | |
| 71 | +//! | Postfix | `x?` | Ternary | 3 | | TRUE | |
| 72 | +//! | Postfix | `[x]` | Index | 20 | | TRUE | |
| 73 | +//! | Postfix | `(x)` | Function call | 20 | | TRUE | |
| 74 | +//! | Postfix | `x++` | PostIncr | 20 | | | |
| 75 | +//! | Postfix | `x--` | PostDecr | 20 | | | |
| 76 | +//! | Infix | `a ** b` | Pow | 28 | Right | | |
| 77 | +//! | Infix | `a * b` | Mul | 16 | Left | | |
| 78 | +//! | Infix | `a / b` | Div | 16 | Left | | |
| 79 | +//! | Infix | `a % b` | Rem | 16 | Left | | |
| 80 | +//! | Infix | `a + b` | Add | 14 | Left | | |
| 81 | +//! | Infix | `a -ne b` | NotEq | 10 | Neither | | |
| 82 | +//! | Infix | `a -eq b` | Eq | 10 | Neither | | |
| 83 | +//! | Infix | `a -gt b` | Greater | 12 | Neither | | |
| 84 | +//! | Infix | `a -ge b` | GreaterEq | 12 | Neither | | |
| 85 | +//! | Infix | `a -lt b` | Less | 12 | Neither | | |
| 86 | +//! | Infix | `a -le b` | LessEqual | 12 | Neither | | |
| 87 | +//! | Infix | `a->b` | ArrowOp | 20 | Left | | |
| 88 | +//! | Infix | `a - b` | Sub | 14 | Left | | |
| 89 | +//! | Infix | `a.b` | Dot | 20 | Left | | |
| 90 | +//! | Infix | `a && b` | And | 6 | Left | | |
| 91 | +//! | Infix | `a & b` | BitAnd | 12 | Left | | |
| 92 | +//! | Infix | `a ^ b` | BitXor | 8 | Left | | |
| 93 | +//! | Infix | `a == b` | Eq | 10 | Neither | | |
| 94 | +//! | Infix | `a = b` | Assign | 2 | Right | | |
| 95 | +//! | Infix | `a >= b` | GreaterEq | 12 | Neither | | |
| 96 | +//! | Infix | `a > b` | Greater | 12 | Neither | | |
| 97 | +//! | Infix | `a <= b` | LessEqual | 12 | Neither | | |
| 98 | +//! | Infix | `a < b` | Less | 2 | Neither | | |
| 99 | +//! | Infix | `a, b` | Comma | 0 | Left | | |
| 100 | +//! | Infix | `a != b` | NotEq | 10 | Neither | | |
| 101 | +//! | Infix | `a \|\| b` | Or | 4 | Left | | |
| 102 | +
|
1 | 103 | use winnow::ascii::{digit1, multispace0}; |
2 | 104 | use winnow::combinator::{ |
3 | 105 | alt, cut_err, delimited, expression, fail, not, opt, peek, separated_pair, trace, |
@@ -63,8 +165,16 @@ pub(crate) enum Expr { |
63 | 165 | BitwiseNot(Box<Expr>), |
64 | 166 | } |
65 | 167 |
|
66 | | -// Parser definition |
| 168 | +/// Parser definition |
| 169 | +/// |
| 170 | +/// We define a helper function `parser()` and call it at the very end. |
| 171 | +/// |
| 172 | +/// `parser()` accepts a minimum `precedence_level` for the entire expression, |
| 173 | +/// and it returns a [Parser] that takes in a string and returns an [Expr] on |
| 174 | +/// success. |
67 | 175 | pub(crate) fn pratt_parser(i: &mut &str) -> ModalResult<Expr> { |
| 176 | + |
| 177 | + |
68 | 178 | fn parser<'i>(precedence: i64) -> impl Parser<&'i str, Expr, ErrMode<ContextError>> { |
69 | 179 | move |i: &mut &str| { |
70 | 180 | use Infix::{Left, Neither, Right}; |
|
0 commit comments