1use super::{ConstrctInfo, OptParser};
2use crate::opt::Index;
3use crate::Error;
4
5#[derive(Debug, Default)]
63pub struct StrParser;
64
65impl StrParser {
66 pub fn new() -> Self {
67 Self {}
68 }
69
70 pub fn parse_creator_string(&self, dat: &str) -> Result<ConstrctInfo, Error> {
71 use neure::prelude::*;
72
73 let start = re::start();
74 let end = re::end();
75 let name = ['=', '!', '*', '@', ';', ':'].not().repeat_one_more();
76 let aliases = name.sep(";");
77 let parser = name.opt().if_then(";", aliases);
78
79 let ctor = neu::alphabetic().repeat_one_more();
80 let parser = parser.if_then("=", ctor);
81
82 let opt = "!".or("*").opt();
83 let parser = parser.then(opt);
84
85 let index = '@'.or(':').not().repeat_one_more();
86 let parser = parser.if_then("@", index);
87
88 let help = re::consume_all();
89 let parser = parser.if_then(":", help);
90
91 let parser = start.then(parser).then(end);
92
93 let to_string = |v: &str| v.trim().to_string();
94
95 let ((_, (((((name, aliases), ctor), opt), index), help)), _) = CharsCtx::new(dat)
96 .ctor(&parser)
97 .map_err(|_| Error::create_str(dat, "can not parsing string"))?;
98
99 let mut ci = ConstrctInfo::default();
100
101 ci = ci.with_name(name.map(to_string));
102 ci = ci.with_alias(aliases.map(|v| v.iter().copied().map(to_string).collect()));
103 ci = ci.with_ctor(ctor.map(to_string));
104 ci = ci.with_force(opt.map(|v| v == "!"));
105 ci = ci.with_index(if let Some(index) = index {
106 Some(Index::parse(index)?)
107 } else {
108 None
109 });
110 ci = ci.with_help(help.map(to_string));
111 Ok(ci)
112 }
113}
114
115impl OptParser for StrParser {
116 type Output = ConstrctInfo;
117
118 type Error = Error;
119
120 fn parse_opt(&self, pattern: &str) -> Result<Self::Output, Self::Error> {
121 if pattern.trim().is_empty() {
122 Ok(Self::Output::default())
123 } else {
124 self.parse_creator_string(pattern)
125 }
126 }
127}
128
129#[cfg(test)]
130mod test {
131
132 use crate::prelude::*;
133
134 #[test]
135 fn test_str_parser() {
136 let options = [
137 "-b",
138 "--bool",
139 "bool",
140 "-b;--bool",
141 "-?;-h;--help",
142 "--bool;-b",
143 "b;bool",
144 "-b;bool",
145 "-/b;--/bool",
146 "-/b;bool",
147 "-b=i",
148 "--bool=u",
149 "bool=s",
150 "-b;--bool=b",
151 "-?;-h;--help=p",
152 "--bool;-b=c",
153 "b;bool=m",
154 "-b;bool=f",
155 "-/b;--/bool=i",
156 "-/b;bool=a",
157 "",
158 ];
159 let options_test = [
160 (Some("-b"), None, None),
161 (Some("--bool"), None, None),
162 (Some("bool"), None, None),
163 (Some("-b"), Some(vec!["--bool"]), None),
164 (Some("-?"), Some(vec!["-h", "--help"]), None),
165 (Some("--bool"), Some(vec!["-b"]), None),
166 (Some("b"), Some(vec!["bool"]), None),
167 (Some("-b"), Some(vec!["bool"]), None),
168 (Some("-/b"), Some(vec!["--/bool"]), None),
169 (Some("-/b"), Some(vec!["bool"]), None),
170 (Some("-b"), None, Some("i")),
171 (Some("--bool"), None, Some("u")),
172 (Some("bool"), None, Some("s")),
173 (Some("-b"), Some(vec!["--bool"]), Some("b")),
174 (Some("-?"), Some(vec!["-h", "--help"]), Some("p")),
175 (Some("--bool"), Some(vec!["-b"]), Some("c")),
176 (Some("b"), Some(vec!["bool"]), Some("m")),
177 (Some("-b"), Some(vec!["bool"]), Some("f")),
178 (Some("-/b"), Some(vec!["--/bool"]), Some("i")),
179 (Some("-/b"), Some(vec!["bool"]), Some("a")),
180 (None, None, None),
181 ];
182 let helps = [": This is an option help message", ""];
183 let helps_test = [Some("This is an option help message"), None];
184 let forces = ["!", "*", ""];
185 let forces_test = [Some(true), Some(false), None];
186 let positions = [
187 "@1",
188 "@68",
189 "@-6",
190 "@+42",
191 "@1..5",
192 "@..8",
193 "@2..",
194 "@[1,3,5]",
195 "@+[2,3,4]",
196 "@-[3,56]",
197 "@*",
198 "",
199 ];
200 let positions_test = [
201 Some(Index::forward(1)),
202 Some(Index::forward(68)),
203 Some(Index::backward(6)),
204 Some(Index::forward(42)),
205 Some(Index::range(Some(1), Some(5))),
206 Some(Index::range(None, Some(8))),
207 Some(Index::range(Some(2), None)),
208 Some(Index::list(vec![1, 3, 5])),
209 Some(Index::list(vec![2, 3, 4])),
210 Some(Index::except(vec![3, 56])),
211 Some(Index::anywhere()),
212 None,
213 ];
214 let parser = StrParser;
215
216 for (option, option_test) in options.iter().zip(options_test.iter()) {
217 for (help, help_test) in helps.iter().zip(helps_test.iter()) {
218 for (force, force_test) in forces.iter().zip(forces_test.iter()) {
219 for (position, position_test) in positions.iter().zip(positions_test.iter()) {
220 let creator = format!("{}{}{}{}", option, force, position, help);
221
222 println!("\"{}\",", creator);
223 if let Ok(cap) = parser.parse_opt(&creator) {
224 assert_eq!(option_test.0, cap.name());
225 assert_eq!(
226 option_test.1,
227 cap.alias().map(|v| v.iter().map(|v| v.as_ref()).collect())
228 );
229 assert_eq!(help_test, &cap.help());
230 assert_eq!(force_test, &cap.force());
231 assert_eq!(position_test.as_ref(), cap.index());
232 assert_eq!(option_test.2, cap.ctor());
233 } else {
234 assert!(
235 option_test.0.is_none(),
236 "{}{}{}{}",
237 option,
238 force,
239 position,
240 help
241 );
242 assert!(option_test.1.is_none());
243 }
244 }
245 }
246 }
247 }
248 }
249}