1 use winnow::combinator::cut_err;
2 use winnow::combinator::delimited;
3 use winnow::combinator::separated;
4 use winnow::combinator::trace;
5 use winnow::token::one_of;
6
7 use crate::key::Key;
8 use crate::parser::error::CustomError;
9 use crate::parser::key::key;
10 use crate::parser::prelude::*;
11 use crate::parser::trivia::ws;
12 use crate::parser::value::value;
13 use crate::table::TableKeyValue;
14 use crate::{InlineTable, InternalString, Item, RawString, Value};
15
16 use indexmap::map::Entry;
17
18 // ;; Inline Table
19
20 // inline-table = inline-table-open inline-table-keyvals inline-table-close
inline_table<'i>(input: &mut Input<'i>) -> PResult<InlineTable>21 pub(crate) fn inline_table<'i>(input: &mut Input<'i>) -> PResult<InlineTable> {
22 trace("inline-table", move |input: &mut Input<'i>| {
23 delimited(
24 INLINE_TABLE_OPEN,
25 cut_err(inline_table_keyvals.try_map(|(kv, p)| table_from_pairs(kv, p))),
26 cut_err(INLINE_TABLE_CLOSE)
27 .context(StrContext::Label("inline table"))
28 .context(StrContext::Expected(StrContextValue::CharLiteral('}'))),
29 )
30 .parse_next(input)
31 })
32 .parse_next(input)
33 }
34
table_from_pairs( v: Vec<(Vec<Key>, TableKeyValue)>, preamble: RawString, ) -> Result<InlineTable, CustomError>35 fn table_from_pairs(
36 v: Vec<(Vec<Key>, TableKeyValue)>,
37 preamble: RawString,
38 ) -> Result<InlineTable, CustomError> {
39 let mut root = InlineTable::new();
40 root.set_preamble(preamble);
41 // Assuming almost all pairs will be directly in `root`
42 root.items.reserve(v.len());
43
44 for (path, kv) in v {
45 let table = descend_path(&mut root, &path)?;
46
47 // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed"
48 let mixed_table_types = table.is_dotted() == path.is_empty();
49 if mixed_table_types {
50 return Err(CustomError::DuplicateKey {
51 key: kv.key.get().into(),
52 table: None,
53 });
54 }
55
56 let key: InternalString = kv.key.get_internal().into();
57 match table.items.entry(key) {
58 Entry::Vacant(o) => {
59 o.insert(kv);
60 }
61 Entry::Occupied(o) => {
62 return Err(CustomError::DuplicateKey {
63 key: o.key().as_str().into(),
64 table: None,
65 });
66 }
67 }
68 }
69 Ok(root)
70 }
71
descend_path<'a>( mut table: &'a mut InlineTable, path: &'a [Key], ) -> Result<&'a mut InlineTable, CustomError>72 fn descend_path<'a>(
73 mut table: &'a mut InlineTable,
74 path: &'a [Key],
75 ) -> Result<&'a mut InlineTable, CustomError> {
76 let dotted = !path.is_empty();
77 for (i, key) in path.iter().enumerate() {
78 let entry = table.entry_format(key).or_insert_with(|| {
79 let mut new_table = InlineTable::new();
80 new_table.set_implicit(dotted);
81 new_table.set_dotted(dotted);
82
83 Value::InlineTable(new_table)
84 });
85 match *entry {
86 Value::InlineTable(ref mut sweet_child_of_mine) => {
87 // Since tables cannot be defined more than once, redefining such tables using a
88 // [table] header is not allowed. Likewise, using dotted keys to redefine tables
89 // already defined in [table] form is not allowed.
90 if dotted && !sweet_child_of_mine.is_implicit() {
91 return Err(CustomError::DuplicateKey {
92 key: key.get().into(),
93 table: None,
94 });
95 }
96 table = sweet_child_of_mine;
97 }
98 ref v => {
99 return Err(CustomError::extend_wrong_type(path, i, v.type_name()));
100 }
101 }
102 }
103 Ok(table)
104 }
105
106 // inline-table-open = %x7B ws ; {
107 pub(crate) const INLINE_TABLE_OPEN: u8 = b'{';
108 // inline-table-close = ws %x7D ; }
109 const INLINE_TABLE_CLOSE: u8 = b'}';
110 // inline-table-sep = ws %x2C ws ; , Comma
111 const INLINE_TABLE_SEP: u8 = b',';
112 // keyval-sep = ws %x3D ws ; =
113 pub(crate) const KEYVAL_SEP: u8 = b'=';
114
115 // inline-table-keyvals = [ inline-table-keyvals-non-empty ]
116 // inline-table-keyvals-non-empty =
117 // ( key keyval-sep val inline-table-sep inline-table-keyvals-non-empty ) /
118 // ( key keyval-sep val )
119
inline_table_keyvals( input: &mut Input<'_>, ) -> PResult<(Vec<(Vec<Key>, TableKeyValue)>, RawString)>120 fn inline_table_keyvals(
121 input: &mut Input<'_>,
122 ) -> PResult<(Vec<(Vec<Key>, TableKeyValue)>, RawString)> {
123 (
124 separated(0.., keyval, INLINE_TABLE_SEP),
125 ws.span().map(RawString::with_span),
126 )
127 .parse_next(input)
128 }
129
keyval(input: &mut Input<'_>) -> PResult<(Vec<Key>, TableKeyValue)>130 fn keyval(input: &mut Input<'_>) -> PResult<(Vec<Key>, TableKeyValue)> {
131 (
132 key,
133 cut_err((
134 one_of(KEYVAL_SEP)
135 .context(StrContext::Expected(StrContextValue::CharLiteral('.')))
136 .context(StrContext::Expected(StrContextValue::CharLiteral('='))),
137 (ws.span(), value, ws.span()),
138 )),
139 )
140 .map(|(key, (_, v))| {
141 let mut path = key;
142 let key = path.pop().expect("grammar ensures at least 1");
143
144 let (pre, v, suf) = v;
145 let pre = RawString::with_span(pre);
146 let suf = RawString::with_span(suf);
147 let v = v.decorated(pre, suf);
148 (
149 path,
150 TableKeyValue {
151 key,
152 value: Item::Value(v),
153 },
154 )
155 })
156 .parse_next(input)
157 }
158
159 #[cfg(test)]
160 #[cfg(feature = "parse")]
161 #[cfg(feature = "display")]
162 mod test {
163 use super::*;
164
165 #[test]
inline_tables()166 fn inline_tables() {
167 let inputs = [
168 r#"{}"#,
169 r#"{ }"#,
170 r#"{a = 1e165}"#,
171 r#"{ hello = "world", a = 1}"#,
172 r#"{ hello.world = "a" }"#,
173 ];
174 for input in inputs {
175 dbg!(input);
176 let mut parsed = inline_table.parse(new_input(input));
177 if let Ok(parsed) = &mut parsed {
178 parsed.despan(input);
179 }
180 assert_eq!(parsed.map(|a| a.to_string()), Ok(input.to_owned()));
181 }
182 }
183
184 #[test]
invalid_inline_tables()185 fn invalid_inline_tables() {
186 let invalid_inputs = [r#"{a = 1e165"#, r#"{ hello = "world", a = 2, hello = 1}"#];
187 for input in invalid_inputs {
188 dbg!(input);
189 let mut parsed = inline_table.parse(new_input(input));
190 if let Ok(parsed) = &mut parsed {
191 parsed.despan(input);
192 }
193 assert!(parsed.is_err());
194 }
195 }
196 }
197