ptx_parser/parser/
mod.rs

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}