/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 | } |