toml_edit/parser/
document.rs

1use std::cell::RefCell;
2
3use nom8::bytes::any;
4use nom8::bytes::one_of;
5use nom8::combinator::cut;
6use nom8::combinator::eof;
7use nom8::combinator::opt;
8use nom8::combinator::peek;
9use nom8::error::FromExternalError;
10use nom8::multi::many0_count;
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: Input<'_>) -> IResult<Input<'_>, Document, ParserError<'_>> {
34    let state = RefCell::new(ParseState::default());
35    let state_ref = &state;
36
37    let (i, _o) = (
38        // Remove BOM if present
39        opt(b"\xEF\xBB\xBF"),
40        parse_ws(state_ref),
41        many0_count((
42            dispatch! {peek(any);
43                crate::parser::trivia::COMMENT_START_SYMBOL => cut(parse_comment(state_ref)),
44                crate::parser::table::STD_TABLE_OPEN => cut(table(state_ref)),
45                crate::parser::trivia::LF |
46                crate::parser::trivia::CR => parse_newline(state_ref),
47                _ => cut(keyval(state_ref)),
48            },
49            parse_ws(state_ref),
50        )),
51        eof,
52    )
53        .parse(input)?;
54    state
55        .into_inner()
56        .into_document()
57        .map(|document| (i, document))
58        .map_err(|err| {
59            nom8::Err::Error(ParserError::from_external_error(
60                i,
61                nom8::error::ErrorKind::MapRes,
62                err,
63            ))
64        })
65}
66
67pub(crate) fn parse_comment<'s, 'i>(
68    state: &'s RefCell<ParseState>,
69) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'_>> + 's {
70    move |i| {
71        (comment, line_ending)
72            .span()
73            .map(|span| {
74                state.borrow_mut().on_comment(span);
75            })
76            .parse(i)
77    }
78}
79
80pub(crate) fn parse_ws<'s, 'i>(
81    state: &'s RefCell<ParseState>,
82) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's {
83    move |i| {
84        ws.span()
85            .map(|span| state.borrow_mut().on_ws(span))
86            .parse(i)
87    }
88}
89
90pub(crate) fn parse_newline<'s, 'i>(
91    state: &'s RefCell<ParseState>,
92) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's {
93    move |i| {
94        newline
95            .span()
96            .map(|span| state.borrow_mut().on_ws(span))
97            .parse(i)
98    }
99}
100
101pub(crate) fn keyval<'s, 'i>(
102    state: &'s RefCell<ParseState>,
103) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's {
104    move |i| {
105        parse_keyval
106            .map_res(|(p, kv)| state.borrow_mut().on_keyval(p, kv))
107            .parse(i)
108    }
109}
110
111// keyval = key keyval-sep val
112pub(crate) fn parse_keyval(
113    input: Input<'_>,
114) -> IResult<Input<'_>, (Vec<Key>, TableKeyValue), ParserError<'_>> {
115    (
116        key,
117        cut((
118            one_of(KEYVAL_SEP)
119                .context(Context::Expected(ParserValue::CharLiteral('.')))
120                .context(Context::Expected(ParserValue::CharLiteral('='))),
121            (
122                ws.span(),
123                value(RecursionCheck::default()),
124                line_trailing
125                    .context(Context::Expected(ParserValue::CharLiteral('\n')))
126                    .context(Context::Expected(ParserValue::CharLiteral('#'))),
127            ),
128        )),
129    )
130        .map_res::<_, _, std::str::Utf8Error>(|(key, (_, v))| {
131            let mut path = key;
132            let key = path.pop().expect("grammar ensures at least 1");
133
134            let (pre, v, suf) = v;
135            let pre = RawString::with_span(pre);
136            let suf = RawString::with_span(suf);
137            let v = v.decorated(pre, suf);
138            Ok((
139                path,
140                TableKeyValue {
141                    key,
142                    value: Item::Value(v),
143                },
144            ))
145        })
146        .parse(input)
147}