1use nom::{
2 bytes::complete::tag,
3 character::complete::{char, one_of},
4 combinator::{map_res, recognize},
5 error::{FromExternalError, ParseError},
6 multi::{many0, many1},
7 sequence::delimited,
8 IResult,
9};
10
11fn newline(input: &str) -> IResult<&str, char> {
12 char('\n')(input)
13}
14pub fn newline0(input: &str) -> IResult<&str, ()> {
15 let (input, _) = many0(newline)(input)?;
16 Ok((input, ()))
17}
18pub fn newline1(input: &str) -> IResult<&str, ()> {
19 let (input, _) = many1(newline)(input)?;
20 Ok((input, ()))
21}
22
23pub fn bind<'a, F: 'a, T: Copy, O, E: ParseError<&'a str> + FromExternalError<&'a str, ()>>(
24 inner: F,
25 val: T,
26) -> impl FnMut(&'a str) -> IResult<&'a str, T, E>
27where
28 F: FnMut(&'a str) -> IResult<&'a str, O, E>,
29{
30 map_res(inner, move |_| -> Result<T, ()> { Ok(val) })
31}
32
33// Parse on of the given strings and return the given value.
34pub fn str<'a, T: Copy, E: ParseError<&'a str> + FromExternalError<&'a str, ()> + 'a>(
35 name: &'a str,
36 val: T,
37) -> impl FnMut(&'a str) -> IResult<&'a str, T, E> {
38 bind(tag(name), val)
39}
40
41pub fn digits(input: &str) -> IResult<&str, &str> {
42 recognize(many1(one_of("0123456789")))(input)
43}
44
45pub fn parse_i64(input: &str) -> IResult<&str, i64> {
46 map_res(digits, |input: &str| i64::from_str_radix(input, 10))(input)
47}
48
49// TODO: Use generics to refactor parse_u64 and parse_i64
50pub fn parse_u64(input: &str) -> IResult<&str, u64> {
51 map_res(digits, |input: &str| u64::from_str_radix(input, 10))(input)
52}
53
54pub fn ws<'a, F: 'a, O, E: ParseError<&'a str>>(
55 inner: F,
56) -> impl FnMut(&'a str) -> IResult<&'a str, O, E>
57where
58 F: Fn(&'a str) -> IResult<&'a str, O, E>,
59{
60 // See https://c9x.me/compile/doc/il-v1.1.html#Spacing
61 delimited(many0(one_of(" \t")), inner, many0(one_of(" \t")))
62}