Coverage Report

Created: 2026-10-28 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/askama/askama_parser/src/expr.rs
Line
Count
Source
1
use winnow::Parser;
2
use winnow::ascii::digit1;
3
use winnow::combinator::{
4
    alt, cut_err, empty, fail, not, opt, peek, preceded, repeat, separated, terminated,
5
};
6
use winnow::error::ErrMode;
7
use winnow::stream::Stream;
8
use winnow::token::{any, one_of, take, take_until};
9
10
use crate::node::CondTest;
11
use crate::{
12
    CharLit, ErrorContext, HashSet, InputStream, Num, ParseResult, PathOrIdentifier, StrLit,
13
    StrPrefix, WithSpan, any_rust_token, char_lit, cut_error, deny_any_rust_token, filter,
14
    identifier, is_rust_keyword, keyword, not_suffix_with_hash, num_lit, path_or_identifier,
15
    skip_ws0, skip_ws1, str_lit, ws,
16
};
17
18
macro_rules! expr_prec_layer {
19
    ( $name:ident, $inner:ident, $op:expr ) => {
20
16.3M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
16.3M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::or::{closure#0}
Line
Count
Source
21
1.88M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::and::{closure#0}
Line
Count
Source
21
1.90M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::bor::{closure#0}
Line
Count
Source
21
1.91M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::band::{closure#0}
Line
Count
Source
21
1.91M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::bxor::{closure#0}
Line
Count
Source
21
1.91M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::addsub::{closure#0}
Line
Count
Source
21
1.95M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::shifts::{closure#0}
Line
Count
Source
21
1.91M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::muldivmod::{closure#0}
Line
Count
Source
21
1.99M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
16.3M
        }
<askama_parser::expr::Expr>::or
Line
Count
Source
20
2.00M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
2.00M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
2.00M
        }
<askama_parser::expr::Expr>::and
Line
Count
Source
20
2.01M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
2.01M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
2.01M
        }
<askama_parser::expr::Expr>::bor
Line
Count
Source
20
2.04M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
2.04M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
2.04M
        }
<askama_parser::expr::Expr>::band
Line
Count
Source
20
2.04M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
2.04M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
2.04M
        }
<askama_parser::expr::Expr>::bxor
Line
Count
Source
20
2.04M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
2.04M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
2.04M
        }
<askama_parser::expr::Expr>::addsub
Line
Count
Source
20
2.04M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
2.04M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
2.04M
        }
<askama_parser::expr::Expr>::shifts
Line
Count
Source
20
2.04M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
2.04M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
2.04M
        }
<askama_parser::expr::Expr>::muldivmod
Line
Count
Source
20
2.10M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
2.10M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
2.10M
        }
23
    };
24
}
25
26
const MAX_REFS: usize = 20;
27
28
16.3M
fn expr_prec_layer<'a: 'l, 'l>(
29
16.3M
    i: &mut InputStream<'a, 'l>,
30
16.3M
    inner: fn(&mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>>,
31
16.3M
    op: fn(&mut InputStream<'a, 'l>) -> ParseResult<'a>,
32
16.3M
) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>> {
33
16.3M
    let mut expr = inner(i)?;
34
35
15.3M
    let mut level_guard = i.state.level.guard();
36
15.4M
    let mut next = opt(|i: &mut _| {
37
        // We need to make sure that we decrement the level before we enter the right-hand side.
38
15.4M
        let i_before = *i;
39
15.4M
        let op = ws(op.with_span()).parse_next(i)?;
40
184k
        level_guard.nest(&i_before)?;
41
184k
        Ok((op, inner(i)?))
42
15.4M
    });
43
15.4M
    while let Some(((op, span), rhs)) = next.parse_next(i)? {
44
99.0k
        expr = WithSpan::new(Box::new(Expr::BinOp(BinOp { op, lhs: expr, rhs })), span);
45
99.0k
    }
46
47
15.3M
    Ok(expr)
48
16.3M
}
49
50
#[derive(Clone, Copy, Default)]
51
struct Allowed {
52
    underscore: bool,
53
    super_keyword: bool,
54
}
55
56
3.85M
fn check_expr<'a>(expr: &WithSpan<Box<Expr<'a>>>, allowed: Allowed) -> ParseResult<'a, ()> {
57
3.85M
    match &*expr.inner {
58
2.23M
        &Expr::Var(name) => {
59
            // List can be found in rust compiler "can_be_raw" function (although in our case, it's
60
            // also used in cases like `match`, so `self` is allowed in this case).
61
2.23M
            if (!allowed.super_keyword && name == "super") || matches!(name, "crate" | "Self") {
62
4
                err_reserved_identifier(&WithSpan::new(name, expr.span))
63
2.23M
            } else if !allowed.underscore && name == "_" {
64
226
                err_underscore_identifier(&WithSpan::new(name, expr.span))
65
            } else {
66
2.23M
                Ok(())
67
            }
68
        }
69
2.99k
        &Expr::IsDefined(var) | &Expr::IsNotDefined(var) => {
70
4.95k
            if var == "_" {
71
2
                err_underscore_identifier(&WithSpan::new(var, expr.span))
72
            } else {
73
4.95k
                Ok(())
74
            }
75
        }
76
137k
        Expr::Path(path) => {
77
137k
            if let [arg] = path.as_slice()
78
135k
                && !crate::can_be_variable_name(*arg.name)
79
            {
80
6
                return err_reserved_identifier(&arg.name);
81
137k
            }
82
137k
            Ok(())
83
        }
84
103k
        Expr::Array(elems) | Expr::Tuple(elems) | Expr::Concat(elems) => {
85
489k
            for elem in elems {
86
295k
                check_expr(elem, allowed)?;
87
            }
88
193k
            Ok(())
89
        }
90
7.06k
        Expr::ArrayRepeat(elem, count) => {
91
7.06k
            check_expr(elem, allowed)?;
92
6.96k
            check_expr(count, allowed)?;
93
6.89k
            Ok(())
94
        }
95
29.4k
        Expr::AssociatedItem(elem, associated_item) => {
96
29.4k
            if *associated_item.name == "_" {
97
5
                err_underscore_identifier(&associated_item.name)
98
29.4k
            } else if !crate::can_be_variable_name(*associated_item.name) {
99
0
                err_reserved_identifier(&associated_item.name)
100
            } else {
101
29.4k
                check_expr(elem, Allowed::default())
102
            }
103
        }
104
44.7k
        Expr::Index(elem1, elem2) => {
105
44.7k
            check_expr(elem1, Allowed::default())?;
106
44.4k
            check_expr(elem2, Allowed::default())
107
        }
108
433k
        Expr::BinOp(v) => {
109
433k
            check_expr(&v.lhs, Allowed::default())?;
110
432k
            check_expr(&v.rhs, Allowed::default())
111
        }
112
33.5k
        Expr::Range(v) => {
113
33.5k
            if let Some(elem1) = v.lhs.as_ref() {
114
12.7k
                check_expr(elem1, Allowed::default())?;
115
20.8k
            }
116
33.5k
            if let Some(elem2) = v.rhs.as_ref() {
117
14.4k
                check_expr(elem2, Allowed::default())?;
118
19.0k
            }
119
33.5k
            Ok(())
120
        }
121
14.4k
        Expr::As(elem, _)
122
172k
        | Expr::Unary(_, elem)
123
118k
        | Expr::Group(elem)
124
2.20k
        | Expr::NamedArgument(_, elem)
125
321k
        | Expr::Try(elem) => check_expr(elem, Allowed::default()),
126
161k
        Expr::Call(v) => {
127
161k
            check_expr(
128
161k
                &v.path,
129
161k
                Allowed {
130
161k
                    underscore: false,
131
161k
                    super_keyword: true,
132
161k
                },
133
150
            )?;
134
238k
            for arg in &v.args {
135
76.8k
                check_expr(arg, Allowed::default())?;
136
            }
137
161k
            Ok(())
138
        }
139
39.5k
        Expr::Filter(filter) => {
140
112k
            for arg in &filter.arguments {
141
73.0k
                check_expr(arg, Allowed::default())?;
142
            }
143
39.2k
            Ok(())
144
        }
145
9.07k
        Expr::Struct(s) => {
146
9.07k
            check_expr(
147
9.07k
                &s.path,
148
9.07k
                Allowed {
149
9.07k
                    underscore: false,
150
9.07k
                    super_keyword: true,
151
9.07k
                },
152
340
            )?;
153
952k
            for field in &s.fields {
154
943k
                if field.name.inner == "_" {
155
11
                    return err_underscore_identifier(&field.name);
156
943k
                } else if !crate::can_be_variable_name(field.name.inner) {
157
8
                    return err_reserved_identifier(&field.name);
158
943k
                }
159
943k
                if let Some(ref value) = field.value {
160
4.20k
                    check_expr(value, Allowed::default())?;
161
939k
                }
162
            }
163
8.71k
            Ok(())
164
        }
165
0
        Expr::LetCond(cond) => check_expr(&cond.expr, Allowed::default()),
166
0
        Expr::ArgumentPlaceholder => cut_error!("unreachable", expr.span),
167
        Expr::BoolLit(_)
168
        | Expr::NumLit(_, _)
169
        | Expr::StrLit(_)
170
        | Expr::CharLit(_)
171
        | Expr::RustMacro(_, _)
172
202k
        | Expr::FilterSource => Ok(()),
173
    }
174
3.85M
}
175
176
#[inline(always)]
177
262
fn err_underscore_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
178
262
    cut_error!("reserved keyword `_` cannot be used here", name.span)
179
262
}
askama_parser::expr::err_underscore_identifier::<askama_parser::expr::TyGenericsKind>
Line
Count
Source
177
18
fn err_underscore_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
178
18
    cut_error!("reserved keyword `_` cannot be used here", name.span)
179
18
}
askama_parser::expr::err_underscore_identifier::<()>
Line
Count
Source
177
244
fn err_underscore_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
178
244
    cut_error!("reserved keyword `_` cannot be used here", name.span)
179
244
}
180
181
#[inline(always)]
182
53
fn err_reserved_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
183
53
    cut_error!(
184
        format!("`{}` cannot be used as an identifier", name.inner),
185
        name.span
186
    )
187
53
}
askama_parser::expr::err_reserved_identifier::<askama_parser::expr::TyGenericsKind>
Line
Count
Source
182
35
fn err_reserved_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
183
35
    cut_error!(
184
        format!("`{}` cannot be used as an identifier", name.inner),
185
        name.span
186
    )
187
35
}
askama_parser::expr::err_reserved_identifier::<()>
Line
Count
Source
182
18
fn err_reserved_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
183
18
    cut_error!(
184
        format!("`{}` cannot be used as an identifier", name.inner),
185
        name.span
186
    )
187
18
}
188
189
#[derive(Clone, Debug, PartialEq)]
190
pub struct PathComponent<'a> {
191
    pub name: WithSpan<&'a str>,
192
    pub generics: Option<WithSpan<Vec<WithSpan<TyGenerics<'a>>>>>,
193
}
194
195
impl<'a: 'l, 'l> PathComponent<'a> {
196
    #[inline]
197
6.85k
    pub fn new_with_name(name: WithSpan<&'a str>) -> Self {
198
6.85k
        Self {
199
6.85k
            name,
200
6.85k
            generics: None,
201
6.85k
        }
202
6.85k
    }
203
204
5.23M
    pub(crate) fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
205
5.23M
        let mut p = (
206
5.23M
            identifier.with_span(),
207
5.23M
            opt(preceded(ws("::"), TyGenerics::args)),
208
5.23M
        );
209
5.23M
        let ((name, name_span), generics) = p.parse_next(i)?;
210
4.97M
        Ok(Self {
211
4.97M
            name: WithSpan::new(name, name_span),
212
4.97M
            generics,
213
4.97M
        })
214
5.23M
    }
215
}
216
217
#[derive(Clone, Debug, PartialEq)]
218
pub enum Expr<'a> {
219
    BoolLit(bool),
220
    NumLit(&'a str, Num<'a>),
