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