use nom::bytes::complete::{is_not, tag};
use nom::{Parser, character::complete::multispace0, sequence::delimited};
pub fn ws<'a, Output, Function>(
inner: Function,
) -> impl Parser<&'a str, Output = Output, Error = nom::error::Error<&'a str>>
where
Function: Parser<&'a str, Output = Output, Error = nom::error::Error<&'a str>>,
{
delimited(multispace0, inner, multispace0)
}
#[macro_export]
macro_rules! ws_separated {
(($($parser:expr),+)) => {
($(ws($parser)),+)
};
}
#[macro_export]
macro_rules! parse_section {
($section:expr, $parser:expr) => {
delimited(
ws(tag(format!(".{}", $section).as_str())),
$parser,
ws(tag(format!(".END_{}", $section).as_str())),
)
};
}
pub fn quote_string(input: &str) -> nom::IResult<&str, &str> {
delimited(tag("\""), is_not("\""), tag("\"")).parse(input)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::primitives::ws;
use nom::Parser;
use nom::bytes::complete::tag;
use nom::character::complete::u32;
use nom::number::complete::float;
#[test]
fn test_ws() {
let input = "\r0 \n\n\n100.0 200.0 \n45.0 ";
let (remaining, (label, x, y, angle)) = (ws(u32), ws(float), ws(float), ws(float))
.parse(input)
.unwrap();
assert_eq!(remaining, "");
assert_eq!(label, 0);
assert_eq!(x, 100.0);
assert_eq!(y, 200.0);
assert_eq!(angle, 45.0);
}
#[test]
fn test_ws_separated() {
let input = "0 100.0 200.0 45.0";
let (remaining, (label, x, y, angle)) = ws_separated!((u32, float, float, float))
.parse(input)
.unwrap();
assert_eq!(remaining, "");
assert_eq!(label, 0);
assert_eq!(x, 100.0);
assert_eq!(y, 200.0);
assert_eq!(angle, 45.0);
}
#[test]
fn test_section() {
let input = ".SECTION\n123 456\n.END_SECTION";
let (remaining, ints) = parse_section!("SECTION", (ws(u32), ws(u32)))
.parse(input)
.unwrap();
assert_eq!(remaining, "");
assert_eq!(ints, (123, 456));
}
#[test]
fn test_quote_string() {
let input = "\"Hello, World!\"";
let (remaining, quoted_str) = quote_string(input).unwrap();
assert_eq!(remaining, "");
assert_eq!(quoted_str, "Hello, World!");
}
}