Coverage Report

Created: 2026-09-14 06:45

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.0M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
16.0M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::or::{closure#0}
Line
Count
Source
21
1.85M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::and::{closure#0}
Line
Count
Source
21
1.87M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::bor::{closure#0}
Line
Count
Source
21
1.88M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::band::{closure#0}
Line
Count
Source
21
1.88M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::bxor::{closure#0}
Line
Count
Source
21
1.88M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::addsub::{closure#0}
Line
Count
Source
21
1.91M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::shifts::{closure#0}
Line
Count
Source
21
1.88M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
<askama_parser::expr::Expr>::muldivmod::{closure#0}
Line
Count
Source
21
1.95M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
16.0M
        }
<askama_parser::expr::Expr>::or
Line
Count
Source
20
1.97M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
1.97M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
1.97M
        }
<askama_parser::expr::Expr>::and
Line
Count
Source
20
1.97M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
1.97M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
1.97M
        }
<askama_parser::expr::Expr>::bor
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>::band
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>::bxor
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>::addsub
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>::shifts
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>::muldivmod
Line
Count
Source
20
2.05M
        fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
21
2.05M
            expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
22
2.05M
        }
23
    };
24
}
25
26
const MAX_REFS: usize = 20;
27
28
16.0M
fn expr_prec_layer<'a: 'l, 'l>(
29
16.0M
    i: &mut InputStream<'a, 'l>,
30
16.0M
    inner: fn(&mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>>,
31
16.0M
    op: fn(&mut InputStream<'a, 'l>) -> ParseResult<'a>,
32
16.0M
) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>> {
33
16.0M
    let mut expr = inner(i)?;
34
35
15.0M
    let mut level_guard = i.state.level.guard();
36
15.1M
    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.1M
        let i_before = *i;
39
15.1M
        let op = ws(op.with_span()).parse_next(i)?;
40
162k
        level_guard.nest(&i_before)?;
41
162k
        Ok((op, inner(i)?))
42
15.1M
    });
43
15.1M
    while let Some(((op, span), rhs)) = next.parse_next(i)? {
44
85.6k
        expr = WithSpan::new(Box::new(Expr::BinOp(BinOp { op, lhs: expr, rhs })), span);
45
85.6k
    }
46
47
15.0M
    Ok(expr)
48
16.0M
}
49
50
#[derive(Clone, Copy, Default)]
51
struct Allowed {
52
    underscore: bool,
53
    super_keyword: bool,
54
}
55
56
4.07M
fn check_expr<'a>(expr: &WithSpan<Box<Expr<'a>>>, allowed: Allowed) -> ParseResult<'a, ()> {
57
4.07M
    match &*expr.inner {
58
2.41M
        &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.41M
            if (!allowed.super_keyword && name == "super") || matches!(name, "crate" | "Self") {
62
5
                err_reserved_identifier(&WithSpan::new(name, expr.span))
63
2.41M
            } else if !allowed.underscore && name == "_" {
64
225
                err_underscore_identifier(&WithSpan::new(name, expr.span))
65
            } else {
66
2.41M
                Ok(())
67
            }
68
        }
69
3.09k
        &Expr::IsDefined(var) | &Expr::IsNotDefined(var) => {
70
4.85k
            if var == "_" {
71
2
                err_underscore_identifier(&WithSpan::new(var, expr.span))
72
            } else {
73
4.84k
                Ok(())
74
            }
75
        }
76
150k
        Expr::Path(path) => {
77
150k
            if let [arg] = path.as_slice()
78
147k
                && !crate::can_be_variable_name(*arg.name)
79
            {
80
6
                return err_reserved_identifier(&arg.name);
81
150k
            }
82
150k
            Ok(())
83
        }
84
120k
        Expr::Array(elems) | Expr::Tuple(elems) | Expr::Concat(elems) => {
85
616k
            for elem in elems {
86
411k
                check_expr(elem, allowed)?;
87
            }
88
205k
            Ok(())
89
        }
90
6.42k
        Expr::ArrayRepeat(elem, count) => {
91
6.42k
            check_expr(elem, allowed)?;
92
6.32k
            check_expr(count, allowed)?;
93
6.24k
            Ok(())
94
        }
95
29.2k
        Expr::AssociatedItem(elem, associated_item) => {
96
29.2k
            if *associated_item.name == "_" {
97
5
                err_underscore_identifier(&associated_item.name)
98
29.2k
            } else if !crate::can_be_variable_name(*associated_item.name) {
99
0
                err_reserved_identifier(&associated_item.name)
100
            } else {
101
29.2k
                check_expr(elem, Allowed::default())
102
            }
103
        }
104
44.9k
        Expr::Index(elem1, elem2) => {
105
44.9k
            check_expr(elem1, Allowed::default())?;
106
44.6k
            check_expr(elem2, Allowed::default())
107
        }
108
410k
        Expr::BinOp(v) => {
109
410k
            check_expr(&v.lhs, Allowed::default())?;
110
409k
            check_expr(&v.rhs, Allowed::default())
111
        }
112
33.8k
        Expr::Range(v) => {
113
33.8k
            if let Some(elem1) = v.lhs.as_ref() {
114
13.6k
                check_expr(elem1, Allowed::default())?;
115
20.1k
            }
116
33.8k
            if let Some(elem2) = v.rhs.as_ref() {
117
14.2k
                check_expr(elem2, Allowed::default())?;
118
19.5k
            }
119
33.8k
            Ok(())
120
        }
121
15.7k
        Expr::As(elem, _)
122
186k
        | Expr::Unary(_, elem)
123
132k
        | Expr::Group(elem)
124
2.15k
        | Expr::NamedArgument(_, elem)
125
351k
        | Expr::Try(elem) => check_expr(elem, Allowed::default()),
126
166k
        Expr::Call(v) => {
127
166k
            check_expr(
128
166k
                &v.path,
129
166k
                Allowed {
130
166k
                    underscore: false,
131
166k
                    super_keyword: true,
132
166k
                },
133
149
            )?;
134
240k
            for arg in &v.args {
135
74.1k
                check_expr(arg, Allowed::default())?;
136
            }
137
166k
            Ok(())
138
        }
139
43.4k
        Expr::Filter(filter) => {
140
262k
            for arg in &filter.arguments {
141
219k
                check_expr(arg, Allowed::default())?;
142
            }
143
43.2k
            Ok(())
144
        }
145
9.32k
        Expr::Struct(s) => {
146
9.32k
            check_expr(
147
9.32k
                &s.path,
148
9.32k
                Allowed {
149
9.32k
                    underscore: false,
150
9.32k
                    super_keyword: true,
151
9.32k
                },
152
355
            )?;
153
712k
            for field in &s.fields {
154
703k
                if field.name.inner == "_" {
155
22
                    return err_underscore_identifier(&field.name);
156
703k
                } else if !crate::can_be_variable_name(field.name.inner) {
157
10
                    return err_reserved_identifier(&field.name);
158
703k
                }
159
703k
                if let Some(ref value) = field.value {
160
5.32k
                    check_expr(value, Allowed::default())?;
161
698k
                }
162
            }
163
8.93k
            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
206k
        | Expr::FilterSource => Ok(()),
173
    }
174
4.07M
}
175
176
#[inline(always)]
177
274
fn err_underscore_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
178
274
    cut_error!("reserved keyword `_` cannot be used here", name.span)
179
274
}
askama_parser::expr::err_underscore_identifier::<askama_parser::expr::TyGenericsKind>
Line
Count
Source
177
20
fn err_underscore_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
178
20
    cut_error!("reserved keyword `_` cannot be used here", name.span)
179
20
}
askama_parser::expr::err_underscore_identifier::<()>
Line
Count
Source
177
254
fn err_underscore_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
178
254
    cut_error!("reserved keyword `_` cannot be used here", name.span)
