toml_edit/parser/
array.rs1use winnow::combinator::cut_err;
2use winnow::combinator::delimited;
3use winnow::combinator::opt;
4use winnow::combinator::peek;
5use winnow::combinator::separated;
6use winnow::combinator::trace;
7
8use crate::parser::trivia::ws_comment_newline;
9use crate::parser::value::value;
10use crate::{Array, Item, RawString};
11
12use crate::parser::prelude::*;
13
14pub(crate) fn array<'i>(input: &mut Input<'i>) -> ModalResult<Array> {
18 trace("array", move |input: &mut Input<'i>| {
19 delimited(
20 ARRAY_OPEN,
21 cut_err(array_values),
22 cut_err(ARRAY_CLOSE)
23 .context(StrContext::Label("array"))
24 .context(StrContext::Expected(StrContextValue::CharLiteral(']'))),
25 )
26 .parse_next(input)
27 })
28 .parse_next(input)
29}
30
31pub(crate) const ARRAY_OPEN: u8 = b'[';
35const ARRAY_CLOSE: u8 = b']';
37const ARRAY_SEP: u8 = b',';
39
40pub(crate) fn array_values(input: &mut Input<'_>) -> ModalResult<Array> {
43 if peek(opt(ARRAY_CLOSE)).parse_next(input)?.is_some() {
44 return Ok(Array::new());
46 }
47
48 let array = separated(0.., array_value, ARRAY_SEP).parse_next(input)?;
49 let mut array = Array::with_vec(array);
50 if !array.is_empty() {
51 let comma = opt(ARRAY_SEP).parse_next(input)?.is_some();
52 array.set_trailing_comma(comma);
53 }
54 let trailing = ws_comment_newline.span().parse_next(input)?;
55 array.set_trailing(RawString::with_span(trailing));
56
57 Ok(array)
58}
59
60pub(crate) fn array_value(input: &mut Input<'_>) -> ModalResult<Item> {
61 let prefix = ws_comment_newline.span().parse_next(input)?;
62 let value = value.parse_next(input)?;
63 let suffix = ws_comment_newline.span().parse_next(input)?;
64 let value = value.decorated(RawString::with_span(prefix), RawString::with_span(suffix));
65 let value = Item::Value(value);
66 Ok(value)
67}
68
69#[cfg(test)]
70#[cfg(feature = "parse")]
71#[cfg(feature = "display")]
72mod test {
73 use super::*;
74
75 #[test]
76 fn arrays() {
77 let inputs = [
78 r#"[]"#,
79 r#"[ ]"#,
80 r#"[
81 1, 2, 3
82]"#,
83 r#"[
84 1,
85 2, # this is ok
86]"#,
87 r#"[# comment
88# comment2
89
90
91 ]"#,
92 r#"[# comment
93# comment2
94 1
95
96#sd
97,
98# comment3
99
100 ]"#,
101 r#"[1]"#,
102 r#"[1,]"#,
103 r#"[ "all", 'strings', """are the same""", '''type''']"#,
104 r#"[ 100, -2,]"#,
105 r#"[1, 2, 3]"#,
106 r#"[1.1, 2.1, 3.1]"#,
107 r#"["a", "b", "c"]"#,
108 r#"[ [ 1, 2 ], [3, 4, 5] ]"#,
109 r#"[ [ 1, 2 ], ["a", "b", "c"] ]"#,
110 r#"[ { x = 1, a = "2" }, {a = "a",b = "b", c = "c"} ]"#,
111 ];
112 for input in inputs {
113 dbg!(input);
114 let mut parsed = array.parse(new_input(input));
115 if let Ok(parsed) = &mut parsed {
116 parsed.despan(input);
117 }
118 assert_eq!(parsed.map(|a| a.to_string()), Ok(input.to_owned()));
119 }
120 }
121
122 #[test]
123 fn invalid_arrays() {
124 let invalid_inputs = [r#"["#, r#"[,]"#, r#"[,2]"#, r#"[1e165,,]"#];
125 for input in invalid_inputs {
126 dbg!(input);
127 let mut parsed = array.parse(new_input(input));
128 if let Ok(parsed) = &mut parsed {
129 parsed.despan(input);
130 }
131 assert!(parsed.is_err());
132 }
133 }
134}