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