179
254
}
180
181
#[inline(always)]
182
54
fn err_reserved_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
183
54
    cut_error!(
184
        format!("`{}` cannot be used as an identifier", name.inner),
185
        name.span
186
    )
187
54
}
askama_parser::expr::err_reserved_identifier::<askama_parser::expr::TyGenericsKind>
Line
Count
Source
182
33
fn err_reserved_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
183
33
    cut_error!(
184
        format!("`{}` cannot be used as an identifier", name.inner),
185
        name.span
186
    )
187
33
}
askama_parser::expr::err_reserved_identifier::<()>
Line
Count
Source
182
21
fn err_reserved_identifier<'a, T>(name: &WithSpan<&str>) -> ParseResult<'a, T> {
183
21
    cut_error!(
184
        format!("`{}` cannot be used as an identifier", name.inner),
185
        name.span
186
    )
187
21
}
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
13.2k
    pub fn new_with_name(name: WithSpan<&'a str>) -> Self {
198
13.2k
        Self {
199
13.2k
            name,
200
13.2k
            generics: None,
201
13.2k
        }
202
13.2k
    }
203
204
5.40M
    pub(crate) fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
205
5.40M
        let mut p = (
206
5.40M
            identifier.with_span(),
207
5.40M
            opt(preceded(ws("::"), TyGenerics::args)),
208
5.40M
        );
209
5.40M
        let ((name, name_span), generics) = p.parse_next(i)?;
210
5.14M
        Ok(Self {
211
5.14M
            name: WithSpan::new(name, name_span),
212
5.14M
            generics,
213
5.14M
        })
214
5.40M
    }
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.04M
    pub(super) fn arguments(
284
2.04M
        i: &mut InputStream<'a, 'l>,
285
2.04M
    ) -> ParseResult<'a, WithSpan<Vec<WithSpan<Box<Self>>>>> {
286
327k
        fn comma<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
287
327k
            (ws(','), no_comma).void().parse_next(i)
288
327k
        }
289
290
345k
        fn no_comma<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
291
345k
            if let Some(span) = opt(','.span()).parse_next(i)? {
292
13
                cut_error!(
293
                    "expected an expression, found a comma in argument list",
294
                    span
295
                )
296
            } else {
297
345k
                Ok(())
298
            }
299
345k
        }
300
301
2.04M
        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
41.8k
        let mut _level_guard = i.state.level.nest_multiple(i, 2)?;
306
307
41.8k
        let mut named_arguments = HashSet::default();
308
41.8k
        let arguments = separated(
309
41.8k
            1..,
310
342k
            move |i: &mut _| {
311
                // Needed to prevent borrowing it twice between this closure and the one
312
                // calling `Self::named_arguments`.
313
342k
                let named_arguments = &mut named_arguments;
314
342k
                let has_named_arguments = !named_arguments.is_empty();
315
316
342k
                let mut p = alt((
317
342k
                    move |i: &mut _| Self::named_argument(i, named_arguments),
318
332k
                    move |i: &mut _| Self::parse(i, false),
319
                ));
320
342k
                let expr = p.parse_next(i)?;
321
312k
                if has_named_arguments && !matches!(**expr, Self::NamedArgument(..)) {
322
39
                    return cut_error!("named arguments must always be passed last", expr.span);
323
312k
                }
324
312k
                Ok(expr)
325
342k
            },
326
            comma,
327
        );
328
329
37.2k
        let (args, closed) =
330
41.8k
            cut_err((opt(terminated(arguments, opt(comma))), opt(ws(')')))).parse_next(i)?;
331
37.2k
        if closed.is_none() {
332
855
            cut_error!("matching closing `)` is missing", span)
333
        } else {
334
36.4k
            Ok(WithSpan::new(args.unwrap_or_default(), span))
335
        }
336
2.04M
    }
337
338
342k
    fn named_argument(
339
342k
        i: &mut InputStream<'a, 'l>,
340
342k
        named_arguments: &mut HashSet<&'a str>,
341
342k
    ) -> ParseResult<'a, WithSpan<Box<Self>>> {
342
9.96k
        let (((argument, arg_span), _, value), span) =
343
342k
            (identifier.with_span(), ws('='), move |i: &mut _| {
344
10.9k
                Self::parse(i, false)
345
10.9k
            })
346
342k
                .with_span()
347
342k
                .parse_next(i)?;
348
9.96k
        if !named_arguments.insert(argument) {
349
22
            return cut_error!(
350
                format!(
351
                    "named argument `{}` was passed more than once",
352
                    argument.escape_debug()
353
                ),
354
                arg_span,
355
            );
356
9.94k
        }
357
358
9.94k
        Ok(WithSpan::new(
359
9.94k
            Box::new(Self::NamedArgument(
360
9.94k
                WithSpan::new(argument, arg_span),
361
9.94k
                value,
362
9.94k
            )),
363
9.94k
            span,
364
9.94k
        ))
365
342k
    }
366
367
1.97M
    pub(super) fn parse(
368
1.97M
        i: &mut InputStream<'a, 'l>,
369
1.97M
        allow_underscore: bool,
370
1.97M
    ) -> ParseResult<'a, WithSpan<Box<Self>>> {
371
1.97M
        let _level_guard = i.state.level.nest(i)?;
372
1.97M
        let mut result = Self::range(i, allow_underscore);
373
1.97M
        if let Err(err) = &mut result {
374
115k
            try_assign_fallback_error(i, err);
375
1.85M
        }
376
1.97M
        result
377
1.97M
    }
378
379
1.97M
    fn range(
380
1.97M
        i: &mut InputStream<'a, 'l>,
381
1.97M
        allow_underscore: bool,
382
1.97M
    ) -> ParseResult<'a, WithSpan<Box<Self>>> {
383
3.82M
        let range_right = move |i: &mut InputStream<'a, 'l>| {
384
12.4k
            let ((op, span), rhs) =
385
3.82M
                (ws(alt(("..=", "..")).with_span()), opt(Self::or)).parse_next(i)?;
386
12.4k
            Ok((op, rhs, span))
387
3.82M
        };
388
389
        // `..expr` or `..`
390
1.97M
        let range_to = range_right.map(move |(op, rhs, span)| {
391
8.39k
            WithSpan::new(Box::new(Self::Range(Range { op, lhs: None, rhs })), span)
392
8.39k
        });
393
394
        // `expr..expr` or `expr..`
395
1.97M
        let range_from = (Self::or, opt(range_right)).map(move |(lhs, rhs)| match rhs {
396
4.04k
            Some((op, rhs, span)) => WithSpan::new(
397
4.04k
                Box::new(Self::Range(Range {
398
4.04k
                    op,
399
4.04k
                    lhs: Some(lhs),
400
4.04k
                    rhs,
401
4.04k
                })),
402
4.04k
                span,
403
            ),
404
1.84M
            None => lhs,
405
1.84M
        });
406
407
1.97M
        let expr = alt((range_to, range_from)).parse_next(i)?;
408
1.85M
        check_expr(
409
1.85M
            &expr,
410
1.85M
            Allowed {
411
1.85M
                underscore: allow_underscore,
412
1.85M
                super_keyword: false,
413
1.85M
            },
414
275
        )?;
415
1.85M
        Ok(expr)
416
1.97M
    }
417
418
    expr_prec_layer!(or, and, "||");
419
    expr_prec_layer!(and, compare, "&&");
