use winnow::combinator::cut_err;
use winnow::combinator::delimited;
use winnow::combinator::opt;
use winnow::combinator::peek;
use winnow::combinator::separated;
use winnow::combinator::trace;
use crate::parser::trivia::ws_comment_newline;
use crate::parser::value::value;
use crate::{Array, Item, RawString};
use crate::parser::prelude::*;
pub(crate) fn array<'i>(input: &mut Input<'i>) -> PResult<Array> {
trace("array", move |input: &mut Input<'i>| {
delimited(
ARRAY_OPEN,
cut_err(array_values),
cut_err(ARRAY_CLOSE)
.context(StrContext::Label("array"))
.context(StrContext::Expected(StrContextValue::CharLiteral(']'))),
)
.parse_next(input)
})
.parse_next(input)
}
pub(crate) const ARRAY_OPEN: u8 = b'[';
const ARRAY_CLOSE: u8 = b']';
const ARRAY_SEP: u8 = b',';
pub(crate) fn array_values(input: &mut Input<'_>) -> PResult<Array> {
if peek(opt(ARRAY_CLOSE)).parse_next(input)?.is_some() {
return Ok(Array::new());
}
let array = separated(0.., array_value, ARRAY_SEP).parse_next(input)?;
let mut array = Array::with_vec(array);
if !array.is_empty() {
let comma = opt(ARRAY_SEP).parse_next(input)?.is_some();
array.set_trailing_comma(comma);
}
let trailing = ws_comment_newline.span().parse_next(input)?;
array.set_trailing(RawString::with_span(trailing));
Ok(array)
}
pub(crate) fn array_value(input: &mut Input<'_>) -> PResult<Item> {
let prefix = ws_comment_newline.span().parse_next(input)?;
let value = value.parse_next(input)?;
let suffix = ws_comment_newline.span().parse_next(input)?;
let value = value.decorated(RawString::with_span(prefix), RawString::with_span(suffix));
let value = Item::Value(value);
Ok(value)
}
#[cfg(test)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
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 {
dbg!(input);
let mut parsed = array.parse(new_input(input));
if let Ok(parsed) = &mut parsed {
parsed.despan(input);
}
assert_eq!(parsed.map(|a| a.to_string()), Ok(input.to_owned()));
}
}
#[test]
fn invalid_arrays() {
let invalid_inputs = [r#"["#, r#"[,]"#, r#"[,2]"#, r#"[1e165,,]"#];
for input in invalid_inputs {
dbg!(input);
let mut parsed = array.parse(new_input(input));
if let Ok(parsed) = &mut parsed {
parsed.despan(input);
}
assert!(parsed.is_err());
}
}
}