1use nom8::combinator::cut;
2use nom8::combinator::opt;
3use nom8::multi::separated_list1;
4use nom8::sequence::delimited;
5
6use crate::parser::trivia::ws_comment_newline;
7use crate::parser::value::value;
8use crate::{Array, Item, RawString, Value};
9
10use crate::parser::prelude::*;
11
12pub(crate) fn array(
16 check: RecursionCheck,
17) -> impl FnMut(Input<'_>) -> IResult<Input<'_>, Array, ParserError<'_>> {
18 move |input| {
19 delimited(
20 ARRAY_OPEN,
21 cut(array_values(check)),
22 cut(ARRAY_CLOSE)
23 .context(Context::Expression("array"))
24 .context(Context::Expected(ParserValue::CharLiteral(']'))),
25 )
26 .parse(input)
27 }
28}
29
30pub(crate) const ARRAY_OPEN: u8 = b'[';
34const ARRAY_CLOSE: u8 = b']';
36const ARRAY_SEP: u8 = b',';
38
39pub(crate) fn array_values(
43 check: RecursionCheck,
44) -> impl FnMut(Input<'_>) -> IResult<Input<'_>, Array, ParserError<'_>> {
45 move |input| {
46 let check = check.recursing(input)?;
47 (
48 opt((
49 separated_list1(ARRAY_SEP, array_value(check)),
50 opt(ARRAY_SEP),
51 )
52 .map(|(v, trailing): (Vec<Value>, Option<u8>)| {
53 (
54 Array::with_vec(v.into_iter().map(Item::Value).collect()),
55 trailing.is_some(),
56 )
57 })),
58 ws_comment_newline.span(),
59 )
60 .map_res::<_, _, std::str::Utf8Error>(|(array, trailing)| {
61 let (mut array, comma) = array.unwrap_or_default();
62 array.set_trailing_comma(comma);
63 array.set_trailing(RawString::with_span(trailing));
64 Ok(array)
65 })
66 .parse(input)
67 }
68}
69
70pub(crate) fn array_value(
71 check: RecursionCheck,
72) -> impl FnMut(Input<'_>) -> IResult<Input<'_>, Value, ParserError<'_>> {
73 move |input| {
74 (
75 ws_comment_newline.span(),
76 value(check),
77 ws_comment_newline.span(),
78 )
79 .map(|(ws1, v, ws2)| v.decorated(RawString::with_span(ws1), RawString::with_span(ws2)))
80 .parse(input)
81 }
82}
83
84#[cfg(test)]
85mod test {
86 use super::*;
87
88 #[test]
89 fn arrays() {
90 let inputs = [
91 r#"[]"#,
92 r#"[ ]"#,
93 r#"[
94 1, 2, 3
95]"#,
96 r#"[
97 1,
98 2, # this is ok
99]"#,
100 r#"[# comment
101# comment2
102
103
104 ]"#,
105 r#"[# comment
106# comment2
107 1
108
109#sd
110,
111# comment3
112
113 ]"#,
114 r#"[1]"#,
115 r#"[1,]"#,
116 r#"[ "all", 'strings', """are the same""", '''type''']"#,
117 r#"[ 100, -2,]"#,
118 r#"[1, 2, 3]"#,
119 r#"[1.1, 2.1, 3.1]"#,
120 r#"["a", "b", "c"]"#,
121 r#"[ [ 1, 2 ], [3, 4, 5] ]"#,
122 r#"[ [ 1, 2 ], ["a", "b", "c"] ]"#,
123 r#"[ { x = 1, a = "2" }, {a = "a",b = "b", c = "c"} ]"#,
124 ];
125 for input in inputs {
126 dbg!(input);
127 let mut parsed = array(Default::default()).parse(new_input(input)).finish();
128 if let Ok(parsed) = &mut parsed {
129 parsed.despan(input);
130 }
131 assert_eq!(parsed.map(|a| a.to_string()), Ok(input.to_owned()));
132 }
133 }
134
135 #[test]
136 fn invalid_arrays() {
137 let invalid_inputs = [r#"["#, r#"[,]"#, r#"[,2]"#, r#"[1e165,,]"#];
138 for input in invalid_inputs {
139 dbg!(input);
140 let mut parsed = array(Default::default()).parse(new_input(input)).finish();
141 if let Ok(parsed) = &mut parsed {
142 parsed.despan(input);
143 }
144 assert!(parsed.is_err());
145 }
146 }
147}