420
421
1.99M
    fn compare(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
422
1.99M
        let mut parse_op = ws(alt(("==", "!=", ">=", ">", "<=", "<")).with_span());
423
424
1.99M
        let (expr, rhs) = (Self::bor, opt((parse_op.by_ref(), Self::bor))).parse_next(i)?;
425
1.87M
        let Some(((op, span), rhs)) = rhs else {
426
1.86M
            return Ok(expr);
427
        };
428
6.82k
        let expr = WithSpan::new(Box::new(Expr::BinOp(BinOp { op, lhs: expr, rhs })), span);
429
430
6.82k
        if let Some((op2, span)) = opt(parse_op).parse_next(i)? {
431
106
            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
6.72k
        }
439
440
6.72k
        Ok(expr)
441
1.99M
    }
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.04M
    fn concat(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
450
        #[allow(clippy::type_complexity)]
451
1.91M
        fn concat_expr<'a: 'l, 'l>(
452
1.91M
            i: &mut InputStream<'a, 'l>,
453
1.91M
        ) -> ParseResult<'a, Option<(WithSpan<Box<Expr<'a>>>, std::ops::Range<usize>)>> {
454
1.92M
            let ws1 = |i: &mut _| opt(skip_ws1).parse_next(i);
455
1.91M
            let tilde = (ws1, '~', ws1).with_span();
456
1.91M
            let data = opt((tilde, Expr::muldivmod)).parse_next(i)?;
457
458
1.91M
            let Some((((t1, _, t2), span), expr)) = data else {
459
1.91M
                return Ok(None);
460
            };
461
5.47k
            if t1.is_none() || t2.is_none() {
462
49
                return cut_error!("the concat operator `~` must be surrounded by spaces", span);
463
5.42k
            }
464
465
5.42k
            Ok(Some((expr, span)))
466
1.91M
        }
467
468
2.04M
        let expr = Self::muldivmod(i)?;
469
1.91M
        let expr2 = concat_expr(i)?;
470
1.91M
        if let Some((expr2, span)) = expr2 {
471
2.15k
            let mut exprs = vec![expr, expr2];
472
5.42k
            while let Some((expr, _)) = concat_expr(i)? {
473
3.27k
                exprs.push(expr);
474
3.27k
            }
475
1.90k
            Ok(WithSpan::new(Box::new(Self::Concat(exprs)), span))
476
        } else {
477
1.90M
            Ok(expr)
478
        }
479
2.04M
    }
480
481
    expr_prec_layer!(muldivmod, is_as, alt(("*", "/", "%")));
482
483
2.15M
    fn is_as(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
484
2.15M
        let lhs = Self::filtered(i)?;
485
1.95M
        let checkpoint = i.checkpoint();
486
1.95M
        let rhs = opt(ws(identifier.with_span())).parse_next(i)?;
487
1.95M
        match rhs {
488
15.6k
            Some(("is", span)) => Self::is_as_handle_is(i, lhs, span),
489
13.9k
            Some(("as", span)) => Self::is_as_handle_as(i, lhs, span),
490
            _ => {
491
1.94M
                i.reset(&checkpoint);
492
1.94M
                Ok(lhs)
493
            }
494
        }
495
2.15M
    }
496
497
1.71k
    fn is_as_handle_is(
498
1.71k
        i: &mut InputStream<'a, 'l>,
499
1.71k
        lhs: WithSpan<Box<Expr<'a>>>,
500
1.71k
        span: std::ops::Range<usize>,
501
1.71k
    ) -> ParseResult<'a, WithSpan<Box<Self>>> {
502
1.71k
        let mut rhs = opt(terminated(opt(keyword("not")), ws(keyword("defined"))));
503
1.71k
        let ctor = match rhs.parse_next(i)? {
504
            None => {
505
54
                return cut_error!("expected `defined` or `not defined` after `is`", span);
506
            }
507
1.11k
            Some(None) => Self::IsDefined,
508
548
            Some(Some(_)) => Self::IsNotDefined,
509
        };
510
1.65k
        let var_name = match &**lhs {
511
1.64k
            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
8
                return cut_error!("`is defined` operator can only be used on variables", span);
520
            }
521
        };
522
1.64k
        Ok(WithSpan::new(Box::new(ctor(var_name)), span))
523
1.71k
    }
524
525
7.93k
    fn is_as_handle_as(
526
7.93k
        i: &mut InputStream<'a, 'l>,
527
7.93k
        lhs: WithSpan<Box<Expr<'a>>>,
528
7.93k
        span: std::ops::Range<usize>,
529
7.93k
    ) -> ParseResult<'a, WithSpan<Box<Self>>> {
530
7.93k
        let target = opt(path_or_identifier).parse_next(i)?;
531
7.92k
        let Some(PathOrIdentifier::Identifier(target)) = target else {
532
8
            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.92k
        if crate::PRIMITIVE_TYPES.contains(&target) {
540
7.61k
            Ok(WithSpan::new(Box::new(Self::As(lhs, target)), span))
541
303
        } 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
303
            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.93k
    }
557
558
2.15M
    fn filtered(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
559
2.15M
        let mut res = Self::prefix(i)?;
560
561
1.95M
        let mut level_guard = i.state.level.guard();
562
1.95M
        let mut i_before = *i;
563
1.96M
        while let Some((mut filter, span)) = opt(ws(filter.with_span())).parse_next(i)? {
564
13.5k
            level_guard.nest(&i_before)?;
565
13.5k
            filter.arguments.insert(0, res);
566
13.5k
            res = WithSpan::new(Box::new(Self::Filter(filter)), span);
567
13.5k
            i_before = *i;
568
        }
569
1.95M
        Ok(res)
570
2.15M
    }
571
572
2.15M
    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.15M
        let mut level_guard = i.state.level.guard();
577
2.15M
        let mut i_before = *i;
578
2.15M
        let mut ops = vec![];
579
2.22M
        while let Some(op) = opt(ws(alt(("!", "-", "*", "&")).with_span())).parse_next(i)? {
580
65.2k
            level_guard.nest(&i_before)?;
581
65.2k
            ops.push(op);
582
65.2k
            i_before = *i;
583
        }
584
585
2.15M
        let mut expr = Suffix::parse(i)?;
586
1.95M
        for (op, span) in ops.into_iter().rev() {
587
59.7k
            expr = WithSpan::new(Box::new(Self::Unary(op, expr)), span);
588
59.7k
        }
589
590
1.95M
        Ok(expr)
591
2.15M
    }
592
593
2.15M
    fn single(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
594
2.15M
        alt((
595
2.15M
            Self::num,
596
2.15M
            Self::str,
597
2.15M
            Self::char,
598
2.15M
            Self::path_var_bool,
599
2.15M
            Self::array,
600
2.15M
            Self::group,
601
2.15M
        ))
602
2.15M
        .parse_next(i)
603
2.15M
    }
604
605
219k
    fn group(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
606
219k
        (skip_ws0, peek('(')).parse_next(i)?;
607
58.5k
        Self::group_actually(i)
608
219k
    }
609
610
    // `Self::group()` is quite big. Let's only put it on the stack if needed.
611
    #[inline(never)]
612
58.5k
    fn group_actually(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
613
58.5k
        let (expr, span) = cut_err(preceded('(', Self::group_actually_inner))
614
58.5k
            .with_span()
615
58.5k
            .parse_next(i)?;
616
44.8k
        Ok(WithSpan::new(expr, span))
617
58.5k
    }
618
619
    #[inline]
