aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-12-11 22:29:27 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-12-11 22:30:32 -0800
commitf9408377c9b42898cf95c01e23a573ee1667c34b (patch)
tree61468cf7680b375a003395b30a921ae911a05f39 /src
parent25e10a82565d81b5243304c835d868a12b179557 (diff)
downloadmilf-rs-f9408377c9b42898cf95c01e23a573ee1667c34b.tar.gz
milf-rs-f9408377c9b42898cf95c01e23a573ee1667c34b.zip
Fix parsing nested tables in arrays
Closes #36
Diffstat (limited to 'src')
-rw-r--r--src/parser.rs80
-rw-r--r--src/serialization.rs1
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<String>,
/// 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.