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                let value = p.match_type(TokenKind::Literal, Parsing::ArrayRep)?;
208                match value.data() {
209                    TokenData::Integer(size) => *size as usize,
210                    _ => {
211                        Err(p.error(ErrorKind::Unexpected(TokenKind::Literal), Parsing::ArrayRep))?
212                    }
213                }
214            },
215        }
216        .into(),
217        TokenKind::RBrack => Array { values: vec![first] }.into(),
218        TokenKind::Comma => Array {
219            values: {
220                p.consume_peeked();
221                let mut out = vec![first];
222                out.extend(sep(Expr::parse, TokenKind::Comma, END, P)(p)?);
223                out
224            },
225        }
226        .into(),
227        ty => Err(p.error(Unexpected(ty), P))?,
228    })
229}
230
231/// [Group] = `(`([Empty](ExprKind::Empty)|[Expr]|[Tuple])`)`
232///
233/// [ExprKind::Empty] and [Group] are special cases of [Tuple]
234fn exprkind_tuplelike(p: &mut Parser) -> PResult<ExprKind> {
235    p.match_type(TokenKind::LParen, Parsing::Group)?;
236    let out = match p.peek_kind(Parsing::Group)? {
237        TokenKind::RParen => Ok(ExprKind::Empty),
238        _ => exprkind_group(p),
239    };
240    p.match_type(TokenKind::RParen, Parsing::Group)?;
241    out
242}
243
244/// [Group] = `(`([Empty](ExprKind::Empty)|[Expr]|[Tuple])`)`
245fn exprkind_group(p: &mut Parser) -> PResult<ExprKind> {
246    let first = Expr::parse(p)?;
247    match p.peek_kind(Parsing::Group)? {
248        TokenKind::Comma => {
249            let mut exprs = vec![first];
250            p.consume_peeked();
251            while TokenKind::RParen != p.peek_kind(Parsing::Tuple)? {
252                exprs.push(Expr::parse(p)?);
253                match p.peek_kind(Parsing::Tuple)? {
254                    TokenKind::Comma => p.consume_peeked(),
255                    _ => break,
256                };
257            }
258            Ok(Tuple { exprs }.into())
259        }
260        _ => Ok(Group { expr: first.into() }.into()),
261    }
262}
263
264/// Parses an expression beginning with a [Path] (i.e. [Path] or [Structor])
265fn exprkind_pathlike(p: &mut Parser) -> PResult<ExprKind> {
266    Path::parse(p).map(Into::into)
267}
268
269/// [Structor]Body = `{` ([Fielder] `,`)* [Fielder]? `}`
270fn structor_body(p: &mut Parser, to: Path) -> PResult<Structor> {
271    let init = delim(
272        sep(
273            Fielder::parse,
274            TokenKind::Comma,
275            CURLIES.1,
276            Parsing::Structor,
277        ),
278        CURLIES,
279        Parsing::Structor,
280    )(p)?;
281
282    Ok(Structor { to, init })
283}
284
285/// Precedence provides a total ordering among operators
286#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
287pub enum Precedence {
288    Assign,
289    Structor,  // A structor is never a valid conditional
290    Condition, // Anything that syntactically needs a block following it
291    Logic,
292    Compare,
293    Range,
294    Bitwise,
295    Shift,
296    Factor,
297    Term,
298    Unary,
299    Index,
300    Cast,
301    Member, // left-associative
302    Call,
303    Deref,
304}
305
306impl Precedence {
307    #[inline]
308    pub const fn level(self) -> u8 {
309        (self as u8) << 1
310    }
311
312    pub fn prefix(self) -> Option<((), u8)> {
313        match self {
314            Self::Assign => Some(((), self.level())),
315            Self::Unary => Some(((), self.level())),
316            Self::Deref => Some(((), self.level())),
317            _ => None,
318        }
319    }
320
321    pub fn infix(self) -> Option<(u8, u8)> {
322        let level = self.level();
323        match self {
324            Self::Unary => None,
325            Self::Assign => Some((level + 1, level)),
326            _ => Some((level, level + 1)),
327        }
328    }
329
330    pub fn postfix(self) -> Option<(u8, ())> {
331        match self {
332            Self::Structor | Self::Index | Self::Call | Self::Member | Self::Cast => {
333                Some((self.level(), ()))
334            }
335            _ => None,
336        }
337    }
338}
339
340impl From<ModifyKind> for Precedence {
341    fn from(_value: ModifyKind) -> Self {
342        Precedence::Assign
343    }
344}
345
346impl From<BinaryKind> for Precedence {
347    fn from(value: BinaryKind) -> Self {
348        use BinaryKind as Op;
349        match value {
350            Op::Call => Precedence::Call,
351            Op::Mul | Op::Div | Op::Rem => Precedence::Term,
352            Op::Add | Op::Sub => Precedence::Factor,
353            Op::Shl | Op::Shr => Precedence::Shift,
354            Op::BitAnd | Op::BitOr | Op::BitXor => Precedence::Bitwise,
355            Op::LogAnd | Op::LogOr | Op::LogXor => Precedence::Logic,
356            Op::RangeExc | Op::RangeInc => Precedence::Range,
357            Op::Lt | Op::LtEq | Op::Equal | Op::NotEq | Op::GtEq | Op::Gt => Precedence::Compare,
358        }
359    }
360}
361
362impl From<UnaryKind> for Precedence {
363    fn from(value: UnaryKind) -> Self {
364        use UnaryKind as Op;
365        match value {
366            Op::Loop => Precedence::Assign,
367            Op::Deref => Precedence::Deref,
368            _ => Precedence::Unary,
369        }
370    }
371}
372
373/// Creates helper functions for turning TokenKinds into AST operators
374macro operator($($name:ident ($takes:ident => $returns:ident) {$($t:ident => $p:ident),*$(,)?};)*) {$(
375    pub fn $name (value: $takes) -> Option<($returns, Precedence)> {
376        match value {
377            $($takes::$t => Some(($returns::$p, Precedence::from($returns::$p))),)*
378            _ => None?,
379        }
380    })*
381}
382
383operator! {
384    from_prefix (TokenKind => UnaryKind) {
385        Loop => Loop,
386        Star => Deref,
387        Minus => Neg,
388        Bang => Not,
389        DotDot => RangeExc,
390        DotDotEq => RangeInc,
391        At => At,
392        Tilde => Tilde,
393    };
394
395    from_modify(TokenKind => ModifyKind) {
396        AmpEq => And,
397        BarEq => Or,
398        XorEq => Xor,
399        LtLtEq => Shl,
400        GtGtEq => Shr,
401        PlusEq => Add,
402        MinusEq => Sub,
403        StarEq => Mul,
404        SlashEq => Div,
405        RemEq => Rem,
406    };
407
408    from_infix (TokenKind => BinaryKind) {
409        Lt => Lt,
410        LtEq => LtEq,
411        EqEq => Equal,
412        BangEq => NotEq,
413        GtEq => GtEq,
414        Gt => Gt,
415        DotDot => RangeExc,
416        DotDotEq => RangeInc,
417        AmpAmp => LogAnd,
418        BarBar => LogOr,
419        XorXor => LogXor,
420        Amp => BitAnd,
421        Bar => BitOr,
422        Xor => BitXor,
423        LtLt => Shl,
424        GtGt => Shr,
425        Plus => Add,
426        Minus => Sub,
427        Star => Mul,
428        Slash => Div,
429        Rem => Rem,
430    };
431}