|
1 | 1 | use winnow::combinator::cut_err;
|
2 | 2 | use winnow::combinator::delimited;
|
3 | 3 | use winnow::combinator::opt;
|
| 4 | +use winnow::combinator::peek; |
4 | 5 | use winnow::combinator::separated;
|
5 | 6 | use winnow::combinator::trace;
|
6 | 7 |
|
7 | 8 | use crate::parser::trivia::ws_comment_newline;
|
8 | 9 | use crate::parser::value::value;
|
9 |
| -use crate::{Array, Item, RawString, Value}; |
| 10 | +use crate::{Array, Item, RawString}; |
10 | 11 |
|
11 | 12 | use crate::parser::prelude::*;
|
12 | 13 |
|
@@ -36,36 +37,33 @@ const ARRAY_CLOSE: u8 = b']';
|
36 | 37 | // array-sep = ws %x2C ws ; , Comma
|
37 | 38 | const ARRAY_SEP: u8 = b',';
|
38 | 39 |
|
39 |
| -// note: this rule is modified |
40 |
| -// array-values = [ ( array-value array-sep array-values ) / |
41 |
| -// array-value / ws-comment-newline ] |
| 40 | +// array-values = ws-comment-newline val ws-comment-newline array-sep array-values |
| 41 | +// array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ] |
42 | 42 | pub(crate) fn array_values(input: &mut Input<'_>) -> PResult<Array> {
|
43 |
| - ( |
44 |
| - opt( |
45 |
| - (separated(1.., array_value, ARRAY_SEP), opt(ARRAY_SEP)).map( |
46 |
| - |(v, trailing): (Vec<Value>, Option<u8>)| { |
47 |
| - ( |
48 |
| - Array::with_vec(v.into_iter().map(Item::Value).collect()), |
49 |
| - trailing.is_some(), |
50 |
| - ) |
51 |
| - }, |
52 |
| - ), |
53 |
| - ), |
54 |
| - ws_comment_newline.span(), |
55 |
| - ) |
56 |
| - .try_map::<_, _, std::str::Utf8Error>(|(array, trailing)| { |
57 |
| - let (mut array, comma) = array.unwrap_or_default(); |
58 |
| - array.set_trailing_comma(comma); |
59 |
| - array.set_trailing(RawString::with_span(trailing)); |
60 |
| - Ok(array) |
61 |
| - }) |
62 |
| - .parse_next(input) |
| 43 | + if peek(opt(ARRAY_CLOSE)).parse_next(input)?.is_some() { |
| 44 | + // Optimize for empty arrays, avoiding `value` from being expected to fail |
| 45 | + 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) |
63 | 58 | }
|
64 | 59 |
|
65 |
| -pub(crate) fn array_value(input: &mut Input<'_>) -> PResult<Value> { |
66 |
| - (ws_comment_newline.span(), value, ws_comment_newline.span()) |
67 |
| - .map(|(ws1, v, ws2)| v.decorated(RawString::with_span(ws1), RawString::with_span(ws2))) |
68 |
| - .parse_next(input) |
| 60 | +pub(crate) fn array_value(input: &mut Input<'_>) -> PResult<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) |
69 | 67 | }
|
70 | 68 |
|
71 | 69 | #[cfg(test)]
|
|
0 commit comments