620
58.5k
    fn group_actually_inner(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Self>> {
621
46.9k
        let (expr, comma, closing) = (
622
58.5k
            ws(opt(|i: &mut _| Self::parse(i, true))),
623
58.5k
            opt(terminated(','.span(), skip_ws0)),
624
58.5k
            opt(')'),
625
        )
626
58.5k
            .parse_next(i)?;
627
628
46.9k
        let expr = match (expr, comma, closing) {
629
            // `(expr,`
630
4.56k
            (Some(expr), Some(_), None) => expr,
631
            // `()`
632
25.6k
            (None, None, Some(_)) => return Ok(Box::new(Self::Tuple(vec![]))),
633
            // `(expr)`
634
13.3k
            (Some(expr), None, Some(_)) => return Ok(Box::new(Self::Group(expr))),
635
            // `(expr,)`
636
3.00k
            (Some(expr), Some(_), Some(_)) => return Ok(Box::new(Self::Tuple(vec![expr]))),
637
            // `(`
638
235
            (None, None, None) => return cut_error!("expected closing `)` or an expression", *i),
639
            // `(expr`
640
147
            (Some(_), None, None) => return cut_error!("expected `,` or `)`", *i),
641
            // `(,`
642
14
            (None, Some(span), _) => return cut_error!("stray comma after opening `(`", span),
643
        };
644
645
4.56k
        let mut exprs = vec![expr];
646
4.56k
        let collect_items = opt(separated(
647
4.56k
            1..,
648
366k
            |i: &mut _| {
649
366k
                exprs.push(Self::parse(i, true)?);
650
363k
                Ok(())
651
366k
            },
652
4.56k
            ws(','),
653
        )
654
4.56k
        .map(|()| ()));
655
656
4.56k
        let ((items, comma, close), span) = cut_err((collect_items, ws(opt(',')), opt(')')))
657
4.56k
            .with_span()
658
4.56k
            .parse_next(i)?;
659
3.04k
        let msg = if items.is_none() {
660
34
            "expected `)` or an expression"
661
3.00k
        } else if close.is_some() {
662
2.84k
            return Ok(Box::new(Self::Tuple(exprs)));
663
165
        } else if comma.is_some() {
664
51
            "expected `)` or an expression"
665
        } else {
666
114
            "expected `,` or `)`"
667
        };
668
199
        cut_error!(msg, span)
669
58.5k
    }
670
671
254k
    fn array(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
672
254k
        let _level_guard = i.state.level.nest(i)?;
673
28.1k
        let (span, mut elements): (_, Vec<_>) = (
674
254k
            '['.span(),
675
983k
            separated(0.., ws(move |i: &mut _| Self::parse(i, true)), ','),
676
        )
677
254k
            .parse_next(i)?;
678
679
28.1k
        let expr = if let Some(semicolon) = opt(ws(';'.span())).parse_next(i)? {
680
            // array repeat [<el_expr>; <cnt_expr>]
681
2.07k
            let Some(elem) = elements.pop() else {
682
9
                return cut_error!(
683
                    "expected element expression for array repeat syntax",
684
                    semicolon
685
                );
686
            };
687
2.06k
            if !elements.is_empty() {
688
27
                return cut_error!("unexpected `;` after expression", semicolon);
689
2.03k
            }
690
2.03k
            let Some(count) = opt(ws(move |i: &mut _| Expr::parse(i, true))).parse_next(i)? else {
691
13
                return cut_error!(
692
                    "expected count expression for array repeat syntax after `;`",
693
                    semicolon
694
                );
695
            };
696
1.77k
            if let Some((delim, span)) = ws(opt(one_of((',', ';')).with_span())).parse_next(i)? {
697
7
                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.77k
            }
706
1.77k
            Self::ArrayRepeat(elem, count)
707
        } else {
708
            // normal array [<expr>,...?]
709
26.0k
            if !elements.is_empty() {
710
                // strip optional trailing comma
711
8.75k
                ws(opt(',')).parse_next(i)?;
712
17.3k
            }
713
26.0k
            Self::Array(elements)
714
        };
715
716
27.8k
        if ws(opt(']')).parse_next(i)?.is_none() {
717
816
            let (next, span) = match opt(any_rust_token.with_span()).parse_next(i)? {
718
218
                Some((next, span)) => (Some(next), span),
719
598
                None => (None, span),
720
            };
721
816
            return cut_error!(
722
816
                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
27.0k
        }
734
27.0k
        Ok(WithSpan::new(Box::new(expr), span))
735
254k
    }
736
737
2.00M
    fn path_var_bool(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
738
2.00M
        let (ret, span) = path_or_identifier.with_span().parse_next(i)?;
739
1.74M
        let ret = match ret {
740
87.9k
            PathOrIdentifier::Path(v) => Box::new(Self::Path(v)),
741
1.65M
            PathOrIdentifier::Identifier(v) if *v == "true" => Box::new(Self::BoolLit(true)),
742
1.65M
            PathOrIdentifier::Identifier(v) if *v == "false" => Box::new(Self::BoolLit(false)),
743
1.65M
            PathOrIdentifier::Identifier(v) => Box::new(Self::Var(*v)),
744
        };
745
1.74M
        Ok(WithSpan::new(ret, span))
746
2.00M
    }
747
748
2.00M
    fn str(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
749
2.00M
        let (s, span) = str_lit.with_span().parse_next(i)?;
750
1.99k
        Ok(WithSpan::new(Box::new(Self::StrLit(s)), span))
751
2.00M
    }
752
753
2.15M
    fn num(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
754
2.15M
        let ((num, full), span) = num_lit.with_taken().with_span().parse_next(i)?;
755
145k
        Ok(WithSpan::new(Box::new(Expr::NumLit(full, num)), span))
756
2.15M
    }
757
758
2.00M
    fn char(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
759
2.00M
        let (c, span) = char_lit.with_span().parse_next(i)?;
760
2.82k
        Ok(WithSpan::new(Box::new(Self::CharLit(c)), span))
761
2.00M
    }
762
763
    #[must_use]
764
87.5k
    pub fn contains_bool_lit_or_is_defined(&self) -> bool {
765
24.3k
        match self {
766
809
            Self::BoolLit(_) | Self::IsDefined(_) | Self::IsNotDefined(_) => true,
767
17.6k
            Self::Unary(_, expr) | Self::Group(expr) => expr.contains_bool_lit_or_is_defined(),
768
24.3k
            Self::BinOp(v) if matches!(v.op, "&&" | "||") => {
769
15.4k
                v.lhs.contains_bool_lit_or_is_defined() || v.rhs.contains_bool_lit_or_is_defined()
770
            }
771
2.85k
            Self::NumLit(_, _)
772
392
            | Self::StrLit(_)
773
459
            | Self::CharLit(_)
774
21.4k
            | Self::Var(_)
775
0
            | Self::FilterSource
776
393
            | Self::RustMacro(_, _)
777
260
            | Self::As(_, _)
778
894
            | Self::Call { .. }
779
5.30k
            | Self::Range(_)
780
1.06k
            | Self::Try(_)
781
392
            | Self::Struct(_)
782
0
            | Self::NamedArgument(_, _)
783
513
            | Self::Filter(_)
784
1.94k
            | Self::AssociatedItem(_, _)
785
261
            | Self::Index(_, _)
786
823
            | Self::Tuple(_)
787
290
            | Self::Array(_)
788
132
            | Self::ArrayRepeat(_, _)
789
8.85k
            | Self::BinOp(_)
790
6.49k
            | Self::Path(_)
791
265
            | Self::Concat(_)
792
568
            | Self::LetCond(_)
793
53.6k
            | Self::ArgumentPlaceholder => false,
794
        }
795
87.5k
    }
796
}
797
798
1.88M
fn token_xor<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a> {
799
1.88M
    let good = keyword("xor").value(None);
800
1.88M
    let bad = ('^', not('=')).span().map(Some);
801
1.88M
    if let Some(span) = alt((good, bad)).parse_next(i)? {
802
14
        cut_error!("the binary XOR operator is called `xor` in askama", span)
803
    } else {
804
295
        Ok("^")
805
    }
806
1.88M
}
807
808
1.88M
fn token_bitand<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a> {
809
1.88M
    let good = keyword("bitand").value(None);
810
1.88M
    let bad = ('&', not(one_of(['&', '=']))).span().map(Some);
811
1.88M
    if let Some(span) = alt((good, bad)).parse_next(i)? {
812
33
        cut_error!("the binary AND operator is called `bitand` in askama", span)
813
    } else {
814
260
        Ok("&")
815
    }
816
1.88M
}
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
20.1k
    pub(crate) fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
826
20.1k
        let mut p = (ws(path_or_identifier), opt(Expr::arguments));
827
20.1k
        let (name, arguments) = p.parse_next(i)?;
828
        Ok(Self {
829
19.4k
            name,
830
19.4k
            arguments: arguments.map_or_else(Vec::new, |arguments| arguments.inner),
831
        })
832
20.1k
    }
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.15M
    fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>> {
871
2.15M
        let mut level_guard = i.state.level.guard();
872
2.15M
        let mut expr = Expr::single(i)?;
873
1.96M
        let mut right = opt(alt((
874
1.96M
            Self::associated_item,
875
1.96M
            Self::index,
876
1.96M
            Self::call,
877
1.96M
            Self::r#try,
878
1.96M
            Self::r#macro,
879
1.96M
            Self::r#struct,
880
1.96M
        )));
881
882
1.96M
        let mut i_before = i.checkpoint();
883
2.05M
        while let Some(suffix) = right.parse_next(i)? {
884
91.1k
            level_guard.nest(i)?;
885
91.1k
            let (suffix, span) = suffix.deconstruct();
886
91.1k
            let inner = match suffix {
887
11.5k
                Self::AssociatedItem(associated_item) => {
888
11.5k
                    Box::new(Expr::AssociatedItem(expr, associated_item))
889
                }
890
26.3k
                Self::Index(index) => Box::new(Expr::Index(expr, index)),
891
31.3k
                Self::Call { generics, args } => Box::new(Expr::Call(Call {
892
31.3k
                    path: expr,
893
31.3k
                    generics,
894
31.3k
                    args,
895
31.3k
                })),
896
5.83k
                Self::Struct { fields, base } => Box::new(Expr::Struct(ExprStruct {
897
5.83k
                    path: expr,
898
5.83k
                    fields,
899
5.83k
                    base,
900
5.83k
                })),
901
8.00k
                Self::Try => Box::new(Expr::Try(expr)),
902
8.04k
                Self::MacroCall(args) => {
903
8.04k
                    let args = WithSpan::new(args, span);
904
8.04k
                    match *expr.inner {
905
2.64k
                        Expr::Path(path) => {
906
2.64k
                            let last = path.last().unwrap();
907
2.64k
                            ensure_macro_name(&last.name)?;
908
909
1.40M
                            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
2.64k
                            }
916
917
2.64k
                            Box::new(Expr::RustMacro(
918
2.64k
                                path.into_iter()
919
2.64k
                                    .map(|c: PathComponent<'_>| c.name)
920
2.64k
                                    .collect(),
921
2.64k
                                args,
922
                            ))
923
                        }
924
3.45k
                        Expr::Var(name) => {
925
3.45k
                            let name = WithSpan::new(name, expr.span);
926
3.45k
                            ensure_macro_name(&name)?;
927
3.44k
                            Box::new(Expr::RustMacro(vec![name], args))
928
                        }
929
                        _ => {
930
1.94k
                            i.reset(&i_before);
931
1.94k
                            return fail(i);
932
                        }
933
                    }
934
                }
935
            };
936
89.1k
            expr = WithSpan::new(inner, span);
937
89.1k
            i_before = i.checkpoint();
938
        }
939
1.95M
        Ok(expr)
940
2.15M
    }
