1use nom::{
2 IResult,
3 character::complete::*,
4 bytes::complete::*,
5};
6use nom::branch::*;
7use nom::combinator::*;
8use nom::sequence::*;
9use nom::multi::*;
10use nom::AsChar;
11
12use crate::{seimcolon_comment, Comment, comment};
13
14use super::{
15 ArgOrComment,
16};
17
18type ArgOrCommentResult<'r> = IResult<&'r str, ArgOrComment<'r>>;
19pub type ManyArgOrCommentsResult<'r> = IResult<&'r str, Option<Vec<ArgOrComment<'r>>>>;
20
21fn string_arg<'r>(input: &'r str) -> ArgOrCommentResult<'r> {
26 map(
27 preceded(
28 space1,
29 escaped(
30 is_not("\n\r;("),
31 '\\',
32 one_of("(); \t\n\\"),
33 ),
34 ),
35 ArgOrComment::TextArg
36 )(input)
37}
38
39#[inline(always)]
40fn key_value_arg<'r>(input: &'r str) -> ArgOrCommentResult<'r> {
41 map(
42 pair(
43 satisfy(AsChar::is_alpha),
44 opt(map_res(
45 is_not(" \t\n\r;("),
46 |s: &str| s.parse(),
47 )),
48 ),
49 ArgOrComment::KeyValue,
50 )(input)
51}
52
53fn combine_args_and_comments<'r>(
54 parser_outputs: (Vec<ArgOrComment<'r>>, Option<&'r str>),
55) -> Option<Vec<ArgOrComment<'r>>> {
56 let (mut args_or_comments, final_comment) = parser_outputs;
57
58 if let Some(final_comment) = final_comment {
59 args_or_comments.push(
60 ArgOrComment::Comment(Comment(final_comment)),
61 );
62 }
63
64 if args_or_comments.is_empty() {
65 None
66 } else {
67 Some(args_or_comments)
68 }
69}
70
71pub fn parse_args<'r>(
73 string_arg_mcode: bool,
74 input: &'r str,
75) -> ManyArgOrCommentsResult<'r> {
76 if string_arg_mcode {
77 map(
79 tuple((
80 opt(map(comment, |c| ArgOrComment::Comment(c))),
81 opt(string_arg),
82 opt(map(comment, |c| ArgOrComment::Comment(c))),
83 ),
84 ),
85 |(c1, arg, c2)| Some(vec![c1, arg, c2].into_iter().flatten().collect()),
86 )(input)
87 } else {
88 map(
89 tuple((
90 many0(
91 alt((
92 preceded(
94 space1,
95 key_value_arg,
96 ),
97 map(comment, |c| ArgOrComment::Comment(c)),
98 )),
99 ),
100 opt(seimcolon_comment),
101 )),
102 combine_args_and_comments,
103 )(input)
104 }
105}
106
107
108pub fn parse_kv_arg<'r>(
110 input: &'r str,
111) -> ArgOrCommentResult<'r> {
112 alt((
120 preceded(
122 space1,
123 key_value_arg,
124 ),
125 map(comment, ArgOrComment::Comment),
126 ))(input)
127}