From 7b204334768d2c35747abbeb0bf486d635e64d55 Mon Sep 17 00:00:00 2001 From: jiyinyiyong Date: Thu, 15 Apr 2021 20:33:25 +0800 Subject: [PATCH 1/4] transforming code, passed type checking --- Cargo.toml | 1 + src/lib.rs | 210 +++++++++++++++++++++++- src/primes.rs | 4 +- tests/{writer_tests.rs => edn_tests.rs} | 2 +- 4 files changed, 209 insertions(+), 8 deletions(-) rename tests/{writer_tests.rs => edn_tests.rs} (66%) diff --git a/Cargo.toml b/Cargo.toml index aa73f0b..8767978 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ edition = "2018" [dependencies] cirru_parser = "0.0.6" +regex = "1.4.5" diff --git a/src/lib.rs b/src/lib.rs index ffd7613..6fee7f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,215 @@ mod primes; -use cirru_parser::{parse, write_cirru}; +use cirru_parser::{parse, write_cirru, CirruNode, CirruWriterOptions}; use primes::CirruEdn; use primes::CirruEdn::*; +use regex::Regex; +use std::collections::HashMap; + +use cirru_parser::CirruNode::*; /// TODO -pub fn parse_cirru_edn(s: String) -> CirruEdn { - CirruEdnNil +pub fn parse_cirru_edn(s: String) -> Result { + match parse(s) { + Ok(nodes) => match nodes { + CirruLeaf(_) => Err(String::from("Expected exprs")), + CirruList(xs) => { + if xs.len() == 1 { + match xs[0] { + CirruLeaf(_) => Err(String::from("Expected expr for data")), + CirruList(_) => extract_cirru_edn(&xs[0]), + } + } else { + Err(String::from("Expected 1 expr for edn")) + } + } + }, + Err(e) => Err(e), + } } -/// TODO +fn extract_cirru_edn(node: &CirruNode) -> Result { + match node { + CirruLeaf(s) => match s.as_str() { + "nil" => Ok(CirruEdnNil), + "true" => Ok(CirruEdnBool(true)), + "false" => Ok(CirruEdnBool(false)), + "" => Err(String::from("Empty string is invalid")), + s1 => match s1.chars().nth(0).unwrap() { + '\'' => Ok(CirruEdnSymbol(String::from(&s1[1..]))), + ':' => Ok(CirruEdnKeyword(String::from(&s1[1..]))), + '"' | '|' => Ok(CirruEdnString(String::from(&s1[1..]))), + _ => { + if matches_float(s1) { + let f: f32 = s1.parse().unwrap(); + Ok(CirruEdnNumber(f)) + } else { + Err(String::from("Unknown token")) + } + } + }, + }, + CirruList(xs) => { + if xs.len() == 0 { + Err(String::from("empty expr is invalid")) + } else { + match &xs[0] { + CirruLeaf(s) => match s.as_str() { + "quote" => { + if xs.len() == 2 { + Ok(CirruEdnQuote(xs[1].clone())) + } else { + Err(String::from("Missing quote value")) + } + } + "do" => { + if xs.len() == 2 { + extract_cirru_edn(&xs[1]) + } else { + Err(String::from("Missing do value")) + } + } + "[]" => { + let mut ys: Vec = vec![]; + for (idx, x) in xs.iter().enumerate() { + if idx > 0 { + match extract_cirru_edn(x) { + Ok(v) => ys.push(v), + Err(v) => return Err(v), + } + } + } + Ok(CirruEdnList(ys)) + } + "{}" => { + let mut zs: HashMap = HashMap::new(); + for (idx, x) in xs.iter().enumerate() { + if idx > 0 { + match x { + CirruLeaf(s) => return Err(format!("Invalid map entry: {}", s)), + CirruList(ys) => { + if ys.len() == 2 { + match (extract_cirru_edn(&ys[0]), extract_cirru_edn(&ys[1])) { + (Ok(k), Ok(v)) => { + zs.insert(k, v); + } + (e1, e2) => return Err(format!("invalid map entry: {:?} {:?}", e1, e2)), + } + } + } + } + } + } + Ok(CirruEdnMap(zs)) + } + "%{}" => { + if xs.len() >= 3 { + let name = match xs[1].clone() { + CirruLeaf(s) => s, + CirruList(e) => return Err(format!("expected record name in string: {:?}", e)), + }; + let mut fields: Vec = vec![]; + let mut values: Vec = vec![]; + for (idx, x) in xs.iter().enumerate() { + if idx > 1 { + match x { + CirruLeaf(s) => return Err(format!("Invalid record entry: {}", s)), + CirruList(ys) => { + if ys.len() == 2 { + match (&ys[0], extract_cirru_edn(&ys[1])) { + (CirruLeaf(s), Ok(v)) => { + fields.push(s.clone()); + values.push(v); + } + (e1, e2) => { + return Err(format!("invalid map entry: {:?} {:?}", e1, e2)) + } + } + } + } + } + } + } + Ok(CirruEdnRecord(name, fields, values)) + } else { + Err(format!("Not enough items for record")) + } + } + a => Err(format!("Invalid operator: {}", a)), + }, + CirruList(a) => Err(format!("Invalid operator: {:?}", a)), + } + } + } + } +} + +fn matches_float(x: &str) -> bool { + let re = Regex::new("^-?[\\d]+(\\.[\\d+]?)$").unwrap(); + re.is_match(x) +} + +fn assemble_cirru_node(data: &CirruEdn) -> CirruNode { + match data { + CirruEdnNil => CirruLeaf(String::from("nil")), + CirruEdnBool(v) => CirruLeaf(format!("{}", v)), + CirruEdnNumber(n) => CirruLeaf(format!("{}", n)), + CirruEdnSymbol(s) => CirruLeaf(format!("'{}", s)), + CirruEdnKeyword(s) => CirruLeaf(format!(":{}", s)), + CirruEdnString(s) => CirruLeaf(format!("|{}", s)), + CirruEdnQuote(v) => CirruList(vec![CirruLeaf(String::from("quote")), (*v).clone()]), + CirruEdnList(xs) => { + let mut ys: Vec = vec![CirruLeaf(String::from("[]"))]; + for x in xs { + ys.push(assemble_cirru_node(x)); + } + return CirruList(ys); + } + CirruEdnSet(xs) => { + let mut ys: Vec = vec![CirruLeaf(String::from("#{}"))]; + for x in xs { + ys.push(assemble_cirru_node(x)); + } + return CirruList(ys); + } + CirruEdnMap(xs) => { + let mut ys: Vec = vec![CirruLeaf(String::from("{}"))]; + for (k, v) in xs { + ys.push(CirruList(vec![ + assemble_cirru_node(k), + assemble_cirru_node(v), + ])) + } + CirruList(ys) + } + CirruEdnRecord(name, fields, values) => { + let mut ys: Vec = vec![ + CirruLeaf(String::from("%{}")), + CirruLeaf(String::from(name)), + ]; + for idx in 0..fields.len() { + let v = &values[idx]; + ys.push(CirruList(vec![ + CirruLeaf(fields[idx].clone()), + assemble_cirru_node(v), + ])); + } + + CirruList(ys) + } + } +} + +/// generate string fro, CirruEdn pub fn write_cirru_edn(data: CirruEdn) -> String { - String::from("TODO") + let options = CirruWriterOptions { use_inline: true }; + match assemble_cirru_node(&data) { + CirruLeaf(s) => write_cirru( + CirruList(vec![ + (CirruList(vec![CirruLeaf(String::from("do")), CirruLeaf(s)])), + ]), + options, + ), + CirruList(xs) => write_cirru(CirruList(vec![(CirruList(xs))]), options), + } } diff --git a/src/primes.rs b/src/primes.rs index 7e0e85c..aae8f4e 100644 --- a/src/primes.rs +++ b/src/primes.rs @@ -179,12 +179,12 @@ impl Ord for CirruEdn { (_, CirruEdnSet(_)) => Greater, (CirruEdnMap(a), CirruEdnMap(b)) => { - unreachable!("TODO maps are not cmp ed") // TODO + unreachable!(format!("TODO maps are not cmp ed {:?} {:?}", a, b)) // TODO } (CirruEdnMap(_), _) => Less, (_, CirruEdnMap(_)) => Greater, - (CirruEdnRecord(name1, fields1, values1), CirruEdnRecord(name2, fields2, values2)) => { + (CirruEdnRecord(_name1, _fields1, _values1), CirruEdnRecord(_name2, _fields2, _values2)) => { unreachable!("TODO records are not cmp ed") // TODO } } diff --git a/tests/writer_tests.rs b/tests/edn_tests.rs similarity index 66% rename from tests/writer_tests.rs rename to tests/edn_tests.rs index 661668f..8dba087 100644 --- a/tests/writer_tests.rs +++ b/tests/edn_tests.rs @@ -1,4 +1,4 @@ #[test] -fn it_works() { +fn parse_edn() { assert_eq!(2 + 2, 4); } From 24d2417d2e09c65265d76691f0ea6b289543d625 Mon Sep 17 00:00:00 2001 From: jiyinyiyong Date: Thu, 15 Apr 2021 21:32:54 +0800 Subject: [PATCH 2/4] add tests; preparing 0.0.1 --- Cargo.toml | 6 ++ README.md | 12 ++- src/lib.rs | 21 +++++- src/primes.rs | 2 +- tests/edn_tests.rs | 183 ++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 217 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8767978..1c0b0f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,12 @@ name = "cirru_edn" version = "0.0.1" authors = ["jiyinyiyong "] edition = "2018" +license = "MIT" +description = "Parser/Writer for Cirru EDN" +homepage = "http://cirru.org" +documentation = "https://docs.rs/crate/cirru_edn/" +repository = "https://github.com/Cirru/cirru_edn.rs" +readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 06ece3b..2a9b3f3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,17 @@ ### Usages -_TODO_ +```bash +cargo add cirru_edn +``` + +```rs +use cirru_edn::{parse_cirru_edn, write_cirru_edn, CirruEdn}; + +parse_cirru_edn(String::from("[] 1 2 true")); // Result + +write_cirru_edn(data); // String +``` ### License diff --git a/src/lib.rs b/src/lib.rs index 6fee7f6..75c7f41 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,11 @@ mod primes; use cirru_parser::{parse, write_cirru, CirruNode, CirruWriterOptions}; -use primes::CirruEdn; +pub use primes::CirruEdn; use primes::CirruEdn::*; use regex::Regex; use std::collections::HashMap; +use std::collections::HashSet; use cirru_parser::CirruNode::*; @@ -44,7 +45,7 @@ fn extract_cirru_edn(node: &CirruNode) -> Result { let f: f32 = s1.parse().unwrap(); Ok(CirruEdnNumber(f)) } else { - Err(String::from("Unknown token")) + Err(format!("Unknown token: {:?}", s1)) } } }, @@ -81,6 +82,20 @@ fn extract_cirru_edn(node: &CirruNode) -> Result { } Ok(CirruEdnList(ys)) } + "#{}" => { + let mut ys: HashSet = HashSet::new(); + for (idx, x) in xs.iter().enumerate() { + if idx > 0 { + match extract_cirru_edn(x) { + Ok(v) => { + ys.insert(v); + } + Err(v) => return Err(v), + } + } + } + Ok(CirruEdnSet(ys)) + } "{}" => { let mut zs: HashMap = HashMap::new(); for (idx, x) in xs.iter().enumerate() { @@ -145,7 +160,7 @@ fn extract_cirru_edn(node: &CirruNode) -> Result { } fn matches_float(x: &str) -> bool { - let re = Regex::new("^-?[\\d]+(\\.[\\d+]?)$").unwrap(); + let re = Regex::new("^-?[\\d]+(\\.[\\d]+)?$").unwrap(); // TODO special cases not handled re.is_match(x) } diff --git a/src/primes.rs b/src/primes.rs index aae8f4e..a124b3f 100644 --- a/src/primes.rs +++ b/src/primes.rs @@ -7,7 +7,7 @@ use std::collections::{HashMap, HashSet}; use std::fmt; use std::hash::{Hash, Hasher}; -#[derive(fmt::Debug)] +#[derive(fmt::Debug, Clone)] pub enum CirruEdn { CirruEdnNil, CirruEdnBool(bool), diff --git a/tests/edn_tests.rs b/tests/edn_tests.rs index 8dba087..5bfed2b 100644 --- a/tests/edn_tests.rs +++ b/tests/edn_tests.rs @@ -1,4 +1,183 @@ +use cirru_edn::CirruEdn; +use cirru_edn::CirruEdn::*; +use cirru_edn::{parse_cirru_edn, write_cirru_edn}; +use std::collections::HashSet; + #[test] -fn parse_edn() { - assert_eq!(2 + 2, 4); +fn edn_parsing() { + assert_eq!(Ok(CirruEdnNil), parse_cirru_edn(String::from("do nil"))); + assert_eq!( + Ok(CirruEdnBool(true)), + parse_cirru_edn(String::from("do true")) + ); + assert_eq!( + Ok(CirruEdnBool(false)), + parse_cirru_edn(String::from("do false")) + ); + + assert_eq!( + Ok(CirruEdnSymbol(String::from("a"))), + parse_cirru_edn(String::from("do 'a")) + ); + assert_eq!( + Ok(CirruEdnKeyword(String::from("k"))), + parse_cirru_edn(String::from("do :k")) + ); + assert_eq!( + Ok(CirruEdnString(String::from("s"))), + parse_cirru_edn(String::from("do |s")) + ); + + assert_eq!( + Ok(CirruEdnString(String::from("a b\n c"))), + parse_cirru_edn(String::from(r#"do "|a b\n c""#)) + ); + + assert_eq!( + Ok(CirruEdnNumber(2.0)), + parse_cirru_edn(String::from("do 2")) + ); + assert_eq!( + Ok(CirruEdnNumber(-2.2)), + parse_cirru_edn(String::from("do -2.2")) + ); +} + +#[test] +fn list_parsing() { + assert_eq!( + Ok(CirruEdnList( + vec![CirruEdnNumber(1.0), CirruEdnNumber(2.0),] + )), + parse_cirru_edn(String::from("[] 1 2")) + ); + assert_eq!( + Ok(CirruEdnList(vec![ + CirruEdnNumber(1.0), + CirruEdnNumber(2.0), + CirruEdnList(vec![CirruEdnNumber(3.0)]) + ])), + parse_cirru_edn(String::from("[] 1 2 $ [] 3")) + ); +} + +#[test] +fn set_parsing() { + let mut v: HashSet = HashSet::new(); + v.insert(CirruEdnKeyword(String::from("a"))); + v.insert(CirruEdnKeyword(String::from("b"))); + v.insert(CirruEdnKeyword(String::from("c"))); + assert_eq!( + Ok(CirruEdnSet(v)), + parse_cirru_edn(String::from("#{} :a :b :c")) + ); +} + +#[test] +fn edn_formatting() { + assert_eq!(write_cirru_edn(CirruEdnNil), "\ndo nil\n"); + assert_eq!(write_cirru_edn(CirruEdnBool(true)), "\ndo true\n"); + assert_eq!(write_cirru_edn(CirruEdnBool(false)), "\ndo false\n"); + + assert_eq!(write_cirru_edn(CirruEdnNumber(1.0)), "\ndo 1\n"); + assert_eq!(write_cirru_edn(CirruEdnNumber(1.1)), "\ndo 1.1\n"); + assert_eq!(write_cirru_edn(CirruEdnNumber(-1.1)), "\ndo -1.1\n"); + + assert_eq!( + write_cirru_edn(CirruEdnSymbol(String::from("a"))), + "\ndo 'a\n" + ); + assert_eq!( + write_cirru_edn(CirruEdnKeyword(String::from("a"))), + "\ndo :a\n" + ); + assert_eq!( + write_cirru_edn(CirruEdnString(String::from("a"))), + "\ndo |a\n" + ); + assert_eq!( + write_cirru_edn(CirruEdnString(String::from("a"))), + "\ndo |a\n" + ); +} + +#[test] +fn list_writing() { + assert_eq!( + write_cirru_edn(CirruEdnList(vec![ + CirruEdnNumber(1.0), + CirruEdnNumber(2.0), + CirruEdnList(vec![CirruEdnNumber(3.0)]) + ])), + "\n[] 1 2 $ [] 3\n" + ); +} + +#[test] +fn set_writing() { + let mut v = HashSet::new(); + v.insert(CirruEdnNumber(1.0)); + v.insert(CirruEdnList(vec![CirruEdnNumber(3.0)])); + + // TODO order is not stable + let r = write_cirru_edn(CirruEdnSet(v)); + let r1 = "\n#{} ([] 3) 1\n"; + let r2 = "\n#{} 1 $ [] 3\n"; + + assert!(r == r1 || r == r2); +} + +const RECORD_DEMO: &str = r#" +%{} Demo (a 1.0) + b 2.0 + c $ [] 1.0 2.0 3.0 +"#; + +const DICT_DEMO: &str = r#" +{} (:a 1.0) + :b $ [] 2.0 3.0 4.0 + :c $ {} (:d 4.0) + :e true + :f :g + :h $ {} (|a 1.0) + |b true +"#; + +const DICT_DEMO2: &str = r#" +{} + :b $ [] 2 3 4 + :a 1 + :c $ {} + :h $ {} (|b true) (|a 1) + :f :g + :e true + :d 4 +"#; + +#[test] +fn demo_parsing() { + // println!("{:?}", parse_cirru_edn(String::from(RECORD_DEMO))); + // println!("{:?}", parse_cirru_edn(String::from(DICT_DEMO))); + + assert_eq!( + parse_cirru_edn(String::from(RECORD_DEMO)), + Ok(CirruEdnRecord( + String::from("Demo"), + vec![String::from("a"), String::from("b"), String::from("c")], + vec![ + CirruEdnNumber(1.0), + CirruEdnNumber(2.0), + CirruEdnList(vec![ + CirruEdnNumber(1.0), + CirruEdnNumber(2.0), + CirruEdnNumber(3.0) + ]) + ] + )) + ); + + let v1 = parse_cirru_edn(String::from(DICT_DEMO)).unwrap(); + let v2 = parse_cirru_edn(String::from(DICT_DEMO2)).unwrap(); + assert_eq!(parse_cirru_edn(write_cirru_edn(v1.clone())), Ok(v1.clone())); + assert_eq!(v1, v2); } From eb0be7977c71228e3fe011455b0c43ac78b092bd Mon Sep 17 00:00:00 2001 From: jiyinyiyong Date: Fri, 16 Apr 2021 10:47:45 +0800 Subject: [PATCH 3/4] fix collection display; bump 0.0.2 --- Cargo.toml | 2 +- src/primes.rs | 17 +++++++++++++---- tests/edn_tests.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1c0b0f3..c9df055 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cirru_edn" -version = "0.0.1" +version = "0.0.2" authors = ["jiyinyiyong "] edition = "2018" license = "MIT" diff --git a/src/primes.rs b/src/primes.rs index a124b3f..d48868b 100644 --- a/src/primes.rs +++ b/src/primes.rs @@ -1,5 +1,6 @@ use cirru_parser::CirruNode; use core::cmp::Ord; +use regex::Regex; use std::cmp::Eq; use std::cmp::Ordering; use std::cmp::Ordering::*; @@ -30,9 +31,16 @@ impl fmt::Display for CirruEdn { CirruEdnNil => f.write_str("nil"), CirruEdnBool(v) => f.write_str(&format!("{}", v)), CirruEdnNumber(n) => f.write_str(&format!("{}", n)), - CirruEdnSymbol(s) => f.write_str(&format!("\"|{}\"", s)), // TODO + CirruEdnSymbol(s) => f.write_str(&format!("'{}", s)), CirruEdnKeyword(s) => f.write_str(&format!(":{}", s)), - CirruEdnString(s) => f.write_str(&format!("'{}", s)), + CirruEdnString(s) => { + let re = Regex::new("^[\\d\\w\\-\\?\\.\\$,]+$").unwrap(); + if re.is_match(s) { + f.write_str(&format!("|{}", s)) + } else { + f.write_str(&format!("\"|{}\"", s)) + } + } CirruEdnQuote(v) => f.write_str(&format!("{}", v)), CirruEdnList(xs) => { f.write_str("([]")?; @@ -49,10 +57,11 @@ impl fmt::Display for CirruEdn { f.write_str(")") } CirruEdnMap(xs) => { + f.write_str("({}")?; for (k, v) in xs { - f.write_str(&format!("{} {}", k, v))?; + f.write_str(&format!(" ({} {})", k, v))?; } - Ok(()) + f.write_str(")") } CirruEdnRecord(name, fields, values) => { f.write_str(&format!("(%{{}} {}", name))?; diff --git a/tests/edn_tests.rs b/tests/edn_tests.rs index 5bfed2b..a0b0932 100644 --- a/tests/edn_tests.rs +++ b/tests/edn_tests.rs @@ -1,6 +1,7 @@ use cirru_edn::CirruEdn; use cirru_edn::CirruEdn::*; use cirru_edn::{parse_cirru_edn, write_cirru_edn}; +use std::collections::HashMap; use std::collections::HashSet; #[test] @@ -181,3 +182,33 @@ fn demo_parsing() { assert_eq!(parse_cirru_edn(write_cirru_edn(v1.clone())), Ok(v1.clone())); assert_eq!(v1, v2); } + +#[test] +fn debug_format() -> Result<(), String> { + // TODO order for hashmap is unstable + + // let DICT_INLINE2: &str = + // r#"({} (:a 1) (:b ([] 2 3 4)) (:c ({} (:h ({} (|b true) (|a 1)) (:e true) (:d 4) (:f :g))"#; + + // let data = parse_cirru_edn(String::from(DICT_DEMO2))?; + // assert_eq!(format!("{}", data), DICT_INLINE2); + + let empty = HashMap::new(); + assert_eq!(format!("{}", CirruEdnMap(empty)), "({})"); + + let mut singleton: HashMap = HashMap::new(); + singleton.insert( + CirruEdnKeyword(String::from("a")), + CirruEdnString(String::from("b")), + ); + assert_eq!(format!("{}", CirruEdnMap(singleton)), "({} (:a |b))"); + + let mut singleton_set: HashSet = HashSet::new(); + singleton_set.insert(CirruEdnSymbol(String::from("a"))); + assert_eq!(format!("{}", CirruEdnSet(singleton_set)), "(#{} 'a)"); + + let singleton_vec = vec![CirruEdnBool(false)]; + assert_eq!(format!("{}", CirruEdnList(singleton_vec)), "([] false)"); + + Ok(()) +} From a2cba26c850438d656d3f47a9c28de5c5dcea4f6 Mon Sep 17 00:00:00 2001 From: jiyinyiyong Date: Fri, 16 Apr 2021 11:02:19 +0800 Subject: [PATCH 4/4] fix quote displaying; bump 0.0.3 --- Cargo.toml | 2 +- src/lib.rs | 2 +- src/primes.rs | 4 +++- tests/edn_tests.rs | 8 ++++++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c9df055..207f27f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cirru_edn" -version = "0.0.2" +version = "0.0.3" authors = ["jiyinyiyong "] edition = "2018" license = "MIT" diff --git a/src/lib.rs b/src/lib.rs index 75c7f41..645d79c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ use std::collections::HashSet; use cirru_parser::CirruNode::*; -/// TODO +/// parse Cirru code into data pub fn parse_cirru_edn(s: String) -> Result { match parse(s) { Ok(nodes) => match nodes { diff --git a/src/primes.rs b/src/primes.rs index d48868b..505bc79 100644 --- a/src/primes.rs +++ b/src/primes.rs @@ -8,6 +8,8 @@ use std::collections::{HashMap, HashSet}; use std::fmt; use std::hash::{Hash, Hasher}; +/// Data format based on subset of EDN, but in Cirru syntax. +/// different parts are quote and Record. #[derive(fmt::Debug, Clone)] pub enum CirruEdn { CirruEdnNil, @@ -41,7 +43,7 @@ impl fmt::Display for CirruEdn { f.write_str(&format!("\"|{}\"", s)) } } - CirruEdnQuote(v) => f.write_str(&format!("{}", v)), + CirruEdnQuote(v) => f.write_str(&format!("(quote {})", v)), CirruEdnList(xs) => { f.write_str("([]")?; for x in xs { diff --git a/tests/edn_tests.rs b/tests/edn_tests.rs index a0b0932..b6fc3d5 100644 --- a/tests/edn_tests.rs +++ b/tests/edn_tests.rs @@ -1,6 +1,7 @@ use cirru_edn::CirruEdn; use cirru_edn::CirruEdn::*; use cirru_edn::{parse_cirru_edn, write_cirru_edn}; +use cirru_parser::CirruNode::*; use std::collections::HashMap; use std::collections::HashSet; @@ -210,5 +211,12 @@ fn debug_format() -> Result<(), String> { let singleton_vec = vec![CirruEdnBool(false)]; assert_eq!(format!("{}", CirruEdnList(singleton_vec)), "([] false)"); + let code = CirruEdnList(vec![CirruEdnQuote(CirruList(vec![ + CirruLeaf(String::from("a")), + CirruLeaf(String::from("b")), + ]))]); + + assert_eq!(format!("{}", code), "([] (quote (a b)))"); + Ok(()) }