221
    StrLit(StrLit<'a>),
222
    CharLit(CharLit<'a>),
223
    Var(&'a str),
224
    Path(Vec<PathComponent<'a>>),
225
    Array(Vec<WithSpan<Box<Expr<'a>>>>),
226
    ArrayRepeat(WithSpan<Box<Expr<'a>>>, WithSpan<Box<Expr<'a>>>),
227
    AssociatedItem(WithSpan<Box<Expr<'a>>>, AssociatedItem<'a>),
228
    Index(WithSpan<Box<Expr<'a>>>, WithSpan<Box<Expr<'a>>>),
229
    Filter(Filter<'a>),
230
    As(WithSpan<Box<Expr<'a>>>, WithSpan<&'a str>),
231
    NamedArgument(WithSpan<&'a str>, WithSpan<Box<Expr<'a>>>),
232
    Unary(&'a str, WithSpan<Box<Expr<'a>>>),
233
    BinOp(BinOp<'a>),
234
    Range(Range<'a>),
235
    Group(WithSpan<Box<Expr<'a>>>),
236
    Tuple(Vec<WithSpan<Box<Expr<'a>>>>),
237
    Call(Call<'a>),
238
    RustMacro(Vec<WithSpan<&'a str>>, WithSpan<&'a str>),
239
    Try(WithSpan<Box<Expr<'a>>>),
240
    /// A struct expression (ie `Foo {a: u32, ..Default::default() })`).
241
    Struct(ExprStruct<'a>),
242
    /// This variant should never be used directly. It is created when generating filter blocks.
243
    FilterSource,
244
    IsDefined(&'a str),
245
    IsNotDefined(&'a str),
246
    Concat(Vec<WithSpan<Box<Expr<'a>>>>),
247
    /// If you have `&& let Some(y)`, this variant handles it.
248
    LetCond(WithSpan<CondTest<'a>>),
249
    /// This variant should never be used directly.
250
    /// It is used for the handling of named arguments in the generator, esp. with filters.
251
    ArgumentPlaceholder,
252
}
253
254
#[derive(Clone, Debug, PartialEq)]
255
pub struct Call<'a> {
256
    pub path: WithSpan<Box<Expr<'a>>>,
257
    pub generics: Option<WithSpan<Vec<WithSpan<TyGenerics<'a>>>>>,
258
    pub args: Vec<WithSpan<Box<Expr<'a>>>>,
259
}
260
261
#[derive(Clone, Debug, PartialEq)]
262
pub struct Range<'a> {
263
    pub op: &'a str,
264
    pub lhs: Option<WithSpan<Box<Expr<'a>>>>,
265
    pub rhs: Option<WithSpan<Box<Expr<'a>>>>,
266
}
267
268
#[derive(Clone, Debug, PartialEq)]
269
pub struct BinOp<'a> {
270
    pub op: &'a str,
271
    pub lhs: WithSpan<Box<Expr<'a>>>,
272
    pub rhs: WithSpan<Box<Expr<'a>>>,
273
}
274
275
#[derive(Clone, Debug, PartialEq)]
276
pub struct ExprStruct<'a> {
277
    pub path: WithSpan<Box<Expr<'a>>>,
278
    pub fields: Vec<ExprStructField<'a>>,
279
    pub base: Option<WithSpan<Box<Expr<'a>>>>,
280
}
281
282
impl<'a: 'l, 'l> Expr<'a> {
283
2.10M
    pub(super) fn arguments(
284
2.10M
        i: &mut InputStream<'a, 'l>,
285
2.10M
    ) -> ParseResult<'a, WithSpan<Vec<WithSpan<Box<Self>>>>> {
286
147k
        fn comma<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
287
147k
            (ws(','), no_comma).void().parse_next(i)
288
147k
        }
289
290
165k
        fn no_comma<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
291
165k
            if let Some(span) = opt(','.span()).parse_next(i)? {
292
12
                cut_error!(
293
                    "expected an expression, found a comma in argument list",
294
                    span
295
                )
296
            } else {
297
165k
                Ok(())
298
            }
299
165k
        }
300
301
2.10M
        let span = terminated(ws('('.span()), no_comma).parse_next(i)?;
302
303
        // The stack footprint of this function is huge. Effectively, we half the maximum nesting
304
        // level of function calls `a(b(c(d(..))))` to make sure not to exceed the stack limit.
305
40.1k
        let mut _level_guard = i.state.level.nest_multiple(i, 2)?;
306
307
40.1k
        let mut named_arguments = HashSet::default();
308
40.1k
        let arguments = separated(
309
40.1k
            1..,
310
163k
            move |i: &mut _| {
311
                // Needed to prevent borrowing it twice between this closure and the one
312
                // calling `Self::named_arguments`.
313
163k
                let named_arguments = &mut named_arguments;
314
163k
                let has_named_arguments = !named_arguments.is_empty();
315
316
163k
                let mut p = alt((
317
163k
                    move |i: &mut _| Self::named_argument(i, named_arguments),
318
155k
                    move |i: &mut _| Self::parse(i, false),
319
                ));
320
163k
                let expr = p.parse_next(i)?;
321
134k
                if has_named_arguments && !matches!(**expr, Self::NamedArgument(..)) {
322
29
                    return cut_error!("named arguments must always be passed last", expr.span);
323
134k
                }
324
134k
                Ok(expr)
325
163k
            },
326
            comma,
327
        );
328
329
35.4k
        let (args, closed) =
330
40.1k
            cut_err((opt(terminated(arguments, opt(comma))), opt(ws(')')))).parse_next(i)?;
331
35.4k
        if closed.is_none() {
332
867
            cut_error!("matching closing `)` is missing", span)
333
        } else {
334
34.6k
            Ok(WithSpan::new(args.unwrap_or_default(), span))
335
        }
336
2.10M
    }
337
338
163k
    fn named_argument(
339
163k
        i: &mut InputStream<'a, 'l>,
340
163k
        named_arguments: &mut HashSet<&'a str>,
341
163k
    ) -> ParseResult<'a, WithSpan<Box<Self>>> {
342
8.40k
        let (((argument, arg_span), _, value), span) =
343
163k
            (identifier.with_span(), ws('='), move |i: &mut _| {
344
9.49k
                Self::parse(i, false)
345
9.49k
            })
346
163k
                .with_span()
347
163k
                .parse_next(i)?;
348
8.40k
        if !named_arguments.insert(argument) {
349
25
            return cut_error!(
350
                format!(
351
                    "named argument `{}` was passed more than once",
352
                    argument.escape_debug()
353
                ),
354
                arg_span,
355
            );
356
8.37k
        }
357
358
8.37k
        Ok(WithSpan::new(
359
8.37k
            Box::new(Self::NamedArgument(
360
8.37k
                WithSpan::new(argument, arg_span),
361
8.37k
                value,
362
8.37k
            )),
363
8.37k
            span,
364
8.37k
        ))
365
163k
    }
366
367
2.00M
    pub(super) fn parse(
368
2.00M
        i: &mut InputStream<'a, 'l>,
369
2.00M
        allow_underscore: bool,
370
2.00M
    ) -> ParseResult<'a, WithSpan<Box<Self>>> {
371
2.00M
        let _level_guard = i.state.level.nest(i)?;
372
2.00M
        let mut result = Self::range(i, allow_underscore);
373
2.00M
        if let Err(err) = &mut result {
374
115k
            try_assign_fallback_error(i, err);
375
1.88M
        }
376
2.00M
        result
377
2.00M
    }
378
379
2.00M
    fn range(
380
2.00M
        i: &mut InputStream<'a, 'l>,
381
2.00M
        allow_underscore: bool,
382
2.00M
    ) -> ParseResult<'a, WithSpan<Box<Self>>> {
383
3.88M
        let range_right = move |i: &mut InputStream<'a, 'l>| {
384
10.5k
            let ((op, span), rhs) =
385
3.88M
                (ws(alt(("..=", "..")).with_span()), opt(Self::or)).parse_next(i)?;
386
10.5k
            Ok((op, rhs, span))
387
3.88M
        };
388
389
        // `..expr` or `..`
390
2.00M
        let range_to = range_right.map(move |(op, rhs, span)| {
391
8.27k
            WithSpan::new(Box::new(Self::Range(Range { op, lhs: None, rhs })), span)
392
8.27k
        });
393
394
        // `expr..expr` or `expr..`
395
2.00M
        let range_from = (Self::or, opt(range_right)).map(move |(lhs, rhs)| match rhs {
396
2.30k
            Some((op, rhs, span)) => WithSpan::new(
397
2.30k
                Box::new(Self::Range(Range {
398
2.30k
                    op,
399
2.30k
                    lhs: Some(lhs),
400
2.30k
                    rhs,
401
2.30k
                })),
402
2.30k
                span,
403
            ),
404
1.87M
            None => lhs,
405
1.87M
        });
406
407
2.00M
        let expr = alt((range_to, range_from)).parse_next(i)?;
408
1.88M
        check_expr(
409
1.88M
            &expr,
410
1.88M
            Allowed {
411
1.88M
                underscore: allow_underscore,
412
1.88M
                super_keyword: false,
413
1.88M
            },
414
262
        )?;
415
1.88M
        Ok(expr)
416
2.00M
    }
417
418
    expr_prec_layer!(or, and, "||");
419
    expr_prec_layer!(and, compare, "&&");
420
421
2.03M
    fn compare(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
422
2.03M
        let mut parse_op = ws(alt(("==", "!=", ">=", ">", "<=", "<")).with_span());
423
424
2.03M
        let (expr, rhs) = (Self::bor, opt((parse_op.by_ref(), Self::bor))).parse_next(i)?;
425
1.90M
        let Some(((op, span), rhs)) = rhs else {
426
1.90M
            return Ok(expr);
427
        };
428
7.31k
        let expr = WithSpan::new(Box::new(Expr::BinOp(BinOp { op, lhs: expr, rhs })), span);
429
430
7.31k
        if let Some((op2, span)) = opt(parse_op).parse_next(i)? {
431
101
            return cut_error!(
432
                format!(
433
                    "comparison operators cannot be chained; \
434
                    consider using explicit parentheses, e.g.  `(_ {op} _) {op2} _`"
435
                ),
436
                span,
437
            );
438
7.21k
        }
439
440
7.21k
        Ok(expr)
441
2.03M
    }
442
443
    expr_prec_layer!(bor, bxor, "bitor".value("|"));
444
    expr_prec_layer!(bxor, band, token_xor);
445
    expr_prec_layer!(band, shifts, token_bitand);
446
    expr_prec_layer!(shifts, addsub, alt((">>", "<<")));
447
    expr_prec_layer!(addsub, concat, alt(("+", "-")));
448
449
2.09M
    fn concat(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
450
        #[allow(clippy::type_complexity)]
451
1.95M
        fn concat_expr<'a: 'l, 'l>(
452
1.95M
            i: &mut InputStream<'a, 'l>,
453
1.95M
        ) -> ParseResult<'a, Option<(WithSpan<Box<Expr<'a>>>, std::ops::Range<usize>)>> {
454
1.96M
            let ws1 = |i: &mut _| opt(skip_ws1).parse_next(i);
455
1.95M
            let tilde = (ws1, '~', ws1).with_span();
456
1.95M
            let data = opt((tilde, Expr::muldivmod)).parse_next(i)?;
457
458
1.95M
            let Some((((t1, _, t2), span), expr)) = data else {
459
1.95M
                return Ok(None);
460
            };
461
5.26k
            if t1.is_none() || t2.is_none() {
462
49
                return cut_error!("the concat operator `~` must be surrounded by spaces", span);
463
5.22k
            }
464
465
5.22k
            Ok(Some((expr, span)))
466
1.95M
        }
467
468
2.09M
        let expr = Self::muldivmod(i)?;
469
1.95M
        let expr2 = concat_expr(i)?;
470
1.95M
        if let Some((expr2, span)) = expr2 {
471
2.07k
            let mut exprs = vec![expr, expr2];
472
5.22k
            while let Some((expr, _)) = concat_expr(i)? {
473
3.14k
                exprs.push(expr);
474
3.14k
            }
475
1.81k
            Ok(WithSpan::new(Box::new(Self::Concat(exprs)), span))
476
        } else {
477
1.95M
            Ok(expr)
478
        }
479
2.09M
    }
480
481
    expr_prec_layer!(muldivmod, is_as, alt(("*", "/", "%")));
482
483
2.20M
    fn is_as(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
484
2.20M
        let lhs = Self::filtered(i)?;
485
1.99M
        let checkpoint = i.checkpoint();
486
1.99M
        let rhs = opt(ws(identifier.with_span())).parse_next(i)?;
487
1.99M
        match rhs {
488
16.0k
            Some(("is", span)) => Self::is_as_handle_is(i, lhs, span),
489
14.1k
            Some(("as", span)) => Self::is_as_handle_as(i, lhs, span),
490
            _ => {
491
1.98M
                i.reset(&checkpoint);
492
1.98M
                Ok(lhs)
493
            }
494
        }
495
2.20M
    }
496
497
1.84k
    fn is_as_handle_is(
498
1.84k
        i: &mut InputStream<'a, 'l>,
499
1.84k
        lhs: WithSpan<Box<Expr<'a>>>,
500
1.84k
        span: std::ops::Range<usize>,
501
1.84k
    ) -> ParseResult<'a, WithSpan<Box<Self>>> {
502
1.84k
        let mut rhs = opt(terminated(opt(keyword("not")), ws(keyword("defined"))));
503
1.84k
        let ctor = match rhs.parse_next(i)? {
504
            None => {
505
56
                return cut_error!("expected `defined` or `not defined` after `is`", span);
506
            }
507
1.10k
            Some(None) => Self::IsDefined,
508
676
            Some(Some(_)) => Self::IsNotDefined,
509
        };
510
1.78k
        let var_name = match &**lhs {
511
1.77k
            Self::Var(var_name) => var_name,
512
2
            Self::AssociatedItem(_, _) => {
513
2
                return cut_error!(
514
                    "`is defined` operator can only be used on variables, not on their fields",
515
                    span,
516
                );
517
            }
518
            _ => {
519
5
                return cut_error!("`is defined` operator can only be used on variables", span);
520
            }
521
        };
522
1.77k
        Ok(WithSpan::new(Box::new(ctor(var_name)), span))
523
1.84k
    }
524
525
7.86k
    fn is_as_handle_as(
526
7.86k
        i: &mut InputStream<'a, 'l>,
527
7.86k
        lhs: WithSpan<Box<Expr<'a>>>,
528
7.86k
        span: std::ops::Range<usize>,
529
7.86k
    ) -> ParseResult<'a, WithSpan<Box<Self>>> {
530
7.86k
        let target = opt(path_or_identifier).parse_next(i)?;
531
7.85k
        let Some(PathOrIdentifier::Identifier(target)) = target else {
532
10
            return cut_error!(
533
                "`as` operator expects the name of a primitive type on its right-hand side, \
534
                not a path or alias",
535
                span,
536
            );
537
        };
538
539
7.85k
        if crate::PRIMITIVE_TYPES.contains(&target) {
540
7.55k
            Ok(WithSpan::new(Box::new(Self::As(lhs, target)), span))
541
304
        } else if target.is_empty() {
542
0
            cut_error!(
543
                "`as` operator expects the name of a primitive type on its right-hand side",
544
                span,
545
            )
546
        } else {
547
304
            cut_error!(
548
                format!(
549
                    "`as` operator expects the name of a primitive type on its right-hand \
550
                    side, found `{}`",
551
                    target.escape_debug()
552
                ),
553
                span,
554
            )
555
        }
556
7.86k
    }
557
558
2.20M
    fn filtered(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
559
2.20M
        let mut res = Self::prefix(i)?;
560
561
1.99M
        let mut level_guard = i.state.level.guard();
562
1.99M
        let mut i_before = *i;
563
2.01M
        while let Some((mut filter, span)) = opt(ws(filter.with_span())).parse_next(i)? {
564
13.1k
            level_guard.nest(&i_before)?;
565
13.1k
            filter.arguments.insert(0, res);
566
13.1k
            res = WithSpan::new(Box::new(Self::Filter(filter)), span);
567
13.1k
            i_before = *i;
568
        }
569
1.99M
        Ok(res)
570
2.20M
    }
571
572
2.20M
    fn prefix(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
573
        // This is a rare place where we create recursion in the parsed AST
574
        // without recursing the parser call stack. However, this can lead
575
        // to stack overflows in drop glue when the AST is very deep.
576
2.20M
        let mut level_guard = i.state.level.guard();
577
2.20M
        let mut i_before = *i;
578
2.20M
        let mut ops = vec![];
579
2.27M
        while let Some(op) = opt(ws(alt(("!", "-", "*", "&")).with_span())).parse_next(i)? {
580
63.2k
            level_guard.nest(&i_before)?;
581
63.2k
            ops.push(op);
582
63.2k
            i_before = *i;
583
        }
584
585
2.20M
        let mut expr = Suffix::parse(i)?;
586
1.99M
        for (op, span) in ops.into_iter().rev() {
587
58.2k
            expr = WithSpan::new(Box::new(Self::Unary(op, expr)), span);
588
58.2k
        }
589
590
1.99M
        Ok(expr)
591
2.20M
    }
592
593
2.20M
    fn single(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
594
2.20M
        alt((
595
2.20M
            Self::num,
596
2.20M
            Self::str,
597
2.20M
            Self::char,
598
2.20M
            Self::path_var_bool,
599
2.20M
            Self::array,
600
2.20M
            Self::group,
601
2.20M
        ))
602
2.20M
        .parse_next(i)
603
2.20M
    }
604
605
209k
    fn group(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
606
209k
        (skip_ws0, peek('(')).parse_next(i)?;
607
54.0k
        Self::group_actually(i)
608
209k
    }
609
610
    // `Self::group()` is quite big. Let's only put it on the stack if needed.
611
    #[inline(never)]
612
54.0k
    fn group_actually(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
613
54.0k
        let (expr, span) = cut_err(preceded('(', Self::group_actually_inner))
614
54.0k
            .with_span()
615
54.0k
            .parse_next(i)?;
616
40.1k
        Ok(WithSpan::new(expr, span))
617
54.0k
    }
618
619
    #[inline]
620
54.0k
    fn group_actually_inner(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Self>> {
621
42.3k
        let (expr, comma, closing) = (
622
54.0k
            ws(opt(|i: &mut _| Self::parse(i, true))),
623
54.0k
            opt(terminated(','.span(), skip_ws0)),
624
54.0k
            opt(')'),
625
        )
626
54.0k
            .parse_next(i)?;
627
628
42.3k
        let expr = match (expr, comma, closing) {
629
            // `(expr,`
630
4.52k
            (Some(expr), Some(_), None) => expr,
631
            // `()`
632
22.1k
            (None, None, Some(_)) => return Ok(Box::new(Self::Tuple(vec![]))),
633
            // `(expr)`
634
12.8k
            (Some(expr), None, Some(_)) => return Ok(Box::new(Self::Group(expr))),
635
            // `(expr,)`
636
2.35k
            (Some(expr), Some(_), Some(_)) => return Ok(Box::new(Self::Tuple(vec![expr]))),
637
            // `(`
638
238
            (None, None, None) => return cut_error!("expected closing `)` or an expression", *i),
639
            // `(expr`
640
135
            (Some(_), None, None) => return cut_error!("expected `,` or `)`", *i),
641
            // `(,`
642
12
            (None, Some(span), _) => return cut_error!("stray comma after opening `(`", span),
643
        };
644
645
4.52k
        let mut exprs = vec![expr];
646
4.52k
        let collect_items = opt(separated(
647
4.52k
            1..,
648
150k
            |i: &mut _| {
649
150k
                exprs.push(Self::parse(i, true)?);
650
147k
                Ok(())
651
150k
            },
652
4.52k
            ws(','),
653
        )
654
4.52k
        .map(|()| ()));
655
656
4.52k
        let ((items, comma, close), span) = cut_err((collect_items, ws(opt(',')), opt(')')))
657
4.52k
            .with_span()
658
4.52k
            .parse_next(i)?;
659
2.97k
        let msg = if items.is_none() {
660
35
            "expected `)` or an expression"
661
2.94k
        } else if close.is_some() {
662
2.77k
            return Ok(Box::new(Self::Tuple(exprs)));
663
165
        } else if comma.is_some() {
664
47
            "expected `)` or an expression"
665
        } else {
666
118
            "expected `,` or `)`"
667
        };
668
200
        cut_error!(msg, span)
669
54.0k
    }
670
671
249k
    fn array(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
672
249k
        let _level_guard = i.state.level.nest(i)?;
673
32.8k
        let (span, mut elements): (_, Vec<_>) = (
674
249k
            '['.span(),
675
1.38M
            separated(0.., ws(move |i: &mut _| Self::parse(i, true)), ','),
676
        )
677
249k
            .parse_next(i)?;
678
679
32.8k
        let expr = if let Some(semicolon) = opt(ws(';'.span())).parse_next(i)? {
680
            // array repeat [<el_expr>; <cnt_expr>]
681
2.00k
            let Some(elem) = elements.pop() else {
682
11
                return cut_error!(
683
                    "expected element expression for array repeat syntax",
684
                    semicolon
685
                );
686
            };
687
1.99k
            if !elements.is_empty() {
688
25
                return cut_error!("unexpected `;` after expression", semicolon);
689
1.96k
            }
690
1.96k
            let Some(count) = opt(ws(move |i: &mut _| Expr::parse(i, true))).parse_next(i)? else {
691
14
                return cut_error!(
692
                    "expected count expression for array repeat syntax after `;`",
693
                    semicolon
694
                );
695
            };
696
1.68k
            if let Some((delim, span)) = ws(opt(one_of((',', ';')).with_span())).parse_next(i)? {
697
9
                return cut_error!(
698
                    format!(
699
                        "unexpected delimiter `{}`.\n\
700
                        Use nested syntax to write a multi-dimensional array: [[expr; N]; M]",
701
                        delim.escape_debug()
702
                    ),
703
                    span
704
                );
705
1.68k
            }
706
1.68k
            Self::ArrayRepeat(elem, count)
707
        } else {
708
            // normal array [<expr>,...?]
709
30.8k
            if !elements.is_empty() {
710
                // strip optional trailing comma
711
8.98k
                ws(opt(',')).parse_next(i)?;
712
21.9k
            }
713
30.8k
            Self::Array(elements)
714
        };
715
716
32.5k
        if ws(opt(']')).parse_next(i)?.is_none() {
717
811
            let (next, span) = match opt(any_rust_token.with_span()).parse_next(i)? {
718
228
                Some((next, span)) => (Some(next), span),
719
583
                None => (None, span),
720
            };
721
811
            return cut_error!(
722
811
                match next {
723
                    Some(delim @ (")" | "}")) => format!(
724
                        "mismatched closing delimiter `{}`, expected `]`",
725
                        delim.escape_debug()
726
                    ),
727
                    Some(token) =>
728
                        format!("unexpected token `{}`, expected `]`", token.escape_debug()),
729
                    _ => "missing closing delimiter `]`".to_owned(),
730
                },
731
                span
732
            );
733
31.7k
        }
734
31.7k
        Ok(WithSpan::new(Box::new(expr), span))
735
249k
    }
736
737
2.05M
    fn path_var_bool(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
738
2.05M
        let (ret, span) = path_or_identifier.with_span().parse_next(i)?;
739
1.80M
        let ret = match ret {
740
85.7k
            PathOrIdentifier::Path(v) => Box::new(Self::Path(v)),
741
1.71M
            PathOrIdentifier::Identifier(v) if *v == "true" => Box::new(Self::BoolLit(true)),
742
1.71M
            PathOrIdentifier::Identifier(v) if *v == "false" => Box::new(Self::BoolLit(false)),
743
1.71M
            PathOrIdentifier::Identifier(v) => Box::new(Self::Var(*v)),
744
        };
745
1.80M
        Ok(WithSpan::new(ret, span))
746
2.05M
    }
747
748
2.05M
    fn str(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
749
2.05M
        let (s, span) = str_lit.with_span().parse_next(i)?;
750
2.07k
        Ok(WithSpan::new(Box::new(Self::StrLit(s)), span))
751
2.05M
    }
752
753
2.20M
    fn num(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
754
2.20M
        let ((num, full), span) = num_lit.with_taken().with_span().parse_next(i)?;
755
149k
        Ok(WithSpan::new(Box::new(Expr::NumLit(full, num)), span))
756
2.20M
    }
757
758
2.05M
    fn char(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
759
2.05M
        let (c, span) = char_lit.with_span().parse_next(i)?;
760
2.62k
        Ok(WithSpan::new(Box::new(Self::CharLit(c)), span))
761
2.05M
    }
762
763
    #[must_use]
764
104k
    pub fn contains_bool_lit_or_is_defined(&self) -> bool {
765
33.5k
        match self {
766
807
            Self::BoolLit(_) | Self::IsDefined(_) | Self::IsNotDefined(_) => true,
767
17.4k
            Self::Unary(_, expr) | Self::Group(expr) => expr.contains_bool_lit_or_is_defined(),
768
33.5k
            Self::BinOp(v) if matches!(v.op, "&&" | "||") => {
769
17.5k
                v.lhs.contains_bool_lit_or_is_defined() || v.rhs.contains_bool_lit_or_is_defined()
770
            }
771
3.39k
            Self::NumLit(_, _)
772
390
            | Self::StrLit(_)
773
453
            | Self::CharLit(_)
774
27.1k
            | Self::Var(_)
775
0
            | Self::FilterSource
776
830
            | Self::RustMacro(_, _)
777
284
            | Self::As(_, _)
778
884
            | Self::Call { .. }
779
5.64k
            | Self::Range(_)
780
1.08k
            | Self::Try(_)
781
390
            | Self::Struct(_)
782
0
            | Self::NamedArgument(_, _)
783
501
            | Self::Filter(_)
784
2.02k
            | Self::AssociatedItem(_, _)
785
263
            | Self::Index(_, _)
786
1.37k
            | Self::Tuple(_)
787
396
            | Self::Array(_)
788
132
            | Self::ArrayRepeat(_, _)
789
15.9k
            | Self::BinOp(_)
790
6.44k
            | Self::Path(_)
791
265
            | Self::Concat(_)
792
985
            | Self::LetCond(_)
793
68.8k
            | Self::ArgumentPlaceholder => false,
794
        }
795
104k
    }
796
}
797
798
1.91M
fn token_xor<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a> {
799
1.91M
    let good = keyword("xor").value(None);
800
1.91M
    let bad = ('^', not('=')).span().map(Some);
801
1.91M
    if let Some(span) = alt((good, bad)).parse_next(i)? {
802
16
        cut_error!("the binary XOR operator is called `xor` in askama", span)
803
    } else {
804
498
        Ok("^")
805
    }
806
1.91M
}
807
808
1.91M
fn token_bitand<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a> {
809
1.91M
    let good = keyword("bitand").value(None);
810
1.91M
    let bad = ('&', not(one_of(['&', '=']))).span().map(Some);
811
1.91M
    if let Some(span) = alt((good, bad)).parse_next(i)? {
812
27
        cut_error!("the binary AND operator is called `bitand` in askama", span)
813
    } else {
814
285
        Ok("&")
815
    }
816
1.91M
}
817
818
#[derive(Clone, Debug, PartialEq)]
819
pub struct Filter<'a> {
820
    pub name: PathOrIdentifier<'a>,
821
    pub arguments: Vec<WithSpan<Box<Expr<'a>>>>,
822
}
823
824
impl<'a: 'l, 'l> Filter<'a> {
825
19.8k
    pub(crate) fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
826
19.8k
        let mut p = (ws(path_or_identifier), opt(Expr::arguments));
827
19.8k
        let (name, arguments) = p.parse_next(i)?;
828
        Ok(Self {
829
19.0k
            name,
830
19.0k
            arguments: arguments.map_or_else(Vec::new, |arguments| arguments.inner),
831
        })
832
19.8k
    }
833
}
834
835
#[derive(Clone, Debug, PartialEq)]
836
pub struct AssociatedItem<'a> {
837
    pub name: WithSpan<&'a str>,
838
    pub generics: Option<WithSpan<Vec<WithSpan<TyGenerics<'a>>>>>,
839
}
840
841
#[derive(Clone, Debug, PartialEq)]
842
pub struct ExprStructField<'a> {
843
    pub name: WithSpan<&'a str>,
