1 | use std::cell::RefCell; |
2 | |
3 | use winnow::combinator::cut_err; |
4 | use winnow::combinator::eof; |
5 | use winnow::combinator::opt; |
6 | use winnow::combinator::peek; |
7 | use winnow::combinator::repeat; |
8 | use winnow::error::FromExternalError; |
9 | use winnow::token::any; |
10 | use winnow::token::one_of; |
11 | |
12 | use crate::document::Document; |
13 | use crate::key::Key; |
14 | use crate::parser::inline_table::KEYVAL_SEP; |
15 | use crate::parser::key::key; |
16 | use crate::parser::prelude::*; |
17 | use crate::parser::state::ParseState; |
18 | use crate::parser::table::table; |
19 | use crate::parser::trivia::{comment, line_ending, line_trailing, newline, ws}; |
20 | use crate::parser::value::value; |
21 | use crate::table::TableKeyValue; |
22 | use crate::Item; |
23 | use 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 ) |
33 | pub(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 | |
68 | pub(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 | |
81 | pub(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 | |
91 | pub(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 | |
102 | pub(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 |
113 | pub(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 | |