1use nom::{bytes::complete::take_while1, character::complete::char, sequence::delimited, IResult};
2
3pub(crate) mod body;
4pub(crate) mod comment;
5pub(crate) mod function;
6pub(crate) mod global;
7pub(crate) mod preamble;
8pub(crate) mod ptx_file;
9
10#[derive(Debug, PartialEq)]
11pub(crate) struct PtxFile<'a> {
12 preamble: Preamble<'a>,
13 body: Option<&'a str>,
14}
15
16#[derive(Debug, PartialEq)]
17pub(crate) enum Comment<'a> {
18 Line(&'a str),
19 Block(&'a str),
20}
21
22#[derive(Debug, PartialEq)]
23pub(crate) struct Preamble<'a> {
24 version: preamble::Version<'a>,
25 target: preamble::Target<'a>,
26 address_size: preamble::AddressSize<'a>,
27}
28
29#[derive(Debug, PartialEq)]
30pub(crate) struct Function<'a> {
31 signature: function::FunctionSignature<'a>,
32 body: Option<body::FunctionBody<'a>>,
33}
34
35#[derive(Debug, PartialEq)]
36pub(crate) struct Global<'a> {
37 raw_string: &'a str,
38}
39
40fn is_special(c: char) -> bool {
41 ['.', '/', '(', ')', '[', ']', '{', '}', ',', ';', ':', '%']
42 .contains(&c)
43}
44
45pub(crate) fn parse_name(input: &str) -> IResult<&str, &str> {
46 take_while1(|c: char| !c.is_whitespace() && !is_special(c))(input)
47}
48
49pub(crate) fn parse_parenthesized_naive(input: &str) -> IResult<&str, &str> {
50 delimited(
51 char('('),
52 take_while1(|c: char| c != ')'),
53 char(')')
54 )(input)
55}
56
57pub(crate) fn _parse_braced_naive(input: &str) -> IResult<&str, &str> {
58 delimited(
59 char('{'),
60 take_while1(|c: char| c != '}'),
61 char('}')
62 )(input)
63}
64
65pub(crate) fn parse_braced_balanced(input: &str) -> IResult<&str, &str> {
66 let mut chars = input.chars().enumerate();
67 let (mut depth, mut end) = match chars.next() {
68 Some((_, '{')) => (1, None),
69 _ => return Err(nom::Err::Error(
70 nom::error::Error::new(input, nom::error::ErrorKind::Char)
71 ))
72 };
73
74 for (i, c) in chars {
75 match c {
76 '{' => depth += 1,
77 '}' => {
78 depth -= 1;
79 if depth == 0 {
80 end = Some(i);
81 break;
82 }
83 }
84 _ => (),
85 }
86 }
87 if let Some(end) = end {
88 Ok((&input[end + 1..], &input[1..end]))
89 } else {
90 Err(nom::Err::Error(nom::error::Error::new(
91 input,
92 nom::error::ErrorKind::Eof,
93 )))
94 }
95}
96
97#[cfg(test)]
98mod test_parse_parenthesized {
99
100 use super::parse_parenthesized_naive;
101
102 #[test]
103 fn no_newline() {
104 let input = "(hello)";
105 let expected = Ok(("", "hello"));
106 assert_eq!(parse_parenthesized_naive(input), expected)
107 }
108
109 #[test]
110 fn newline() {
111 let input = "(hello\n)";
112 let expected = Ok(("", "hello\n"));
113 assert_eq!(parse_parenthesized_naive(input), expected)
114 }
115
116 #[test]
117 fn one_left_parenthesis() {
118 let input = "(hello";
119 assert!(parse_parenthesized_naive(input).is_err())
120 }
121
122 #[test]
123 fn two_left_one_right() {
124 let input = "((hello)";
125 assert_eq!(
126 parse_parenthesized_naive(input),
127 Ok(("", "(hello")),
128 )
129 }
130}
131
132#[cfg(test)]
133mod test_parse_braced {
134
135 use super::_parse_braced_naive;
136
137 #[test]
138 fn no_newline() {
139 let input = "{hello}";
140 let expected = Ok(("", "hello"));
141 assert_eq!(_parse_braced_naive(input), expected)
142 }
143
144 #[test]
145 fn newline() {
146 let input = "{hello\n}";
147 let expected = Ok(("", "hello\n"));
148 assert_eq!(_parse_braced_naive(input), expected)
149 }
150
151 #[test]
152 fn one_left_brace() {
153 let input = "{hello";
154 assert!(_parse_braced_naive(input).is_err())
155 }
156
157 #[test]
158 fn two_left_one_right() {
159 let input = "{{hello}";
160 assert_eq!(
161 _parse_braced_naive(input),
162 Ok(("", "{hello")),
163 )
164 }
165
166 #[test]
167 fn mock_function_body() {
168 let input = "{.reg .b32 %r<3>}";
169 let expected = Ok(("", ".reg .b32 %r<3>"));
170 assert_eq!(_parse_braced_naive(input), expected)
171 }
172}
173
174#[cfg(test)]
175mod test_parse_braced_balanced {
176
177 use super::parse_braced_balanced;
178
179 #[test]
180 fn one_pair() {
181 let input = "{hello}";
182 let expected = Ok(("", "hello"));
183 assert_eq!(parse_braced_balanced(input), expected)
184 }
185
186 #[test]
187 fn two_pairs() {
188 let input = "{hello}{world}";
189 let expected = Ok(("{world}", "hello"));
190 assert_eq!(parse_braced_balanced(input), expected)
191 }
192
193 #[test]
194 fn nested_pair() {
195 let input = "{hello{world}}";
196 let expected = Ok(("", "hello{world}"));
197 assert_eq!(parse_braced_balanced(input), expected)
198 }
199
200 #[test]
201 fn imbalanced() {
202 let input = "{hello{world}";
203 assert!(parse_braced_balanced(input).is_err())
204 }
205}