844
    pub value: Option<WithSpan<Box<Expr<'a>>>>,
845
}
846
847
enum Suffix<'a> {
848
    AssociatedItem(AssociatedItem<'a>),
849
    Index(WithSpan<Box<Expr<'a>>>),
850
    Call {
851
        generics: Option<WithSpan<Vec<WithSpan<TyGenerics<'a>>>>>,
852
        args: Vec<WithSpan<Box<Expr<'a>>>>,
853
    },
854
    Struct {
855
        fields: Vec<ExprStructField<'a>>,
856
        base: Option<WithSpan<Box<Expr<'a>>>>,
857
    },
858
    // The value is the arguments of the macro call.
859
    MacroCall(&'a str),
860
    Try,
861
}
862
863
#[derive(Debug)]
864
enum Field<'a> {
865
    Base(WithSpan<Box<Expr<'a>>>),
866
    Field(ExprStructField<'a>),
867
}
868
869
impl<'a: 'l, 'l> Suffix<'a> {
870
2.20M
    fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>> {
871
2.20M
        let mut level_guard = i.state.level.guard();
872
2.20M
        let mut expr = Expr::single(i)?;
873
2.02M
        let mut right = opt(alt((
874
2.02M
            Self::associated_item,
875
2.02M
            Self::index,
876
2.02M
            Self::call,
877
2.02M
            Self::r#try,
878
2.02M
            Self::r#macro,
879
2.02M
            Self::r#struct,
880
2.02M
        )));
881
882
2.02M
        let mut i_before = i.checkpoint();
883
2.11M
        while let Some(suffix) = right.parse_next(i)? {
884
100k
            level_guard.nest(i)?;
885
100k
            let (suffix, span) = suffix.deconstruct();
886
100k
            let inner = match suffix {
887
11.4k
                Self::AssociatedItem(associated_item) => {
888
11.4k
                    Box::new(Expr::AssociatedItem(expr, associated_item))
889
                }
890
26.2k
                Self::Index(index) => Box::new(Expr::Index(expr, index)),
891
29.0k
                Self::Call { generics, args } => Box::new(Expr::Call(Call {
892
29.0k
                    path: expr,
893
29.0k
                    generics,
894
29.0k
                    args,
895
29.0k
                })),
896
5.82k
                Self::Struct { fields, base } => Box::new(Expr::Struct(ExprStruct {
897
5.82k
                    path: expr,
898
5.82k
                    fields,
899
5.82k
                    base,
900
5.82k
                })),
901
5.85k
                Self::Try => Box::new(Expr::Try(expr)),
902
22.4k
                Self::MacroCall(args) => {
903
22.4k
                    let args = WithSpan::new(args, span);
904
22.4k
                    match *expr.inner {
905
3.47k
                        Expr::Path(path) => {
906
3.47k
                            let last = path.last().unwrap();
907
3.47k
                            ensure_macro_name(&last.name)?;
908
909
1.17M
                            if let Some(r) = path.iter().find_map(|r| r.generics.as_ref()) {
910
2
                                return Err(ErrorContext::new(
911
2
                                    "macro paths cannot have generics",
912
2
                                    r.span,
913
2
                                )
914
2
                                .cut());
915
3.46k
                            }
916
917
3.46k
                            Box::new(Expr::RustMacro(
918
3.46k
                                path.into_iter()
919
3.46k
                                    .map(|c: PathComponent<'_>| c.name)
920
3.46k
                                    .collect(),
921
3.46k
                                args,
922
                            ))
923
                        }
924
3.73k
                        Expr::Var(name) => {
925
3.73k
                            let name = WithSpan::new(name, expr.span);
926
3.73k
                            ensure_macro_name(&name)?;
927
3.71k
                            Box::new(Expr::RustMacro(vec![name], args))
928
                        }
929
                        _ => {
930
15.2k
                            i.reset(&i_before);
931
15.2k
                            return fail(i);
932
                        }
933
                    }
934
                }
935
            };
936
85.6k
            expr = WithSpan::new(inner, span);
937
85.6k
            i_before = i.checkpoint();
938
        }
939
1.99M
        Ok(expr)
940
2.20M
    }
941
942
2.03M
    fn r#macro(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
943
        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
944
        enum Token {
945
            SomeOther,
946
            Open(Group),
947
            Close(Group),
948
        }
949
950
        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
951
        enum Group {
952
            Paren,   // `(`
953
            Brace,   // `{`
954
            Bracket, // `[`
955
        }
956
957
        impl Group {
958
74
            fn as_close_char(self) -> char {
959
74
                match self {
960
27
                    Group::Paren => ')',
961
26
                    Group::Brace => '}',
962
21
                    Group::Bracket => ']',
963
                }
964
74
            }
965
        }
966
967
25.2k
        fn macro_arguments<'a: 'l, 'l>(
968
25.2k
            i: &mut InputStream<'a, 'l>,
969
25.2k
            open_token: Group,
970
25.2k
        ) -> ParseResult<'a, Suffix<'a>> {
971
25.2k
            fn inner<'a: 'l, 'l>(
972
25.2k
                i: &mut InputStream<'a, 'l>,
973
25.2k
                open_token: Group,
974
25.2k
            ) -> ParseResult<'a, <InputStream<'a, 'l> as Stream>::Checkpoint> {
975
25.2k
                let mut open_list = vec![open_token];
976
                loop {
977
4.29M
                    let before = i.checkpoint();
978
4.29M
                    let token = ws(opt(token.with_span())).parse_next(i)?;
979
4.29M
                    let after = i.checkpoint();
980
4.29M
                    let Some((token, span)) = token else {
981
2.04k
                        return cut_error!("expected valid tokens in macro call", *i);
982
                    };
983
4.29M
                    let close_token = match token {
984
1.70M
                        Token::SomeOther => continue,
985
2.52M
                        Token::Open(group) => {
986
2.52M
                            open_list.push(group);
987
2.52M
                            continue;
988
                        }
989
70.6k
                        Token::Close(close_token) => close_token,
990
                    };
991
70.6k
                    let open_token = open_list.pop().unwrap();
992
993
70.6k
                    if open_token != close_token {
994
37
                        return cut_error!(
995
                            format!(
996
                                "expected `{}` but found `{}`",
997
                                open_token.as_close_char(),
998
                                close_token.as_close_char(),
999
                            ),
1000
                            span,
1001
                        );
1002
70.6k
                    } else if open_list.is_empty() {
1003
22.4k
                        i.reset(&before);
1004
22.4k
                        return Ok(after);
1005
48.2k
                    }
1006
                }
1007
25.2k
            }
1008
1009
25.2k
            let p = |i: &mut _| inner(i, open_token);
1010
25.2k
            let (checkpoint, inner) = p.with_taken().parse_next(i)?;
1011
22.4k
            i.reset(&checkpoint);
1012
22.4k
            Ok(Suffix::MacroCall(inner))
1013
25.2k
        }
1014
1015
891k
        fn lifetime<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
1016
            // this code assumes that we tried to match char literals before calling this function
1017
891k
            let p = (
1018
891k
                '\''.void(),
1019
                identifier,
1020
891k
                opt((repeat(1.., '#'), opt(identifier))),
1021
891k
                opt('\'').map(|o| o.is_some()),
1022
            );
1023
891k
            let ((_, front, back, quot), span) = p.with_span().parse_next(i)?;
1024
2.77k
            match (front, back, quot) {
1025
                // this case should never be encountered
1026
0
                (_, _, true) => cut_error!(
1027
                    "cannot have multiple characters in a character literal, \
1028
                    use `\"...\"` to write a string",
1029
                    span
1030
                ),
1031
                // a normal lifetime
1032
1.34k
                (identifier, None, _) => {
1033
1.34k
                    if !is_rust_keyword(identifier) {
1034
1.33k
                        Ok(())
1035
                    } else {
1036
8
                        cut_error!(
1037
                            "a non-raw lifetime cannot be named like an existing keyword",
1038
                            span,
1039
                        )
1040
                    }
1041
                }
1042
                // a raw lifetime
1043
1.43k
                ("r", Some((1, Some(identifier))), _) => {
1044
1.37k
                    if matches!(identifier, "Self" | "self" | "crate" | "super" | "_") {
1045
10
                        cut_error!(
1046
                            format!("`{}` cannot be a raw lifetime", identifier.escape_debug()),
1047
                            span,
1048
                        )
1049
                    } else {
1050
1.36k
                        Ok(())
1051
                    }
1052
                }
1053
                // an illegal prefix (not `'r#..`, multiple `#` or no identifier after `#`)
1054
62
                (_, Some(_), _) => cut_error!("wrong lifetime format", span),
1055
            }
1056
891k
        }
1057
1058
4.29M
        fn token<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Token> {
1059
            // <https://doc.rust-lang.org/reference/tokens.html>
1060
4.29M
            let some_other = alt((
1061
4.29M
                // literals
1062
4.29M
                char_lit.value(Token::SomeOther),
1063
4.29M
                str_lit.value(Token::SomeOther),
1064
4.29M
                num_lit.value(Token::SomeOther),
1065
4.29M
                // keywords + (raw) identifiers + raw strings
1066
4.29M
                identifier_or_prefixed_string.value(Token::SomeOther),
1067
4.29M
                lifetime.value(Token::SomeOther),
1068
4.29M
                // comments
1069
4.29M
                line_comment.value(Token::SomeOther),
1070
4.29M
                block_comment.value(Token::SomeOther),
1071
4.29M
                // punctuations
1072
4.29M
                punctuation.value(Token::SomeOther),
1073
4.29M
                hash,
1074
4.29M
            ));
1075
4.29M
            alt((open.map(Token::Open), close.map(Token::Close), some_other)).parse_next(i)
1076
4.29M
        }
1077
1078
888k
        fn line_comment<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
1079
888k
            fn inner<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, bool> {
1080
888k
                let mut p = (
1081
888k
                    "//".span(),
1082
888k
                    alt((
1083
888k
                        ('/', not(peek('/'))).value(true),
1084
888k
                        '!'.value(true),
1085
888k
                        empty.value(false),
1086
888k
                    )),
1087
888k
                );
1088
888k
                let (start, is_doc_comment) = p.parse_next(i)?;
1089
193k
                if opt((take_until(.., '\n'), '\n')).parse_next(i)?.is_none() {
1090
62
                    return cut_error!(
1091
                        format!(
1092
                            "you are probably missing a line break to end {}comment",
1093
                            if is_doc_comment { "doc " } else { "" }
1094
                        ),
1095
                        start,
1096
                    );
1097
193k
                };
1098
193k
                Ok(is_doc_comment)
1099
888k
            }
1100
1101
888k
            doc_comment_no_bare_cr(i, inner)
1102
888k
        }
