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