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