1use crate::raw_symbol_token::RawSymbolToken;
2use crate::text::parse_result::{IonParseResult, UpgradeIResult, UpgradeParser};
3use nom::branch::alt;
4use nom::bytes::streaming::tag;
5use nom::combinator::{map, peek, value};
6use nom::sequence::{delimited, pair, preceded, terminated};
7use nom::{IResult, Parser};
8
9use crate::text::parsers::annotations::parse_annotations;
10use crate::text::parsers::comments::whitespace_or_comments;
11use crate::text::parsers::string::parse_string;
12use crate::text::parsers::symbol::{parse_operator, parse_symbol};
13use crate::text::parsers::top_level::top_level_value;
14use crate::text::parsers::value::{annotated_container_start, annotated_scalar};
15use crate::text::text_value::{AnnotatedTextValue, TextValue};
16
17pub(crate) fn container_start(input: &str) -> IonParseResult<TextValue> {
19 alt((struct_start, list_start, s_expression_start))(input).upgrade()
20}
21
22pub(crate) fn struct_start(input: &str) -> IResult<&str, TextValue> {
24 value(TextValue::StructStart, tag("{"))(input)
25}
26
27pub(crate) fn list_start(input: &str) -> IResult<&str, TextValue> {
29 value(TextValue::ListStart, tag("["))(input)
30}
31
32pub(crate) fn s_expression_start(input: &str) -> IResult<&str, TextValue> {
34 value(TextValue::SExpStart, tag("("))(input)
35}
36
37pub(crate) fn struct_end(input: &str) -> IonParseResult<&str> {
39 preceded(whitespace_or_comments, tag("}").upgrade())(input)
40}
41
42pub(crate) fn list_end(input: &str) -> IonParseResult<&str> {
44 preceded(whitespace_or_comments, tag("]").upgrade())(input)
45}
46
47pub(crate) fn s_expression_end(input: &str) -> IonParseResult<&str> {
49 preceded(whitespace_or_comments, tag(")").upgrade())(input)
50}
51
52pub(crate) fn list_value(input: &str) -> IonParseResult<AnnotatedTextValue> {
57 alt((
58 list_scalar,
60 preceded(whitespace_or_comments, annotated_container_start),
63 ))(input)
64}
65
66pub(crate) fn list_scalar(input: &str) -> IonParseResult<AnnotatedTextValue> {
69 delimited(
71 whitespace_or_comments,
73 annotated_scalar,
75 list_delimiter,
77 )(input)
78}
79
80pub(crate) fn list_delimiter(input: &str) -> IonParseResult<()> {
83 preceded(
84 whitespace_or_comments,
85 alt((tag(",").upgrade(), peek(list_end))),
86 )
87 .map(|_| ())
90 .parse(input)
91}
92
93pub(crate) fn list_value_or_end(input: &str) -> IonParseResult<Option<AnnotatedTextValue>> {
96 map(list_end, |_end_marker| None)
97 .or(map(list_value, Some))
98 .parse(input)
99}
100
101pub(crate) fn s_expression_value(input: &str) -> IonParseResult<AnnotatedTextValue> {
105 alt((
106 s_expression_scalar,
108 preceded(whitespace_or_comments, annotated_container_start),
111 ))(input)
112}
113
114pub(crate) fn s_expression_scalar(input: &str) -> IonParseResult<AnnotatedTextValue> {
117 preceded(
118 whitespace_or_comments,
119 alt((
121 pair(parse_annotations, parse_operator)
123 .map(|(annotations, value)| AnnotatedTextValue::new(annotations, value)),
124 top_level_value,
126 parse_operator.map(|op| op.without_annotations()),
128 )),
129 )(input)
140}
141
142pub(crate) fn s_expression_value_or_end(input: &str) -> IonParseResult<Option<AnnotatedTextValue>> {
146 map(s_expression_end, |_end_marker| None)
147 .or(map(s_expression_value, Some))
148 .parse(input)
149}
150
151pub(crate) fn s_expression_delimiter(input: &str) -> IonParseResult<()> {
154 Ok((input, ()))
163}
164
165pub(crate) fn struct_field_name(input: &str) -> IonParseResult<RawSymbolToken> {
168 delimited(
169 whitespace_or_comments,
170 parse_string.or(parse_symbol),
173 pair(whitespace_or_comments, tag(":")),
174 )
175 .map(|value| match value {
176 TextValue::String(text) => RawSymbolToken::Text(text),
177 TextValue::Symbol(token) => token,
178 other => unreachable!(
179 "Struct field names can only be strings or symbols. Found a {:?}",
180 other
181 ),
182 })
183 .parse(input)
184}
185
186pub(crate) fn struct_field_value(input: &str) -> IonParseResult<AnnotatedTextValue> {
191 alt((
192 struct_field_scalar,
194 preceded(whitespace_or_comments, annotated_container_start),
197 ))(input)
198}
199
200pub(crate) fn struct_field_scalar(input: &str) -> IonParseResult<AnnotatedTextValue> {
203 terminated(
204 top_level_value,
206 struct_delimiter,
208 )(input)
209}
210
211pub(crate) fn struct_field_name_or_end(input: &str) -> IonParseResult<Option<RawSymbolToken>> {
214 map(struct_end, |_end_marker| None)
215 .or(map(struct_field_name, Some))
216 .parse(input)
217}
218
219pub(crate) fn struct_delimiter(input: &str) -> IonParseResult<()> {
222 preceded(whitespace_or_comments, alt((tag(","), peek(struct_end))))
223 .map(|_| ())
226 .parse(input)
227}
228
229#[cfg(test)]
230mod container_parsing_tests {
231 use rstest::*;
232
233 use crate::raw_symbol_token::{local_sid_token, text_token};
234 use crate::text::parsers::unit_test_support::{parse_test_err, parse_test_ok};
235 use crate::text::text_value::TextValue;
236 use crate::types::{Decimal, Int};
237
238 use super::*;
239
240 #[rstest]
241 #[case::start_of_struct("{", TextValue::StructStart)]
242 #[case::start_of_list("[", TextValue::ListStart)]
243 #[case::start_of_s_expression("(", TextValue::SExpStart)]
244 fn test_parse_container_start_ok(#[case] text: &str, #[case] expected: TextValue) {
245 parse_test_ok(container_start, text, expected)
246 }
247
248 #[rstest]
249 #[case("5")]
250 #[case("true")]
251 #[case("foo")]
252 #[case("foo::{")]
253 #[case("\"hello\"")]
254 #[case("<")]
255 fn test_parse_container_start_err(#[case] text: &str) {
256 parse_test_err(container_start, text)
257 }
258
259 #[rstest]
260 #[case("5,", TextValue::Int(Int::I64(5)).without_annotations())]
261 #[case("foo::bar::5,", TextValue::Int(Int::I64(5)).with_annotations(["foo", "bar"]))]
262 #[case("foo::bar,", TextValue::Symbol(text_token("bar")).with_annotations("foo"))]
263 #[case("bar]", TextValue::Symbol(text_token("bar")).without_annotations())]
264 #[case("7.]", TextValue::Decimal(Decimal::new(7, 0)).without_annotations())]
265 #[should_panic]
266 #[case("5 ", TextValue::String(String::from("<should panic>")).without_annotations())]
268 #[should_panic]
269 #[case(", ", TextValue::String(String::from("<should panic>")).without_annotations())]
271 fn test_parse_list_values(#[case] text: &str, #[case] expected: AnnotatedTextValue) {
272 parse_test_ok(list_value, text, expected);
273 }
274
275 #[rstest]
276 #[case("'++',", Some(TextValue::Symbol(text_token("++")).without_annotations()))]
277 #[case("foo::'++',", Some(TextValue::Symbol(text_token("++")).with_annotations("foo")))]
278 #[case("5 ,", Some(TextValue::Int(Int::I64(5)).without_annotations()))]
279 #[case("5]", Some(TextValue::Int(Int::I64(5)).without_annotations()))]
280 #[case("]", None)]
281 #[case(" ]", None)]
282 #[case(" /*comment*/ ]", None)]
283 fn test_parse_list_value_or_end(
284 #[case] text: &str,
285 #[case] expected: Option<AnnotatedTextValue>,
286 ) {
287 parse_test_ok(list_value_or_end, text, expected);
288 }
289
290 #[rstest]
291 #[case("++ ", TextValue::Symbol(text_token("++")).without_annotations())]
292 #[case("foo::++ ", TextValue::Symbol(text_token("++")).with_annotations("foo"))]
293 #[case("5 ", TextValue::Int(Int::I64(5)).without_annotations())]
294 #[case("5)", TextValue::Int(Int::I64(5)).without_annotations())]
295 #[case("foo::bar::5 ", TextValue::Int(Int::I64(5)).with_annotations(["foo", "bar"]))]
296 #[case("foo::bar 0", TextValue::Symbol(text_token("bar")).with_annotations("foo"))]
298 #[case("bar)", TextValue::Symbol(text_token("bar")).without_annotations())]
299 #[case("7.)", TextValue::Decimal(Decimal::new(7, 0)).without_annotations())]
300 #[should_panic]
301 #[case("5, ", TextValue::String(String::from("<should panic>")).without_annotations())]
303 #[should_panic]
304 #[case("5]", TextValue::String(String::from("<should panic>")).without_annotations())]
306 fn test_parse_s_expression_values(#[case] text: &str, #[case] expected: AnnotatedTextValue) {
307 parse_test_ok(s_expression_value, text, expected);
308 }
309
310 #[rstest]
311 #[case("++ ", Some(TextValue::Symbol(text_token("++")).without_annotations()))]
312 #[case("foo::++ ", Some(TextValue::Symbol(text_token("++")).with_annotations("foo")))]
313 #[case("5 ", Some(TextValue::Int(Int::I64(5)).without_annotations()))]
314 #[case(")", None)]
315 #[case(" )", None)]
316 #[case(" /*comment*/ )", None)]
317 fn test_parse_s_expression_value_or_end(
318 #[case] text: &str,
319 #[case] expected: Option<AnnotatedTextValue>,
320 ) {
321 parse_test_ok(s_expression_value_or_end, text, expected);
322 }
323
324 #[rstest]
325 #[case("5,", TextValue::Int(Int::I64(5)).without_annotations())]
326 #[case("5 ,", TextValue::Int(Int::I64(5)).without_annotations())]
327 #[case("foo::bar::5,", TextValue::Int(Int::I64(5)).with_annotations(["foo", "bar"]))]
328 #[case("foo::bar,", TextValue::Symbol(text_token("bar")).with_annotations("foo"))]
329 #[case("bar}", TextValue::Symbol(text_token("bar")).without_annotations())]
330 #[case("7.}", TextValue::Decimal(Decimal::new(7, 0)).without_annotations())]
331 #[should_panic]
332 #[case("5 ", TextValue::String(String::from("<should panic>")).without_annotations())]
334 #[should_panic]
335 #[case(", ", TextValue::String(String::from("<should panic>")).without_annotations())]
337 fn test_parse_struct_field_values(#[case] text: &str, #[case] expected: AnnotatedTextValue) {
338 parse_test_ok(struct_field_value, text, expected);
339 }
340
341 #[rstest]
342 #[case("foo:", text_token("foo"))]
343 #[case(" foo :", text_token("foo"))]
344 #[case(
345 "/* Here's a field name */ foo // And here's a delimiter\n:",
346 text_token("foo")
347 )]
348 #[case("'foo':", text_token("foo"))]
349 #[case(" 'foo' :", text_token("foo"))]
350 #[case("$10:", local_sid_token(10))]
351 #[case(" $10 :", local_sid_token(10))]
352 #[case("\"foo\":", text_token("foo"))]
353 #[case(" \"foo\" :", text_token("foo"))]
354 fn test_parse_struct_field_name(#[case] text: &str, #[case] expected: RawSymbolToken) {
355 parse_test_ok(struct_field_name, text, expected);
356 }
357
358 #[rstest]
359 #[case("foo:", Some(text_token("foo")))]
360 #[case(" foo :", Some(text_token("foo")))]
361 #[case("'foo':", Some(text_token("foo")))]
362 #[case("}", None)]
363 #[case(" }", None)]
364 #[case("/*comment*/}", None)]
365 fn test_parse_struct_field_name_or_end(
366 #[case] text: &str,
367 #[case] expected: Option<RawSymbolToken>,
368 ) {
369 parse_test_ok(struct_field_name_or_end, text, expected);
370 }
371}