Skip to content

Commit

Permalink
feat: Support for parsing inline dotted keys (#155)
Browse files Browse the repository at this point in the history
This is a step towards #91
  • Loading branch information
epage authored Sep 2, 2021
1 parent 145e14c commit ba74f3c
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 28 deletions.
71 changes: 49 additions & 22 deletions src/parser/inline_table.rs
Original file line number Diff line number Diff line change
@@ -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::*;
Expand All @@ -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<TableKeyValue>) -> Result<InlineTable, CustomError> {
let mut table = InlineTable {
fn table_from_pairs(
v: Vec<(Vec<Key>, TableKeyValue)>,
preamble: &str,
) -> Result<InlineTable, CustomError> {
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(),
Expand All @@ -33,7 +38,29 @@ fn table_from_pairs(preamble: &str, v: Vec<TableKeyValue>) -> Result<InlineTable
}
table.items.insert(kv.key.get().to_owned(), kv);
}
Ok(table)
Ok(root)
}

fn descend_path<'a>(
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 ; {
Expand All @@ -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<TableKeyValue>), {
parse!(inline_table_keyvals() -> (Vec<(Vec<Key>, TableKeyValue)>, &'a str), {
(
sep_by(keyval(), char(INLINE_TABLE_SEP)),
ws(),
).map(|(v, w)| {
(w, v)
})
)
});

parse!(keyval() -> TableKeyValue, {
parse!(keyval() -> (Vec<Key>, 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),
}
)
})
});
4 changes: 2 additions & 2 deletions src/parser/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ use vec1::Vec1;
// dotted-key = simple-key 1*( dot-sep simple-key )
parse!(key() -> Vec1<Key>, {
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)
Expand Down
5 changes: 1 addition & 4 deletions tests/decoder_compliance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down

0 comments on commit ba74f3c

Please sign in to comment.