cl_parser/parser/
prec.rs

1//! Parses an [ExprKind] using a modified pratt parser
2//!
3//! See also: [Expr::parse], [ExprKind::parse]
4//!
5//! Implementer's note: [ExprKind::parse] is the public API for parsing [ExprKind]s.
6//! Do not call it from within this function.
7
8use super::{Parse, *};
9
10/// Parses an [ExprKind]
11pub fn expr(p: &mut Parser, power: u8) -> PResult<Expr> {
12    let parsing = Parsing::ExprKind;
13    let start = p.loc();
14    // Prefix expressions
15    let mut head = Expr {
16        kind: match p.peek_kind(Parsing::Unary)? {
17            literal_like!() => Literal::parse(p)?.into(),
18            path_like!() => exprkind_pathlike(p)?,
19            TokenKind::Amp | TokenKind::AmpAmp => AddrOf::parse(p)?.into(),
20            TokenKind::Bar | TokenKind::BarBar => Closure::parse(p)?.into(),
21            TokenKind::Grave => Quote::parse(p)?.into(),
22            TokenKind::LCurly => Block::parse(p)?.into(),
23            TokenKind::LBrack => exprkind_arraylike(p)?,
24            TokenKind::LParen => exprkind_tuplelike(p)?,
25            TokenKind::Let => Let::parse(p)?.into(),
26            TokenKind::Match => Match::parse(p)?.into(),
27            TokenKind::While => ExprKind::While(While::parse(p)?),
28            TokenKind::If => ExprKind::If(If::parse(p)?),
29            TokenKind::For => ExprKind::For(For::parse(p)?),
30            TokenKind::Break => ExprKind::Break(Break::parse(p)?),
31            TokenKind::Return => ExprKind::Return(Return::parse(p)?),
32            TokenKind::Continue => {
33                p.consume_peeked();
34                ExprKind::Continue
35            }
36
37            op => {
38                let (kind, prec) =
39                    from_prefix(op).ok_or_else(|| p.error(Unexpected(op), parsing))?;
40                let ((), after) = prec.prefix().expect("should have a precedence");
41                p.consume_peeked();
42                Unary { kind, tail: expr(p, after)?.into() }.into()
43            }
44        },
45        span: Span(start, p.loc()),
46    };
47
48    fn from_postfix(op: TokenKind) -> Option<Precedence> {
49        Some(match op {
50            TokenKind::LBrack => Precedence::Index,
51            TokenKind::LParen => Precedence::Call,
52            TokenKind::LCurly => Precedence::Structor,
53            TokenKind::Dot => Precedence::Member,
54            TokenKind::As => Precedence::Cast,
55            _ => None?,
56        })
57    }
58
59    while let Ok(op) = p.peek_kind(parsing) {
60        // Postfix expressions
61        if let Some((before, ())) = from_postfix(op).and_then(Precedence::postfix) {
62            if before < power {
63                break;
64            }
65
66            head = Expr {
67                kind: match op {
68                    TokenKind::LBrack => {
69                        p.consume_peeked();
70                        let indices =
71                            sep(Expr::parse, TokenKind::Comma, TokenKind::RBrack, parsing)(p)?;
72                        p.match_type(TokenKind::RBrack, parsing)?;
73                        ExprKind::Index(Index { head: head.into(), indices })
74                    }
75                    TokenKind::LParen => {
76                        p.consume_peeked();
77                        let exprs =
78                            sep(Expr::parse, TokenKind::Comma, TokenKind::RParen, parsing)(p)?;
79                        p.match_type(TokenKind::RParen, parsing)?;
80                        Binary {
81                            kind: BinaryKind::Call,
82                            parts: (
83                                head,
84                                Expr { kind: Tuple { exprs }.into(), span: Span(start, p.loc()) },
85                            )
86                                .into(),
87                        }
88                        .into()
89                    }
90                    TokenKind::LCurly => match head.kind {
91                        ExprKind::Path(path) => ExprKind::Structor(structor_body(p, path)?),
92                        _ => break,
93                    },
94                    TokenKind::Dot => {
95                        p.consume_peeked();
96                        let kind = MemberKind::parse(p)?;
97                        Member { head: Box::new(head), kind }.into()
98                    }
99                    TokenKind::As => {
100                        p.consume_peeked();
101                        let ty = Ty::parse(p)?;
102                        Cast { head: head.into(), ty }.into()
103                    }
104                    _ => Err(p.error(Unexpected(op), parsing))?,
105                },
106                span: Span(start, p.loc()),
107            };
108            continue;
109        }
110        // infix expressions
111        if let Some((kind, prec)) = from_infix(op) {
112            let (before, after) = prec.infix().expect("should have a precedence");
113            if before < power {
114                break;
115            }
116            p.consume_peeked();
117
118            let tail = expr(p, after)?;
119            head = Expr {
120                kind: Binary { kind, parts: (head, tail).into() }.into(),
121                span: Span(start, p.loc()),
122            };
123            continue;
124        }
125
126        if let Some((kind, prec)) = from_modify(op) {
127            let (before, after) = prec.infix().expect("should have a precedence");
128            if before < power {
129                break;
130            }
131            p.consume_peeked();
132
133            let tail = expr(p, after)?;
134            head = Expr {
135                kind: Modify { kind, parts: (head, tail).into() }.into(),
136                span: Span(start, p.loc()),
137            };
138            continue;
139        }
140
141        if let TokenKind::Eq = op {
142            let (before, after) = Precedence::Assign
143                .infix()
144                .expect("should have a precedence");
145            if before < power {
146                break;
147            }
148            p.consume_peeked();
149
150            let tail = expr(p, after)?;
151            head = Expr {
152                kind: Assign { parts: (head, tail).into() }.into(),
153                span: Span(start, p.loc()),
154            };
155
156            continue;
157        }
158
159        if let TokenKind::As = op {
160            let before = Precedence::Cast.level();
161            if before < power {
162                break;
163            }
164            p.consume_peeked();
165
166            let ty = Ty::parse(p)?;
167            head = Expr { kind: Cast { head: head.into(), ty }.into(), span: Span(start, p.loc()) };
168
169            continue;
170        }
171
172        break;
173    }
174
175    Ok(head)
176}
177
178/// [Array] = '[' ([Expr] ',')* [Expr]? ']'
179///
180/// Array and ArrayRef are ambiguous until the second token,
181/// so they can't be independent subexpressions
182fn exprkind_arraylike(p: &mut Parser) -> PResult<ExprKind> {
183    const P: Parsing = Parsing::Array;
184    const START: TokenKind = TokenKind::LBrack;
185    const END: TokenKind = TokenKind::RBrack;
186
187    p.match_type(START, P)?;
188    let out = match p.peek_kind(P)? {
189        END => Array { values: vec![] }.into(),
190        _ => exprkind_array_rep(p)?,
191    };
192    p.match_type(END, P)?;
193    Ok(out)
194}
195
196/// [ArrayRep] = `[` [Expr] `;` [Expr] `]`
197fn exprkind_array_rep(p: &mut Parser) -> PResult<ExprKind> {
198    const P: Parsing = Parsing::Array;
199    const END: TokenKind = TokenKind::RBrack;
200
201    let first = Expr::parse(p)?;
202    Ok(match p.peek_kind(P)? {
203        TokenKind::Semi => ArrayRep {
204            value: first.into(),
205            repeat: {
206                p.consume_peeked();
207                p.parse()?
208            },
209        }
210        .into(),
211        TokenKind::RBrack => Array { values: vec![first] }.into(),
212        TokenKind::Comma => Array {
213            values: {
214                p.consume_peeked();
215                let mut out = vec![first];
216                out.extend(sep(Expr::parse, TokenKind::Comma, END, P)(p)?);
217                out
218            },
219        }
220        .into(),
221        ty => Err(p.error(Unexpected(ty), P))?,
222    })
223}
224
225/// [Group] = `(`([Empty](ExprKind::Empty)|[Expr]|[Tuple])`)`
226///
227/// [ExprKind::Empty] and [Group] are special cases of [Tuple]
228fn exprkind_tuplelike(p: &mut Parser) -> PResult<ExprKind> {
229    p.match_type(TokenKind::LParen, Parsing::Group)?;
230    let out = match p.peek_kind(Parsing::Group)? {
231        TokenKind::RParen => Ok(ExprKind::Empty),
232        _ => exprkind_group(p),
233    };
234    p.match_type(TokenKind::RParen, Parsing::Group)?;
235    out
236}
237
238/// [Group] = `(`([Empty](ExprKind::Empty)|[Expr]|[Tuple])`)`
239fn exprkind_group(p: &mut Parser) -> PResult<ExprKind> {
240    let first = Expr::parse(p)?;
241    match p.peek_kind(Parsing::Group)? {
242        TokenKind::Comma => {
243            let mut exprs = vec![first];
244            p.consume_peeked();
245            while TokenKind::RParen != p.peek_kind(Parsing::Tuple)? {
246                exprs.push(Expr::parse(p)?);
247                match p.peek_kind(Parsing::Tuple)? {
248                    TokenKind::Comma => p.consume_peeked(),
249                    _ => break,
250                };
251            }
252            Ok(Tuple { exprs }.into())
253        }
254        _ => Ok(Group { expr: first.into() }.into()),
255    }
256}
257
258/// Parses an expression beginning with a [Path] (i.e. [Path] or [Structor])
259fn exprkind_pathlike(p: &mut Parser) -> PResult<ExprKind> {
260    Path::parse(p).map(Into::into)
261}
262
263/// [Structor]Body = `{` ([Fielder] `,`)* [Fielder]? `}`
264fn structor_body(p: &mut Parser, to: Path) -> PResult<Structor> {
265    let init = delim(
266        sep(
267            Fielder::parse,
268            TokenKind::Comma,
269            CURLIES.1,
270            Parsing::Structor,
271        ),
272        CURLIES,
273        Parsing::Structor,
274    )(p)?;
275
276    Ok(Structor { to, init })
277}
278
279/// Precedence provides a total ordering among operators
280#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
281pub enum Precedence {
282    Assign,
283    Structor,  // A structor is never a valid conditional
284    Condition, // Anything that syntactically needs a block following it
285    Logic,
286    Compare,
287    Range,
288    Bitwise,
289    Shift,
290    Factor,
291    Term,
292    Unary,
293    Index,
294    Cast,
295    Member, // left-associative
296    Call,
297    Deref,
298}
299
300impl Precedence {
301    #[inline]
302    pub const fn level(self) -> u8 {
303        (self as u8) << 1
304    }
305
306    pub fn prefix(self) -> Option<((), u8)> {
307        match self {
308            Self::Assign => Some(((), self.level())),
309            Self::Unary => Some(((), self.level())),
310            Self::Deref => Some(((), self.level())),
311            _ => None,
312        }
313    }
314
315    pub fn infix(self) -> Option<(u8, u8)> {
316        let level = self.level();
317        match self {
318            Self::Unary => None,
319            Self::Assign => Some((level + 1, level)),
320            _ => Some((level, level + 1)),
321        }
322    }
323
324    pub fn postfix(self) -> Option<(u8, ())> {
325        match self {
326            Self::Structor | Self::Index | Self::Call | Self::Member | Self::Cast => {
327                Some((self.level(), ()))
328            }
329            _ => None,
330        }
331    }
332}
333
334impl From<ModifyKind> for Precedence {
335    fn from(_value: ModifyKind) -> Self {
336        Precedence::Assign
337    }
338}
339
340impl From<BinaryKind> for Precedence {
341    fn from(value: BinaryKind) -> Self {
342        use BinaryKind as Op;
343        match value {
344            Op::Call => Precedence::Call,
345            Op::Mul | Op::Div | Op::Rem => Precedence::Term,
346            Op::Add | Op::Sub => Precedence::Factor,
347            Op::Shl | Op::Shr => Precedence::Shift,
348            Op::BitAnd | Op::BitOr | Op::BitXor => Precedence::Bitwise,
349            Op::LogAnd | Op::LogOr | Op::LogXor => Precedence::Logic,
350            Op::RangeExc | Op::RangeInc => Precedence::Range,
351            Op::Lt | Op::LtEq | Op::Equal | Op::NotEq | Op::GtEq | Op::Gt => Precedence::Compare,
352        }
353    }
354}
355
356impl From<UnaryKind> for Precedence {
357    fn from(value: UnaryKind) -> Self {
358        use UnaryKind as Op;
359        match value {
360            Op::Loop => Precedence::Assign,
361            Op::Deref => Precedence::Deref,
362            _ => Precedence::Unary,
363        }
364    }
365}
366
367/// Creates helper functions for turning TokenKinds into AST operators
368macro operator($($name:ident ($takes:ident => $returns:ident) {$($t:ident => $p:ident),*$(,)?};)*) {$(
369    pub fn $name (value: $takes) -> Option<($returns, Precedence)> {
370        match value {
371            $($takes::$t => Some(($returns::$p, Precedence::from($returns::$p))),)*
372            _ => None?,
373        }
374    })*
375}
376
377operator! {
378    from_prefix (TokenKind => UnaryKind) {
379        Loop => Loop,
380        Star => Deref,
381        Minus => Neg,
382        Bang => Not,
383        DotDot => RangeExc,
384        DotDotEq => RangeInc,
385        At => At,
386        Tilde => Tilde,
387    };
388
389    from_modify(TokenKind => ModifyKind) {
390        AmpEq => And,
391        BarEq => Or,
392        XorEq => Xor,
393        LtLtEq => Shl,
394        GtGtEq => Shr,
395        PlusEq => Add,
396        MinusEq => Sub,
397        StarEq => Mul,
398        SlashEq => Div,
399        RemEq => Rem,
400    };
401
402    from_infix (TokenKind => BinaryKind) {
403        Lt => Lt,
404        LtEq => LtEq,
405        EqEq => Equal,
406        BangEq => NotEq,
407        GtEq => GtEq,
408        Gt => Gt,
409        DotDot => RangeExc,
410        DotDotEq => RangeInc,
411        AmpAmp => LogAnd,
412        BarBar => LogOr,
413        XorXor => LogXor,
414        Amp => BitAnd,
415        Bar => BitOr,
416        Xor => BitXor,
417        LtLt => Shl,
418        GtGt => Shr,
419        Plus => Add,
420        Minus => Sub,
421        Star => Mul,
422        Slash => Div,
423        Rem => Rem,
424    };
425}