toml_edit/parser/
array.rs

1use crate::parser::inline_table::on_inline_table;
2use crate::parser::value::on_scalar;
3use crate::{Array, RawString, Value};
4
5use crate::parser::prelude::*;
6
7/// ```bnf
8/// ;; Array
9///
10/// array = array-open array-values array-close
11/// array-values =  ws-comment-newline val ws-comment-newline array-sep array-values
12/// array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ]
13/// ```
14pub(crate) fn on_array(
15    open_event: &toml_parser::parser::Event,
16    input: &mut Input<'_>,
17    source: toml_parser::Source<'_>,
18    errors: &mut dyn ErrorSink,
19) -> Value {
20    #[cfg(feature = "debug")]
21    let _scope = TraceScope::new("array::on_array");
22    let mut result = Array::new();
23
24    let mut state = State::default();
25    state.open(open_event);
26    while let Some(event) = input.next_token() {
27        match event.kind() {
28            EventKind::StdTableOpen
29            | EventKind::ArrayTableOpen
30            | EventKind::InlineTableClose
31            | EventKind::SimpleKey
32            | EventKind::KeySep
33            | EventKind::KeyValSep
34            | EventKind::StdTableClose
35            | EventKind::ArrayTableClose => {
36                #[cfg(feature = "debug")]
37                trace(
38                    &format!("unexpected {event:?}"),
39                    anstyle::AnsiColor::Red.on_default(),
40                );
41                break;
42            }
43            EventKind::Error => {
44                #[cfg(feature = "debug")]
45                trace(
46                    &format!("unexpected {event:?}"),
47                    anstyle::AnsiColor::Red.on_default(),
48                );
49                continue;
50            }
51            EventKind::InlineTableOpen => {
52                let value = on_inline_table(event, input, source, errors);
53                state.capture_value(event, value);
54            }
55            EventKind::ArrayOpen => {
56                let value = on_array(event, input, source, errors);
57                state.capture_value(event, value);
58            }
59            EventKind::Scalar => {
60                let value = on_scalar(event, source, errors);
61                state.capture_value(event, value);
62            }
63            EventKind::ValueSep => {
64                state.finish_value(event, &mut result);
65                state.sep_value(event);
66            }
67            EventKind::Whitespace | EventKind::Comment | EventKind::Newline => {
68                state.whitespace(event);
69            }
70            EventKind::ArrayClose => {
71                state.finish_value(event, &mut result);
72                state.close(open_event, event, &mut result);
73                break;
74            }
75        }
76    }
77
78    Value::Array(result)
79}
80
81#[derive(Default)]
82struct State {
83    current_prefix: Option<toml_parser::Span>,
84    current_value: Option<Value>,
85    trailing_start: Option<usize>,
86    current_suffix: Option<toml_parser::Span>,
87}
88
89impl State {
90    fn open(&mut self, open_event: &toml_parser::parser::Event) {
91        self.trailing_start = Some(open_event.span().end());
92    }
93
94    fn whitespace(&mut self, event: &toml_parser::parser::Event) {
95        let decor = if self.is_prefix() {
96            self.current_prefix.get_or_insert(event.span())
97        } else {
98            self.current_suffix.get_or_insert(event.span())
99        };
100        *decor = decor.append(event.span());
101    }
102
103    fn is_prefix(&self) -> bool {
104        self.current_value.is_none()
105    }
106
107    fn capture_value(&mut self, event: &toml_parser::parser::Event, value: Value) {
108        self.trailing_start = None;
109        self.current_prefix
110            .get_or_insert_with(|| event.span().before());
111        self.current_value = Some(value);
112    }
113
114    fn finish_value(&mut self, event: &toml_parser::parser::Event, result: &mut Array) {
115        #[cfg(feature = "debug")]
116        let _scope = TraceScope::new("array::finish_value");
117        if let Some(mut value) = self.current_value.take() {
118            let prefix = self
119                .current_prefix
120                .take()
121                .expect("setting a value should set a prefix");
122            let suffix = self
123                .current_suffix
124                .take()
125                .unwrap_or_else(|| event.span().before());
126            let decor = value.decor_mut();
127            decor.set_prefix(RawString::with_span(prefix.start()..prefix.end()));
128            decor.set_suffix(RawString::with_span(suffix.start()..suffix.end()));
129            result.push_formatted(value);
130        }
131    }
132
133    fn sep_value(&mut self, event: &toml_parser::parser::Event) {
134        self.trailing_start = Some(event.span().end());
135    }
136
137    fn close(
138        &mut self,
139        open_event: &toml_parser::parser::Event,
140        close_event: &toml_parser::parser::Event,
141        result: &mut Array,
142    ) {
143        #[cfg(feature = "debug")]
144        let _scope = TraceScope::new("array::close");
145        let trailing_comma = self.trailing_start.is_some() && !result.is_empty();
146        let span = open_event.span().append(close_event.span());
147        let trailing_start = self
148            .trailing_start
149            .unwrap_or_else(|| close_event.span().start());
150        let trailing_end = close_event.span().start();
151
152        result.set_trailing_comma(trailing_comma);
153        result.set_trailing(RawString::with_span(trailing_start..trailing_end));
154        result.span = Some(span.start()..span.end());
155    }
156}