941
942
1.97M
    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
94
            fn as_close_char(self) -> char {
959
94
                match self {
960
31
                    Group::Paren => ')',
961
39
                    Group::Brace => '}',
962
24
                    Group::Bracket => ']',
963
                }
964
94
            }
965
        }
966
967
10.8k
        fn macro_arguments<'a: 'l, 'l>(
968
10.8k
            i: &mut InputStream<'a, 'l>,
969
10.8k
            open_token: Group,
970
10.8k
        ) -> ParseResult<'a, Suffix<'a>> {
971
10.8k
            fn inner<'a: 'l, 'l>(
972
10.8k
                i: &mut InputStream<'a, 'l>,
973
10.8k
                open_token: Group,
974
10.8k
            ) -> ParseResult<'a, <InputStream<'a, 'l> as Stream>::Checkpoint> {
975
10.8k
                let mut open_list = vec![open_token];
976
                loop {
977
3.90M
                    let before = i.checkpoint();
978
3.90M
                    let token = ws(opt(token.with_span())).parse_next(i)?;
979
3.90M
                    let after = i.checkpoint();
980
3.90M
                    let Some((token, span)) = token else {
981
2.09k
                        return cut_error!("expected valid tokens in macro call", *i);
982
                    };
983
3.90M
                    let close_token = match token {
984
1.59M
                        Token::SomeOther => continue,
985
2.25M
                        Token::Open(group) => {
986
2.25M
                            open_list.push(group);
987
2.25M
                            continue;
988
                        }
989
43.9k
                        Token::Close(close_token) => close_token,
990
                    };
991
43.9k
                    let open_token = open_list.pop().unwrap();
992
993
43.9k
                    if open_token != close_token {
994
47
                        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
43.9k
                    } else if open_list.is_empty() {
1003
8.04k
                        i.reset(&before);
1004
8.04k
                        return Ok(after);
1005
35.8k
                    }
1006
                }
1007
10.8k
            }
1008
1009
10.8k
            let p = |i: &mut _| inner(i, open_token);
1010
10.8k
            let (checkpoint, inner) = p.with_taken().parse_next(i)?;
1011
8.04k
            i.reset(&checkpoint);
1012
8.04k
            Ok(Suffix::MacroCall(inner))
1013
10.8k
        }
1014
1015
747k
        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
747k
            let p = (
1018
747k
                '\''.void(),
1019
                identifier,
1020
747k
                opt((repeat(1.., '#'), opt(identifier))),
1021
747k
                opt('\'').map(|o| o.is_some()),
1022
            );
1023
747k
            let ((_, front, back, quot), span) = p.with_span().parse_next(i)?;
1024
286
            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
161
                (identifier, None, _) => {
1033
161
                    if !is_rust_keyword(identifier) {
1034
153
                        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
125
                ("r", Some((1, Some(identifier))), _) => {
1044
68
                    if matches!(identifier, "Self" | "self" | "crate" | "super" | "_") {
1045
12
                        cut_error!(
1046
                            format!("`{}` cannot be a raw lifetime", identifier.escape_debug()),
1047
                            span,
1048
                        )
1049
                    } else {
1050
56
                        Ok(())
1051
                    }
1052
                }
1053
                // an illegal prefix (not `'r#..`, multiple `#` or no identifier after `#`)
1054
57
                (_, Some(_), _) => cut_error!("wrong lifetime format", span),
1055
            }
1056
747k
        }
1057
1058
3.90M
        fn token<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Token> {
1059
            // <https://doc.rust-lang.org/reference/tokens.html>
1060
3.90M
            let some_other = alt((
1061
3.90M
                // literals
1062
3.90M
                char_lit.value(Token::SomeOther),
1063
3.90M
                str_lit.value(Token::SomeOther),
1064
3.90M
                num_lit.value(Token::SomeOther),
1065
3.90M
                // keywords + (raw) identifiers + raw strings
1066
3.90M
                identifier_or_prefixed_string.value(Token::SomeOther),
1067
3.90M
                lifetime.value(Token::SomeOther),
1068
3.90M
                // comments
1069
3.90M
                line_comment.value(Token::SomeOther),
1070
3.90M
                block_comment.value(Token::SomeOther),
1071
3.90M
                // punctuations
1072
3.90M
                punctuation.value(Token::SomeOther),
1073
3.90M
                hash,
1074
3.90M
            ));
1075
3.90M
            alt((open.map(Token::Open), close.map(Token::Close), some_other)).parse_next(i)
1076
3.90M
        }
