1use nom::{
2 branch::alt,
3 bytes::complete::{tag, take_while1},
4 character::complete::char,
5 character::complete::{alpha1, alphanumeric1, multispace0, multispace1},
6 combinator::{eof, fail, map, not, opt, recognize, value},
7 error::{ContextError, ParseError},
8 multi::{many0, separated_list0},
9 sequence::{delimited, pair, preceded},
10 IResult,
11};
12
13use crate::query::*;
14
15type Symbol = String;
16
17pub fn parse_query(i: &str) -> IResult<&str, Query> {
18 parse_function_query(i)
19}
20
21fn parse_symbol<'a, E>(i: &'a str) -> IResult<&'a str, Symbol, E>
22where
23 E: ParseError<&'a str> + ContextError<&'a str>,
24{
25 map(
26 recognize(pair(
27 alt((tag("_"), alpha1)),
28 many0(alt((tag("_"), alphanumeric1))),
29 )),
30 |symbol: &str| symbol.to_string(),
31 )(i)
32}
33
34fn parse_function_query<'a, E>(i: &'a str) -> IResult<&'a str, Query, E>
35where
36 E: ParseError<&'a str> + ContextError<&'a str>,
37{
38 let (i, qualifiers) = opt(preceded(
39 multispace0,
40 many0(preceded(
41 multispace0,
42 alt((
43 tag("pub"),
44 tag("async"),
45 tag("unsafe"),
46 tag("extern"),
47 tag("const"),
48 tag("fn"),
49 )),
50 )),
51 ))(i)?;
52
53 let qualifiers = qualifiers
54 .unwrap_or_default()
55 .into_iter()
56 .filter_map(|q| match q {
57 "async" => Some(Qualifier::Async),
58 "const" => Some(Qualifier::Const),
59 "unsafe" => Some(Qualifier::Unsafe),
60 _ => None,
61 })
62 .collect::<HashSet<_>>();
63
64 let (i, name) = opt(preceded(multispace1, parse_symbol))(i)?;
65 let (i, mut decl) = opt(preceded(multispace0, parse_function))(i)?;
66
67 decl.as_mut().map(|d| d.qualifiers = qualifiers);
68
69 let query = Query {
70 name,
71 kind: decl.map(QueryKind::FunctionQuery),
72 };
73 Ok((i, query))
74}
75
76fn parse_function<'a, E>(i: &'a str) -> IResult<&'a str, Function, E>
77where
78 E: ParseError<&'a str> + ContextError<&'a str>,
79{
80 let (i, decl) = parse_function_decl(i)?;
81
82 let function = Function {
83 decl,
84 qualifiers: HashSet::new(),
85 };
86 Ok((i, function))
87}
88
89fn parse_function_decl<'a, E>(i: &'a str) -> IResult<&'a str, FnDecl, E>
90where
91 E: ParseError<&'a str> + ContextError<&'a str>,
92{
93 let (i, inputs) = delimited(
94 char('('),
95 alt((
96 value(None, tag("..")),
97 opt(parse_arguments),
98 value(Some(Vec::new()), not(eof)),
99 )),
100 char(')'),
101 )(i)?;
102 let (i, output) = opt(parse_output)(i)?;
103
104 let decl = FnDecl { inputs, output };
105 Ok((i, decl))
106}
107
108fn parse_arguments<'a, E>(i: &'a str) -> IResult<&'a str, Vec<Argument>, E>
109where
110 E: ParseError<&'a str> + ContextError<&'a str>,
111{
112 separated_list0(
113 char(','),
114 preceded(
115 multispace0,
116 alt((
117 parse_argument,
118 value(
119 Argument {
120 ty: None,
121 name: None,
122 },
123 char('_'),
124 ),
125 map(parse_type, |ty| Argument {
126 ty: Some(ty),
127 name: None,
128 }),
129 )),
130 ),
131 )(i)
132}
133
134fn parse_argument<'a, E>(i: &'a str) -> IResult<&'a str, Argument, E>
135where
136 E: ParseError<&'a str> + ContextError<&'a str>,
137{
138 let (i, name) = alt((value(None, char('_')), opt(parse_symbol)))(i)?;
139 let (i, _) = char(':')(i)?;
140 let (i, _) = multispace0(i)?;
141 let (i, ty) = alt((value(None, char('_')), opt(parse_type)))(i)?;
142
143 let arg = Argument { ty, name };
144 Ok((i, arg))
145}
146
147fn parse_output<'a, E>(i: &'a str) -> IResult<&'a str, FnRetTy, E>
148where
149 E: ParseError<&'a str> + ContextError<&'a str>,
150{
151 preceded(
152 multispace0,
153 alt((
154 value(
155 FnRetTy::DefaultReturn,
156 preceded(preceded(tag("->"), multispace0), tag("()")),
157 ),
158 map(preceded(tag("->"), parse_type), FnRetTy::Return),
159 value(FnRetTy::DefaultReturn, eof),
160 )),
161 )(i)
162}
163
164fn parse_type<'a, E>(i: &'a str) -> IResult<&'a str, Type, E>
165where
166 E: ParseError<&'a str> + ContextError<&'a str>,
167{
168 preceded(
169 multispace0,
170 alt((
171 map(parse_primitive_type, Type::Primitive),
172 parse_generic_type,
173 parse_unresolved_path,
174 parse_tuple,
175 parse_slice,
176 value(Type::Never, char('!')),
177 parse_raw_pointer,
178 parse_borrowed_ref,
179 )),
180 )(i)
181}
182
183fn parse_tuple<'a, E>(i: &'a str) -> IResult<&'a str, Type, E>
184where
185 E: ParseError<&'a str> + ContextError<&'a str>,
186{
187 map(
188 delimited(
189 char('('),
190 separated_list0(
191 char(','),
192 preceded(
193 multispace0,
194 alt((value(None, tag("_")), map(parse_type, Some))),
195 ),
196 ),
197 char(')'),
198 ),
199 Type::Tuple,
200 )(i)
201}
202
203fn parse_slice<'a, E>(i: &'a str) -> IResult<&'a str, Type, E>
204where
205 E: ParseError<&'a str> + ContextError<&'a str>,
206{
207 map(
208 delimited(
209 char('['),
210 alt((value(None, tag("_")), map(parse_type, Some))),
211 char(']'),
212 ),
213 |ty| Type::Slice(ty.map(Box::new)),
214 )(i)
215}
216
217fn parse_raw_pointer<'a, E>(i: &'a str) -> IResult<&'a str, Type, E>
218where
219 E: ParseError<&'a str> + ContextError<&'a str>,
220{
221 let (i, mutable) = alt((value(true, tag("*mut")), value(false, tag("*const"))))(i)?;
222 let (i, type_) = parse_type(i)?;
223
224 Ok((
225 i,
226 Type::RawPointer {
227 mutable,
228 type_: Box::new(type_),
229 },
230 ))
231}
232
233fn parse_borrowed_ref<'a, E>(i: &'a str) -> IResult<&'a str, Type, E>
234where
235 E: ParseError<&'a str> + ContextError<&'a str>,
236{
237 let (i, mutable) = alt((value(true, tag("&mut")), value(false, tag("&"))))(i)?;
238 let (i, type_) = parse_type(i)?;
239
240 Ok((
241 i,
242 Type::BorrowedRef {
243 mutable,
244 type_: Box::new(type_),
245 },
246 ))
247}
248
249fn parse_unresolved_path<'a, E>(i: &'a str) -> IResult<&'a str, Type, E>
250where
251 E: ParseError<&'a str> + ContextError<&'a str>,
252{
253 let (i, name) = parse_symbol(i)?;
254 let (i, args) = opt(parse_generic_args)(i)?;
255
256 Ok((
257 i,
258 Type::UnresolvedPath {
259 name,
260 args: args.map(Box::new),
261 },
262 ))
263}
264
265fn parse_generic_args<'a, E>(i: &'a str) -> IResult<&'a str, GenericArgs, E>
266where
267 E: ParseError<&'a str> + ContextError<&'a str>,
268{
269 map(
270 delimited(
271 char('<'),
272 separated_list0(
273 char(','),
274 preceded(
275 multispace0,
276 alt((
277 value(None, tag("_")),
278 opt(map(parse_type, GenericArg::Type)),
279 )),
280 ),
281 ),
282 char('>'),
283 ),
284 |args| GenericArgs::AngleBracketed { args },
285 )(i)
286}
287
288fn parse_generic_type<'a, E>(i: &'a str) -> IResult<&'a str, Type, E>
289where
290 E: ParseError<&'a str> + ContextError<&'a str>,
291{
292 let (i, gen) = map(take_while1(|c: char| c.is_ascii_uppercase()), |s: &str| {
293 Type::Generic(s.to_owned())
294 })(i)?;
295
296 if i.chars().next().is_some_and(|c| c.is_ascii_lowercase()) {
297 fail(i)
298 } else {
299 Ok((i, gen))
300 }
301}
302
303fn parse_primitive_type<'a, E>(i: &'a str) -> IResult<&'a str, PrimitiveType, E>
304where
305 E: ParseError<&'a str> + ContextError<&'a str>,
306{
307 use PrimitiveType::*;
308 alt((
309 value(Isize, tag("isize")),
310 value(I8, tag("i8")),
311 value(I16, tag("i16")),
312 value(I32, tag("i32")),
313 value(I64, tag("i64")),
314 value(I128, tag("i128")),
315 value(Usize, tag("usize")),
316 value(U8, tag("u8")),
317 value(U16, tag("u16")),
318 value(U32, tag("u32")),
319 value(U64, tag("u64")),
320 value(U128, tag("u128")),
321 value(F32, tag("f32")),
322 value(F64, tag("f64")),
323 value(Char, tag("char")),
324 value(Bool, tag("bool")),
325 value(Str, tag("str")),
326 ))(i)
327}
328
329#[cfg(test)]
330mod tests {
331 use super::*;
332
333 #[test]
334 fn test_parse_complex_type1() {
335 let input = "&mut [Option<i32>]";
336 let (_, ty) = parse_type::<nom::error::VerboseError<&str>>(input).unwrap();
337 assert_eq!(
338 ty,
339 Type::BorrowedRef {
340 mutable: true,
341 type_: Box::new(Type::Slice(Some(Box::new(Type::UnresolvedPath {
342 name: "Option".to_string(),
343 args: Some(Box::new(GenericArgs::AngleBracketed {
344 args: vec![Some(GenericArg::Type(Type::Primitive(PrimitiveType::I32)))]
345 }))
346 }))))
347 }
348 );
349 }
350
351 #[test]
352 fn test_parse_complex_type2() {
353 let input = "*const (i32, &str, T)";
354 let (_, ty) = parse_type::<nom::error::VerboseError<&str>>(input).unwrap();
355 assert_eq!(
356 ty,
357 Type::RawPointer {
358 mutable: false,
359 type_: Box::new(Type::Tuple(vec![
360 Some(Type::Primitive(PrimitiveType::I32)),
361 Some(Type::BorrowedRef {
362 mutable: false,
363 type_: Box::new(Type::Primitive(PrimitiveType::Str)),
364 }),
365 Some(Type::Generic("T".to_string())),
366 ]))
367 }
368 );
369 }
370
371 #[test]
372 fn test_parse_complex_type3() {
373 let input = "Result<_, E>";
374 let (_, ty) = parse_type::<nom::error::VerboseError<&str>>(input).unwrap();
375 assert_eq!(
376 ty,
377 Type::UnresolvedPath {
378 name: "Result".to_string(),
379 args: Some(Box::new(GenericArgs::AngleBracketed {
380 args: vec![None, Some(GenericArg::Type(Type::Generic("E".to_string()))),]
381 }))
382 }
383 );
384 }
385
386 #[test]
387 fn test_parse_function_decl() {
388 let input = "(x: i32, y: &str) -> bool";
389 let (_, decl) = parse_function_decl::<nom::error::VerboseError<&str>>(input).unwrap();
390 assert_eq!(
391 decl,
392 FnDecl {
393 inputs: Some(vec![
394 Argument {
395 name: Some("x".to_string()),
396 ty: Some(Type::Primitive(PrimitiveType::I32)),
397 },
398 Argument {
399 name: Some("y".to_string()),
400 ty: Some(Type::BorrowedRef {
401 mutable: false,
402 type_: Box::new(Type::Primitive(PrimitiveType::Str)),
403 }),
404 },
405 ]),
406 output: Some(FnRetTy::Return(Type::Primitive(PrimitiveType::Bool))),
407 }
408 );
409 }
410
411 #[test]
412 fn test_parse_function_decl_with_underscore() {
413 let input = "(_, y: &str) -> ()";
414 let (_, decl) = parse_function_decl::<nom::error::VerboseError<&str>>(input).unwrap();
415 assert_eq!(
416 decl,
417 FnDecl {
418 inputs: Some(vec![
419 Argument {
420 name: None,
421 ty: None,
422 },
423 Argument {
424 name: Some("y".to_string()),
425 ty: Some(Type::BorrowedRef {
426 mutable: false,
427 type_: Box::new(Type::Primitive(PrimitiveType::Str)),
428 }),
429 },
430 ]),
431 output: Some(FnRetTy::DefaultReturn),
432 }
433 );
434 }
435
436 #[test]
437 fn test_parse_complex_output_type() {
438 let input = "(x: i32) -> (i32, &str, T)";
439 let (_, decl) = parse_function_decl::<nom::error::VerboseError<&str>>(input).unwrap();
440 assert_eq!(
441 decl,
442 FnDecl {
443 inputs: Some(vec![Argument {
444 name: Some("x".to_string()),
445 ty: Some(Type::Primitive(PrimitiveType::I32)),
446 },]),
447 output: Some(FnRetTy::Return(Type::Tuple(vec![
448 Some(Type::Primitive(PrimitiveType::I32)),
449 Some(Type::BorrowedRef {
450 mutable: false,
451 type_: Box::new(Type::Primitive(PrimitiveType::Str)),
452 }),
453 Some(Type::Generic("T".to_string())),
454 ]))),
455 }
456 );
457 }
458
459 #[test]
460 fn test_parse_complex_output_type2() {
461 let input = "fn abc() -> Result<Vec<i32>>";
462 let (_, decl) = parse_query(input).unwrap();
463 assert_eq!(
464 decl,
465 Query {
466 name: Some("abc".to_string()),
467 kind: Some(QueryKind::FunctionQuery(Function {
468 decl: FnDecl {
469 inputs: Some(vec![]),
470 output: Some(FnRetTy::Return(Type::UnresolvedPath {
471 name: "Result".to_string(),
472 args: Some(Box::new(GenericArgs::AngleBracketed {
473 args: vec![Some(GenericArg::Type(Type::UnresolvedPath {
474 name: "Vec".to_string(),
475 args: Some(Box::new(GenericArgs::AngleBracketed {
476 args: vec![Some(GenericArg::Type(Type::Primitive(
477 PrimitiveType::I32
478 )))]
479 }))
480 }))]
481 }))
482 })),
483 },
484 qualifiers: HashSet::new(),
485 })),
486 }
487 );
488 }
489
490 #[test]
491 fn test_parse_qualified_function() {
492 let input = "pub async fn foo(bar: i32, _: &str) -> bool";
493 let (_, query) = parse_query(input).unwrap();
494 assert_eq!(
495 query,
496 Query {
497 name: Some("foo".to_string()),
498 kind: Some(QueryKind::FunctionQuery(Function {
499 decl: FnDecl {
500 inputs: Some(vec![
501 Argument {
502 name: Some("bar".to_string()),
503 ty: Some(Type::Primitive(PrimitiveType::I32)),
504 },
505 Argument {
506 name: None,
507 ty: Some(Type::BorrowedRef {
508 mutable: false,
509 type_: Box::new(Type::Primitive(PrimitiveType::Str)),
510 }),
511 },
512 ]),
513 output: Some(FnRetTy::Return(Type::Primitive(PrimitiveType::Bool))),
514 },
515 qualifiers: HashSet::from_iter(vec![Qualifier::Async]),
516 })),
517 }
518 );
519 }
520}