diff --git a/src/compare/diff.rs b/src/compare/diff.rs index d4af397c..23d2575d 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -13,6 +13,8 @@ use super::util::get_property_boolean; use super::util::get_property_numeric; use super::util::get_property_quoted_string; use super::util::get_property_unquoted_atom; +use crate::compare::elisp_fact::EmacsField; +use crate::compare::macros::compare_properties; use crate::types::AngleLink; use crate::types::AstNode; use crate::types::BabelCall; @@ -2688,6 +2690,9 @@ fn compare_code<'b, 's>( )); } + let foo: Result)>, Box> = + compare_properties!(emacs, EmacsField::Required(":value")); + Ok(DiffResult { status: this_status, name: rust.get_elisp_name(), diff --git a/src/compare/elisp_fact.rs b/src/compare/elisp_fact.rs index fd2810b0..8f97ed3d 100644 --- a/src/compare/elisp_fact.rs +++ b/src/compare/elisp_fact.rs @@ -550,3 +550,9 @@ impl<'s> ElispFact<'s> for PlainText<'s> { "plain-text".into() } } + +#[derive(Debug)] +pub(crate) enum EmacsField<'s> { + Required(&'s str), + Optional(&'s str), +} diff --git a/src/compare/macros.rs b/src/compare/macros.rs new file mode 100644 index 00000000..b71aa03c --- /dev/null +++ b/src/compare/macros.rs @@ -0,0 +1,59 @@ +/// Create iterators for ast nodes where it only has to iterate over children +macro_rules! compare_properties { + ($emacs:expr, $($emacs_field:expr),+) => { + { + let mut this_status = DiffStatus::Good; + let mut message: Option = None; + let children = $emacs.as_list()?; + let attributes_child = children + .iter() + .nth(1) + .ok_or("Should have an attributes child.")?; + let attributes_map = attributes_child.as_map()?; + let mut emacs_keys: BTreeSet<&str> = attributes_map.keys().map(|s| *s).collect(); + $( + match $emacs_field { + EmacsField::Required(name) if emacs_keys.contains(name) => { + emacs_keys.remove(name); + }, + EmacsField::Optional(name) if emacs_keys.contains(name) => { + emacs_keys.remove(name); + }, + EmacsField::Required(name) => { + this_status = DiffStatus::Bad; + message = Some(format!( + "Emacs token lacks required field: {}", + name + )); + }, + EmacsField::Optional(_name) => {}, + } + ),+ + + if !emacs_keys.is_empty() { + let unexpected_keys: Vec<&str> = emacs_keys.into_iter().collect(); + let unexpected_keys = unexpected_keys.join(", "); + this_status = DiffStatus::Bad; + message = Some(format!( + "Emacs token had extra field(s): {}", + unexpected_keys + )); + } + + $( + println!("{:?}", $emacs_field); + ),+ + + match this_status { + DiffStatus::Good => { + Ok(None) + }, + _ => { + Ok(Some((this_status, message))) + } + } + } + }; +} + +pub(crate) use compare_properties; diff --git a/src/compare/mod.rs b/src/compare/mod.rs index 1a75e2e7..e7bcde8f 100644 --- a/src/compare/mod.rs +++ b/src/compare/mod.rs @@ -1,6 +1,7 @@ mod compare; mod diff; mod elisp_fact; +mod macros; mod parse; mod sexp; mod util;