1077
1078
747k
        fn line_comment<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
1079
747k
            fn inner<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, bool> {
1080
747k
                let mut p = (
1081
747k
                    "//".span(),
1082
747k
                    alt((
1083
747k
                        ('/', not(peek('/'))).value(true),
1084
747k
                        '!'.value(true),
1085
747k
                        empty.value(false),
1086
747k
                    )),
1087
747k
                );
1088
747k
                let (start, is_doc_comment) = p.parse_next(i)?;
1089
26.5k
                if opt((take_until(.., '\n'), '\n')).parse_next(i)?.is_none() {
1090
54
                    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
26.4k
                };
1098
26.4k
                Ok(is_doc_comment)
1099
747k
            }
1100
1101
747k
            doc_comment_no_bare_cr(i, inner)
1102
747k
        }
1103
1104
720k
        fn block_comment<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
1105
720k
            fn inner<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, bool> {
1106
720k
                let is_doc_comment = alt((
1107
720k
                    ('*', not(peek(one_of(['*', '/'])))).value(true),
1108
720k
                    '!'.value(true),
1109
720k
                    empty.value(false),
1110
720k
                ));
1111
6.08k
                let (is_doc_comment, start) =
1112
720k
                    preceded("/*", is_doc_comment).with_span().parse_next(i)?;
1113
1114
6.08k
                let mut depth = 0usize;
1115
                loop {
1116
471k
                    if opt(take_until(.., ("/*", "*/"))).parse_next(i)?.is_none() {
1117
107
                        return cut_error!(
1118
                            format!(
1119
                                "missing `*/` to close block {}comment",
1120
                                if is_doc_comment { "doc " } else { "" }
1121
                            ),
1122
                            start,
1123
                        );
1124
471k
                    } else if alt(("/*".value(true), "*/".value(false))).parse_next(i)? {
1125
320k
                        // cannot overflow: `i` cannot be longer than `isize::MAX`, cf. [std::alloc::Layout]
1126
320k
                        depth += 1;
1127
320k
                    } else if let Some(new_depth) = depth.checked_sub(1) {
1128
145k
                        depth = new_depth;
1129
145k
                    } else {
1130
5.97k
                        return Ok(is_doc_comment);
1131
                    }
1132
                }
1133
720k
            }
1134
1135
720k
            doc_comment_no_bare_cr(i, inner)
1136
720k
        }
1137
1138
1.50M
        fn identifier_or_prefixed_string<'a: 'l, 'l>(
1139
1.50M
            i: &mut InputStream<'a, 'l>,
1140
1.50M
        ) -> ParseResult<'a, ()> {
1141
            // <https://doc.rust-lang.org/reference/tokens.html#r-lex.token.literal.str-raw.syntax>
1142
1143
756k
            let ((prefix, hashes, quot), prefix_span): ((_, usize, _), _) =
1144
1.50M
                (identifier, repeat(.., '#'), opt('"'))
1145
1.50M
                    .with_span()
1146
1.50M
                    .parse_next(i)?;
1147
756k
            if hashes >= 256 {
1148
3
                return cut_error!(
1149
                    "a maximum of 255 hashes `#` are allowed with raw and prefixed strings",
1150
                    prefix_span,
1151
                );
1152
756k
            }
1153
1154
689k
            let str_kind = match prefix {
1155
                // raw cstring or byte slice
1156
756k
                "br" => Some(StrPrefix::Binary),
1157
753k
                "cr" => Some(StrPrefix::CLike),
1158
                // raw string string or identifier
1159
697k
                "r" => None,
1160
                // a simple identifier
1161
689k
                _ if hashes == 0 && quot.is_none() => return Ok(()),
1162
                // reserved prefix: reject
1163
                _ => {
1164
25
                    return cut_error!(
1165
                        format!("reserved prefix `{}#`", prefix.escape_debug()),
1166
                        prefix_span,
1167
                    );
1168
                }
1169
            };
1170
1171
66.8k
            if quot.is_some() {
1172
                // got a raw string
1173
1174
7.48k
                let delim = format!("\"{:#<hashes$}", "");
1175
7.48k
                let p = terminated(take_until(.., delim.as_str()).with_span(), delim.as_str());
1176
7.48k
                let Some((inner, inner_span)) = opt(p).parse_next(i)? else {
1177
89
                    return cut_error!("unterminated raw string", prefix_span);
1178
                };
1179
1180
7.39k
                if inner.split('\r').skip(1).any(|s| !s.starts_with('\n')) {
1181
81
                    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.31k
                }
1188
1189
7.31k
                let msg = match str_kind {
1190
2.37k
                    Some(StrPrefix::Binary) => inner
1191
2.37k
                        .bytes()
1192
257k
                        .any(|b| !b.is_ascii())
1193
2.37k
                        .then_some("binary string literals must not contain non-ASCII characters"),
1194
2.24k
                    Some(StrPrefix::CLike) => inner
1195
2.24k
                        .bytes()
1196
25.4k
                        .any(|b| b == 0)
1197
2.24k
                        .then_some("cstring literals must not contain NUL characters"),
1198
2.69k
                    None => None,
1199
                };
1200
7.31k
                if let Some(msg) = msg {
1201
8
                    return cut_error!(msg, prefix_span);
1202
7.30k
                }
1203
1204
7.30k
                not_suffix_with_hash(i)?;
1205
7.29k
                Ok(())
1206
59.4k
            } else if hashes == 0 {
1207
                // a simple identifier
1208
56.7k
                Ok(())
1209
2.64k
            } else if let Some((id, span)) = opt(identifier.with_span()).parse_next(i)? {
1210
                // got a raw identifier
1211
1212
2.61k
                if str_kind.is_some() {
1213
                    // an invalid raw identifier like `cr#async`
1214
2
                    cut_error!(
1215
                        format!(
1216
                            "reserved prefix `{}#`, only `r#` is allowed with raw identifiers",
1217
                            prefix.escape_debug(),
1218
                        ),
1219
                        prefix_span,
1220
                    )
1221
2.61k
                } else if hashes > 1 {
1222
                    // an invalid raw identifier like `r##async`
1223
3
                    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
2.61k
                    if matches!(id, "self" | "Self" | "super" | "crate" | "_") {
1230
10
                        cut_error!(
1231
                            format!("`{}` cannot be a raw identifier", id.escape_debug()),
1232
                            span,
1233
                        )
1234
                    } else {
1235
2.60k
                        Ok(())
1236
                    }
1237
                }
1238
            } else {
1239
29
                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.50M
        }
1248
1249
12.3k
        fn hash<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Token> {
1250
12.3k
            let (quot, span) = preceded('#', opt('"')).with_span().parse_next(i)?;
1251
10.2k
            if quot.is_some() {
1252
6
                return cut_error!(
1253
                    "unprefixed guarded string literals are reserved for future use",
1254
                    span,
1255
                );
1256
10.2k
            }
1257
10.2k
            Ok(Token::SomeOther)
1258
12.3k
        }
1259
1260
714k
        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
714k
            let three_chars = take(3usize).verify_map(|head: &str| {
1273
711k
                if let Ok(head) = head.as_bytes().try_into()
1274
709k
                    && THREE_CHARS.contains(head)
1275
                {
1276
1.78k
                    Some(())
1277
                } else {
1278
710k
                    None
1279
                }
1280
711k
            });
1281
714k
            let two_chars = take(2usize).verify_map(|head: &str| {
1282
710k
                if let Ok(head) = head.as_bytes().try_into()
1283
709k
                    && TWO_CHARS.contains(head)
1284
                {
1285
27.8k
                    Some(())
1286
                } else {
1287
683k
                    None
1288
                }
1289
710k
            });
