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(input: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(input: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(input: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(input: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}
142