From ab041291fb1d806fc1e9c09ecac4a931289bd38f Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Tue, 17 Jan 2017 11:26:45 -0800 Subject: [PATCH] edn: Bound values by optional whitespace; treat comma as whitespace. --- edn/src/edn.rustpeg | 21 +++++++++++++-------- edn/tests/tests.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/edn/src/edn.rustpeg b/edn/src/edn.rustpeg index 6de00f05..6ab5df2c 100644 --- a/edn/src/edn.rustpeg +++ b/edn/src/edn.rustpeg @@ -104,26 +104,26 @@ keyword -> Value } #[export] -list -> Value = "(" __ v:(__ value)* __ ")" { +list -> Value = "(" v:(value)* ")" { Value::List(LinkedList::from_iter(v)) } #[export] -vector -> Value = "[" __ v:(__ value)* __ "]" { +vector -> Value = "[" v:(value)* "]" { Value::Vector(v) } #[export] -set -> Value = "#{" __ v:(__ value)* __ "}" { +set -> Value = "#{" v:(value)* "}" { Value::Set(BTreeSet::from_iter(v)) } -pair -> (Value, Value) = k:(value) " " v:(value) ", "? { +pair -> (Value, Value) = k:(value) v:(value) { (k, v) } #[export] -map -> Value = "{" __ v:(pair)* __ "}" { +map -> Value = "{" v:(pair)* "}" { Value::Map(BTreeMap::from_iter(v)) } @@ -131,11 +131,16 @@ map -> Value = "{" __ v:(pair)* __ "}" { // floats are integers and fails to parse #[export] value -> Value - = nil / boolean / float / bigint / integer / text / + = __ v:(nil / boolean / float / bigint / integer / text / keyword / symbol / - list / vector / map / set + list / vector / map / set) __ { + v +} + +// Clojure (and thus EDN) regards commas as whitespace, and thus the two-element vectors [1 2] and +// [1,,,,2] are equivalent, as are the maps {:a 1, :b 2} and {:a 1 :b 2}. +whitespace = (" " / "\r" / "\n" / "\t" / ",") -whitespace = (" " / "\r" / "\n" / "\t") comment = ";" [^\r\n]* ("\r" / "\n")? __ = (whitespace / comment)* diff --git a/edn/tests/tests.rs b/edn/tests/tests.rs index a8cbb918..ade8c7b1 100644 --- a/edn/tests/tests.rs +++ b/edn/tests/tests.rs @@ -809,6 +809,47 @@ fn test_comments() { assert_eq!(value(";\n0"), result); assert_eq!(value(";\r0"), result); } + +#[test] +fn test_whitespace() { + let result = Ok(Value::Vector(vec![Value::Integer(1)])); + assert_eq!(value(" [1]"), result); + assert_eq!(value("[1] "), result); + assert_eq!(value(" [ 1 ] "), result); +} + +#[test] +fn test_inner_whitespace() { + let result = Ok(Value::Vector(vec![Value::Vector(vec![Value::Integer(1)])])); + assert_eq!(value("[ [1]]"), result); + assert_eq!(value("[ [1] ]"), result); + assert_eq!(value("[[1] ]"), result); +} + +#[test] +fn test_commas() { + let result = Ok(Value::Vector(vec![Value::Integer(1), Value::Integer(2)])); + assert_eq!(value("[1,2]"), result); + assert_eq!(value("[1 ,2]"), result); + assert_eq!(value("[1 , 2]"), result); + assert_eq!(value("[1 ,2]"), result); + assert_eq!(value("[ 1,2]"), result); + assert_eq!(value("[1,2 ]"), result); +} + +#[test] +fn test_spurious_commas() { + let result = Ok(Value::Vector(vec![Value::Integer(3)])); + assert_eq!(value("[3,]"), result); + assert_eq!(value("[3 ,]"), result); + assert_eq!(value("[3 , ]"), result); + assert_eq!(value("[3, ]"), result); + assert_eq!(value("[,3]"), result); + assert_eq!(value("[,,3]"), result); + assert_eq!(value("[,3,]"), result); + assert_eq!(value("[3,,]"), result); +} + /* // Handy templates for creating test cases follow: