1use super::LocationQuery;
2use crate::parser::Span;
3use nom::{
4 bytes::complete::{tag, take_while1},
5 character::complete::one_of,
6 combinator::opt,
7 sequence::{delimited, preceded},
8 IResult,
9};
10use thiserror::Error;
11
12#[derive(Debug, Error)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub enum QueryParseError {
16 #[error("Query parsing failed at position {position}: `{fragment}`")]
18 FailedToParse { position: usize, fragment: String },
19
20 #[error("Query parsing failed because of incomplete input.{}", .0.map(|s| format!(" Need at least {s} more characters to continue.")).unwrap_or_default())]
22 IncompleteInput(Option<usize>),
23}
24
25impl<'s> From<nom::Err<nom::error::Error<Span<'s>>>> for QueryParseError {
26 fn from(e: nom::Err<nom::error::Error<Span<'s>>>) -> Self {
27 match e {
28 nom::Err::Incomplete(nom::Needed::Unknown) => QueryParseError::IncompleteInput(None),
29 nom::Err::Incomplete(nom::Needed::Size(size)) => {
30 QueryParseError::IncompleteInput(Some(size.get()))
31 }
32 nom::Err::Error(e) | nom::Err::Failure(e) => {
33 let position = e.input.offset;
34 QueryParseError::FailedToParse {
35 position,
36 fragment: e.input.input.chars().take(7).collect(),
37 }
38 }
39 }
40 }
41}
42
43fn nonzero_integer(s: Span) -> IResult<Span, usize> {
44 let (_s, val) = take_while1(|c: char| c.is_ascii_digit())(s)?;
45 let val = val.input.parse::<usize>().map_err(|_| todo!())?;
46 if val == 0 {
47 return Err(nom::Err::Error(nom::error::Error::new(
48 s,
49 nom::error::ErrorKind::Digit,
50 )));
51 }
52 Ok((_s, val))
53}
54
55fn nonzero_array_access(s: Span) -> IResult<Span, usize> {
56 delimited(tag("["), nonzero_integer, tag("]"))(s)
57}
58
59fn preceeded_nonzero_integer(s: Span) -> IResult<Span, usize> {
60 preceded(one_of(".- "), nonzero_integer)(s)
61}
62
63pub fn parse_query(i: Span) -> IResult<Span, LocationQuery> {
64 let (i, segment) = crate::parser::segment::parse_segment_name(i)?;
65 let (i, segment_index) = opt(nonzero_array_access)(i)?;
66 let (i, field) = opt(preceeded_nonzero_integer)(i)?;
67 let (i, repeat) = if field.is_some() {
68 opt(nonzero_array_access)(i)?
69 } else {
70 (i, None)
71 };
72 let (i, component) = if field.is_some() {
73 opt(preceeded_nonzero_integer)(i)?
74 } else {
75 (i, None)
76 };
77 let (i, subcomponent) = if component.is_some() {
78 opt(preceeded_nonzero_integer)(i)?
79 } else {
80 (i, None)
81 };
82
83 let segment = segment.input.to_string();
84 Ok((
85 i,
86 LocationQuery {
87 segment,
88 segment_index,
89 field,
90 repeat,
91 component,
92 subcomponent,
93 },
94 ))
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use pretty_assertions_sorted::assert_eq;
101
102 #[test]
103 fn can_parse_preceeded_nonzero_integer() {
104 let input = Span::new(".123");
105 let actual = preceeded_nonzero_integer(input).unwrap().1;
106 assert_eq!(actual, 123);
107
108 let input = Span::new(" 123");
109 let actual = preceeded_nonzero_integer(input).unwrap().1;
110 assert_eq!(actual, 123);
111
112 let input = Span::new("-123");
113 let actual = preceeded_nonzero_integer(input).unwrap().1;
114 assert_eq!(actual, 123);
115
116 let input = Span::new("123");
117 assert!(preceeded_nonzero_integer(input).is_err());
118
119 let input = Span::new(".abc");
120 assert!(preceeded_nonzero_integer(input).is_err());
121 }
122
123 #[test]
124 fn can_parse_array_access() {
125 let input = Span::new("[123]");
126 let actual = nonzero_array_access(input).unwrap().1;
127 assert_eq!(actual, 123);
128
129 let input = Span::new("[0]");
130 assert!(nonzero_array_access(input).is_err());
131
132 let input = Span::new("[-10]");
133 assert!(nonzero_array_access(input).is_err());
134
135 let input = Span::new("[abc]");
136 assert!(nonzero_array_access(input).is_err());
137 }
138
139 #[test]
140 fn can_parse_full_query() {
141 let input = Span::new("MSH[1].2[3].4.5");
142 let actual = parse_query(input).unwrap().1;
143 assert_eq!(actual.segment, "MSH");
144 assert_eq!(actual.segment_index, Some(1));
145 assert_eq!(actual.field, Some(2));
146 assert_eq!(actual.repeat, Some(3));
147 assert_eq!(actual.component, Some(4));
148 assert_eq!(actual.subcomponent, Some(5));
149 }
150
151 #[test]
152 fn can_parse_truncated_queries() {
153 let input = Span::new("MSH[1].2[3].4");
154 let actual = parse_query(input).unwrap().1;
155 assert_eq!(actual.segment, "MSH");
156 assert_eq!(actual.segment_index, Some(1));
157 assert_eq!(actual.field, Some(2));
158 assert_eq!(actual.repeat, Some(3));
159 assert_eq!(actual.component, Some(4));
160 assert_eq!(actual.subcomponent, None);
161
162 let input = Span::new("MSH[1].2[3]");
163 let actual = parse_query(input).unwrap().1;
164 assert_eq!(actual.segment, "MSH");
165 assert_eq!(actual.segment_index, Some(1));
166 assert_eq!(actual.field, Some(2));
167 assert_eq!(actual.repeat, Some(3));
168 assert_eq!(actual.component, None);
169 assert_eq!(actual.subcomponent, None);
170
171 let input = Span::new("MSH[1].2");
172 let actual = parse_query(input).unwrap().1;
173 assert_eq!(actual.segment, "MSH");
174 assert_eq!(actual.segment_index, Some(1));
175 assert_eq!(actual.field, Some(2));
176 assert_eq!(actual.repeat, None);
177 assert_eq!(actual.component, None);
178 assert_eq!(actual.subcomponent, None);
179
180 let input = Span::new("MSH[1]");
181 let actual = parse_query(input).unwrap().1;
182 assert_eq!(actual.segment, "MSH");
183 assert_eq!(actual.segment_index, Some(1));
184 assert_eq!(actual.field, None);
185 assert_eq!(actual.repeat, None);
186 assert_eq!(actual.component, None);
187 assert_eq!(actual.subcomponent, None);
188
189 let input = Span::new("MSH");
190 let actual = parse_query(input).unwrap().1;
191 assert_eq!(actual.segment, "MSH");
192 assert_eq!(actual.segment_index, None);
193 assert_eq!(actual.field, None);
194 assert_eq!(actual.repeat, None);
195 assert_eq!(actual.component, None);
196 assert_eq!(actual.subcomponent, None);
197
198 let input = Span::new("PID.3");
199 let actual = parse_query(input).unwrap().1;
200 assert_eq!(actual.segment, "PID");
201 assert_eq!(actual.segment_index, None);
202 assert_eq!(actual.field, Some(3));
203 assert_eq!(actual.repeat, None);
204 assert_eq!(actual.component, None);
205 assert_eq!(actual.subcomponent, None);
206 }
207}