flux_syntax/parser/
mod.rs

1pub(crate) mod lookahead;
2mod utils;
3use std::{collections::HashSet, str::FromStr, vec};
4
5use lookahead::{AnyLit, LAngle, NonReserved, RAngle};
6use rustc_span::{Symbol, sym::Output};
7use utils::{
8    angle, braces, brackets, delimited, opt_angle, parens, punctuated_until,
9    punctuated_with_trailing, repeat_while, sep1, until,
10};
11
12use crate::{
13    ParseCtxt, ParseError, ParseResult,
14    parser::lookahead::{AnyOf, Expected, PeekExpected},
15    surface::{
16        self, Async,
17        Attr::{self},
18        BaseSort, BaseTy, BaseTyKind, BinOp, BindKind, ConstArg, ConstArgKind, ConstructorArg,
19        DetachedInherentImpl, DetachedItem, DetachedItemKind, DetachedSpecs, DetachedTrait,
20        DetachedTraitImpl, Ensures, EnumDef, Expr, ExprKind, ExprPath, ExprPathSegment, FieldExpr,
21        FluxItem, FnInput, FnOutput, FnRetTy, FnSig, GenericArg, GenericArgKind, GenericBounds,
22        GenericParam, Generics, Ident, ImplAssocReft, Indices, LetDecl, LitKind, Mutability,
23        ParamMode, Path, PathSegment, PrimOpProp, Qualifier, QualifierKind, QuantKind, RefineArg,
24        RefineParam, RefineParams, Requires, Sort, SortDecl, SortPath, SpecFunc, Spread, StructDef,
25        TraitAssocReft, TraitRef, Trusted, Ty, TyAlias, TyKind, UnOp, VariantDef, VariantRet,
26        WhereBoundPredicate,
27    },
28    symbols::{kw, sym},
29    token::{self, Comma, Delimiter::*, IdentIsRaw, Or, Token, TokenKind},
30};
31
32/// An attribute that's considered part of the *syntax* of an item.
33///
34/// This is in contrast to a [`surface::Attr`] which changes the behavior of an item. For example,
35/// a `#[refined_by(...)]` is part of the syntax of an adt: we could think of a different syntax
36/// that doesn't use an attribute. The existence of a syntax attribute in the token stream can be
37/// used to decide how to keep parsing, for example, if we see a `#[reft]` we know that the next
38/// item must be an associated refinement and not a method inside an impl or trait.
39enum SyntaxAttr {
40    /// A `#[reft]` attribute
41    Reft,
42    /// A `#[invariant]` attribute
43    Invariant(Expr),
44    /// A `#[refined_by(...)]` attribute
45    RefinedBy(RefineParams),
46    /// A `#[hide]` attribute
47    ///
48    /// NOTE(nilehmann) This should be considered a normal attribute, but we haven't implemented
49    /// attributes for flux items. If we start seeing more of these we should consider implementing
50    /// the infrastructure necesary to keep a list of attributes inside the flux item like we do
51    /// for rust items.
52    Hide,
53    /// a `#[opaque]` attribute
54    Opaque,
55}
56
57#[derive(Default)]
58struct ParsedAttrs {
59    normal: Vec<Attr>,
60    syntax: Vec<SyntaxAttr>,
61}
62
63impl ParsedAttrs {
64    fn is_reft(&self) -> bool {
65        self.syntax
66            .iter()
67            .any(|attr| matches!(attr, SyntaxAttr::Reft))
68    }
69
70    fn is_hide(&self) -> bool {
71        self.syntax
72            .iter()
73            .any(|attr| matches!(attr, SyntaxAttr::Hide))
74    }
75
76    fn is_opaque(&self) -> bool {
77        self.syntax
78            .iter()
79            .any(|attr| matches!(attr, SyntaxAttr::Opaque))
80    }
81
82    fn refined_by(&mut self) -> Option<RefineParams> {
83        let pos = self
84            .syntax
85            .iter()
86            .position(|x| matches!(x, SyntaxAttr::RefinedBy(_)))?;
87        if let SyntaxAttr::RefinedBy(params) = self.syntax.remove(pos) {
88            Some(params)
89        } else {
90            None
91        }
92    }
93
94    fn invariant(&mut self) -> Option<Expr> {
95        let pos = self
96            .syntax
97            .iter()
98            .position(|x| matches!(x, SyntaxAttr::Invariant(_)))?;
99        if let SyntaxAttr::Invariant(exp) = self.syntax.remove(pos) { Some(exp) } else { None }
100    }
101}
102
103/// ```text
104///   yes ⟨ , reason = ⟨literal⟩ ⟩?
105/// | no ⟨ , reason = ⟨literal⟩ ⟩?
106/// | reason = ⟨literal⟩
107/// ```
108pub(crate) fn parse_yes_or_no_with_reason(cx: &mut ParseCtxt) -> ParseResult<bool> {
109    let mut lookahead = cx.lookahead1();
110    if lookahead.advance_if(sym::yes) {
111        if cx.advance_if(token::Comma) {
112            parse_reason(cx)?;
113        }
114        Ok(true)
115    } else if lookahead.advance_if(sym::no) {
116        if cx.advance_if(token::Comma) {
117            parse_reason(cx)?;
118        }
119        Ok(false)
120    } else if lookahead.peek(sym::reason) {
121        parse_reason(cx)?;
122        Ok(true)
123    } else {
124        Err(lookahead.into_error())
125    }
126}
127
128/// ```text
129/// ⟨reason⟩ := reason = ⟨literal⟩
130/// ```
131fn parse_reason(cx: &mut ParseCtxt) -> ParseResult {
132    cx.expect(sym::reason)?;
133    cx.expect(token::Eq)?;
134    cx.expect(AnyLit)
135}
136
137/// ```text
138/// ⟨ident_list⟩ := ⟨ident⟩,*
139/// ```
140pub(crate) fn parse_ident_list(cx: &mut ParseCtxt) -> ParseResult<Vec<Ident>> {
141    punctuated_until(cx, Comma, token::Eof, parse_ident)
142}
143
144/// ```text
145/// ⟨flux_items⟩ := ⟨flux_item⟩*
146/// ```
147pub(crate) fn parse_flux_items(cx: &mut ParseCtxt) -> ParseResult<Vec<FluxItem>> {
148    until(cx, token::Eof, parse_flux_item)
149}
150
151/// ```text
152/// ⟨flux_item⟩ := ⟨func_def⟩
153///              | ⟨qualifier⟩
154///              | ⟨sort_decl⟩
155///              | ⟨primop_prop⟩
156/// ```
157fn parse_flux_item(cx: &mut ParseCtxt) -> ParseResult<FluxItem> {
158    let mut lookahead = cx.lookahead1();
159    if lookahead.peek(token::Pound) || lookahead.peek(kw::Fn) {
160        parse_reft_func(cx).map(FluxItem::FuncDef)
161    } else if lookahead.peek(kw::Local)
162        || lookahead.peek(kw::Invariant)
163        || lookahead.peek(kw::Qualifier)
164    {
165        parse_qualifier(cx).map(FluxItem::Qualifier)
166    } else if lookahead.peek(kw::Opaque) {
167        parse_sort_decl(cx).map(FluxItem::SortDecl)
168    } else if lookahead.peek(kw::Property) {
169        parse_primop_property(cx).map(FluxItem::PrimOpProp)
170    } else {
171        Err(lookahead.into_error())
172    }
173}
174
175///```text
176/// ⟨specs⟩ ::= ⟨specs⟩*
177/// ```
178pub(crate) fn parse_detached_specs(cx: &mut ParseCtxt) -> ParseResult<surface::DetachedSpecs> {
179    let items = until(cx, token::Eof, parse_detached_item)?;
180    Ok(surface::DetachedSpecs { items })
181}
182
183///```text
184/// ⟨specs⟩ ::= ⟨fn-spec⟩
185///           | ⟨struct-spec⟩
186///           | ⟨enum-spec⟩
187///           | ⟨mod⟩
188///           | ⟨impl⟩
189/// ```
190pub(crate) fn parse_detached_item(cx: &mut ParseCtxt) -> ParseResult<DetachedItem> {
191    let attrs = parse_attrs(cx)?;
192    let mut lookahead = cx.lookahead1();
193    if lookahead.peek(kw::Fn) {
194        Ok(parse_detached_fn_sig(cx, attrs)?.map_kind(DetachedItemKind::FnSig))
195    } else if lookahead.peek(kw::Mod) {
196        parse_detached_mod(cx)
197    } else if lookahead.peek(kw::Struct) {
198        parse_detached_struct(cx, attrs)
199    } else if lookahead.peek(kw::Enum) {
200        parse_detached_enum(cx, attrs)
201    } else if lookahead.peek(kw::Impl) {
202        parse_detached_impl(cx, attrs)
203    } else if lookahead.peek(kw::Trait) {
204        parse_detached_trait(cx, attrs)
205    } else {
206        Err(lookahead.into_error())
207    }
208}
209
210///```text
211/// ⟨field⟩ ::= ⟨ident⟩ : ⟨type⟩
212/// ```
213fn parse_detached_field(cx: &mut ParseCtxt) -> ParseResult<(Ident, Ty)> {
214    let ident = parse_ident(cx)?;
215    cx.expect(token::Colon)?;
216    let ty = parse_type(cx)?;
217    Ok((ident, ty))
218}
219
220///```text
221/// ⟨enum⟩ := enum Ident ⟨refine_info⟩ { ⟨variant⟩* }
222/// ```
223fn parse_detached_enum(cx: &mut ParseCtxt, mut attrs: ParsedAttrs) -> ParseResult<DetachedItem> {
224    cx.expect(kw::Enum)?;
225    let path = parse_expr_path(cx)?;
226    let generics = Some(parse_opt_generics(cx)?);
227    let refined_by = attrs.refined_by();
228    let invariants = attrs.invariant().into_iter().collect();
229    let variants = braces(cx, Comma, |cx| parse_variant(cx, true))?
230        .into_iter()
231        .map(Some)
232        .collect();
233    let enum_def = EnumDef { generics, refined_by, variants, invariants, reflected: false };
234    Ok(DetachedItem {
235        attrs: attrs.normal,
236        path,
237        kind: DetachedItemKind::Enum(enum_def),
238        node_id: cx.next_node_id(),
239    })
240}
241
242fn parse_detached_struct(cx: &mut ParseCtxt, mut attrs: ParsedAttrs) -> ParseResult<DetachedItem> {
243    cx.expect(kw::Struct)?;
244    let path = parse_expr_path(cx)?;
245    let generics = Some(parse_opt_generics(cx)?);
246    let refined_by = attrs.refined_by();
247    let opaque = attrs.is_opaque();
248    let invariants = attrs.invariant().into_iter().collect();
249    let fields = if cx.peek(token::OpenBrace) {
250        braces(cx, Comma, parse_detached_field)?
251            .into_iter()
252            .map(|(_, ty)| Some(ty))
253            .collect()
254    } else if cx.peek(token::OpenParen) {
255        parens(cx, Comma, parse_type)?
256            .into_iter()
257            .map(Some)
258            .collect()
259    } else {
260        cx.expect(token::Semi)?;
261        vec![]
262    };
263    let struct_def = StructDef { generics, opaque, refined_by, invariants, fields };
264    Ok(DetachedItem {
265        attrs: attrs.normal,
266        path,
267        kind: DetachedItemKind::Struct(struct_def),
268        node_id: cx.next_node_id(),
269    })
270}
271
272fn ident_path(cx: &mut ParseCtxt, ident: Ident) -> ExprPath {
273    let span = ident.span;
274    let segments = vec![ExprPathSegment { ident, node_id: cx.next_node_id() }];
275    ExprPath { segments, span, node_id: cx.next_node_id() }
276}
277
278fn parse_detached_fn_sig(
279    cx: &mut ParseCtxt,
280    attrs: ParsedAttrs,
281) -> ParseResult<DetachedItem<FnSig>> {
282    let fn_sig = parse_fn_sig(cx, token::Semi)?;
283    let span = fn_sig.span;
284    let ident = fn_sig
285        .ident
286        .ok_or(ParseError { kind: crate::ParseErrorKind::InvalidDetachedSpec, span })?;
287    let path = ident_path(cx, ident);
288    Ok(DetachedItem { attrs: attrs.normal, path, kind: fn_sig, node_id: cx.next_node_id() })
289}
290
291///```text
292/// ⟨mod⟩ ::= mod ⟨ident⟩ { ⟨specs⟩ }
293/// ```
294fn parse_detached_mod(cx: &mut ParseCtxt) -> ParseResult<DetachedItem> {
295    cx.expect(kw::Mod)?;
296    let path = parse_expr_path(cx)?;
297    cx.expect(TokenKind::open_delim(Brace))?;
298    let items = until(cx, TokenKind::close_delim(Brace), parse_detached_item)?;
299    cx.expect(TokenKind::close_delim(Brace))?;
300    Ok(DetachedItem {
301        attrs: vec![],
302        path,
303        kind: DetachedItemKind::Mod(DetachedSpecs { items }),
304        node_id: cx.next_node_id(),
305    })
306}
307
308///```text
309/// ⟨trait-spec⟩ ::= trait Ident { ⟨fn-spec⟩* }
310/// ```
311fn parse_detached_trait(cx: &mut ParseCtxt, attrs: ParsedAttrs) -> ParseResult<DetachedItem> {
312    cx.expect(kw::Trait)?;
313    let path = parse_expr_path(cx)?;
314    let _generics = parse_opt_generics(cx)?;
315    cx.expect(TokenKind::open_delim(Brace))?;
316
317    let mut items = vec![];
318    let mut refts = vec![];
319    while !cx.peek(TokenKind::close_delim(Brace)) {
320        let assoc_item_attrs = parse_attrs(cx)?;
321        if assoc_item_attrs.is_reft() {
322            refts.push(parse_trait_assoc_reft(cx)?);
323        } else {
324            items.push(parse_detached_fn_sig(cx, assoc_item_attrs)?);
325        }
326    }
327    cx.expect(TokenKind::close_delim(Brace))?;
328    Ok(DetachedItem {
329        attrs: attrs.normal,
330        path,
331        kind: DetachedItemKind::Trait(DetachedTrait { items, refts }),
332        node_id: cx.next_node_id(),
333    })
334}
335
336///```text
337/// ⟨impl-spec⟩ ::= impl Ident (for Ident)? { ⟨#[assoc] impl_assoc_reft⟩* ⟨fn-spec⟩* }
338/// ```
339fn parse_detached_impl(cx: &mut ParseCtxt, attrs: ParsedAttrs) -> ParseResult<DetachedItem> {
340    let lo = cx.lo();
341    cx.expect(kw::Impl)?;
342    let hi = cx.hi();
343    let span = cx.mk_span(lo, hi);
344    let outer_path = parse_expr_path(cx)?;
345    let _generics = parse_opt_generics(cx)?;
346    let inner_path = if cx.advance_if(kw::For) {
347        let path = parse_expr_path(cx)?;
348        let _generics = parse_opt_generics(cx)?;
349        Some(path)
350    } else {
351        None
352    };
353    cx.expect(TokenKind::open_delim(Brace))?;
354
355    let mut items = vec![];
356    let mut refts = vec![];
357    while !cx.peek(TokenKind::close_delim(Brace)) {
358        // if inner_path.is_none, we are parsing an inherent impl with no associated-refts
359        let assoc_item_attrs = parse_attrs(cx)?;
360        if assoc_item_attrs.is_reft() && inner_path.is_some() {
361            refts.push(parse_impl_assoc_reft(cx)?);
362        } else {
363            items.push(parse_detached_fn_sig(cx, assoc_item_attrs)?);
364        }
365    }
366    cx.expect(TokenKind::close_delim(Brace))?;
367    if let Some(path) = inner_path {
368        Ok(DetachedItem {
369            attrs: attrs.normal,
370            path,
371            kind: DetachedItemKind::TraitImpl(DetachedTraitImpl {
372                trait_: outer_path,
373                items,
374                refts,
375                span,
376            }),
377            node_id: cx.next_node_id(),
378        })
379    } else {
380        Ok(DetachedItem {
381            attrs: attrs.normal,
382            path: outer_path,
383            kind: DetachedItemKind::InherentImpl(DetachedInherentImpl { items, span }),
384            node_id: cx.next_node_id(),
385        })
386    }
387}
388
389fn parse_attr(cx: &mut ParseCtxt, attrs: &mut ParsedAttrs) -> ParseResult {
390    cx.expect(token::Pound)?;
391    cx.expect(token::OpenBracket)?;
392    let mut lookahead = cx.lookahead1();
393    if lookahead.advance_if(kw::Trusted) {
394        if cx.advance_if(token::OpenParen) {
395            parse_reason(cx)?;
396            cx.expect(token::CloseParen)?;
397        }
398        attrs.normal.push(Attr::Trusted(Trusted::Yes));
399    } else if lookahead.advance_if(sym::hide) {
400        attrs.syntax.push(SyntaxAttr::Hide);
401    } else if lookahead.advance_if(kw::Opaque) {
402        attrs.syntax.push(SyntaxAttr::Opaque);
403    } else if lookahead.advance_if(kw::Reft) {
404        attrs.syntax.push(SyntaxAttr::Reft);
405    } else if lookahead.advance_if(kw::RefinedBy) {
406        attrs
407            .syntax
408            .push(SyntaxAttr::RefinedBy(delimited(cx, Parenthesis, parse_refined_by)?));
409    } else if lookahead.advance_if(kw::Invariant) {
410        attrs
411            .syntax
412            .push(SyntaxAttr::Invariant(delimited(cx, Parenthesis, |cx| parse_expr(cx, true))?));
413    } else {
414        return Err(lookahead.into_error());
415    };
416    cx.expect(token::CloseBracket)
417}
418
419fn parse_attrs(cx: &mut ParseCtxt) -> ParseResult<ParsedAttrs> {
420    let mut attrs = ParsedAttrs::default();
421    repeat_while(cx, token::Pound, |cx| parse_attr(cx, &mut attrs))?;
422    Ok(attrs)
423}
424
425/// ```text
426/// ⟨func_def⟩ := ⟨ # [ hide ] ⟩?
427///               fn ⟨ident⟩ ⟨ < ⟨ident⟩,* > ⟩?
428///               ( ⟨refine_param⟩,* )
429///               ->
430///               ⟨sort⟩
431/// ```
432fn parse_reft_func(cx: &mut ParseCtxt) -> ParseResult<SpecFunc> {
433    let attrs = parse_attrs(cx)?;
434    let hide = attrs.is_hide();
435    cx.expect(kw::Fn)?;
436    let name = parse_ident(cx)?;
437    let sort_vars = opt_angle(cx, Comma, parse_ident)?;
438    let params = parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Yes))?;
439    cx.expect(token::RArrow)?;
440    let output = parse_sort(cx)?;
441    let body = if cx.peek(token::OpenBrace) {
442        Some(parse_block(cx)?)
443    } else {
444        cx.expect(token::Semi)?;
445        None
446    };
447    Ok(SpecFunc { name, sort_vars, params, output, body, hide })
448}
449
450/// ```text
451/// ⟨qualifier_kind⟩ :=  local
452///                   |  invariant
453/// ```
454fn parse_qualifier_kind(cx: &mut ParseCtxt) -> ParseResult<QualifierKind> {
455    let mut lookahead = cx.lookahead1();
456    if lookahead.advance_if(kw::Local) {
457        Ok(QualifierKind::Local)
458    } else if lookahead.advance_if(kw::Invariant) {
459        Ok(QualifierKind::Hint)
460    } else {
461        Ok(QualifierKind::Global)
462    }
463}
464
465/// ```text
466/// ⟨qualifier⟩ :=  ⟨ qualifier_kind ⟩?
467///                 qualifier ⟨ident⟩ ( ⟨refine_param⟩,* )
468///                 ⟨block⟩
469/// ```
470fn parse_qualifier(cx: &mut ParseCtxt) -> ParseResult<Qualifier> {
471    let lo = cx.lo();
472    let kind = parse_qualifier_kind(cx)?;
473    cx.expect(kw::Qualifier)?;
474    let mut name = parse_ident(cx)?;
475    let mut params = parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Yes))?;
476    let expr = parse_block(cx)?;
477    let hi = cx.hi();
478
479    if let QualifierKind::Hint = kind {
480        let mut fvars = expr.free_vars();
481        for param in &params {
482            fvars.remove(&param.ident);
483        }
484        params.extend(fvars.into_iter().map(|ident| {
485            RefineParam {
486                ident,
487                sort: Sort::Infer,
488                mode: None,
489                span: ident.span,
490                node_id: cx.next_node_id(),
491            }
492        }));
493
494        let span = name.span;
495        let str = format!("{}_{}_{}", name.name.to_ident_string(), span.lo().0, span.hi().0);
496        name = Ident { name: Symbol::intern(&str), ..name };
497    }
498
499    Ok(Qualifier { name, params, expr, span: cx.mk_span(lo, hi), kind })
500}
501
502/// ```text
503/// ⟨sort_decl⟩ := opaque sort ⟨ident⟩ ;
504/// ```
505fn parse_sort_decl(cx: &mut ParseCtxt) -> ParseResult<SortDecl> {
506    cx.expect(kw::Opaque)?;
507    cx.expect(kw::Sort)?;
508    let name = parse_ident(cx)?;
509    let sort_vars = opt_angle(cx, Comma, parse_ident)?;
510    cx.expect(token::Semi)?;
511    Ok(SortDecl { name, sort_vars })
512}
513
514/// `⟨bin_op⟩ := ⟨ a binary operator ⟩
515fn parse_binop(cx: &mut ParseCtxt) -> ParseResult<BinOp> {
516    let (op, ntokens) = cx
517        .peek_binop()
518        .ok_or_else(|| cx.unexpected_token(vec![Expected::Str("binary operator")]))?;
519    cx.advance_by(ntokens);
520    Ok(op)
521}
522
523/// ```text
524/// ⟨primop_prop⟩ := property ⟨ident⟩ [ ⟨bin_op⟩ ] ( ⟨refine_param⟩,* ) ⟨block⟩
525/// ```
526fn parse_primop_property(cx: &mut ParseCtxt) -> ParseResult<PrimOpProp> {
527    let lo = cx.lo();
528    cx.expect(kw::Property)?;
529
530    // Parse the name
531    let name = parse_ident(cx)?;
532
533    // Parse the operator
534    cx.expect(token::OpenBracket)?;
535    let op = parse_binop(cx)?;
536    cx.expect(token::CloseBracket)?;
537
538    // Parse the args
539    let params = parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::No))?;
540
541    let body = parse_block(cx)?;
542    let hi = cx.hi();
543
544    Ok(PrimOpProp { name, op, params, body, span: cx.mk_span(lo, hi) })
545}
546
547pub(crate) fn parse_trait_assoc_refts(cx: &mut ParseCtxt) -> ParseResult<Vec<TraitAssocReft>> {
548    until(cx, token::Eof, parse_trait_assoc_reft)
549}
550
551/// ```text
552/// ⟨trait_assoc_reft⟩ := fn ⟨ident⟩ ( ⟨refine_param⟩,* ) -> ⟨base_sort⟩ ;?
553///                     | fn ⟨ident⟩ ( ⟨refine_param⟩,* ) -> ⟨base_sort⟩ ⟨block⟩
554///                     | final fn ⟨ident⟩ ( ⟨refine_param⟩,* ) -> ⟨base_sort⟩ ⟨block⟩
555/// ```
556fn parse_trait_assoc_reft(cx: &mut ParseCtxt) -> ParseResult<TraitAssocReft> {
557    let lo = cx.lo();
558    let final_ = cx.advance_if(kw::Final);
559    cx.expect(kw::Fn)?;
560    let name = parse_ident(cx)?;
561    let params = parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Yes))?;
562    cx.expect(token::RArrow)?;
563    let output = parse_base_sort(cx)?;
564    let body = if cx.peek(token::OpenBrace) {
565        Some(parse_block(cx)?)
566    } else {
567        cx.advance_if(token::Semi);
568        None
569    };
570    let hi = cx.hi();
571    Ok(TraitAssocReft { name, params, output, body, span: cx.mk_span(lo, hi), final_ })
572}
573
574pub(crate) fn parse_impl_assoc_refts(cx: &mut ParseCtxt) -> ParseResult<Vec<ImplAssocReft>> {
575    until(cx, token::Eof, parse_impl_assoc_reft)
576}
577
578/// ```text
579/// ⟨impl_assoc_reft⟩ := fn ⟨ident⟩ ( ⟨refine_param⟩,* ) -> ⟨base_sort⟩ ⟨block⟩
580/// ```
581fn parse_impl_assoc_reft(cx: &mut ParseCtxt) -> ParseResult<ImplAssocReft> {
582    let lo = cx.lo();
583    cx.expect(kw::Fn)?;
584    let name = parse_ident(cx)?;
585    let params = parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Yes))?;
586    cx.expect(token::RArrow)?;
587    let output = parse_base_sort(cx)?;
588    let body = parse_block(cx)?;
589    let hi = cx.hi();
590    Ok(ImplAssocReft { name, params, output, body, span: cx.mk_span(lo, hi) })
591}
592
593/// ```text
594/// ⟨refined_by⟩ := ⟨refine_param⟩,*
595/// ```
596pub(crate) fn parse_refined_by(cx: &mut ParseCtxt) -> ParseResult<RefineParams> {
597    punctuated_until(cx, Comma, token::Eof, |cx| parse_refine_param(cx, RequireSort::Yes))
598}
599
600/// ```text
601/// ⟨variant⟩ := ⟨fields⟩ -> ⟨variant_ret⟩
602///            | ⟨fields⟩
603///            | ⟨variant_ret⟩
604/// ```
605pub(crate) fn parse_variant(cx: &mut ParseCtxt, ret_arrow: bool) -> ParseResult<VariantDef> {
606    let lo = cx.lo();
607    let mut fields = vec![];
608    let mut ret = None;
609    let ident = if ret_arrow || cx.peek2(NonReserved, token::OpenParen) {
610        Some(parse_ident(cx)?)
611    } else {
612        None
613    };
614    if cx.peek(token::OpenParen) || cx.peek(token::OpenBrace) {
615        fields = parse_fields(cx)?;
616        if cx.advance_if(token::RArrow) {
617            ret = Some(parse_variant_ret(cx)?);
618        }
619    } else {
620        if ret_arrow {
621            cx.expect(token::RArrow)?;
622        }
623        ret = Some(parse_variant_ret(cx)?);
624    };
625    let hi = cx.hi();
626    Ok(VariantDef { ident, fields, ret, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
627}
628
629/// ```text
630/// ⟨fields⟩ := ( ⟨ty⟩,* ) | { ⟨ty⟩,* }
631/// ```
632fn parse_fields(cx: &mut ParseCtxt) -> ParseResult<Vec<Ty>> {
633    let mut lookahead = cx.lookahead1();
634    if lookahead.peek(token::OpenParen) {
635        parens(cx, Comma, parse_type)
636    } else if lookahead.peek(token::OpenBrace) {
637        braces(cx, Comma, parse_type)
638    } else {
639        Err(lookahead.into_error())
640    }
641}
642
643/// ```text
644/// ⟨variant_ret⟩ := ⟨path⟩ ⟨ [ ⟨refine_arg⟩,? ] ⟩?
645/// ```
646fn parse_variant_ret(cx: &mut ParseCtxt) -> ParseResult<VariantRet> {
647    let path = parse_path(cx)?;
648    let indices = if cx.peek(token::OpenBracket) {
649        parse_indices(cx)?
650    } else {
651        let hi = cx.hi();
652        Indices { indices: vec![], span: cx.mk_span(hi, hi) }
653    };
654    Ok(VariantRet { path, indices })
655}
656
657pub(crate) fn parse_type_alias(cx: &mut ParseCtxt) -> ParseResult<TyAlias> {
658    let lo = cx.lo();
659    cx.expect(kw::Type)?;
660    let ident = parse_ident(cx)?;
661    let generics = parse_opt_generics(cx)?;
662    let params = if cx.peek(token::OpenParen) {
663        parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Yes))?
664    } else {
665        vec![]
666    };
667    let index = if cx.peek(token::OpenBracket) {
668        Some(delimited(cx, Bracket, |cx| parse_refine_param(cx, RequireSort::Yes))?)
669    } else {
670        None
671    };
672    cx.expect(token::Eq)?;
673    let ty = parse_type(cx)?;
674    let hi = cx.hi();
675    Ok(TyAlias {
676        ident,
677        generics,
678        params,
679        index,
680        ty,
681        node_id: cx.next_node_id(),
682        span: cx.mk_span(lo, hi),
683    })
684}
685
686fn parse_opt_generics(cx: &mut ParseCtxt) -> ParseResult<Generics> {
687    if !cx.peek(LAngle) {
688        let hi = cx.hi();
689        return Ok(Generics { params: vec![], predicates: None, span: cx.mk_span(hi, hi) });
690    }
691    let lo = cx.lo();
692    let params = angle(cx, Comma, parse_generic_param)?;
693    let hi = cx.hi();
694    Ok(Generics { params, predicates: None, span: cx.mk_span(lo, hi) })
695}
696
697fn parse_generic_param(cx: &mut ParseCtxt) -> ParseResult<GenericParam> {
698    let name = parse_ident(cx)?;
699    Ok(GenericParam { name, node_id: cx.next_node_id() })
700}
701
702fn invalid_ident_err(ident: &Ident) -> ParseError {
703    ParseError { kind: crate::ParseErrorKind::InvalidBinding, span: ident.span }
704}
705
706fn mut_as_strg(inputs: Vec<FnInput>, ensures: &[Ensures]) -> ParseResult<Vec<FnInput>> {
707    // 1. Gather ensures
708    let locs = ensures
709        .iter()
710        .filter_map(|ens| if let Ensures::Type(ident, _, _) = ens { Some(ident) } else { None })
711        .collect::<HashSet<_>>();
712    // 2. Walk over inputs and transform references mentioned in ensures
713    let mut res = vec![];
714    for input in inputs {
715        if let FnInput::Ty(Some(ident), _, _) = &input
716            && locs.contains(&ident)
717        {
718            // a known location: better be a mut or else, error!
719            let FnInput::Ty(Some(ident), ty, id) = input else {
720                return Err(invalid_ident_err(ident));
721            };
722            let TyKind::Ref(Mutability::Mut, inner_ty) = ty.kind else {
723                return Err(invalid_ident_err(&ident));
724            };
725            res.push(FnInput::StrgRef(ident, *inner_ty, id));
726        } else {
727            // not a known location, leave unchanged
728            res.push(input);
729        }
730    }
731    Ok(res)
732}
733
734/// ```text
735/// ⟨fn_sig⟩ := ⟨asyncness⟩ fn ⟨ident⟩?
736///             ⟨ [ ⟨refine_param⟩,* ] ⟩?
737///             ( ⟨fn_inputs⟩,* )
738///             ⟨-> ⟨ty⟩⟩?
739///             ⟨requires⟩ ⟨ensures⟩ ⟨where⟩
740/// ```
741pub(crate) fn parse_fn_sig<T: PeekExpected>(cx: &mut ParseCtxt, end: T) -> ParseResult<FnSig> {
742    let lo = cx.lo();
743    let asyncness = parse_asyncness(cx);
744    cx.expect(kw::Fn)?;
745    let ident = if cx.peek(NonReserved) { Some(parse_ident(cx)?) } else { None };
746    let mut generics = parse_opt_generics(cx)?;
747    let params = if cx.peek(token::OpenBracket) {
748        brackets(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Maybe))?
749    } else {
750        vec![]
751    };
752    let inputs = parens(cx, Comma, parse_fn_input)?;
753    let returns = parse_fn_ret(cx)?;
754    let requires = parse_opt_requires(cx)?;
755    let ensures = parse_opt_ensures(cx)?;
756    let inputs = mut_as_strg(inputs, &ensures)?;
757    generics.predicates = parse_opt_where(cx)?;
758    cx.expect(end)?;
759    let hi = cx.hi();
760    Ok(FnSig {
761        asyncness,
762        generics,
763        params,
764        ident,
765        inputs,
766        requires,
767        output: FnOutput { returns, ensures, node_id: cx.next_node_id() },
768        node_id: cx.next_node_id(),
769        span: cx.mk_span(lo, hi),
770    })
771}
772
773/// ```text
774/// ⟨requires⟩ := ⟨ requires ⟨requires_clause⟩,* ⟩?
775/// ```
776fn parse_opt_requires(cx: &mut ParseCtxt) -> ParseResult<Vec<Requires>> {
777    if !cx.advance_if(kw::Requires) {
778        return Ok(vec![]);
779    }
780    punctuated_until(
781        cx,
782        Comma,
783        |t: TokenKind| t.is_keyword(kw::Ensures) || t.is_keyword(kw::Where) || t.is_eof(),
784        parse_requires_clause,
785    )
786}
787
788/// ```text
789/// ⟨requires_clause⟩ := ⟨ forall ⟨refine_param⟩,+ . ⟩? ⟨expr⟩
790/// ```
791fn parse_requires_clause(cx: &mut ParseCtxt) -> ParseResult<Requires> {
792    let mut params = vec![];
793    if cx.advance_if(kw::Forall) {
794        params = sep1(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Maybe))?;
795        cx.expect(token::Dot)?;
796    }
797    let pred = parse_expr(cx, true)?;
798    Ok(Requires { params, pred })
799}
800
801/// ```text
802/// ⟨ensures⟩ := ⟨ensures ⟨ensures_clause⟩,*⟩?
803/// ```
804fn parse_opt_ensures(cx: &mut ParseCtxt) -> ParseResult<Vec<Ensures>> {
805    if !cx.advance_if(kw::Ensures) {
806        return Ok(vec![]);
807    }
808    punctuated_until(
809        cx,
810        Comma,
811        |t: TokenKind| t.is_keyword(kw::Where) || t.is_eof(),
812        parse_ensures_clause,
813    )
814}
815
816/// ```text
817/// ⟨ensures_clause⟩ :=  ⟨ident⟩ : ⟨ty⟩
818///                   |  ⟨expr⟩
819/// ```
820fn parse_ensures_clause(cx: &mut ParseCtxt) -> ParseResult<Ensures> {
821    if cx.peek2(NonReserved, token::Colon) {
822        // ⟨ident⟩ : ⟨ty⟩
823        let ident = parse_ident(cx)?;
824        cx.expect(token::Colon)?;
825        let ty = parse_type(cx)?;
826        Ok(Ensures::Type(ident, ty, cx.next_node_id()))
827    } else {
828        // ⟨expr⟩
829        Ok(Ensures::Pred(parse_expr(cx, true)?))
830    }
831}
832
833fn parse_opt_where(cx: &mut ParseCtxt) -> ParseResult<Option<Vec<WhereBoundPredicate>>> {
834    if !cx.advance_if(kw::Where) {
835        return Ok(None);
836    }
837    Ok(Some(punctuated_until(cx, Comma, token::Eof, parse_where_bound)?))
838}
839
840fn parse_where_bound(cx: &mut ParseCtxt) -> ParseResult<WhereBoundPredicate> {
841    let lo = cx.lo();
842    let bounded_ty = parse_type(cx)?;
843    cx.expect(token::Colon)?;
844    let bounds = parse_generic_bounds(cx)?;
845    let hi = cx.hi();
846    Ok(WhereBoundPredicate { span: cx.mk_span(lo, hi), bounded_ty, bounds })
847}
848
849/// ```text
850/// ⟨fn_ret⟩ := ⟨ -> ⟨ty⟩ ⟩?
851/// ```
852fn parse_fn_ret(cx: &mut ParseCtxt) -> ParseResult<FnRetTy> {
853    if cx.advance_if(token::RArrow) {
854        Ok(FnRetTy::Ty(Box::new(parse_type(cx)?)))
855    } else {
856        let hi = cx.hi();
857        Ok(FnRetTy::Default(cx.mk_span(hi, hi)))
858    }
859}
860
861/// ```text
862/// ⟨fn_input⟩ := ⟨ident⟩ : &strg ⟨ty⟩
863///             | ⟨ident⟩ : ⟨path⟩ { ⟨expr⟩ }
864///             | ⟨ident⟩ : ⟨ty⟩
865///             | ⟨ty⟩
866/// ```
867fn parse_fn_input(cx: &mut ParseCtxt) -> ParseResult<FnInput> {
868    if cx.peek2(NonReserved, token::Colon) {
869        let bind = parse_ident(cx)?;
870        cx.expect(token::Colon)?;
871        if cx.advance_if2(token::And, kw::Strg) {
872            // ⟨ident⟩ : &strg ⟨ty⟩
873            Ok(FnInput::StrgRef(bind, parse_type(cx)?, cx.next_node_id()))
874        } else if cx.peek(NonReserved) {
875            let path = parse_path(cx)?;
876            if cx.peek3(token::OpenBrace, NonReserved, token::Colon) {
877                // ⟨ident⟩ : ⟨path⟩ { ⟨ident⟩ : ⟨expr⟩ }
878                let bty = path_to_bty(path);
879                let ty = parse_bty_exists(cx, bty)?;
880                Ok(FnInput::Ty(Some(bind), ty, cx.next_node_id()))
881            } else if cx.peek(token::OpenBrace) {
882                // ⟨ident⟩ : ⟨path⟩ { ⟨expr⟩ }
883                let pred = delimited(cx, Brace, |cx| parse_expr(cx, true))?;
884                Ok(FnInput::Constr(bind, path, pred, cx.next_node_id()))
885            } else {
886                // ⟨ident⟩ : ⟨ty⟩
887                let bty = path_to_bty(path);
888                let ty = parse_bty_rhs(cx, bty)?;
889                Ok(FnInput::Ty(Some(bind), ty, cx.next_node_id()))
890            }
891        } else {
892            // ⟨ident⟩ : ⟨ty⟩
893            Ok(FnInput::Ty(Some(bind), parse_type(cx)?, cx.next_node_id()))
894        }
895    } else {
896        // ⟨ty⟩
897        Ok(FnInput::Ty(None, parse_type(cx)?, cx.next_node_id()))
898    }
899}
900
901/// ```text
902/// ⟨asyncness⟩ := async?
903/// ```
904fn parse_asyncness(cx: &mut ParseCtxt) -> Async {
905    let lo = cx.lo();
906    if cx.advance_if(kw::Async) {
907        Async::Yes { node_id: cx.next_node_id(), span: cx.mk_span(lo, cx.hi()) }
908    } else {
909        Async::No
910    }
911}
912
913/// ```text
914/// ⟨ty⟩ := _
915///       | { ⟨ident⟩ ⟨,⟨ident⟩⟩* . ⟨ty⟩ | ⟨block_expr⟩ }
916///       | ( ⟨ty⟩,* )
917///       | { ⟨ty⟩ | ⟨block_expr⟩ }
918///       | { ⟨refine_param⟩ ⟨,⟨refine_param⟩⟩* . ⟨ty⟩ | ⟨block_expr⟩ }
919///       | & mut? ⟨ty⟩
920///       | [ ⟨ty⟩ ; ⟨const_arg⟩ ]
921///       | impl ⟨path⟩
922///       | ⟨bty⟩
923///       | ⟨bty⟩ [ ⟨refine_arg⟩,* ]
924///       | ⟨bty⟩ { ⟨ident⟩ : ⟨block_expr⟩ }
925///
926/// ⟨bty⟩ := ⟨path⟩ | ⟨qpath⟩ | [ ⟨ty⟩ ]
927/// ```
928pub(crate) fn parse_type(cx: &mut ParseCtxt) -> ParseResult<Ty> {
929    let lo = cx.lo();
930    let mut lookahead = cx.lookahead1();
931    let kind = if lookahead.advance_if(kw::Underscore) {
932        TyKind::Hole
933    } else if lookahead.advance_if(token::OpenParen) {
934        // ( ⟨ty⟩,* )
935        let (mut tys, trailing) =
936            punctuated_with_trailing(cx, Comma, token::CloseParen, parse_type)?;
937        cx.expect(token::CloseParen)?;
938        if tys.len() == 1 && !trailing {
939            return Ok(tys.remove(0));
940        } else {
941            TyKind::Tuple(tys)
942        }
943    } else if lookahead.peek(token::OpenBrace) {
944        delimited(cx, Brace, |cx| {
945            if cx.peek2(NonReserved, AnyOf([token::Comma, token::Dot, token::Colon])) {
946                // { ⟨refine_param⟩ ⟨,⟨refine_param⟩⟩* . ⟨ty⟩ | ⟨block_expr⟩ }
947                parse_general_exists(cx)
948            } else {
949                // { ⟨ty⟩ | ⟨block_expr⟩ }
950                let ty = parse_type(cx)?;
951                cx.expect(token::Or)?;
952                let pred = parse_block_expr(cx)?;
953                Ok(TyKind::Constr(pred, Box::new(ty)))
954            }
955        })?
956    } else if lookahead.advance_if(token::And) {
957        //  & mut? ⟨ty⟩
958        let mutbl = if cx.advance_if(kw::Mut) { Mutability::Mut } else { Mutability::Not };
959        TyKind::Ref(mutbl, Box::new(parse_type(cx)?))
960    } else if lookahead.advance_if(token::OpenBracket) {
961        let ty = parse_type(cx)?;
962        if cx.advance_if(token::Semi) {
963            // [ ⟨ty⟩ ; ⟨const_arg⟩ ]
964            let len = parse_const_arg(cx)?;
965            cx.expect(token::CloseBracket)?;
966            TyKind::Array(Box::new(ty), len)
967        } else {
968            // [ ⟨ty⟩ ] ...
969            cx.expect(token::CloseBracket)?;
970            let span = cx.mk_span(lo, cx.hi());
971            let kind = BaseTyKind::Slice(Box::new(ty));
972            return parse_bty_rhs(cx, BaseTy { kind, span });
973        }
974    } else if lookahead.advance_if(kw::Impl) {
975        // impl ⟨bounds⟩
976        TyKind::ImplTrait(cx.next_node_id(), parse_generic_bounds(cx)?)
977    } else if lookahead.peek(NonReserved) {
978        // ⟨path⟩ ...
979        let path = parse_path(cx)?;
980        let bty = path_to_bty(path);
981        return parse_bty_rhs(cx, bty);
982    } else if lookahead.peek(LAngle) {
983        // ⟨qpath⟩ ...
984        let bty = parse_qpath(cx)?;
985        return parse_bty_rhs(cx, bty);
986    } else {
987        return Err(lookahead.into_error());
988    };
989    let hi = cx.hi();
990    Ok(Ty { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
991}
992
993/// ```text
994/// ⟨qpath⟩ := < ⟨ty⟩ as ⟨segments⟩> :: ⟨segments⟩
995/// ```
996fn parse_qpath(cx: &mut ParseCtxt) -> ParseResult<BaseTy> {
997    let lo = cx.lo();
998    cx.expect(LAngle)?;
999    let qself = parse_type(cx)?;
1000    cx.expect(kw::As)?;
1001    let mut segments = parse_segments(cx)?;
1002    cx.expect(RAngle)?;
1003    cx.expect(token::PathSep)?;
1004    segments.extend(parse_segments(cx)?);
1005    let hi = cx.hi();
1006
1007    let span = cx.mk_span(lo, hi);
1008    let path = Path { segments, refine: vec![], node_id: cx.next_node_id(), span };
1009    let kind = BaseTyKind::Path(Some(Box::new(qself)), path);
1010    Ok(BaseTy { kind, span })
1011}
1012
1013/// ```text
1014/// { ⟨refine_param⟩ ⟨,⟨refine_param⟩⟩* . ⟨ty⟩ | ⟨block_expr⟩ }
1015/// ```
1016fn parse_general_exists(cx: &mut ParseCtxt) -> ParseResult<TyKind> {
1017    let params = sep1(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Maybe))?;
1018    cx.expect(token::Dot)?;
1019    let ty = parse_type(cx)?;
1020    let pred = if cx.advance_if(token::Or) { Some(parse_block_expr(cx)?) } else { None };
1021    Ok(TyKind::GeneralExists { params, ty: Box::new(ty), pred })
1022}
1023
1024/// ```text
1025///    ⟨bty⟩ [ ⟨refine_arg⟩,* ]
1026/// |  ⟨bty⟩ { ⟨ident⟩ : ⟨block_expr⟩ }
1027/// |  ⟨bty⟩
1028/// ```
1029fn parse_bty_rhs(cx: &mut ParseCtxt, bty: BaseTy) -> ParseResult<Ty> {
1030    let lo = bty.span.lo();
1031    if cx.peek(token::OpenBracket) {
1032        // ⟨bty⟩ [ ⟨refine_arg⟩,* ]
1033        let indices = parse_indices(cx)?;
1034        let hi = cx.hi();
1035        let kind = TyKind::Indexed { bty, indices };
1036        Ok(Ty { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1037    } else if cx.peek(token::OpenBrace) {
1038        // ⟨bty⟩ { ⟨ident⟩ : ⟨block_expr⟩ }
1039        parse_bty_exists(cx, bty)
1040    } else {
1041        // ⟨bty⟩
1042        let hi = cx.hi();
1043        let kind = TyKind::Base(bty);
1044        Ok(Ty { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1045    }
1046}
1047
1048/// ```text
1049/// ⟨bty⟩ { ⟨ident⟩ : ⟨block_expr⟩ }
1050/// ```
1051fn parse_bty_exists(cx: &mut ParseCtxt, bty: BaseTy) -> ParseResult<Ty> {
1052    let lo = bty.span.lo();
1053    delimited(cx, Brace, |cx| {
1054        let bind = parse_ident(cx)?;
1055        cx.expect(token::Colon)?;
1056        let pred = parse_block_expr(cx)?;
1057        let hi = cx.hi();
1058        let kind = TyKind::Exists { bind, bty, pred };
1059        Ok(Ty { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1060    })
1061}
1062
1063fn path_to_bty(path: Path) -> BaseTy {
1064    let span = path.span;
1065    BaseTy { kind: BaseTyKind::Path(None, path), span }
1066}
1067
1068fn parse_indices(cx: &mut ParseCtxt) -> ParseResult<Indices> {
1069    let lo = cx.lo();
1070    let indices = brackets(cx, Comma, parse_refine_arg)?;
1071    let hi = cx.hi();
1072    Ok(Indices { indices, span: cx.mk_span(lo, hi) })
1073}
1074
1075fn parse_fn_bound_input(cx: &mut ParseCtxt) -> ParseResult<GenericArg> {
1076    let lo = cx.lo();
1077    let tys = parens(cx, Comma, parse_type)?;
1078    let hi = cx.hi();
1079    let kind = TyKind::Tuple(tys);
1080    let span = cx.mk_span(lo, hi);
1081    let in_ty = Ty { kind, node_id: cx.next_node_id(), span };
1082    Ok(GenericArg { kind: GenericArgKind::Type(in_ty), node_id: cx.next_node_id() })
1083}
1084
1085fn parse_fn_bound_output(cx: &mut ParseCtxt) -> ParseResult<GenericArg> {
1086    let lo = cx.lo();
1087
1088    let ty = if cx.advance_if(token::RArrow) {
1089        parse_type(cx)?
1090    } else {
1091        Ty { kind: TyKind::Tuple(vec![]), node_id: cx.next_node_id(), span: cx.mk_span(lo, lo) }
1092    };
1093    let hi = cx.hi();
1094    let ident = Ident { name: Output, span: cx.mk_span(lo, hi) };
1095    Ok(GenericArg { kind: GenericArgKind::Constraint(ident, ty), node_id: cx.next_node_id() })
1096}
1097
1098fn parse_fn_bound_path(cx: &mut ParseCtxt) -> ParseResult<Path> {
1099    let lo = cx.lo();
1100    let ident = parse_ident(cx)?;
1101    let in_arg = parse_fn_bound_input(cx)?;
1102    let out_arg = parse_fn_bound_output(cx)?;
1103    let args = vec![in_arg, out_arg];
1104    let segment = PathSegment { ident, args, node_id: cx.next_node_id() };
1105    let hi = cx.hi();
1106    Ok(Path {
1107        segments: vec![segment],
1108        refine: vec![],
1109        node_id: cx.next_node_id(),
1110        span: cx.mk_span(lo, hi),
1111    })
1112}
1113
1114fn parse_generic_bounds(cx: &mut ParseCtxt) -> ParseResult<GenericBounds> {
1115    let path = if cx.peek(sym::FnOnce) || cx.peek(sym::FnMut) || cx.peek(sym::Fn) {
1116        parse_fn_bound_path(cx)?
1117    } else {
1118        parse_path(cx)?
1119    };
1120    Ok(vec![TraitRef { path, node_id: cx.next_node_id() }])
1121}
1122
1123fn parse_const_arg(cx: &mut ParseCtxt) -> ParseResult<ConstArg> {
1124    let lo = cx.lo();
1125    let mut lookahead = cx.lookahead1();
1126    let kind = if lookahead.peek(AnyLit) {
1127        let len = parse_int(cx)?;
1128        ConstArgKind::Lit(len)
1129    } else if lookahead.advance_if(kw::Underscore) {
1130        ConstArgKind::Infer
1131    } else {
1132        return Err(lookahead.into_error());
1133    };
1134    let hi = cx.hi();
1135    Ok(ConstArg { kind, span: cx.mk_span(lo, hi) })
1136}
1137
1138/// ```text
1139/// ⟨path⟩ := ⟨segments⟩ ⟨ ( ⟨refine_arg⟩,* ) ⟩?
1140/// ```
1141fn parse_path(cx: &mut ParseCtxt) -> ParseResult<Path> {
1142    let lo = cx.lo();
1143    let segments = parse_segments(cx)?;
1144    let refine =
1145        if cx.peek(token::OpenParen) { parens(cx, Comma, parse_refine_arg)? } else { vec![] };
1146    let hi = cx.hi();
1147    Ok(Path { segments, refine, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1148}
1149
1150/// ```text
1151/// ⟨segments⟩ := ⟨segment⟩ ⟨:: ⟨segment⟩ ⟩*
1152/// ```
1153fn parse_segments(cx: &mut ParseCtxt) -> ParseResult<Vec<PathSegment>> {
1154    sep1(cx, token::PathSep, parse_segment)
1155}
1156
1157/// ```text
1158/// ⟨segment⟩ := ⟨ident⟩ ⟨ < ⟨generic_arg⟩,* > ⟩?
1159/// ```
1160fn parse_segment(cx: &mut ParseCtxt) -> ParseResult<PathSegment> {
1161    let ident = parse_ident(cx)?;
1162    let args = opt_angle(cx, Comma, parse_generic_arg)?;
1163    Ok(PathSegment { ident, node_id: cx.next_node_id(), args })
1164}
1165
1166/// ```text
1167/// ⟨generic_arg⟩ := ⟨ty⟩ | ⟨ident⟩ = ⟨ty⟩
1168/// ```
1169fn parse_generic_arg(cx: &mut ParseCtxt) -> ParseResult<GenericArg> {
1170    let kind = if cx.peek2(NonReserved, token::Eq) {
1171        let ident = parse_ident(cx)?;
1172        cx.expect(token::Eq)?;
1173        let ty = parse_type(cx)?;
1174        GenericArgKind::Constraint(ident, ty)
1175    } else {
1176        GenericArgKind::Type(parse_type(cx)?)
1177    };
1178    Ok(GenericArg { kind, node_id: cx.next_node_id() })
1179}
1180
1181/// ```text
1182/// ⟨refine_arg⟩ :=  @ ⟨ident⟩
1183///               |  # ⟨ident⟩
1184///               |  |⟨⟨refine_parm⟩,*| ⟨expr⟩
1185///               |  ⟨expr⟩
1186/// ```
1187fn parse_refine_arg(cx: &mut ParseCtxt) -> ParseResult<RefineArg> {
1188    let lo = cx.lo();
1189    let arg = if cx.advance_if(token::At) {
1190        // @ ⟨ident⟩
1191        let bind = parse_ident(cx)?;
1192        let hi = cx.hi();
1193        RefineArg::Bind(bind, BindKind::At, cx.mk_span(lo, hi), cx.next_node_id())
1194    } else if cx.peek2(token::Pound, NonReserved) {
1195        // # ⟨ident⟩
1196        cx.expect(token::Pound)?;
1197        let bind = parse_ident(cx)?;
1198        let hi = cx.hi();
1199        RefineArg::Bind(bind, BindKind::Pound, cx.mk_span(lo, hi), cx.next_node_id())
1200    } else if cx.advance_if(Or) {
1201        let params =
1202            punctuated_until(cx, Comma, Or, |cx| parse_refine_param(cx, RequireSort::Maybe))?;
1203        cx.expect(Or)?;
1204        let body = parse_expr(cx, true)?;
1205        let hi = cx.hi();
1206        RefineArg::Abs(params, body, cx.mk_span(lo, hi), cx.next_node_id())
1207    } else {
1208        // ⟨expr⟩
1209        RefineArg::Expr(parse_expr(cx, true)?)
1210    };
1211    Ok(arg)
1212}
1213
1214/// Whether a sort is required in a refinement parameter declaration.
1215enum RequireSort {
1216    /// Definitely require a sort
1217    Yes,
1218    /// Optional sort. Use [`Sort::Infer`] if not present
1219    Maybe,
1220    /// Definitely do not not require a sort. Always use [`Sort::Infer`]
1221    No,
1222}
1223
1224fn parse_sort_if_required(cx: &mut ParseCtxt, require_sort: RequireSort) -> ParseResult<Sort> {
1225    match require_sort {
1226        RequireSort::No => Ok(Sort::Infer),
1227        RequireSort::Maybe => {
1228            if cx.advance_if(token::Colon) {
1229                parse_sort(cx)
1230            } else {
1231                Ok(Sort::Infer)
1232            }
1233        }
1234        RequireSort::Yes => {
1235            cx.expect(token::Colon)?;
1236            parse_sort(cx)
1237        }
1238    }
1239}
1240
1241/// ```text
1242/// ⟨refine_param⟩ := ⟨mode⟩? ⟨ident⟩ ⟨ : ⟨sort⟩ ⟩?    if require_sort is Maybe
1243///                 | ⟨mode⟩? ⟨ident⟩ : ⟨sort⟩         if require_sort is Yes
1244///                 | ⟨mode⟩? ⟨ident⟩                  if require_sort is No
1245/// ```
1246fn parse_refine_param(cx: &mut ParseCtxt, require_sort: RequireSort) -> ParseResult<RefineParam> {
1247    let lo = cx.lo();
1248    let mode = parse_opt_param_mode(cx);
1249    let ident = parse_ident(cx)?;
1250    let sort = parse_sort_if_required(cx, require_sort)?;
1251    let hi = cx.hi();
1252    Ok(RefineParam { mode, ident, sort, span: cx.mk_span(lo, hi), node_id: cx.next_node_id() })
1253}
1254
1255/// ```text
1256/// ⟨mode⟩ := ⟨ hrn | hdl ⟩?
1257/// ```
1258fn parse_opt_param_mode(cx: &mut ParseCtxt) -> Option<ParamMode> {
1259    if cx.advance_if(kw::Hrn) {
1260        Some(ParamMode::Horn)
1261    } else if cx.advance_if(kw::Hdl) {
1262        Some(ParamMode::Hindley)
1263    } else {
1264        None
1265    }
1266}
1267
1268pub(crate) fn parse_expr(cx: &mut ParseCtxt, allow_struct: bool) -> ParseResult<Expr> {
1269    parse_binops(cx, Precedence::MIN, allow_struct)
1270}
1271
1272fn parse_binops(cx: &mut ParseCtxt, base: Precedence, allow_struct: bool) -> ParseResult<Expr> {
1273    let mut lhs = unary_expr(cx, allow_struct)?;
1274    loop {
1275        let lo = cx.lo();
1276        let Some((op, ntokens)) = cx.peek_binop() else { break };
1277        let precedence = Precedence::of_binop(&op);
1278        if precedence < base {
1279            break;
1280        }
1281        cx.advance_by(ntokens);
1282        let next = match precedence.associativity() {
1283            Associativity::Right => precedence,
1284            Associativity::Left => precedence.next(),
1285            Associativity::None => {
1286                if let ExprKind::BinaryOp(op, ..) = &lhs.kind
1287                    && Precedence::of_binop(op) == precedence
1288                {
1289                    return Err(cx.cannot_be_chained(lo, cx.hi()));
1290                }
1291                precedence.next()
1292            }
1293        };
1294        let rhs = parse_binops(cx, next, allow_struct)?;
1295        let span = lhs.span.to(rhs.span);
1296        lhs = Expr {
1297            kind: ExprKind::BinaryOp(op, Box::new([lhs, rhs])),
1298            node_id: cx.next_node_id(),
1299            span,
1300        }
1301    }
1302    Ok(lhs)
1303}
1304
1305/// ```text
1306/// ⟨unary_expr⟩ := - ⟨unary_expr⟩ | ! ⟨unary_expr⟩ | ⟨trailer_expr⟩
1307/// ```
1308fn unary_expr(cx: &mut ParseCtxt, allow_struct: bool) -> ParseResult<Expr> {
1309    let lo = cx.lo();
1310    let kind = if cx.advance_if(token::Minus) {
1311        ExprKind::UnaryOp(UnOp::Neg, Box::new(unary_expr(cx, allow_struct)?))
1312    } else if cx.advance_if(token::Bang) {
1313        ExprKind::UnaryOp(UnOp::Not, Box::new(unary_expr(cx, allow_struct)?))
1314    } else {
1315        return parse_trailer_expr(cx, allow_struct);
1316    };
1317    let hi = cx.hi();
1318    Ok(Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1319}
1320
1321/// ```text
1322/// ⟨trailer_expr⟩ :=  ⟨trailer_expr⟩ . ⟨ident⟩
1323///                 |  ⟨trailer_expr⟩ ( ⟨expr⟩,* )
1324///                 |  ⟨atom⟩
1325/// ```
1326fn parse_trailer_expr(cx: &mut ParseCtxt, allow_struct: bool) -> ParseResult<Expr> {
1327    let lo = cx.lo();
1328    let mut e = parse_atom(cx, allow_struct)?;
1329    loop {
1330        let kind = if cx.advance_if(token::Dot) {
1331            // ⟨trailer_expr⟩ . ⟨ident⟩
1332            let field = parse_ident(cx)?;
1333            ExprKind::Dot(Box::new(e), field)
1334        } else if cx.peek(token::OpenParen) {
1335            // ⟨trailer_expr⟩ ( ⟨expr⟩,* )
1336            let args = parens(cx, Comma, |cx| parse_expr(cx, true))?;
1337            ExprKind::Call(Box::new(e), args)
1338        } else {
1339            break;
1340        };
1341        let hi = cx.hi();
1342        e = Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) };
1343    }
1344    Ok(e)
1345}
1346
1347/// ```text
1348/// ⟨atom⟩ := ⟨if_expr⟩
1349///         | ⟨lit⟩
1350///         | ( ⟨expr⟩ )
1351///         | ⟨epath⟩
1352///         | ⟨bounded_quant⟩
1353///         |  <⟨ty⟩ as ⟨path⟩> :: ⟨ident⟩
1354///         | [binop]
1355///         | ⟨epath⟩ { ⟨constructor_arg⟩,* }    if allow_struct
1356///         | { ⟨constructor_arg⟩,* }            if allow_struct
1357///         | #{ ⟨expr⟩,* }
1358/// ```
1359fn parse_atom(cx: &mut ParseCtxt, allow_struct: bool) -> ParseResult<Expr> {
1360    let lo = cx.lo();
1361    let mut lookahead = cx.lookahead1();
1362    if lookahead.peek(kw::If) {
1363        // ⟨if_expr⟩
1364        parse_if_expr(cx)
1365    } else if lookahead.peek(AnyLit) {
1366        // ⟨lit⟩
1367        parse_lit(cx)
1368    } else if lookahead.peek(token::OpenParen) {
1369        delimited(cx, Parenthesis, |cx| parse_expr(cx, true))
1370    } else if lookahead.advance_if(token::Pound) {
1371        // #{ ⟨expr⟩,* }
1372        let lo = cx.lo();
1373        let exprs = braces(cx, Comma, |cx| parse_expr(cx, true))?;
1374        let hi = cx.hi();
1375        let kind = ExprKind::SetLiteral(exprs);
1376        Ok(Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1377    } else if lookahead.peek(NonReserved) {
1378        let path = parse_expr_path(cx)?;
1379        let kind = if allow_struct && cx.peek(token::OpenBrace) {
1380            // ⟨epath⟩ { ⟨constructor_arg⟩,* }
1381            let args = braces(cx, Comma, parse_constructor_arg)?;
1382            ExprKind::Constructor(Some(path), args)
1383        } else {
1384            // ⟨epath⟩
1385            ExprKind::Path(path)
1386        };
1387        let hi = cx.hi();
1388        Ok(Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1389    } else if allow_struct && lookahead.peek(token::OpenBrace) {
1390        // { ⟨constructor_arg⟩,* }
1391        let args = braces(cx, Comma, parse_constructor_arg)?;
1392        let hi = cx.hi();
1393        Ok(Expr {
1394            kind: ExprKind::Constructor(None, args),
1395            node_id: cx.next_node_id(),
1396            span: cx.mk_span(lo, hi),
1397        })
1398    } else if lookahead.advance_if(LAngle) {
1399        // <⟨ty⟩ as ⟨path⟩> :: ⟨ident⟩
1400        let lo = cx.lo();
1401        let qself = parse_type(cx)?;
1402        cx.expect(kw::As)?;
1403        let path = parse_path(cx)?;
1404        cx.expect(RAngle)?;
1405        cx.expect(token::PathSep)?;
1406        let name = parse_ident(cx)?;
1407        let hi = cx.hi();
1408        let kind = ExprKind::AssocReft(Box::new(qself), path, name);
1409        Ok(Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1410    } else if lookahead.peek(token::OpenBracket) {
1411        parse_prim_uif(cx)
1412    } else if lookahead.peek(kw::Exists) || lookahead.peek(kw::Forall) {
1413        parse_bounded_quantifier(cx)
1414    } else {
1415        Err(lookahead.into_error())
1416    }
1417}
1418
1419fn parse_prim_uif(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1420    let lo = cx.lo();
1421    cx.expect(token::OpenBracket)?;
1422    let op = parse_binop(cx)?;
1423    cx.expect(token::CloseBracket)?;
1424    let hi = cx.hi();
1425    Ok(Expr { kind: ExprKind::PrimUIF(op), node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1426}
1427
1428/// ```text
1429/// ⟨bounded_quant⟩ := forall ⟨refine_param⟩ in ⟨int⟩..⟨int⟩ ⟨block⟩
1430///                  | exists ⟨refine_param⟩ in ⟨int⟩..⟨int⟩ ⟨block⟩
1431/// ```
1432fn parse_bounded_quantifier(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1433    let lo = cx.lo();
1434    let mut lookahead = cx.lookahead1();
1435    let quant = if lookahead.advance_if(kw::Forall) {
1436        QuantKind::Forall
1437    } else if lookahead.advance_if(kw::Exists) {
1438        QuantKind::Exists
1439    } else {
1440        return Err(lookahead.into_error());
1441    };
1442    let param = parse_refine_param(cx, RequireSort::Maybe)?;
1443    cx.expect(kw::In)?;
1444    let start = parse_int(cx)?;
1445    cx.expect(token::DotDot)?;
1446    let end = parse_int(cx)?;
1447    let body = parse_block(cx)?;
1448    let hi = cx.hi();
1449    Ok(Expr {
1450        kind: ExprKind::BoundedQuant(quant, param, start..end, Box::new(body)),
1451        node_id: cx.next_node_id(),
1452        span: cx.mk_span(lo, hi),
1453    })
1454}
1455
1456/// ```text
1457/// ⟨constructor_arg⟩ :=  ⟨ident⟩ : ⟨expr⟩ |  ..
1458/// ```
1459fn parse_constructor_arg(cx: &mut ParseCtxt) -> ParseResult<ConstructorArg> {
1460    let lo = cx.lo();
1461    let mut lookahead = cx.lookahead1();
1462    if lookahead.peek(NonReserved) {
1463        let ident = parse_ident(cx)?;
1464        cx.expect(token::Colon)?;
1465        let expr = parse_expr(cx, true)?;
1466        let hi = cx.hi();
1467        Ok(ConstructorArg::FieldExpr(FieldExpr {
1468            ident,
1469            expr,
1470            node_id: cx.next_node_id(),
1471            span: cx.mk_span(lo, hi),
1472        }))
1473    } else if lookahead.advance_if(token::DotDot) {
1474        let spread = parse_expr(cx, true)?;
1475        let hi = cx.hi();
1476        Ok(ConstructorArg::Spread(Spread {
1477            expr: spread,
1478            node_id: cx.next_node_id(),
1479            span: cx.mk_span(lo, hi),
1480        }))
1481    } else {
1482        Err(lookahead.into_error())
1483    }
1484}
1485
1486/// `⟨epath⟩ := ⟨ident⟩ ⟨ :: ⟨ident⟩ ⟩*`
1487fn parse_expr_path(cx: &mut ParseCtxt) -> ParseResult<ExprPath> {
1488    let lo = cx.lo();
1489    let segments = sep1(cx, token::PathSep, parse_expr_path_segment)?;
1490    let hi = cx.hi();
1491    Ok(ExprPath { segments, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1492}
1493
1494fn parse_expr_path_segment(cx: &mut ParseCtxt) -> ParseResult<ExprPathSegment> {
1495    Ok(ExprPathSegment { ident: parse_ident(cx)?, node_id: cx.next_node_id() })
1496}
1497
1498/// `⟨if_expr⟩ := if ⟨expr⟩ ⟨block⟩ ⟨ else if ⟨expr⟩ ⟨block⟩ ⟩* else ⟨block⟩`
1499///
1500/// The `⟨expr⟩` in conditions is parsed with `allow_struct = false`
1501fn parse_if_expr(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1502    let mut branches = vec![];
1503
1504    loop {
1505        let lo = cx.lo();
1506        cx.expect(kw::If)?;
1507        let cond = parse_expr(cx, false)?;
1508        let then_ = parse_block(cx)?;
1509        branches.push((lo, cond, then_));
1510        cx.expect(kw::Else)?;
1511
1512        if !cx.peek(kw::If) {
1513            break;
1514        }
1515    }
1516    let mut else_ = parse_block(cx)?;
1517
1518    let hi = cx.hi();
1519    while let Some((lo, cond, then_)) = branches.pop() {
1520        else_ = Expr {
1521            kind: ExprKind::IfThenElse(Box::new([cond, then_, else_])),
1522            node_id: cx.next_node_id(),
1523            span: cx.mk_span(lo, hi),
1524        };
1525    }
1526    Ok(else_)
1527}
1528
1529/// `⟨block⟩ := { ⟨block_expr⟩ }`
1530fn parse_block(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1531    delimited(cx, Brace, parse_block_expr)
1532}
1533
1534/// `⟨block_expr⟩ = ⟨let_decl⟩* ⟨expr⟩`
1535fn parse_block_expr(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1536    let lo = cx.lo();
1537    let decls = repeat_while(cx, kw::Let, parse_let_decl)?;
1538    let body = parse_expr(cx, true)?;
1539    let hi = cx.hi();
1540
1541    if decls.is_empty() {
1542        Ok(body)
1543    } else {
1544        let kind = ExprKind::Block(decls, Box::new(body));
1545        Ok(Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1546    }
1547}
1548
1549/// `⟨let_decl⟩ := let ⟨refine_param⟩ = ⟨expr⟩ ;`
1550fn parse_let_decl(cx: &mut ParseCtxt) -> ParseResult<LetDecl> {
1551    cx.expect(kw::Let)?;
1552    let param = parse_refine_param(cx, RequireSort::Maybe)?;
1553    cx.expect(token::Eq)?;
1554    let init = parse_expr(cx, true)?;
1555    cx.expect(token::Semi)?;
1556    Ok(LetDecl { param, init })
1557}
1558
1559/// ```text
1560/// ⟨lit⟩ := ⟨a Rust literal like an integer or a boolean⟩
1561/// ```
1562fn parse_lit(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1563    if let Token { kind: token::Literal(lit), lo, hi } = cx.at(0) {
1564        cx.advance();
1565        Ok(Expr {
1566            kind: ExprKind::Literal(lit),
1567            node_id: cx.next_node_id(),
1568            span: cx.mk_span(lo, hi),
1569        })
1570    } else {
1571        Err(cx.unexpected_token(vec![AnyLit.expected()]))
1572    }
1573}
1574
1575fn parse_ident(cx: &mut ParseCtxt) -> ParseResult<Ident> {
1576    if let Token { kind: token::Ident(name, is_raw), lo, hi } = cx.at(0)
1577        && (!cx.is_reserved(name) || is_raw == IdentIsRaw::Yes)
1578    {
1579        cx.advance();
1580        return Ok(Ident { name, span: cx.mk_span(lo, hi) });
1581    }
1582    Err(cx.unexpected_token(vec![NonReserved.expected()]))
1583}
1584
1585fn parse_int<T: FromStr>(cx: &mut ParseCtxt) -> ParseResult<T> {
1586    if let token::Literal(lit) = cx.at(0).kind
1587        && let LitKind::Integer = lit.kind
1588        && let Ok(value) = lit.symbol.as_str().parse::<T>()
1589    {
1590        cx.advance();
1591        return Ok(value);
1592    }
1593
1594    Err(cx.unexpected_token(vec![Expected::Str(std::any::type_name::<T>())]))
1595}
1596
1597/// ```text
1598/// ⟨sort⟩ :=  ⟨base_sort⟩
1599///         |  ( ⟨base_sort⟩,* ) -> ⟨base_sort⟩
1600///         |  ⟨base_sort⟩ -> ⟨base_sort⟩
1601/// ```
1602fn parse_sort(cx: &mut ParseCtxt) -> ParseResult<Sort> {
1603    if cx.peek(token::OpenParen) {
1604        // ( ⟨base_sort⟩,* ) -> ⟨base_sort⟩
1605        let inputs = parens(cx, Comma, parse_base_sort)?;
1606        cx.expect(token::RArrow)?;
1607        let output = parse_base_sort(cx)?;
1608        Ok(Sort::Func { inputs, output })
1609    } else {
1610        let bsort = parse_base_sort(cx)?;
1611        if cx.advance_if(token::RArrow) {
1612            // ⟨base_sort⟩ -> ⟨base_sort⟩
1613            let output = parse_base_sort(cx)?;
1614            Ok(Sort::Func { inputs: vec![bsort], output })
1615        } else {
1616            // ⟨base_sort⟩
1617            Ok(Sort::Base(bsort))
1618        }
1619    }
1620}
1621
1622/// ```text
1623/// ⟨base_sort⟩ := bitvec < ⟨u32⟩ >
1624///              | ⟨sort_path⟩ < ⟨base_sort⟩,* >
1625///              | < ⟨ty⟩ as ⟨path⟩ > :: ⟨segment⟩
1626/// ⟨sort_path⟩ := ⟨ident⟩ ⟨ :: ⟨ident⟩ ⟩* < (⟨base_sort⟩,*) >
1627/// ```
1628fn parse_base_sort(cx: &mut ParseCtxt) -> ParseResult<BaseSort> {
1629    if cx.advance_if(kw::Bitvec) {
1630        // bitvec < ⟨u32⟩ >
1631        cx.expect(LAngle)?;
1632        let len = parse_int(cx)?;
1633        cx.expect(RAngle)?;
1634        Ok(BaseSort::BitVec(len))
1635    } else if cx.advance_if(LAngle) {
1636        // < ⟨ty⟩ as ⟨path⟩ > :: ⟨segment⟩
1637        let qself = parse_type(cx)?;
1638        cx.expect(kw::As)?;
1639        let mut path = parse_path(cx)?;
1640        cx.expect(RAngle)?;
1641        cx.expect(token::PathSep)?;
1642        path.segments.push(parse_segment(cx)?);
1643        Ok(BaseSort::SortOf(Box::new(qself), path))
1644    } else {
1645        // ⟨sort_path⟩ < ⟨base_sort⟩,* >
1646        let segments = sep1(cx, token::PathSep, parse_ident)?;
1647        let args = opt_angle(cx, Comma, parse_base_sort)?;
1648        let path = SortPath { segments, args, node_id: cx.next_node_id() };
1649        Ok(BaseSort::Path(path))
1650    }
1651}
1652
1653// Reference: https://doc.rust-lang.org/reference/expressions.html#expression-precedence
1654#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
1655enum Precedence {
1656    /// <=>
1657    Iff,
1658    /// =>
1659    Implies,
1660    /// ||
1661    Or,
1662    /// &&
1663    And,
1664    /// == != < > <= >=
1665    Compare,
1666    /// |
1667    BitOr,
1668    /// ^
1669    BitXor,
1670    /// &
1671    BitAnd,
1672    /// << >>
1673    Shift,
1674    /// + -
1675    Sum,
1676    /// * / %
1677    Product,
1678    /// unary - and !
1679    Prefix,
1680}
1681
1682enum Associativity {
1683    Right,
1684    Left,
1685    None,
1686}
1687
1688impl Precedence {
1689    const MIN: Self = Precedence::Iff;
1690
1691    fn of_binop(op: &BinOp) -> Precedence {
1692        match op {
1693            BinOp::Iff => Precedence::Iff,
1694            BinOp::Imp => Precedence::Implies,
1695            BinOp::Or => Precedence::Or,
1696            BinOp::And => Precedence::And,
1697            BinOp::Eq | BinOp::Ne | BinOp::Gt | BinOp::Ge | BinOp::Lt | BinOp::Le => {
1698                Precedence::Compare
1699            }
1700            BinOp::BitOr => Precedence::BitOr,
1701            BinOp::BitXor => Precedence::BitXor,
1702            BinOp::BitAnd => Precedence::BitAnd,
1703            BinOp::BitShl | BinOp::BitShr => Precedence::Shift,
1704            BinOp::Add | BinOp::Sub => Precedence::Sum,
1705            BinOp::Mul | BinOp::Div | BinOp::Mod => Precedence::Product,
1706        }
1707    }
1708
1709    fn next(self) -> Precedence {
1710        match self {
1711            Precedence::Iff => Precedence::Implies,
1712            Precedence::Implies => Precedence::Or,
1713            Precedence::Or => Precedence::And,
1714            Precedence::And => Precedence::Compare,
1715            Precedence::Compare => Precedence::BitOr,
1716            Precedence::BitOr => Precedence::BitXor,
1717            Precedence::BitXor => Precedence::BitAnd,
1718            Precedence::BitAnd => Precedence::Shift,
1719            Precedence::Shift => Precedence::Sum,
1720            Precedence::Sum => Precedence::Product,
1721            Precedence::Product => Precedence::Prefix,
1722            Precedence::Prefix => Precedence::Prefix,
1723        }
1724    }
1725
1726    fn associativity(self) -> Associativity {
1727        match self {
1728            Precedence::Or
1729            | Precedence::And
1730            | Precedence::BitOr
1731            | Precedence::BitXor
1732            | Precedence::BitAnd
1733            | Precedence::Shift
1734            | Precedence::Sum
1735            | Precedence::Product => Associativity::Left,
1736            Precedence::Compare | Precedence::Iff => Associativity::None,
1737            Precedence::Implies | Precedence::Prefix => Associativity::Right,
1738        }
1739    }
1740}