toml_edit/parser/
key.rs

1use crate::key::Key;
2use crate::parser::prelude::*;
3use crate::repr::Decor;
4use crate::repr::Repr;
5use crate::RawString;
6
7/// ```bnf
8/// key = simple-key / dotted-key
9/// dotted-key = simple-key 1*( dot-sep simple-key )
10/// ```
11pub(crate) fn on_key(
12    key_event: &toml_parser::parser::Event,
13    input: &mut Input<'_>,
14    source: toml_parser::Source<'_>,
15    errors: &mut dyn ErrorSink,
16) -> (Vec<Key>, Option<Key>) {
17    #[cfg(feature = "debug")]
18    let _scope = TraceScope::new("key::on_key");
19    let mut result_path = Vec::new();
20    let mut result_key = None;
21
22    let mut state = State::new(key_event);
23    if more_key(input) {
24        while let Some(event) = input.next_token() {
25            match event.kind() {
26                EventKind::StdTableOpen
27                | EventKind::ArrayTableOpen
28                | EventKind::InlineTableOpen
29                | EventKind::InlineTableClose
30                | EventKind::ArrayOpen
31                | EventKind::ArrayClose
32                | EventKind::Scalar
33                | EventKind::ValueSep
34                | EventKind::Comment
35                | EventKind::Newline
36                | EventKind::KeyValSep
37                | EventKind::StdTableClose
38                | EventKind::ArrayTableClose
39                | EventKind::Error => {
40                    #[cfg(feature = "debug")]
41                    trace(
42                        &format!("unexpected {event:?}"),
43                        anstyle::AnsiColor::Red.on_default(),
44                    );
45                    continue;
46                }
47                EventKind::SimpleKey => {
48                    state.current_key = Some(*event);
49
50                    if !more_key(input) {
51                        break;
52                    }
53                }
54                EventKind::Whitespace => {
55                    state.whitespace(event);
56                }
57                EventKind::KeySep => {
58                    state.close_key(&mut result_path, &mut result_key, source, errors);
59                }
60            }
61        }
62    }
63
64    state.close_key(&mut result_path, &mut result_key, source, errors);
65
66    #[cfg(not(feature = "unbounded"))]
67    if super::LIMIT <= result_path.len() as u32 {
68        errors.report_error(ParseError::new("recursion limit"));
69        return (Vec::new(), None);
70    }
71
72    (result_path, result_key)
73}
74
75fn more_key(input: &Input<'_>) -> bool {
76    let first = input.get(0).map(|e| e.kind());
77    let second = input.get(1).map(|e| e.kind());
78    if first == Some(EventKind::KeySep) {
79        true
80    } else if first == Some(EventKind::Whitespace) && second == Some(EventKind::KeySep) {
81        true
82    } else {
83        false
84    }
85}
86
87struct State {
88    current_prefix: Option<toml_parser::Span>,
89    current_key: Option<toml_parser::parser::Event>,
90    current_suffix: Option<toml_parser::Span>,
91}
92
93impl State {
94    fn new(key_event: &toml_parser::parser::Event) -> Self {
95        Self {
96            current_prefix: None,
97            current_key: Some(*key_event),
98            current_suffix: None,
99        }
100    }
101
102    fn whitespace(&mut self, event: &toml_parser::parser::Event) {
103        if self.current_key.is_some() {
104            self.current_suffix = Some(event.span());
105        } else {
106            self.current_prefix = Some(event.span());
107        }
108    }
109
110    fn close_key(
111        &mut self,
112        result_path: &mut Vec<Key>,
113        result_key: &mut Option<Key>,
114        source: toml_parser::Source<'_>,
115        errors: &mut dyn ErrorSink,
116    ) {
117        let Some(key) = self.current_key.take() else {
118            return;
119        };
120        let prefix_span = self
121            .current_prefix
122            .take()
123            .unwrap_or_else(|| key.span().before());
124        let prefix = RawString::with_span(prefix_span.start()..prefix_span.end());
125
126        let suffix_span = self
127            .current_suffix
128            .take()
129            .unwrap_or_else(|| key.span().after());
130        let suffix = RawString::with_span(suffix_span.start()..suffix_span.end());
131
132        let key_span = key.span();
133        let key_raw = RawString::with_span(key_span.start()..key_span.end());
134
135        let raw = source.get(key).unwrap();
136        let mut decoded = std::borrow::Cow::Borrowed("");
137        raw.decode_key(&mut decoded, errors);
138
139        let key = Key::new(decoded)
140            .with_repr_unchecked(Repr::new_unchecked(key_raw))
141            .with_dotted_decor(Decor::new(prefix, suffix));
142        if let Some(last_key) = result_key.replace(key) {
143            result_path.push(last_key);
144        }
145    }
146}
147
148/// ```bnf
149/// simple-key = quoted-key / unquoted-key
150/// quoted-key = basic-string / literal-string
151/// ```
152pub(crate) fn on_simple_key(
153    event: &toml_parser::parser::Event,
154    source: toml_parser::Source<'_>,
155    errors: &mut dyn ErrorSink,
156) -> (RawString, String) {
157    #[cfg(feature = "debug")]
158    let _scope = TraceScope::new("key::on_simple_key");
159    let raw = source.get(event).unwrap();
160
161    let mut key = std::borrow::Cow::Borrowed("");
162    raw.decode_key(&mut key, errors);
163
164    let span = event.span();
165    let raw = RawString::with_span(span.start()..span.end());
166    let key = String::from(key);
167    (raw, key)
168}