color_print_proc_macro/parse/
util.rs
1use nom::{
2 Err,
3 sequence::{delimited, preceded},
4 character::complete::{multispace0, alpha1},
5 bytes::complete::tag,
6 combinator::{map, opt},
7 error::ErrorKind,
8};
9
10use super::{Parser, Result, Input, Error, ErrorDetail};
11
12pub fn with_failure_message<'a, P, V>(mut parser: P, message: &'a str) -> impl Parser<'a, V>
14where
15 P: Parser<'a, V>,
16{
17 move |input: Input<'a>| parser(input).map_err(
18 |nom_err: Err<Error>| match nom_err {
19 Err::Error(e) => {
20 Err::Failure(e.with_detail(ErrorDetail::new(input, message)))
21 }
22 e => e,
23 }
24 )
25}
26
27pub fn check_parser_before_failure<'a, C, CV, P, PV>(
30 mut check_parser: C,
31 mut parser: P,
32 failure_msg: &'a str
33) -> impl Parser<'a, PV>
34where
35 C: Parser<'a, CV>,
36 P: Parser<'a, PV>,
37{
38 move |input| {
39 check_parser(input)?;
40 with_failure_message(|input| { parser(input) }, failure_msg)
41 (input)
42 }
43}
44
45pub fn spaced<'a, P, V>(parser: P) -> impl Parser<'a, V>
47where
48 P: Parser<'a, V>,
49{
50 delimited(
51 multispace0,
52 parser,
53 multispace0,
54 )
55}
56
57pub fn stag(s: &str) -> impl Parser<'_, &str> {
59 spaced(tag(s))
60}
61
62pub fn is_present<'a, P, V>(parser: P) -> impl Parser<'a, bool>
64where
65 P: Parser<'a, V>,
66{
67 map(opt(parser), |v| v.is_some())
68}
69
70pub fn function<'a, PV, N, P>(word_parser: N, parser: P) -> impl Parser<'a, PV>
72where
73 N: Parser<'a, &'a str>,
74 P: Parser<'a, PV>,
75{
76 preceded(
77 word(word_parser),
78 delimited(
79 with_failure_message(stag("("), "Missing opening brace"),
80 parser,
81 with_failure_message(stag(")"), "Missing closing brace")
82 )
83 )
84}
85
86pub fn word<'a, P>(mut word_parser: P) -> impl Parser<'a, &'a str>
89where
90 P: Parser<'a, &'a str>,
91{
92 move |input| {
93 let (input, word) = alpha1(input)?;
94 match word_parser(word) {
95 Ok((_, parsed_word)) => {
96 if word == parsed_word {
97 Ok((input, word))
98 } else {
99 Err(Err::Error(Error::new(input, ErrorKind::Alpha, None)))
100 }
101 }
102 Err(e) => Err(e),
103 }
104 }
105}
106
107pub fn uppercase_word(input: Input<'_>) -> Result<'_, &str> {
109 let (input, word) = alpha1(input)?;
110 if word.chars().all(|c| c.is_ascii_uppercase()) {
111 Ok((input, word))
112 } else {
113 Err(Err::Error(Error::new(input, ErrorKind::Alpha, None)))
114 }
115}
116
117pub fn lowercase_word(input: Input<'_>) -> Result<'_, &str> {
119 let (input, word) = alpha1(input)?;
120 if word.chars().all(|c| c.is_ascii_lowercase()) {
121 Ok((input, word))
122 } else {
123 Err(Err::Error(Error::new(input, ErrorKind::Alpha, None)))
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn test_uppercase_word() {
133 let input = "foo";
134 assert!(uppercase_word(input).is_err());
135 let input = "FOOfoo";
136 assert!(uppercase_word(input).is_err());
137 let input = "FOO";
138 assert!(uppercase_word(input).is_ok());
139 let input = "FOO;;";
140 assert!(uppercase_word(input).is_ok());
141 }
142}