1290
714k
            let one_char = any.verify_map(|head: char| {
1291
683k
                if let Ok(head) = head.try_into()
1292
683k
                    && ONE_CHAR.contains(&head)
1293
                {
1294
672k
                    Some(())
1295
                } else {
1296
10.6k
                    None
1297
                }
1298
683k
            });
1299
1300
            // need to check long to short
1301
714k
            alt((three_chars, two_chars, one_char)).parse_next(i)
1302
714k
        }
1303
1304
3.91M
        fn open<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Group> {
1305
3.91M
            alt((
1306
3.91M
                '('.value(Group::Paren),
1307
3.91M
                '{'.value(Group::Brace),
1308
3.91M
                '['.value(Group::Bracket),
1309
3.91M
            ))
1310
3.91M
            .parse_next(i)
1311
3.91M
        }
1312
1313
1.64M
        fn close<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Group> {
1314
1.64M
            alt((
1315
1.64M
                ')'.value(Group::Paren),
1316
1.64M
                '}'.value(Group::Brace),
1317
1.64M
                ']'.value(Group::Bracket),
1318
1.64M
            ))
1319
1.64M
            .parse_next(i)
1320
1.64M
        }
1321
1322
1.97M
        let (span, open_token) = (ws('!'.span()), open).parse_next(i)?;
1323
10.8k
        let inner = (|i: &mut _| macro_arguments(i, open_token)).parse_next(i)?;
1324
8.04k
        Ok(WithSpan::new(inner, span))
1325
1.97M
    }
1326
1327
2.05M
    fn associated_item(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1328
2.05M
        let mut p = (
1329
2.05M
            ws(terminated('.'.span(), not('.'))),
1330
2.05M
            cut_err((
1331
11.7k
                |i: &mut _| {
1332
11.7k
                    let (name, span) = alt((digit1, identifier)).with_span().parse_next(i)?;
1333
11.5k
                    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.5k
                    }
1339
11.5k
                    Ok(WithSpan::new(name, span))
1340
11.7k
                },
1341
2.05M
                opt(call_generics),
1342
            )),
1343
        );
1344
2.05M
        let (span, (name, generics)) = p.parse_next(i)?;
1345
11.5k
        Ok(WithSpan::new(
1346
11.5k
            Self::AssociatedItem(AssociatedItem { name, generics }),
1347
11.5k
            span,
1348
11.5k
        ))
1349
2.05M
    }
1350
1351
2.04M
    fn index(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1352
2.04M
        let mut p = (
1353
2.04M
            ws('['.span()),
1354
2.04M
            cut_err((ws(move |i: &mut _| Expr::parse(i, true)), opt(']'))),
1355
        );
1356
2.04M
        let (span, (expr, closed)) = p.parse_next(i)?;
1357
26.5k
        if closed.is_none() {
1358
207
            return cut_error!("matching closing `]` is missing", span);
1359
26.3k
        }
1360
26.3k
        Ok(WithSpan::new(Self::Index(expr), span))
1361
2.04M
    }
1362
1363
2.01M
    fn call(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1364
2.01M
        let mut p = (opt(call_generics), Expr::arguments);
1365
2.01M
        let (generics, args) = p.parse_next(i)?;
1366
31.3k
        let (args, span) = args.deconstruct();
1367
31.3k
        Ok(WithSpan::new(Self::Call { generics, args }, span))
1368
2.01M
    }
1369
1370
1.97M
    fn r#try(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1371
1.97M
        let span = preceded(skip_ws0, '?'.span()).parse_next(i)?;
1372
8.00k
        Ok(WithSpan::new(Self::Try, span))
1373
1.97M
    }
1374
1375
1.96M
    fn r#struct(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1376
1.96M
        let _level_guard = i.state.level.nest(i)?;
1377
1.96M
        let mut p = (
1378
1.96M
            ws('{'.span()),
1379
1.96M
            cut_err((separated(
1380
1.96M
                0..,
1381
1.96M
                alt((Self::struct_field, Self::struct_base)),
1382
1.96M
                ws(','),
1383
1.96M
            ),)),
1384
1.96M
            opt(ws(',')), // Trailing comma.
1385
1.96M
            opt(ws(winnow::token::any.with_span())),
1386
1.96M
        );
1387
6.16k
        let (span, (all_fields,), trailing_comma, closed): (
1388
6.16k
            _,
1389
6.16k
            (Vec<Field<'_>>,),
1390
6.16k
            Option<_>,
1391
6.16k
            Option<_>,
1392
1.96M
        ) = p.parse_next(i)?;
1393
6.16k
        if trailing_comma.is_some() && all_fields.is_empty() {
1394
4
            return cut_error!("missing field before `,`", span);
1395
6.16k
        }
1396
6.16k
        let mut base: Option<WithSpan<Box<Expr<'a>>>> = None;
1397
6.16k
        let mut fields = Vec::with_capacity(all_fields.len());
1398
3.52M
        for field in all_fields {
1399
3.51M
            match field {
1400
3.51M
                Field::Field(field) => {
1401
3.51M
                    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.51M
                    }
1407
3.51M
                    fields.push(field);
1408
                }
1409
1.02k
                Field::Base(new_base) => {
1410
1.02k
                    if base.is_some() {
1411
8
                        return cut_error!(
1412
                            "expected end of struct expression after `..` was used",
1413
                            new_base.span()
1414
                        );
1415
1.01k
                    }
1416
1.01k
                    base = Some(new_base);
1417
                }
1418
            }
1419
        }
1420
6.15k
        if closed.as_ref().is_none_or(|(c, _)| *c != '}') {
1421
312
            let err_span = match closed {
1422
147
                Some((_, span)) => span,
1423
165
                _ => span,
1424
            };
1425
312
            if base.is_some() {
1426
11
                return cut_error!(
1427
                    "expected end of struct expression after `..` was used",
1428
                    err_span
1429
                );
1430
301
            } else if !fields.is_empty() {
1431
150
                return cut_error!("expected `,`, `..`, field name or `}`", err_span);
1432
            } else {
1433
151
                return cut_error!("expected field name, `..` or `}`", err_span);
1434
            }
1435
5.83k
        }
1436
1437
5.83k
        Ok(WithSpan::new(Self::Struct { fields, base }, span))
1438
1.96M
    }
1439
1440
5.58k
    fn struct_base(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Field<'a>> {
1441
5.58k
        let ((_, base_expr), span) = (ws(".."), opt(ws(move |i: &mut _| Expr::parse(i, true))))
1442
5.58k
            .with_span()
1443
5.58k
            .parse_next(i)?;
1444
1.48k
        match base_expr {
1445
1.44k
            Some(base_expr) => Ok(Field::Base(base_expr)),
1446
39
            None => cut_error!("expected expression after `..`", span),
1447
        }
1448
5.58k
    }
1449
1450
3.52M
    fn struct_field(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Field<'a>> {
1451
3.52M
        let ((name, name_span), has_colon, value) = alt((
1452
            (
1453
3.52M
                alt((identifier, digit1)).with_span(),
1454
3.52M
                ws(':'),
1455
3.52M
                opt(ws(|i: &mut _| Expr::parse(i, true))),
1456
            )
1457
3.52M
                .map(|(name, _, expr)| (name, true, expr)),
1458
3.52M
            identifier.with_span().map(|name| (name, false, None)),
1459
        ))
1460
3.52M
        .parse_next(i)?;
1461
3.51M
        if has_colon && value.is_none() {
1462
58
            cut_error!("expected expression after `:`", *i)
1463
        } else {
1464
3.51M
            Ok(Field::Field(ExprStructField {
1465
3.51M
                name: WithSpan::new(name, name_span),
1466
3.51M
                value,
1467
3.51M
            }))
1468
        }
1469
3.52M
    }
1470
}
1471
1472
1.46M
fn doc_comment_no_bare_cr<'a: 'l, 'l>(
1473
1.46M
    i: &mut InputStream<'a, 'l>,