1103
1104
695k
        fn block_comment<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
1105
695k
            fn inner<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, bool> {
1106
695k
                let is_doc_comment = alt((
1107
695k
                    ('*', not(peek(one_of(['*', '/'])))).value(true),
1108
695k
                    '!'.value(true),
1109
695k
                    empty.value(false),
1110
695k
                ));
1111
9.47k
                let (is_doc_comment, start) =
1112
695k
                    preceded("/*", is_doc_comment).with_span().parse_next(i)?;
1113
1114
9.47k
                let mut depth = 0usize;
1115
                loop {
1116
948k
                    if opt(take_until(.., ("/*", "*/"))).parse_next(i)?.is_none() {
1117
102
                        return cut_error!(
1118
                            format!(
1119
                                "missing `*/` to close block {}comment",
1120
                                if is_doc_comment { "doc " } else { "" }
1121
                            ),
1122
                            start,
1123
                        );
1124
948k
                    } else if alt(("/*".value(true), "*/".value(false))).parse_next(i)? {
1125
927k
                        // cannot overflow: `i` cannot be longer than `isize::MAX`, cf. [std::alloc::Layout]
1126
927k
                        depth += 1;
1127
927k
                    } else if let Some(new_depth) = depth.checked_sub(1) {
1128
11.5k
                        depth = new_depth;
1129
11.5k
                    } else {
1130
9.37k
                        return Ok(is_doc_comment);
1131
                    }
1132
                }
1133
695k
            }
