From f9408377c9b42898cf95c01e23a573ee1667c34b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Dec 2014 22:29:27 -0800 Subject: Fix parsing nested tables in arrays Closes #36 --- src/parser.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++-------- src/serialization.rs | 1 + 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 892f173..d21b304 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,5 @@ use std::char; -use std::collections::{TreeMap, HashSet}; +use std::collections::TreeMap; use std::error::Error; use std::num::FromStrRadix; use std::str; @@ -14,7 +14,6 @@ use Value::{mod, Array, Table, Float, Integer, Boolean, Datetime}; pub struct Parser<'a> { input: &'a str, cur: str::CharOffsets<'a>, - tables_defined: HashSet, /// A list of all errors which have occurred during parsing. /// @@ -64,7 +63,6 @@ impl<'a> Parser<'a> { input: s, cur: s.char_indices(), errors: Vec::new(), - tables_defined: HashSet::new(), } } @@ -690,25 +688,26 @@ impl<'a> Parser<'a> { fn insert_table(&mut self, into: &mut TomlTable, key: String, value: TomlTable, key_lo: uint) { - if !self.tables_defined.insert(key.clone()) { - self.errors.push(ParserError { - lo: key_lo, - hi: key_lo + key.len(), - desc: format!("redefinition of table `{}`", key), - }); - return - } - let (into, key) = match self.recurse(into, key.as_slice(), key_lo) { Some(pair) => pair, None => return, }; let key = key.to_string(); + let mut added = false; if !into.contains_key(&key) { into.insert(key.clone(), Table(TreeMap::new())); + added = true; } match into.get_mut(&key) { Some(&Table(ref mut table)) => { + let any_tables = table.values().any(|v| v.as_table().is_some()); + if !any_tables && !added { + self.errors.push(ParserError { + lo: key_lo, + hi: key_lo + key.len(), + desc: format!("redefinition of table `{}`", key), + }); + } for (k, v) in value.into_iter() { if table.insert(k.clone(), v).is_some() { self.errors.push(ParserError { @@ -875,4 +874,61 @@ trimmed in raw strings. All other whitespace\n \ is preserved.\n")); } + + #[test] + fn tables_in_arrays() { + let mut p = Parser::new(r#" +[[foo]] + #… + [foo.bar] + #… + +[[foo]] + #… + [foo.bar] + #... +"#); + let table = Table(p.parse().unwrap()); + table.lookup("foo.0.bar").unwrap().as_table().unwrap(); + table.lookup("foo.1.bar").unwrap().as_table().unwrap(); + } + + #[test] + fn fruit() { + let mut p = Parser::new(r#" +[[fruit]] + name = "apple" + + [fruit.physical] + color = "red" + shape = "round" + + [[fruit.variety]] + name = "red delicious" + + [[fruit.variety]] + name = "granny smith" + +[[fruit]] + name = "banana" + + [[fruit.variety]] + name = "plantain" +"#); + let table = Table(p.parse().unwrap()); + assert_eq!(table.lookup("fruit.0.name").and_then(|k| k.as_str()), + Some("apple")); + assert_eq!(table.lookup("fruit.0.physical.color").and_then(|k| k.as_str()), + Some("red")); + assert_eq!(table.lookup("fruit.0.physical.shape").and_then(|k| k.as_str()), + Some("round")); + assert_eq!(table.lookup("fruit.0.variety.0.name").and_then(|k| k.as_str()), + Some("red delicious")); + assert_eq!(table.lookup("fruit.0.variety.1.name").and_then(|k| k.as_str()), + Some("granny smith")); + assert_eq!(table.lookup("fruit.1.name").and_then(|k| k.as_str()), + Some("banana")); + assert_eq!(table.lookup("fruit.1.variety.0.name").and_then(|k| k.as_str()), + Some("plantain")); + } } diff --git a/src/serialization.rs b/src/serialization.rs index ba96f89..457f361 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -64,6 +64,7 @@ pub struct Decoder { /// Enumeration of errors which can occur while encoding a rust value into a /// TOML value. +#[allow(missing_copy_implementations)] pub enum Error { /// Indication that a key was needed when a value was emitted, but no key /// was previously emitted. -- cgit v1.2.3