1 | use super::nom_prelude::complete::*; |
2 | use super::{Parser, Result, Input, Error, ErrorDetail}; |
3 | |
4 | /// Transforms an error into a failure, while adding a message in the error detail. |
5 | pub fn with_failure_message<'a, P, V>(mut parser: P, message: &'a str) -> impl Parser<'a, V> |
6 | where |
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. |
21 | pub 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> |
26 | where |
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. |
38 | pub fn spaced<'a, P, V>(parser: P) -> impl Parser<'a, V> |
39 | where |
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. |
50 | pub 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. |
55 | pub fn is_present<'a, P, V>(parser: P) -> impl Parser<'a, bool> |
56 | where |
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. |
63 | pub fn function<'a, PV, N, P>(word_parser: N, parser: P) -> impl Parser<'a, PV> |
64 | where |
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. |
80 | pub fn word<'a, P>(mut word_parser: P) -> impl Parser<'a, &'a str> |
81 | where |
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. |
100 | pub 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. |
110 | pub 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)] |
120 | mod 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 | |