1134
1135
695k
            doc_comment_no_bare_cr(i, inner)
1136
695k
        }
1137
1138
1.58M
        fn identifier_or_prefixed_string<'a: 'l, 'l>(
1139
1.58M
            i: &mut InputStream<'a, 'l>,
1140
1.58M
        ) -> ParseResult<'a, ()> {
1141
            // <https://doc.rust-lang.org/reference/tokens.html#r-lex.token.literal.str-raw.syntax>
1142
1143
697k
            let ((prefix, hashes, quot), prefix_span): ((_, usize, _), _) =
1144
1.58M
                (identifier, repeat(.., '#'), opt('"'))
1145
1.58M
                    .with_span()
1146
1.58M
                    .parse_next(i)?;
1147
697k
            if hashes >= 256 {
1148
2
                return cut_error!(
1149
                    "a maximum of 255 hashes `#` are allowed with raw and prefixed strings",
1150
                    prefix_span,
1151
                );
1152
697k
            }
1153
1154
616k
            let str_kind = match prefix {
1155
                // raw cstring or byte slice
1156
697k
                "br" => Some(StrPrefix::Binary),
1157
695k
                "cr" => Some(StrPrefix::CLike),
1158
                // raw string string or identifier
1159
625k
                "r" => None,
1160
                // a simple identifier
1161
616k
                _ if hashes == 0 && quot.is_none() => return Ok(()),
1162
                // reserved prefix: reject
1163
                _ => {
1164
16
                    return cut_error!(
1165
                        format!("reserved prefix `{}#`", prefix.escape_debug()),
1166
                        prefix_span,
1167
                    );
1168
                }
1169
            };
1170
1171
81.5k
            if quot.is_some() {
1172
                // got a raw string
1173
1174
7.42k
                let delim = format!("\"{:#<hashes$}", "");
1175
7.42k
                let p = terminated(take_until(.., delim.as_str()).with_span(), delim.as_str());
1176
7.42k
                let Some((inner, inner_span)) = opt(p).parse_next(i)? else {
1177
113
                    return cut_error!("unterminated raw string", prefix_span);
1178
                };
1179
1180
7.30k
                if inner.split('\r').skip(1).any(|s| !s.starts_with('\n')) {
1181
87
                    return cut_error!(
1182
                        "a bare CR (Mac linebreak) is not allowed in string literals, \
1183
                         use NL (Unix linebreak) or CRNL (Windows linebreak) instead, \
1184
                         or type `\\r` explicitly",
1185
                        inner_span,
1186
                    );
1187
7.22k
                }
1188
1189
7.22k
                let msg = match str_kind {
1190
1.75k
                    Some(StrPrefix::Binary) => inner
1191
1.75k
                        .bytes()
1192
176k
                        .any(|b| !b.is_ascii())
1193
1.75k
                        .then_some("binary string literals must not contain non-ASCII characters"),
1194
1.79k
                    Some(StrPrefix::CLike) => inner
1195
1.79k
                        .bytes()
1196
18.9k
                        .any(|b| b == 0)
1197
1.79k
                        .then_some("cstring literals must not contain NUL characters"),
1198
3.66k
                    None => None,
1199
                };
1200
7.22k
                if let Some(msg) = msg {
1201
14
                    return cut_error!(msg, prefix_span);
1202
7.20k
                }
1203
1204
7.20k
                not_suffix_with_hash(i)?;
1205
7.19k
                Ok(())
1206
74.1k
            } else if hashes == 0 {
1207
                // a simple identifier
1208
70.3k
                Ok(())
1209
3.80k
            } else if let Some((id, span)) = opt(identifier.with_span()).parse_next(i)? {
1210
                // got a raw identifier
1211
1212
3.78k
                if str_kind.is_some() {
1213
                    // an invalid raw identifier like `cr#async`
1214
3
                    cut_error!(
1215
                        format!(
1216
                            "reserved prefix `{}#`, only `r#` is allowed with raw identifiers",
1217
                            prefix.escape_debug(),
1218
                        ),
1219
                        prefix_span,
1220
                    )
1221
3.77k
                } else if hashes > 1 {
1222
                    // an invalid raw identifier like `r##async`
1223
2
                    cut_error!(
1224
                        "only one `#` is allowed in raw identifier delimitation",
1225
                        prefix_span,
1226
                    )
1227
                } else {
1228
                    // a raw identifier like `r#async`
1229
3.77k
                    if matches!(id, "self" | "Self" | "super" | "crate" | "_") {
1230
11
                        cut_error!(
1231
                            format!("`{}` cannot be a raw identifier", id.escape_debug()),
1232
                            span,
1233
                        )
1234
                    } else {
1235
3.76k
                        Ok(())
1236
                    }
1237
                }
1238
            } else {
1239
23
                cut_error!(
1240
                    format!(
1241
                        "prefix `{}#` is only allowed with raw identifiers and raw strings",
1242
                        prefix.escape_debug(),
1243
                    ),
1244
                    prefix_span,
1245
                )
1246
            }
1247
1.58M
        }
1248
1249
14.7k
        fn hash<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Token> {
1250
14.7k
            let (quot, span) = preceded('#', opt('"')).with_span().parse_next(i)?;
1251
12.6k
            if quot.is_some() {
1252
5
                return cut_error!(
1253
                    "unprefixed guarded string literals are reserved for future use",
1254
                    span,
1255
                );
1256
12.6k
            }
1257
12.6k
            Ok(Token::SomeOther)
1258
14.7k
        }
