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::error::FromExternalError;
9use winnow::token::any;
10use winnow::token::one_of;
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 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
56 .into_inner()
57 .into_document()
58 .map(|document| (i, document))
59 .map_err(|err| {
60 winnow::error::ErrMode::Backtrack(ParserError::from_external_error(
61 i,
62 winnow::error::ErrorKind::Verify,
63 err,
64 ))
65 })
66}
67
68pub(crate) fn parse_comment<'s, 'i>(
69 state: &'s RefCell<ParseState>,
70) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'_>> + 's {
71 move |i: Located<&BStr>| {
72 (comment, line_ending)
73 .span()
74 .map(|span| {
75 state.borrow_mut().on_comment(span);
76 })
77 .parse_next(input:i)
78 }
79}
80
81pub(crate) fn parse_ws<'s, 'i>(
82 state: &'s RefCell<ParseState>,
83) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's {
84 move |i: Located<&BStr>| {
85 ws.span()
86 .map(|span| state.borrow_mut().on_ws(span))
87 .parse_next(input:i)
88 }
89}
90
91pub(crate) fn parse_newline<'s, 'i>(
92 state: &'s RefCell<ParseState>,
93) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's {
94 move |i: Located<&BStr>| {
95 newline
96 .span()
97 .map(|span| state.borrow_mut().on_ws(span))
98 .parse_next(input:i)
99 }
100}
101
102pub(crate) fn keyval<'s, 'i>(
103 state: &'s RefCell<ParseState>,
104) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's {
105 move |i: Located<&BStr>| {
106 parse_keyval
107 .try_map(|(p, kv)| state.borrow_mut().on_keyval(p, kv))
108 .parse_next(input:i)
109 }
110}
111
112// keyval = key keyval-sep val
113pub(crate) fn parse_keyval(
114 input: Input<'_>,
115) -> IResult<Input<'_>, (Vec<Key>, TableKeyValue), ParserError<'_>> {
116 (
117 key,
118 cut_err((
119 one_of(KEYVAL_SEP)
120 .context(Context::Expected(ParserValue::CharLiteral('.')))
121 .context(Context::Expected(ParserValue::CharLiteral('='))),
122 (
123 ws.span(),
124 value(RecursionCheck::default()),
125 line_trailing
126 .context(Context::Expected(ParserValue::CharLiteral('\n')))
127 .context(Context::Expected(ParserValue::CharLiteral('#'))),
128 ),
129 )),
130 )
131 .try_map::<_, _, std::str::Utf8Error>(|(key, (_, v))| {
132 let mut path = key;
133 let key = path.pop().expect("grammar ensures at least 1");
134
135 let (pre, v, suf) = v;
136 let pre = RawString::with_span(pre);
137 let suf = RawString::with_span(suf);
138 let v = v.decorated(pre, suf);
139 Ok((
140 path,
141 TableKeyValue {
142 key,
143 value: Item::Value(v),
144 },
145 ))
146 })
147 .parse_next(input)
148}
149