1use nom::bytes::complete::{is_not, tag};
2use nom::{Parser, character::complete::multispace0, sequence::delimited};
3
4pub fn ws<'a, Output, Function>(
7 inner: Function,
8) -> impl Parser<&'a str, Output = Output, Error = nom::error::Error<&'a str>>
9where
10 Function: Parser<&'a str, Output = Output, Error = nom::error::Error<&'a str>>,
11{
12 delimited(multispace0, inner, multispace0)
13}
14
15#[macro_export]
31macro_rules! ws_separated {
32 (($($parser:expr),+)) => {
33 ($(ws($parser)),+)
34 };
35}
36
37#[macro_export]
58macro_rules! parse_section {
59 ($section:expr, $parser:expr) => {
60 delimited(
61 ws(tag(format!(".{}", $section).as_str())),
62 $parser,
63 ws(tag(format!(".END_{}", $section).as_str())),
64 )
65 };
66}
67
68pub fn quote_string(input: &str) -> nom::IResult<&str, &str> {
81 delimited(tag("\""), is_not("\""), tag("\"")).parse(input)
82}
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use crate::primitives::ws;
87 use nom::Parser;
88 use nom::bytes::complete::tag;
89 use nom::character::complete::u32;
90 use nom::number::complete::float;
91
92 #[test]
93 fn test_ws() {
94 let input = "\r0 \n\n\n100.0 200.0 \n45.0 ";
95 let (remaining, (label, x, y, angle)) = (ws(u32), ws(float), ws(float), ws(float))
96 .parse(input)
97 .unwrap();
98 assert_eq!(remaining, "");
99 assert_eq!(label, 0);
100 assert_eq!(x, 100.0);
101 assert_eq!(y, 200.0);
102 assert_eq!(angle, 45.0);
103 }
104
105 #[test]
106 fn test_ws_separated() {
107 let input = "0 100.0 200.0 45.0";
108 let (remaining, (label, x, y, angle)) = ws_separated!((u32, float, float, float))
109 .parse(input)
110 .unwrap();
111 assert_eq!(remaining, "");
112 assert_eq!(label, 0);
113 assert_eq!(x, 100.0);
114 assert_eq!(y, 200.0);
115 assert_eq!(angle, 45.0);
116 }
117
118 #[test]
119 fn test_section() {
120 let input = ".SECTION\n123 456\n.END_SECTION";
121 let (remaining, ints) = parse_section!("SECTION", (ws(u32), ws(u32)))
122 .parse(input)
123 .unwrap();
124 assert_eq!(remaining, "");
125 assert_eq!(ints, (123, 456));
126 }
127
128 #[test]
129 fn test_quote_string() {
130 let input = "\"Hello, World!\"";
131 let (remaining, quoted_str) = quote_string(input).unwrap();
132 assert_eq!(remaining, "");
133 assert_eq!(quoted_str, "Hello, World!");
134 }
135}