1259
1260
685k
        fn punctuation<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
1261
            // <https://doc.rust-lang.org/reference/tokens.html#punctuation>
1262
            // hash '#' omitted
1263
1264
            const ONE_CHAR: &[u8] = b"+-*/%^!&|=><@_.,;:$?~";
1265
            const TWO_CHARS: &[[u8; 2]] = &[
1266
                *b"&&", *b"||", *b"<<", *b">>", *b"+=", *b"-=", *b"*=", *b"/=", *b"%=", *b"^=",
1267
                *b"&=", *b"|=", *b"==", *b"!=", *b">=", *b"<=", *b"..", *b"::", *b"->", *b"=>",
1268
                *b"<-",
1269
            ];
1270
            const THREE_CHARS: &[[u8; 3]] = &[*b"<<=", *b">>=", *b"...", *b"..="];
1271
1272
685k
            let three_chars = take(3usize).verify_map(|head: &str| {
1273
680k
                if let Ok(head) = head.as_bytes().try_into()
1274
675k
                    && THREE_CHARS.contains(head)
1275
                {
1276
2.55k
                    Some(())
1277
                } else {
1278
678k
                    None
1279
                }
1280
680k
            });
1281
685k
            let two_chars = take(2usize).verify_map(|head: &str| {
1282
681k
                if let Ok(head) = head.as_bytes().try_into()
1283
677k
                    && TWO_CHARS.contains(head)
1284
                {
1285
33.6k
                    Some(())
1286
                } else {
1287
647k
                    None
1288
                }
1289
681k
            });
1290
685k
            let one_char = any.verify_map(|head: char| {
1291
648k
                if let Ok(head) = head.try_into()
1292
647k
                    && ONE_CHAR.contains(&head)
1293
                {
1294
634k
                    Some(())
1295
                } else {
1296
13.1k
                    None
1297
                }
1298
648k
            });
1299
1300
            // need to check long to short
1301
685k
            alt((three_chars, two_chars, one_char)).parse_next(i)
1302
685k
        }
1303
1304
4.32M
        fn open<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Group> {
1305
4.32M
            alt((
1306
4.32M
                '('.value(Group::Paren),
1307
4.32M
                '{'.value(Group::Brace),
1308
4.32M
                '['.value(Group::Bracket),
1309
4.32M
            ))
1310
4.32M
            .parse_next(i)
1311
4.32M
        }
1312
1313
1.77M
        fn close<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Group> {
1314
1.77M
            alt((
1315
1.77M
                ')'.value(Group::Paren),
1316
1.77M
                '}'.value(Group::Brace),
1317
1.77M
                ']'.value(Group::Bracket),
1318
1.77M
            ))
1319
1.77M
            .parse_next(i)
1320
1.77M
        }
1321
1322
2.03M
        let (span, open_token) = (ws('!'.span()), open).parse_next(i)?;
1323
25.2k
        let inner = (|i: &mut _| macro_arguments(i, open_token)).parse_next(i)?;
1324
22.4k
        Ok(WithSpan::new(inner, span))
1325
2.03M
    }
1326
1327
2.11M
    fn associated_item(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1328
2.11M
        let mut p = (
1329
2.11M
            ws(terminated('.'.span(), not('.'))),
1330
2.11M
            cut_err((
1331
11.5k
                |i: &mut _| {
1332
11.5k
                    let (name, span) = alt((digit1, identifier)).with_span().parse_next(i)?;
1333
11.4k
                    if !crate::can_be_variable_name(name) {
1334
8
                        return cut_error!(
1335
                            format!("`{}` cannot be used as an identifier", name.escape_debug()),
1336
                            span,
1337
                        );
1338
11.4k
                    }
1339
11.4k
                    Ok(WithSpan::new(name, span))
1340
11.5k
                },
1341
2.11M
                opt(call_generics),
1342
            )),
1343
        );
1344
2.11M
        let (span, (name, generics)) = p.parse_next(i)?;
1345
11.4k
        Ok(WithSpan::new(
1346
11.4k
            Self::AssociatedItem(AssociatedItem { name, generics }),
1347
11.4k
            span,
1348
11.4k
        ))
1349
2.11M
    }
1350
1351
2.10M
    fn index(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1352
2.10M
        let mut p = (
1353
2.10M
            ws('['.span()),
1354
2.10M
            cut_err((ws(move |i: &mut _| Expr::parse(i, true)), opt(']'))),
1355
        );
1356
2.10M
        let (span, (expr, closed)) = p.parse_next(i)?;
1357
26.4k
        if closed.is_none() {
1358
190
            return cut_error!("matching closing `]` is missing", span);
1359
26.2k
        }
1360
26.2k
        Ok(WithSpan::new(Self::Index(expr), span))
1361
2.10M
    }
1362
1363
2.07M
    fn call(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1364
2.07M
        let mut p = (opt(call_generics), Expr::arguments);
1365
2.07M
        let (generics, args) = p.parse_next(i)?;
1366
29.0k
        let (args, span) = args.deconstruct();
1367
29.0k
        Ok(WithSpan::new(Self::Call { generics, args }, span))
1368
2.07M
    }
1369
1370
2.03M
    fn r#try(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1371
2.03M
        let span = preceded(skip_ws0, '?'.span()).parse_next(i)?;
1372
5.85k
        Ok(WithSpan::new(Self::Try, span))
1373
2.03M
    }
1374
1375
2.00M
    fn r#struct(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1376
2.00M
        let _level_guard = i.state.level.nest(i)?;
1377
2.00M
        let mut p = (
1378
2.00M
            ws('{'.span()),
1379
2.00M
            cut_err((separated(
1380
2.00M
                0..,
1381
2.00M
                alt((Self::struct_field, Self::struct_base)),
1382
2.00M
                ws(','),
1383
2.00M
            ),)),
1384
2.00M
            opt(ws(',')), // Trailing comma.
1385
2.00M
            opt(ws(winnow::token::any.with_span())),
1386
2.00M
        );
1387
6.18k
        let (span, (all_fields,), trailing_comma, closed): (
1388
6.18k
            _,
1389
6.18k
            (Vec<Field<'_>>,),
1390
6.18k
            Option<_>,
1391
6.18k
            Option<_>,
1392
2.00M
        ) = p.parse_next(i)?;
1393
6.18k
        if trailing_comma.is_some() && all_fields.is_empty() {
1394
5
            return cut_error!("missing field before `,`", span);
1395
6.17k
        }
1396
6.17k
        let mut base: Option<WithSpan<Box<Expr<'a>>>> = None;
1397
6.17k
        let mut fields = Vec::with_capacity(all_fields.len());
1398
3.43M
        for field in all_fields {
1399
3.42M
            match field {
1400
3.42M
                Field::Field(field) => {
1401
3.42M
                    if base.is_some() {
1402
4
                        return cut_error!(
1403
                            "expected end of struct expression after `..` was used",
1404
                            field.name.span()
1405
                        );
1406
3.42M
                    }
1407
3.42M
                    fields.push(field);
1408
                }
1409
1.06k
                Field::Base(new_base) => {
1410
1.06k
                    if base.is_some() {
1411
9
                        return cut_error!(
1412
                            "expected end of struct expression after `..` was used",
1413
                            new_base.span()
1414
                        );
1415
1.06k
                    }
1416
1.06k
                    base = Some(new_base);
1417
                }
1418
            }
1419
        }
1420
6.16k
        if closed.as_ref().is_none_or(|(c, _)| *c != '}') {
1421
336
            let err_span = match closed {
1422
149
                Some((_, span)) => span,
1423
187
                _ => span,
1424
            };
1425
336
            if base.is_some() {
1426
12
                return cut_error!(
1427
                    "expected end of struct expression after `..` was used",
1428
                    err_span
1429
                );
1430
324
            } else if !fields.is_empty() {
1431
163
                return cut_error!("expected `,`, `..`, field name or `}`", err_span);
1432
            } else {
1433
161
                return cut_error!("expected field name, `..` or `}`", err_span);
1434
            }
1435
5.82k
        }
1436
1437
5.82k
        Ok(WithSpan::new(Self::Struct { fields, base }, span))
1438
2.00M
    }
1439
1440
5.73k
    fn struct_base(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Field<'a>> {
1441
5.73k
        let ((_, base_expr), span) = (ws(".."), opt(ws(move |i: &mut _| Expr::parse(i, true))))
1442
5.73k
            .with_span()
1443
5.73k
            .parse_next(i)?;
1444
1.61k
        match base_expr {
1445
1.57k
            Some(base_expr) => Ok(Field::Base(base_expr)),
1446
42
            None => cut_error!("expected expression after `..`", span),
1447
        }
1448
5.73k
    }
1449
1450
3.43M
    fn struct_field(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Field<'a>> {
1451
3.43M
        let ((name, name_span), has_colon, value) = alt((
1452
            (
1453
3.43M
                alt((identifier, digit1)).with_span(),
1454
3.43M
                ws(':'),
1455
3.43M
                opt(ws(|i: &mut _| Expr::parse(i, true))),
1456
            )
1457
3.43M
                .map(|(name, _, expr)| (name, true, expr)),
1458
3.43M
            identifier.with_span().map(|name| (name, false, None)),
1459
        ))
1460
3.43M
        .parse_next(i)?;
1461
3.42M
        if has_colon && value.is_none() {
1462
63
            cut_error!("expected expression after `:`", *i)
1463
        } else {
1464
3.42M
            Ok(Field::Field(ExprStructField {
1465
3.42M
                name: WithSpan::new(name, name_span),
1466
3.42M
                value,
1467
3.42M
            }))
1468
        }
1469
3.43M
    }
1470
}
1471
1472
1.58M
fn doc_comment_no_bare_cr<'a: 'l, 'l>(
1473
1.58M
    i: &mut InputStream<'a, 'l>,