1474
1.46M
    inner: fn(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, bool>,
1475
1.46M
) -> ParseResult<'a, ()> {
1476
1.46M
    let ((is_doc_comment, comment), span) = inner.with_taken().with_span().parse_next(i)?;
1477
32.4k
    if is_doc_comment && comment.split('\r').skip(1).any(|s| !s.starts_with('\n')) {
1478
37
        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
32.3k
        Ok(())
1485
    }
1486
1.46M
}
1487
1488
6.10k
fn ensure_macro_name<'a>(name: &WithSpan<&'a str>) -> ParseResult<'a, ()> {
1489
6.10k
    if matches!(**name, "_" | "crate" | "super" | "Self" | "self") {
1490
17
        return cut_error!(format!("`{}` is not a valid macro name", **name), name.span);
1491
6.08k
    }
1492
6.08k
    Ok(())
1493
6.10k
}
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
2.41M
    pub(crate) fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
1503
2.41M
        let p = ws((repeat(0.., ws('&')), TyGenericsKind::parse.with_span()));
1504
2.41M
        let ((refs, (kind, kind_span)), span) = p.with_span().parse_next(i)?;
1505
2.39M
        if refs > MAX_REFS {
1506
18
            return cut_error!(format!("too many references (> {MAX_REFS})"), span);
1507
2.39M
        }
1508
1509
2.39M
        Ok(WithSpan::new(
1510
2.39M
            TyGenerics {
1511
2.39M
                refs,
1512
2.39M
                kind: WithSpan::new(kind, kind_span),
1513
2.39M
            },
1514
2.39M
            span,
1515
2.39M
        ))
1516
2.41M
    }
1517
1518
4.93M
    fn args(
1519
4.93M
        i: &mut InputStream<'a, 'l>,
1520
4.93M
    ) -> ParseResult<'a, WithSpan<Vec<WithSpan<TyGenerics<'a>>>>> {
1521
4.93M
        let mut p = cut_err(terminated(
1522
4.93M
            opt(terminated(
1523
4.93M
                separated(1.., TyGenerics::parse, ws(',')),
1524
4.93M
                ws(opt(',')),
1525
            )),
1526
            '>',
1527
        ));
1528
1529
4.93M
        let span = ws('<'.span()).parse_next(i)?;
1530
24.2k
        let _level_guard = i.state.level.nest(i)?;
1531
24.2k
        let args = p.parse_next(i)?;
1532
22.2k
        Ok(WithSpan::new(args.unwrap_or_default(), span))
1533
4.93M
    }
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
2.41M
    fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
1551
2.41M
        let _level_guard = i.state.level.nest(i)?;
1552
2.41M
        alt((Self::tuple, Self::array, Self::ty_path)).parse_next(i)
1553
2.41M
    }
1554
1555
2.39M
    fn ty_path(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, TyGenericsKind<'a>> {
1556
2.39M
        let path = separated(
1557
2.39M
            1..,
1558
2.39M
            ws(identifier
1559
2.39M
                .with_span()
1560
2.43M
                .map(|(name, span)| WithSpan::new(name, span))),
1561
            "::",
1562
        )
1563
2.39M
        .map(|v: Vec<_>| v);
1564
1565
2.39M
        let (path, args) = (path, opt(TyGenerics::args)).parse_next(i)?;
1566
1567
2.37M
        if let [name] = path.as_slice() {
1568
2.37M
            if matches!(**name, "super" | "self" | "crate") {
1569
                // `Self` and `_` are allowed
1570
25
                return err_reserved_identifier(name);
1571
2.37M
            }
1572
        } else {
1573
18.1k
            for (idx, name) in path.iter().enumerate() {
1574
18.1k
                if **name == "_" {
1575
                    // `_` is never allowed
1576
20
                    return err_underscore_identifier(name);
1577
18.1k
                } 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
18.1k
                }
1582
            }
1583
        }
1584
2.37M
        Ok(TyGenericsKind::Path { path, args })
1585
2.39M
    }
1586
1587
2.41M
    fn tuple(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, TyGenericsKind<'a>> {
1588
2.41M
        let start = *i;
1589
        // We ensure we're in the right function to get better errors later on.
1590
2.41M
        ws('(').parse_next(i)?;
1591
8.97k
        let Ok(tuple_elems) = separated(0.., TyGenerics::parse, ws(',')).parse_next(i) else {
1592
1.52k
            return cut_error!("expected a list of type separated by a comma", start);
1593
        };
1594
7.45k
        if (opt(ws(',')), ws(')')).parse_next(i).is_err() {
1595
210
            return cut_error!("expected a list of type separated by a comma", start);
1596
7.24k
        }
1597
7.24k
        Ok(TyGenericsKind::Tuple(tuple_elems))
1598
2.41M
    }
1599
1600
2.40M
    fn array(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, TyGenericsKind<'a>> {
1601
2.40M
        let start = *i;
1602
        // We ensure we're in the right function to get better errors later on.
1603
2.40M
        ws('[').parse_next(i)?;
1604
1605
6.85k
        let ty = match TyGenerics::parse.parse_next(i) {
1606
5.75k
            Ok(ty) => ty,
1607
1.04k
            Err(error @ ErrMode::Cut(_)) => return Err(error),
1608
55
            Err(_) => return cut_error!("expected a type", *i),
1609
        };
1610
5.75k
        let mut nb_elems = None;
1611
5.75k
        if let Ok((_, colon_span)) = ws(';').with_span().parse_next(i) {
1612
384
            let Ok((parsed_nb, nb_span)) = num_lit.with_span().parse_next(i) else {
1613
63
                return cut_error!("expected a number after `;`", colon_span);
1614
            };
1615
11
            match parsed_nb {
1616
274
                Num::Int(nb, Some(crate::IntKind::Usize) | None) => nb_elems = Some(nb),
1617
11
                Num::Int(_, Some(kind)) => {
1618
11
                    return cut_error!(
1619
                        format!("array size should be `usize`, found `{kind}`"),
1620
                        nb_span,
1621
                    );
1622
                }
1623
36
                Num::Float(nb, _) => {
1624
36
                    return cut_error!(
1625
                        format!("expected a number after `;`, found a float (`{nb}`)"),
1626
                        nb_span,
1627
                    );
1628
                }
1629
            }
1630
5.37k
        }
1631
5.64k
        if ws(']').parse_next(i).is_err() {
1632
74
            return cut_error!("missing `]` to close the array", start);
1633
5.57k
        }
1634
5.57k
        Ok(TyGenericsKind::Array {
1635
5.57k
            ty: Box::new(ty),
1636
5.57k
            nb_elems,
1637
5.57k
        })
1638
2.40M
    }
1639
}
1640
1641
2.02M
pub(crate) fn call_generics<'a: 'l, 'l>(
1642
2.02M
    i: &mut InputStream<'a, 'l>,
1643
2.02M
) -> ParseResult<'a, WithSpan<Vec<WithSpan<TyGenerics<'a>>>>> {
1644
2.02M
    preceded(ws("::"), cut_err(TyGenerics::args)).parse_next(i)
1645
2.02M
}
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.2k
        let checkpoint = i.checkpoint();
1657
84.2k
        i.input.reset_to_start();
1658
84.2k
        if take::<_, _, ()>(err_ctx.span.start).parse_next(i).is_ok()
1659
82.6k
            && let Err(better_err) = opt(deny_any_rust_token).parse_next(i)
1660
58.3k
            && let ErrMode::Backtrack(better_ctx) | ErrMode::Cut(better_ctx) = better_err
1661
58.3k
            && better_ctx.message.is_some()
1662
58.3k
        {
1663
58.3k
            *err_ctx = better_ctx;
1664
58.3k
        }
1665
84.2k
        i.reset(&checkpoint);
1666
31.1k
    }
1667
115k
}