From ba74f3c1fb6680373f7bc53a9bc0e4252bf0ab64 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 2 Sep 2021 14:05:44 -0500 Subject: [PATCH] feat: Support for parsing inline dotted keys (#155) This is a step towards #91 --- src/parser/inline_table.rs | 71 +++++++++++++++++++++++++------------ src/parser/key.rs | 4 +-- tests/decoder_compliance.rs | 5 +-- 3 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/parser/inline_table.rs b/src/parser/inline_table.rs index a42309d0..83eb1c84 100644 --- a/src/parser/inline_table.rs +++ b/src/parser/inline_table.rs @@ -1,11 +1,12 @@ use crate::key::Key; use crate::parser::errors::CustomError; -use crate::parser::key::simple_key; +use crate::parser::key::key; +use crate::parser::table::duplicate_key; use crate::parser::trivia::ws; use crate::parser::value::value; -use crate::repr::{Decor, InternalString, Repr}; +use crate::repr::InternalString; use crate::table::TableKeyValue; -use crate::{InlineTable, Item}; +use crate::{InlineTable, Item, Value}; use combine::parser::char::char; use combine::stream::RangeStream; use combine::*; @@ -15,16 +16,20 @@ use combine::*; // inline-table = inline-table-open inline-table-keyvals inline-table-close parse!(inline_table() -> InlineTable, { between(char(INLINE_TABLE_OPEN), char(INLINE_TABLE_CLOSE), - inline_table_keyvals().and_then(|(p, v)| table_from_pairs(p, v))) + inline_table_keyvals().and_then(|(kv, p)| table_from_pairs(kv, p))) }); -fn table_from_pairs(preamble: &str, v: Vec) -> Result { - let mut table = InlineTable { +fn table_from_pairs( + v: Vec<(Vec, TableKeyValue)>, + preamble: &str, +) -> Result { + let mut root = InlineTable { preamble: InternalString::from(preamble), ..Default::default() }; - for kv in v { + for (path, kv) in v { + let table = descend_path(&mut root, &path, 0)?; if table.contains_key(kv.key.get()) { return Err(CustomError::DuplicateKey { key: kv.key.into(), @@ -33,7 +38,29 @@ fn table_from_pairs(preamble: &str, v: Vec) -> Result( + table: &'a mut InlineTable, + path: &'a [Key], + i: usize, +) -> Result<&'a mut InlineTable, CustomError> { + if let Some(key) = path.get(i) { + let entry = table.entry_format(key).or_insert_with(|| { + let new_table = InlineTable::new(); + + Value::InlineTable(new_table) + }); + match *entry { + Value::InlineTable(ref mut sweet_child_of_mine) => { + descend_path(sweet_child_of_mine, path, i + 1) + } + _ => Err(duplicate_key(path, i)), + } + } else { + Ok(table) + } } // inline-table-open = %x7B ws ; { @@ -50,30 +77,30 @@ pub(crate) const KEYVAL_SEP: char = '='; // ( key keyval-sep val inline-table-sep inline-table-keyvals-non-empty ) / // ( key keyval-sep val ) -parse!(inline_table_keyvals() -> (&'a str, Vec), { +parse!(inline_table_keyvals() -> (Vec<(Vec, TableKeyValue)>, &'a str), { ( sep_by(keyval(), char(INLINE_TABLE_SEP)), ws(), - ).map(|(v, w)| { - (w, v) - }) + ) }); -parse!(keyval() -> TableKeyValue, { +parse!(keyval() -> (Vec, TableKeyValue), { ( - attempt((ws(), simple_key(), ws())), + key(), char(KEYVAL_SEP), (ws(), value(), ws()), - ).map(|(k, _, v)| { - let (pre, (raw, key), suf) = k; - let key_decor = Decor::new(pre, suf); - let key = Key::new_unchecked(Repr::new_unchecked(raw), key, key_decor); + ).map(|(key, _, v)| { + let mut path = key.into_vec(); + let key = path.pop().expect("Was vec1, so at least one exists"); let (pre, v, suf) = v; let v = v.decorated(pre, suf); - TableKeyValue { - key, - value: Item::Value(v), - } + ( + path, + TableKeyValue { + key, + value: Item::Value(v), + } + ) }) }); diff --git a/src/parser/key.rs b/src/parser/key.rs index 8711fdc0..af757fe8 100644 --- a/src/parser/key.rs +++ b/src/parser/key.rs @@ -12,11 +12,11 @@ use vec1::Vec1; // dotted-key = simple-key 1*( dot-sep simple-key ) parse!(key() -> Vec1, { sep_by1( - ( + attempt(( ws(), simple_key(), ws(), - ).map(|(pre, (raw, key), suffix)| { + )).map(|(pre, (raw, key), suffix)| { Key::new_unchecked(Repr::new_unchecked(raw), key, Decor::new(pre, suffix)) }), char(DOT_SEP) diff --git a/tests/decoder_compliance.rs b/tests/decoder_compliance.rs index a8fbd62d..775b0faf 100644 --- a/tests/decoder_compliance.rs +++ b/tests/decoder_compliance.rs @@ -2,10 +2,7 @@ fn main() { let decoder = Decoder; let mut harness = toml_test_harness::DecoderHarness::new(decoder); harness - .ignore([ - "valid/inline-table/key-dotted.toml", - "valid/string/multiline-quotes.toml", - ]) + .ignore(["valid/string/multiline-quotes.toml"]) .unwrap(); harness.test(); }