1use crate::{
4 ast::*,
5 parser::{basic::*, combinator::*},
6};
7use nom::{
8 Parser,
9 branch::alt,
10 bytes::complete::tag,
11 character::complete::{
12 char, digit0, digit1, multispace0, none_of, satisfy,
13 },
14 combinator::{map, opt},
15 multi::{many0, many1},
16};
17
18pub fn sign(input: &str) -> ParseResult<'_, char> {
20 alt((char('+'), char('-'))).parse(input)
21}
22
23pub fn integer(input: &str) -> ParseResult<'_, i64> {
25 tuple((opt(sign), multispace0, digit1))
26 .map(|(sign, _space, numbers)| {
27 let num: i64 =
28 numbers.parse().expect("Failed to parse into integer");
29 match sign {
30 Some('-') => -num,
31 _ => num,
32 }
33 })
34 .parse(input)
35}
36
37fn exponent(input: &str) -> ParseResult<'_, i64> {
39 tuple((char('E'), multispace0, opt(sign), multispace0, digit1))
40 .map(|(_e, _sp1, sign, _sp2, digit)| {
41 let num: i64 =
42 digit.parse().expect("Failed to parse integer in exponent");
43 match sign {
44 Some('-') => -num,
45 _ => num,
46 }
47 })
48 .parse(input)
49}
50
51pub fn real(input: &str) -> ParseResult<'_, f64> {
54 tuple((
55 opt(sign),
56 multispace0,
57 digit1,
58 char('.'),
59 digit0,
60 opt(exponent),
61 ))
62 .map(|(sign, _space, integral, _point, fractional, exp)| {
63 let num: f64 =
64 format!("{}.{}e{}", integral, fractional, exp.unwrap_or(0))
65 .parse()
66 .expect("Failed to parse Float");
67 match sign {
68 Some('-') => -num,
69 _ => num,
70 }
71 })
72 .parse(input)
73}
74
75pub fn string(input: &str) -> ParseResult<'_, String> {
79 let escaped_char = map(tag("''"), |_| '\''); let normal_char = none_of("'"); let string_content = many0(escaped_char.or(normal_char.map(|c| c)));
83
84 tuple((char('\''), string_content, char('\'')))
85 .map(|(_start, s, _end)| s.iter().collect())
86 .parse(input)
87}
88
89pub fn resource(input: &str) -> ParseResult<'_, URI> {
93 tuple((char('<'), many0(none_of(">")), char('>')))
94 .map(|(_start, s, _end)| URI(s.iter().collect()))
95 .parse(input)
96}
97
98pub fn enumeration(input: &str) -> ParseResult<'_, String> {
100 tuple((char('.'), standard_keyword, char('.')))
101 .map(|(_head, name, _tail)| name)
102 .parse(input)
103}
104
105fn u64_overflow(
110 input: &str,
111) -> nom::Err<nom_language::error::VerboseError<&str>> {
112 nom::Err::Failure(nom_language::error::VerboseError {
113 errors: vec![(
114 input,
115 nom_language::error::VerboseErrorKind::Context("u64-overflow"),
116 )],
117 })
118}
119
120pub fn entity_instance_name(input: &str) -> ParseResult<'_, u64> {
134 let (input, name) = tuple((char('#'), digit1))
135 .map(|(_sharp, name): (_, &str)| name.parse())
136 .parse(input)?;
137 if let Ok(name) = name {
138 Ok((input, name))
139 } else {
140 Err(u64_overflow(input))
141 }
142}
143
144pub fn value_instance_name(input: &str) -> ParseResult<'_, u64> {
153 let (input, name) = tuple((char('@'), digit1))
154 .map(|(_sharp, name): (_, &str)| name.parse())
155 .parse(input)?;
156 if let Ok(name) = name {
157 Ok((input, name))
158 } else {
159 Err(u64_overflow(input))
160 }
161}
162
163pub fn constant_entity_name(input: &str) -> ParseResult<'_, String> {
165 tuple((char('#'), standard_keyword))
166 .map(|(_sharp, name)| name)
167 .parse(input)
168}
169
170pub fn constant_value_name(input: &str) -> ParseResult<'_, String> {
172 tuple((char('@'), standard_keyword))
173 .map(|(_sharp, name)| name)
174 .parse(input)
175}
176
177pub fn lhs_occurrence_name(input: &str) -> ParseResult<'_, Name> {
179 alt((
180 entity_instance_name.map(Name::Entity),
181 value_instance_name.map(Name::Value),
182 ))
183 .parse(input)
184}
185
186pub fn rhs_occurrence_name(input: &str) -> ParseResult<'_, Name> {
189 alt((
190 entity_instance_name.map(Name::Entity),
191 value_instance_name.map(Name::Value),
192 constant_entity_name.map(Name::ConstantEntity),
193 constant_value_name.map(Name::ConstantValue),
194 ))
195 .parse(input)
196}
197
198pub fn anchor_name(input: &str) -> ParseResult<'_, String> {
202 tuple((char('<'), many0(none_of(">")), char('>')))
203 .map(|(_start, s, _end)| s.iter().collect())
204 .parse(input)
205}
206
207pub fn keyword(input: &str) -> ParseResult<'_, String> {
209 alt((user_defined_keyword, standard_keyword)).parse(input)
210}
211
212pub fn standard_keyword(input: &str) -> ParseResult<'_, String> {
214 tuple((upper, many0(alt((upper, digit)))))
215 .map(|(first, tail)| {
216 let head = &[first];
217 head.iter().chain(tail.iter()).collect()
218 })
219 .parse(input)
220}
221
222pub fn user_defined_keyword(input: &str) -> ParseResult<'_, String> {
224 tuple((char('!'), standard_keyword))
225 .map(|(_e, name)| name)
226 .parse(input)
227}
228
229pub fn tag_name(input: &str) -> ParseResult<'_, String> {
231 tuple((alt((upper, lower)), many0(alt((upper, lower, digit)))))
232 .map(|(first, tail)| {
233 let head = &[first];
234 head.iter().chain(tail.iter()).collect()
235 })
236 .parse(input)
237}
238
239pub fn signature_content(input: &str) -> ParseResult<'_, String> {
241 let base_char = satisfy(
242 |c| matches!(c, '0'..='9' | 'a'..='z' | 'A'..='Z' | '+' | '/' | '='),
243 );
244 many1(base_char)
245 .map(|chars| chars.iter().collect())
246 .parse(input)
247}
248
249#[cfg(test)]
250mod tests {
251 use nom::Finish;
252
253 #[test]
254 fn real() {
255 let (res, s) = super::real("1.23").finish().unwrap();
256 assert_eq!(res, "");
257 assert_eq!(s, 1.23);
258
259 let (res, s) = super::real("1.23E4").finish().unwrap();
260 assert_eq!(res, "");
261 assert_eq!(s, 1.23e4);
262
263 let (res, s) = super::real("1.23E-4").finish().unwrap();
264 assert_eq!(res, "");
265 assert_eq!(s, 1.23e-4);
266
267 let (res, s) = super::real("-1.23E4").finish().unwrap();
268 assert_eq!(res, "");
269 assert_eq!(s, -1.23e4);
270
271 let (res, s) = super::real("-1.23E-4").finish().unwrap();
272 assert_eq!(res, "");
273 assert_eq!(s, -1.23e-4);
274
275 assert!(super::real("123").finish().is_err());
276 }
277
278 #[test]
279 fn string() {
280 let (res, s) = super::string("'vim'").finish().unwrap();
281 assert_eq!(res, "");
282 assert_eq!(s, "vim");
283 }
284
285 #[test]
286 fn escaped_string() {
287 let (res, s) = super::string("'vim''s'").finish().unwrap();
288 assert_eq!(res, "");
289 assert_eq!(s, "vim's");
290 }
291
292 #[test]
293 fn instance_name() {
294 let (res, s) = super::entity_instance_name(
295 "#18446744073709551615", )
297 .finish()
298 .unwrap();
299 assert_eq!(res, "");
300 assert_eq!(s, u64::MAX);
301
302 let (res, s) = super::value_instance_name(
303 "@18446744073709551615", )
305 .finish()
306 .unwrap();
307 assert_eq!(res, "");
308 assert_eq!(s, u64::MAX);
309
310 assert!(
312 super::entity_instance_name(
313 "#18446744073709551616" )
315 .finish()
316 .is_err()
317 );
318 assert!(
319 super::value_instance_name(
320 "@18446744073709551616" )
322 .finish()
323 .is_err()
324 );
325
326 let (res, s) = super::entity_instance_name("#001").finish().unwrap();
328 assert_eq!(res, "");
329 assert_eq!(s, 1);
330 let (res, s) = super::value_instance_name("@001").finish().unwrap();
331 assert_eq!(res, "");
332 assert_eq!(s, 1);
333 }
334}