1474
1.58M
    inner: fn(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, bool>,
1475
1.58M
) -> ParseResult<'a, ()> {
1476
1.58M
    let ((is_doc_comment, comment), span) = inner.with_taken().with_span().parse_next(i)?;
1477
202k
    if is_doc_comment && comment.split('\r').skip(1).any(|s| !s.starts_with('\n')) {
1478
40
        cut_error!(
1479
            "bare CR not allowed in doc comment,
1480
            use NL (Unix linebreak) or CRNL (Windows linebreak) instead",
1481
            span,
1482
        )
1483
    } else {
1484
202k
        Ok(())
1485
    }
1486
1.58M
}
1487
1488
7.21k
fn ensure_macro_name<'a>(name: &WithSpan<&'a str>) -> ParseResult<'a, ()> {
1489
7.21k
    if matches!(**name, "_" | "crate" | "super" | "Self" | "self") {
1490
22
        return cut_error!(format!("`{}` is not a valid macro name", **name), name.span);
1491
7.19k
    }
1492
7.19k
    Ok(())
1493
7.21k
}
1494
1495
#[derive(Clone, Debug, PartialEq)]
1496
pub struct TyGenerics<'a> {
1497
    pub refs: usize,
1498
    pub kind: WithSpan<TyGenericsKind<'a>>,
1499
}
1500
1501
impl<'a: 'l, 'l> TyGenerics<'a> {
1502
4.77M
    pub(crate) fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1503
4.77M
        let p = ws((repeat(0.., ws('&')), TyGenericsKind::parse.with_span()));
1504
4.77M
        let ((refs, (kind, kind_span)), span) = p.with_span().parse_next(i)?;
1505
4.75M
        if refs > MAX_REFS {
1506
13
            return cut_error!(format!("too many references (> {MAX_REFS})"), span);
1507
4.75M
        }
1508
1509
4.75M
        Ok(WithSpan::new(
1510
4.75M
            TyGenerics {
1511
4.75M
                refs,
1512
4.75M
                kind: WithSpan::new(kind, kind_span),
1513
4.75M
            },
1514
4.75M
            span,
1515
4.75M
        ))
1516
4.77M
    }
1517
1518
7.01M
    fn args(
1519
7.01M
        i: &mut InputStream<'a, 'l>,
1520
7.01M
    ) -> ParseResult<'a, WithSpan<Vec<WithSpan<TyGenerics<'a>>>>> {
1521
7.01M
        let mut p = cut_err(terminated(
1522
7.01M
            opt(terminated(
1523
7.01M
                separated(1.., TyGenerics::parse, ws(',')),
1524
7.01M
                ws(opt(',')),
1525
            )),
1526
            '>',
1527
        ));
1528
1529
7.01M
        let span = ws('<'.span()).parse_next(i)?;
1530
24.6k
        let _level_guard = i.state.level.nest(i)?;
1531
24.6k
        let args = p.parse_next(i)?;
1532
22.5k
        Ok(WithSpan::new(args.unwrap_or_default(), span))
1533
7.01M
    }
1534
}
1535
1536
#[derive(Clone, Debug, PartialEq)]
1537
pub enum TyGenericsKind<'a> {
1538
    Path {
1539
        path: Vec<WithSpan<&'a str>>,
1540
        args: Option<WithSpan<Vec<WithSpan<TyGenerics<'a>>>>>,
1541
    },
1542
    Tuple(Vec<WithSpan<TyGenerics<'a>>>),
1543
    Array {
1544
        ty: Box<WithSpan<TyGenerics<'a>>>,
1545
        nb_elems: Option<&'a str>,
1546
    },
1547
}
1548
1549
impl<'a: 'l, 'l> TyGenericsKind<'a> {
1550
4.77M
    fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
1551
4.77M
        let _level_guard = i.state.level.nest(i)?;
1552
4.77M
        alt((Self::tuple, Self::array, Self::ty_path)).parse_next(i)
1553
4.77M
    }
1554
1555
4.76M
    fn ty_path(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, TyGenericsKind<'a>> {
1556
4.76M
        let path = separated(
1557
4.76M
            1..,
1558
4.76M
            ws(identifier
1559
4.76M
                .with_span()
1560
4.76M
                .map(|(name, span)| WithSpan::new(name, span))),
1561
            "::",
1562
        )
1563
4.76M
        .map(|v: Vec<_>| v);
1564
1565
4.76M
        let (path, args) = (path, opt(TyGenerics::args)).parse_next(i)?;
1566
1567
4.74M
        if let [name] = path.as_slice() {
1568
4.74M
            if matches!(**name, "super" | "self" | "crate") {
1569
                // `Self` and `_` are allowed
1570
27
                return err_reserved_identifier(name);
1571
4.74M
            }
1572
        } else {
1573
8.40k
            for (idx, name) in path.iter().enumerate() {
1574
8.40k
                if **name == "_" {
1575
                    // `_` is never allowed
1576
18
                    return err_underscore_identifier(name);
1577
8.38k
                } else if idx > 0 && matches!(**name, "super" | "self" | "Self" | "crate") {
1578
                    // At the front of the path, "super" | "self" | "Self" | "crate" are allowed.
1579
                    // Inside the path, they are not allowed.
1580
8
                    return err_reserved_identifier(name);
1581
8.38k
                }
1582
            }
1583
        }
1584
4.74M
        Ok(TyGenericsKind::Path { path, args })
1585
4.76M
    }
1586
1587
4.77M
    fn tuple(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, TyGenericsKind<'a>> {
1588
4.77M
        let start = *i;
1589
        // We ensure we're in the right function to get better errors later on.
1590
4.77M
        ws('(').parse_next(i)?;
1591
9.16k
        let Ok(tuple_elems) = separated(0.., TyGenerics::parse, ws(',')).parse_next(i) else {
1592
1.60k
            return cut_error!("expected a list of type separated by a comma", start);
1593
        };
1594
7.55k
        if (opt(ws(',')), ws(')')).parse_next(i).is_err() {
1595
211
            return cut_error!("expected a list of type separated by a comma", start);
1596
7.34k
        }
1597
7.34k
        Ok(TyGenericsKind::Tuple(tuple_elems))
1598
4.77M
    }
1599
1600
4.76M
    fn array(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, TyGenericsKind<'a>> {
1601
4.76M
        let start = *i;
1602
        // We ensure we're in the right function to get better errors later on.
1603
4.76M
        ws('[').parse_next(i)?;
1604
1605
6.65k
        let ty = match TyGenerics::parse.parse_next(i) {
1606
5.53k
            Ok(ty) => ty,
1607
1.05k
            Err(error @ ErrMode::Cut(_)) => return Err(error),
1608
62
            Err(_) => return cut_error!("expected a type", *i),
1609
        };
1610
5.53k
        let mut nb_elems = None;
1611
5.53k
        if let Ok((_, colon_span)) = ws(';').with_span().parse_next(i) {
1612
368
            let Ok((parsed_nb, nb_span)) = num_lit.with_span().parse_next(i) else {
1613
66
                return cut_error!("expected a number after `;`", colon_span);
1614
            };
1615
2
            match parsed_nb {
1616
269
                Num::Int(nb, Some(crate::IntKind::Usize) | None) => nb_elems = Some(nb),
1617
2
                Num::Int(_, Some(kind)) => {
1618
2
                    return cut_error!(
1619
                        format!("array size should be `usize`, found `{kind}`"),
1620
                        nb_span,
1621
                    );
1622
                }
1623
31
                Num::Float(nb, _) => {
1624
31
                    return cut_error!(
1625
                        format!("expected a number after `;`, found a float (`{nb}`)"),
1626
                        nb_span,
1627
                    );
1628
                }
1629
            }
1630
5.17k
        }
1631
5.44k
        if ws(']').parse_next(i).is_err() {
1632
89
            return cut_error!("missing `]` to close the array", start);
1633
5.35k
        }
1634
5.35k
        Ok(TyGenericsKind::Array {
1635
5.35k
            ty: Box::new(ty),
1636
5.35k
            nb_elems,
1637
5.35k
        })
1638
4.76M
    }
1639
}
1640
1641
2.08M
pub(crate) fn call_generics<'a: 'l, 'l>(
1642
2.08M
    i: &mut InputStream<'a, 'l>,
1643
2.08M
) -> ParseResult<'a, WithSpan<Vec<WithSpan<TyGenerics<'a>>>>> {
1644
2.08M
    preceded(ws("::"), cut_err(TyGenerics::args)).parse_next(i)
1645
2.08M
}
1646
1647
#[cold]
1648
#[inline(never)]
1649
115k
fn try_assign_fallback_error<'a: 'l, 'l>(
1650
115k
    i: &mut InputStream<'a, 'l>,
1651
115k
    err: &mut ErrMode<ErrorContext>,
1652
115k
) {
1653
115k
    if let ErrMode::Backtrack(err_ctx) | ErrMode::Cut(err_ctx) = err
1654
115k
        && err_ctx.message.is_none()
1655
    {
1656
84.5k
        let checkpoint = i.checkpoint();
1657
84.5k
        i.input.reset_to_start();
1658
84.5k
        if take::<_, _, ()>(err_ctx.span.start).parse_next(i).is_ok()
1659
83.0k
            && let Err(better_err) = opt(deny_any_rust_token).parse_next(i)
1660
56.5k
            && let ErrMode::Backtrack(better_ctx) | ErrMode::Cut(better_ctx) = better_err
1661
56.5k
            && better_ctx.message.is_some()
1662
56.5k
        {
1663
56.5k
            *err_ctx = better_ctx;
1664
56.5k
        }
1665
84.5k
        i.reset(&checkpoint);
1666
31.2k
    }
1667
115k
}