1use super::nom_prelude::complete::*;
2use super::{Parser, Result, Input, Error, ErrorDetail};
3
4/// Transforms an error into a failure, while adding a message in the error detail.
5pub fn with_failure_message<'a, P, V>(mut parser: P, message: &'a str) -> impl Parser<'a, V>
6where
7 P: Parser<'a, V>,
8{
9 move |input: Input<'a>| parser(input).map_err(
10 |nom_err: Err<Error>| match nom_err {
11 Err::Error(e: Error<'_>) => {
12 Err::Failure(e.with_detail(ErrorDetail::new(input, message)))
13 }
14 e: Err> => e,
15 }
16 )
17}
18
19/// Checks if the first parser succeeds, then parses the input with the second parser. If an error
20/// is encountered with the second parser, then a failure message is thrown.
21pub fn check_parser_before_failure<'a, C, CV, P, PV>(
22 mut check_parser: C,
23 mut parser: P,
24 failure_msg: &'a str
25) -> impl Parser<'a, PV>
26where
27 C: Parser<'a, CV>,
28 P: Parser<'a, PV>,
29{
30 move |input: &str| {
31 check_parser(input)?;
32 with_failure_message(|input| { parser(input) }, message:failure_msg)
33 (input)
34 }
35}
36
37/// Creates a parser which accpets spaces around the original parsed input.
38pub fn spaced<'a, P, V>(parser: P) -> impl Parser<'a, V>
39where
40 P: Parser<'a, V>,
41{
42 delimited(
43 first:multispace0,
44 second:parser,
45 third:multispace0,
46 )
47}
48
49/// Parsed a spaced tag.
50pub fn stag<'a>(s: &'a str) -> impl Parser<'a, &'a str> {
51 spaced(parser:tag(s))
52}
53
54/// Creates a parser which makes the parser optional and returns true if the parse was successful.
55pub fn is_present<'a, P, V>(parser: P) -> impl Parser<'a, bool>
56where
57 P: Parser<'a, V>,
58{
59 map(parser:opt(parser), |v: Option| v.is_some())
60}
61
62/// Creates a parser which parses a function call.
63pub fn function<'a, PV, N, P>(word_parser: N, parser: P) -> impl Parser<'a, PV>
64where
65 N: Parser<'a, &'a str>,
66 P: Parser<'a, PV>,
67{
68 preceded(
69 first:word(word_parser),
70 second:delimited(
71 first:with_failure_message(stag("("), "Missing opening brace"),
72 second:parser,
73 third:with_failure_message(parser:stag(")"), message:"Missing closing brace")
74 )
75 )
76}
77
78/// Parses a word made only by alpha characters ('a' => 'z' and 'A' => 'Z'), and checks if this
79/// word matches exactly the given parser.
80pub fn word<'a, P>(mut word_parser: P) -> impl Parser<'a, &'a str>
81where
82 P: Parser<'a, &'a str>,
83{
84 move |input: &str| {
85 let (input: &str, word: &str) = alpha1(input)?;
86 match word_parser(word) {
87 Ok((_, parsed_word: &str)) => {
88 if word == parsed_word {
89 Ok((input, word))
90 } else {
91 Err(Err::Error(Error::new(input, code:ErrorKind::Alpha, detail:None)))
92 }
93 }
94 Err(e: Err>) => Err(e),
95 }
96 }
97}
98
99/// Parses an uppercase word.
100pub fn uppercase_word<'a>(input: Input<'a>) -> Result<'a, &'a str> {
101 let (input: &str, word: &str) = alpha1(input)?;
102 if word.chars().all(|c: char| c >= 'A' && c <= 'Z') {
103 Ok((input, word))
104 } else {
105 Err(Err::Error(Error::new(input, code:ErrorKind::Alpha, detail:None)))
106 }
107}
108
109/// Parses a lowercase word.
110pub fn lowercase_word<'a>(input: Input<'a>) -> Result<'a, &'a str> {
111 let (input: &str, word: &str) = alpha1(input)?;
112 if word.chars().all(|c: char| c >= 'a' && c <= 'z') {
113 Ok((input, word))
114 } else {
115 Err(Err::Error(Error::new(input, code:ErrorKind::Alpha, detail:None)))
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_uppercase_word() {
125 let input = "foo";
126 assert!(uppercase_word(input).is_err());
127 let input = "FOOfoo";
128 assert!(uppercase_word(input).is_err());
129 let input = "FOO";
130 assert!(uppercase_word(input).is_ok());
131 let input = "FOO;;";
132 assert!(uppercase_word(input).is_ok());
133 }
134}
135