toml_edit/parser/
document.rs

1use std::cell::RefCell;
2
3use winnow::combinator::cut_err;
4use winnow::combinator::eof;
5use winnow::combinator::opt;
6use winnow::combinator::peek;
7use winnow::combinator::repeat;
8use winnow::token::any;
9use winnow::token::one_of;
10use winnow::trace::trace;
11
12use crate::document::Document;
13use crate::key::Key;
14use crate::parser::inline_table::KEYVAL_SEP;
15use crate::parser::key::key;
16use crate::parser::prelude::*;
17use crate::parser::state::ParseState;
18use crate::parser::table::table;
19use crate::parser::trivia::{comment, line_ending, line_trailing, newline, ws};
20use crate::parser::value::value;
21use crate::table::TableKeyValue;
22use crate::Item;
23use crate::RawString;
24
25// ;; TOML
26
27// toml = expression *( newline expression )
28
29// expression = ( ( ws comment ) /
30//                ( ws keyval ws [ comment ] ) /
31//                ( ws table ws [ comment ] ) /
32//                  ws )
33pub(crate) fn document(input: &mut Input<'_>) -> PResult<Document> {
34    let state = RefCell::new(ParseState::default());
35    let state_ref = &state;
36
37    let _o = (
38        // Remove BOM if present
39        opt(b"\xEF\xBB\xBF"),
40        parse_ws(state_ref),
41        repeat(0.., (
42            dispatch! {peek(any);
43                crate::parser::trivia::COMMENT_START_SYMBOL => cut_err(parse_comment(state_ref)),
44                crate::parser::table::STD_TABLE_OPEN => cut_err(table(state_ref)),
45                crate::parser::trivia::LF |
46                crate::parser::trivia::CR => parse_newline(state_ref),
47                _ => cut_err(keyval(state_ref)),
48            },
49            parse_ws(state_ref),
50        ))
51        .map(|()| ()),
52        eof,
53    )
54        .parse_next(input)?;
55    state.into_inner().into_document().map_err(|err| {
56        winnow::error::ErrMode::from_external_error(input, winnow::error::ErrorKind::Verify, err)
57    })
58}
59
60pub(crate) fn parse_comment<'s, 'i>(
61    state: &'s RefCell<ParseState>,
62) -> impl Parser<Input<'i>, (), ContextError> + 's {
63    move |i: &mut Input<'i>| {
64        (comment, line_ending)
65            .span()
66            .map(|span| {
67                state.borrow_mut().on_comment(span);
68            })
69            .parse_next(i)
70    }
71}
72
73pub(crate) fn parse_ws<'s, 'i>(
74    state: &'s RefCell<ParseState>,
75) -> impl Parser<Input<'i>, (), ContextError> + 's {
76    move |i: &mut Input<'i>| {
77        ws.span()
78            .map(|span| state.borrow_mut().on_ws(span))
79            .parse_next(i)
80    }
81}
82
83pub(crate) fn parse_newline<'s, 'i>(
84    state: &'s RefCell<ParseState>,
85) -> impl Parser<Input<'i>, (), ContextError> + 's {
86    move |i: &mut Input<'i>| {
87        newline
88            .span()
89            .map(|span| state.borrow_mut().on_ws(span))
90            .parse_next(i)
91    }
92}
93
94pub(crate) fn keyval<'s, 'i>(
95    state: &'s RefCell<ParseState>,
96) -> impl Parser<Input<'i>, (), ContextError> + 's {
97    move |i: &mut Input<'i>| {
98        parse_keyval
99            .try_map(|(p, kv)| state.borrow_mut().on_keyval(p, kv))
100            .parse_next(i)
101    }
102}
103
104// keyval = key keyval-sep val
105pub(crate) fn parse_keyval(input: &mut Input<'_>) -> PResult<(Vec<Key>, TableKeyValue)> {
106    trace(
107        "keyval",
108        (
109            key,
110            cut_err((
111                one_of(KEYVAL_SEP)
112                    .context(StrContext::Expected(StrContextValue::CharLiteral('.')))
113                    .context(StrContext::Expected(StrContextValue::CharLiteral('='))),
114                (
115                    ws.span(),
116                    value(RecursionCheck::default()),
117                    line_trailing
118                        .context(StrContext::Expected(StrContextValue::CharLiteral('\n')))
119                        .context(StrContext::Expected(StrContextValue::CharLiteral('#'))),
120                ),
121            )),
122        )
123            .try_map::<_, _, std::str::Utf8Error>(|(key, (_, v))| {
124                let mut path = key;
125                let key = path.pop().expect("grammar ensures at least 1");
126
127                let (pre, v, suf) = v;
128                let pre = RawString::with_span(pre);
129                let suf = RawString::with_span(suf);
130                let v = v.decorated(pre, suf);
131                Ok((
132                    path,
133                    TableKeyValue {
134                        key,
135                        value: Item::Value(v),
136                    },
137                ))
138            }),
139    )
140    .parse_next(input)
141}