1use std::borrow::Cow;
2use std::collections::HashSet;
3use std::str;
4
5use nom::branch::alt;
6use nom::bytes::complete::{tag, take_till};
7use nom::character::complete::char;
8use nom::combinator::{cut, map, not, opt, peek, recognize};
9use nom::error::ErrorKind;
10use nom::error_position;
11use nom::multi::{fold_many0, many0, separated_list0};
12use nom::sequence::{pair, preceded, terminated, tuple};
13
14use super::{
15 char_lit, identifier, not_ws, num_lit, path_or_identifier, str_lit, ws, Level, PathOrIdentifier,
16};
17use crate::{ErrorContext, ParseResult};
18
19macro_rules! expr_prec_layer {
20 ( $name:ident, $inner:ident, $op:expr ) => {
21 fn $name(i: &'a str, level: Level) -> ParseResult<'a, Self> {
22 let (_, level) = level.nest(i)?;
23 let (i, left) = Self::$inner(i, level)?;
24 let (i, right) = many0(pair(
25 ws(tag($op)),
26 |i| Self::$inner(i, level),
27 ))(i)?;
28 Ok((
29 i,
30 right.into_iter().fold(left, |left, (op, right)| {
31 Self::BinOp(op, Box::new(left), Box::new(right))
32 }),
33 ))
34 }
35 };
36 ( $name:ident, $inner:ident, $( $op:expr ),+ ) => {
37 fn $name(i: &'a str, level: Level) -> ParseResult<'a, Self> {
38 let (_, level) = level.nest(i)?;
39 let (i, left) = Self::$inner(i, level)?;
40 let (i, right) = many0(pair(
41 ws(alt(($( tag($op) ),+,))),
42 |i| Self::$inner(i, level),
43 ))(i)?;
44 Ok((
45 i,
46 right.into_iter().fold(left, |left, (op, right)| {
47 Self::BinOp(op, Box::new(left), Box::new(right))
48 }),
49 ))
50 }
51 }
52}
53
54#[derive(Clone, Debug, PartialEq)]
55pub enum Expr<'a> {
56 BoolLit(&'a str),
57 NumLit(&'a str),
58 StrLit(&'a str),
59 CharLit(&'a str),
60 Var(&'a str),
61 Path(Vec<&'a str>),
62 Array(Vec<Expr<'a>>),
63 Attr(Box<Expr<'a>>, &'a str),
64 Index(Box<Expr<'a>>, Box<Expr<'a>>),
65 Filter(&'a str, Vec<Expr<'a>>),
66 NamedArgument(&'a str, Box<Expr<'a>>),
67 Unary(&'a str, Box<Expr<'a>>),
68 BinOp(&'a str, Box<Expr<'a>>, Box<Expr<'a>>),
69 Range(&'a str, Option<Box<Expr<'a>>>, Option<Box<Expr<'a>>>),
70 Group(Box<Expr<'a>>),
71 Tuple(Vec<Expr<'a>>),
72 Call(Box<Expr<'a>>, Vec<Expr<'a>>),
73 RustMacro(Vec<&'a str>, &'a str),
74 Try(Box<Expr<'a>>),
75}
76
77impl<'a> Expr<'a> {
78 pub(super) fn arguments(
79 i: &'a str,
80 level: Level,
81 is_template_macro: bool,
82 ) -> ParseResult<'a, Vec<Self>> {
83 let (_, level) = level.nest(i)?;
84 let mut named_arguments = HashSet::new();
85 let start = i;
86
87 preceded(
88 ws(char('(')),
89 cut(terminated(
90 separated_list0(
91 char(','),
92 ws(move |i| {
93 // Needed to prevent borrowing it twice between this closure and the one
94 // calling `Self::named_arguments`.
95 let named_arguments = &mut named_arguments;
96 let has_named_arguments = !named_arguments.is_empty();
97
98 let (i, expr) = alt((
99 move |i| {
100 Self::named_argument(
101 i,
102 level,
103 named_arguments,
104 start,
105 is_template_macro,
106 )
107 },
108 move |i| Self::parse(i, level),
109 ))(i)?;
110 if has_named_arguments && !matches!(expr, Self::NamedArgument(_, _)) {
111 Err(nom::Err::Failure(ErrorContext {
112 input: start,
113 message: Some(Cow::Borrowed(
114 "named arguments must always be passed last",
115 )),
116 }))
117 } else {
118 Ok((i, expr))
119 }
120 }),
121 ),
122 tuple((opt(ws(char(','))), char(')'))),
123 )),
124 )(i)
125 }
126
127 fn named_argument(
128 i: &'a str,
129 level: Level,
130 named_arguments: &mut HashSet<&'a str>,
131 start: &'a str,
132 is_template_macro: bool,
133 ) -> ParseResult<'a, Self> {
134 if !is_template_macro {
135 // If this is not a template macro, we don't want to parse named arguments so
136 // we instead return an error which will allow to continue the parsing.
137 return Err(nom::Err::Error(error_position!(i, ErrorKind::Alt)));
138 }
139
140 let (_, level) = level.nest(i)?;
141 let (i, (argument, _, value)) =
142 tuple((identifier, ws(char('=')), move |i| Self::parse(i, level)))(i)?;
143 if named_arguments.insert(argument) {
144 Ok((i, Self::NamedArgument(argument, Box::new(value))))
145 } else {
146 Err(nom::Err::Failure(ErrorContext {
147 input: start,
148 message: Some(Cow::Owned(format!(
149 "named argument `{argument}` was passed more than once"
150 ))),
151 }))
152 }
153 }
154
155 pub(super) fn parse(i: &'a str, level: Level) -> ParseResult<'a, Self> {
156 let (_, level) = level.nest(i)?;
157 let range_right = move |i| {
158 pair(
159 ws(alt((tag("..="), tag("..")))),
160 opt(move |i| Self::or(i, level)),
161 )(i)
162 };
163 alt((
164 map(range_right, |(op, right)| {
165 Self::Range(op, None, right.map(Box::new))
166 }),
167 map(
168 pair(move |i| Self::or(i, level), opt(range_right)),
169 |(left, right)| match right {
170 Some((op, right)) => Self::Range(op, Some(Box::new(left)), right.map(Box::new)),
171 None => left,
172 },
173 ),
174 ))(i)
175 }
176
177 expr_prec_layer!(or, and, "||");
178 expr_prec_layer!(and, compare, "&&");
179 expr_prec_layer!(compare, bor, "==", "!=", ">=", ">", "<=", "<");
180 expr_prec_layer!(bor, bxor, "|");
181 expr_prec_layer!(bxor, band, "^");
182 expr_prec_layer!(band, shifts, "&");
183 expr_prec_layer!(shifts, addsub, ">>", "<<");
184 expr_prec_layer!(addsub, muldivmod, "+", "-");
185 expr_prec_layer!(muldivmod, filtered, "*", "/", "%");
186
187 fn filtered(i: &'a str, level: Level) -> ParseResult<'a, Self> {
188 let (_, level) = level.nest(i)?;
189 #[allow(clippy::type_complexity)]
190 fn filter(i: &str, level: Level) -> ParseResult<'_, (&str, Option<Vec<Expr<'_>>>)> {
191 let (i, (_, fname, args)) = tuple((
192 char('|'),
193 ws(identifier),
194 opt(|i| Expr::arguments(i, level, false)),
195 ))(i)?;
196 Ok((i, (fname, args)))
197 }
198
199 let (i, (obj, filters)) =
200 tuple((|i| Self::prefix(i, level), many0(|i| filter(i, level))))(i)?;
201
202 let mut res = obj;
203 for (fname, args) in filters {
204 res = Self::Filter(fname, {
205 let mut args = match args {
206 Some(inner) => inner,
207 None => Vec::new(),
208 };
209 args.insert(0, res);
210 args
211 });
212 }
213
214 Ok((i, res))
215 }
216
217 fn prefix(i: &'a str, mut level: Level) -> ParseResult<'a, Self> {
218 let (_, nested) = level.nest(i)?;
219 let (i, (ops, mut expr)) = pair(many0(ws(alt((tag("!"), tag("-"))))), |i| {
220 Suffix::parse(i, nested)
221 })(i)?;
222
223 for op in ops.iter().rev() {
224 // This is a rare place where we create recursion in the parsed AST
225 // without recursing the parser call stack. However, this can lead
226 // to stack overflows in drop glue when the AST is very deep.
227 level = level.nest(i)?.1;
228 expr = Self::Unary(op, Box::new(expr));
229 }
230
231 Ok((i, expr))
232 }
233
234 fn single(i: &'a str, level: Level) -> ParseResult<'a, Self> {
235 let (_, level) = level.nest(i)?;
236 alt((
237 Self::num,
238 Self::str,
239 Self::char,
240 Self::path_var_bool,
241 move |i| Self::array(i, level),
242 move |i| Self::group(i, level),
243 ))(i)
244 }
245
246 fn group(i: &'a str, level: Level) -> ParseResult<'a, Self> {
247 let (_, level) = level.nest(i)?;
248 let (i, expr) = preceded(ws(char('(')), opt(|i| Self::parse(i, level)))(i)?;
249 let expr = match expr {
250 Some(expr) => expr,
251 None => {
252 let (i, _) = char(')')(i)?;
253 return Ok((i, Self::Tuple(vec![])));
254 }
255 };
256
257 let (i, comma) = ws(opt(peek(char(','))))(i)?;
258 if comma.is_none() {
259 let (i, _) = char(')')(i)?;
260 return Ok((i, Self::Group(Box::new(expr))));
261 }
262
263 let mut exprs = vec![expr];
264 let (i, _) = fold_many0(
265 preceded(char(','), ws(|i| Self::parse(i, level))),
266 || (),
267 |_, expr| {
268 exprs.push(expr);
269 },
270 )(i)?;
271 let (i, _) = pair(ws(opt(char(','))), char(')'))(i)?;
272 Ok((i, Self::Tuple(exprs)))
273 }
274
275 fn array(i: &'a str, level: Level) -> ParseResult<'a, Self> {
276 let (_, level) = level.nest(i)?;
277 preceded(
278 ws(char('[')),
279 cut(terminated(
280 map(
281 separated_list0(char(','), ws(move |i| Self::parse(i, level))),
282 Self::Array,
283 ),
284 char(']'),
285 )),
286 )(i)
287 }
288
289 fn path_var_bool(i: &'a str) -> ParseResult<'a, Self> {
290 map(path_or_identifier, |v| match v {
291 PathOrIdentifier::Path(v) => Self::Path(v),
292 PathOrIdentifier::Identifier(v @ "true") => Self::BoolLit(v),
293 PathOrIdentifier::Identifier(v @ "false") => Self::BoolLit(v),
294 PathOrIdentifier::Identifier(v) => Self::Var(v),
295 })(i)
296 }
297
298 fn str(i: &'a str) -> ParseResult<'a, Self> {
299 map(str_lit, Self::StrLit)(i)
300 }
301
302 fn num(i: &'a str) -> ParseResult<'a, Self> {
303 map(num_lit, Self::NumLit)(i)
304 }
305
306 fn char(i: &'a str) -> ParseResult<'a, Self> {
307 map(char_lit, Self::CharLit)(i)
308 }
309}
310
311enum Suffix<'a> {
312 Attr(&'a str),
313 Index(Expr<'a>),
314 Call(Vec<Expr<'a>>),
315 // The value is the arguments of the macro call.
316 MacroCall(&'a str),
317 Try,
318}
319
320impl<'a> Suffix<'a> {
321 fn parse(i: &'a str, level: Level) -> ParseResult<'a, Expr<'a>> {
322 let (_, level) = level.nest(i)?;
323 let (mut i, mut expr) = Expr::single(i, level)?;
324 loop {
325 let (j, suffix) = opt(alt((
326 Self::attr,
327 |i| Self::index(i, level),
328 |i| Self::call(i, level),
329 Self::r#try,
330 Self::r#macro,
331 )))(i)?;
332
333 match suffix {
334 Some(Self::Attr(attr)) => expr = Expr::Attr(expr.into(), attr),
335 Some(Self::Index(index)) => expr = Expr::Index(expr.into(), index.into()),
336 Some(Self::Call(args)) => expr = Expr::Call(expr.into(), args),
337 Some(Self::Try) => expr = Expr::Try(expr.into()),
338 Some(Self::MacroCall(args)) => match expr {
339 Expr::Path(path) => expr = Expr::RustMacro(path, args),
340 Expr::Var(name) => expr = Expr::RustMacro(vec![name], args),
341 _ => return Err(nom::Err::Failure(error_position!(i, ErrorKind::Tag))),
342 },
343 None => break,
344 }
345
346 i = j;
347 }
348 Ok((i, expr))
349 }
350
351 fn r#macro(i: &'a str) -> ParseResult<'a, Self> {
352 fn nested_parenthesis(input: &str) -> ParseResult<'_, ()> {
353 let mut nested = 0;
354 let mut last = 0;
355 let mut in_str = false;
356 let mut escaped = false;
357
358 for (i, c) in input.char_indices() {
359 if !(c == '(' || c == ')') || !in_str {
360 match c {
361 '(' => nested += 1,
362 ')' => {
363 if nested == 0 {
364 last = i;
365 break;
366 }
367 nested -= 1;
368 }
369 '"' => {
370 if in_str {
371 if !escaped {
372 in_str = false;
373 }
374 } else {
375 in_str = true;
376 }
377 }
378 '\\' => {
379 escaped = !escaped;
380 }
381 _ => (),
382 }
383 }
384
385 if escaped && c != '\\' {
386 escaped = false;
387 }
388 }
389
390 if nested == 0 {
391 Ok((&input[last..], ()))
392 } else {
393 Err(nom::Err::Error(error_position!(
394 input,
395 ErrorKind::SeparatedNonEmptyList
396 )))
397 }
398 }
399
400 preceded(
401 pair(ws(char('!')), char('(')),
402 cut(terminated(
403 map(recognize(nested_parenthesis), Self::MacroCall),
404 char(')'),
405 )),
406 )(i)
407 }
408
409 fn attr(i: &'a str) -> ParseResult<'a, Self> {
410 map(
411 preceded(
412 ws(pair(char('.'), not(char('.')))),
413 cut(alt((num_lit, identifier))),
414 ),
415 Self::Attr,
416 )(i)
417 }
418
419 fn index(i: &'a str, level: Level) -> ParseResult<'a, Self> {
420 let (_, level) = level.nest(i)?;
421 map(
422 preceded(
423 ws(char('[')),
424 cut(terminated(ws(move |i| Expr::parse(i, level)), char(']'))),
425 ),
426 Self::Index,
427 )(i)
428 }
429
430 fn call(i: &'a str, level: Level) -> ParseResult<'a, Self> {
431 let (_, level) = level.nest(i)?;
432 map(move |i| Expr::arguments(i, level, false), Self::Call)(i)
433 }
434
435 fn r#try(i: &'a str) -> ParseResult<'a, Self> {
436 map(preceded(take_till(not_ws), char('?')), |_| Self::Try)(i)
437 }
438}
439