1 | use std::borrow::Cow; |
2 | use std::collections::HashSet; |
3 | use std::str; |
4 | |
5 | use nom::branch::alt; |
6 | use nom::bytes::complete::{tag, take_till}; |
7 | use nom::character::complete::char; |
8 | use nom::combinator::{cut, map, not, opt, peek, recognize}; |
9 | use nom::error::ErrorKind; |
10 | use nom::error_position; |
11 | use nom::multi::{fold_many0, many0, separated_list0}; |
12 | use nom::sequence::{pair, preceded, terminated, tuple}; |
13 | |
14 | use super::{ |
15 | char_lit, identifier, not_ws, num_lit, path_or_identifier, str_lit, ws, Level, PathOrIdentifier, |
16 | }; |
17 | use crate::{ErrorContext, ParseResult}; |
18 | |
19 | macro_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)] |
55 | pub 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 | |
77 | impl<'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 | |
311 | enum 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 | |
320 | impl<'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 | |