diff --git a/src/compare/compare_field.rs b/src/compare/compare_field.rs index f4af14d..319ba7f 100644 --- a/src/compare/compare_field.rs +++ b/src/compare/compare_field.rs @@ -1,6 +1,7 @@ use std::fmt::Debug; use super::diff::DiffStatus; +use super::sexp::unquote; use super::sexp::Token; use super::util::get_property; use super::util::get_property_quoted_string; @@ -102,3 +103,57 @@ pub(crate) fn compare_property_unquoted_atom<'b, 's, 'x, R, RG: Fn(R) -> Option< Ok(None) } } + +pub(crate) fn compare_property_list_of_quoted_string< + 'b, + 's, + 'x, + 'y, + R, + RV: AsRef + std::fmt::Debug + 'y, + RG: Fn(R) -> Option<&'y Vec>, +>( + emacs: &'b Token<'s>, + rust_node: R, + emacs_field: &'x str, + rust_value_getter: RG, +) -> Result)>, Box> { + let value = get_property(emacs, emacs_field)? + .map(Token::as_list) + .map_or(Ok(None), |r| r.map(Some))?; + let rust_value = rust_value_getter(rust_node); + match (value, rust_value) { + (None, None) => {} + (None, Some(_)) | (Some(_), None) => { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, value, rust_value + )); + return Ok(Some((this_status, message))); + } + (Some(el), Some(rl)) if el.len() != rl.len() => { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, value, rust_value + )); + return Ok(Some((this_status, message))); + } + (Some(el), Some(rl)) => { + for (e, r) in el.iter().zip(rl) { + let e = unquote(e.as_atom()?)?; + let r = r.as_ref(); + if e != r { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, value, rust_value + )); + return Ok(Some((this_status, message))); + } + } + } + } + Ok(None) +} diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 2f26f22..c105821 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -6,6 +6,7 @@ use std::collections::HashSet; use super::compare_field::compare_identity; use super::compare_field::compare_property_always_nil; +use super::compare_field::compare_property_list_of_quoted_string; use super::compare_field::compare_property_quoted_string; use super::compare_field::compare_property_unquoted_atom; use super::elisp_fact::ElispFact; @@ -3068,10 +3069,35 @@ fn compare_org_macro<'b, 's>( emacs: &'b Token<'s>, rust: &'b OrgMacro<'s>, ) -> Result, Box> { - let this_status = DiffStatus::Good; - let message = None; + let mut this_status = DiffStatus::Good; + let mut message = None; - // TODO: Compare :key :value :args + if let Some((new_status, new_message)) = compare_properties!( + emacs, + rust, + ( + EmacsField::Required(":key"), + |r| Some(r.macro_name), + compare_property_quoted_string + ), + ( + EmacsField::Required(":value"), + |r| Some(r.source), + compare_property_quoted_string + ), + ( + EmacsField::Required(":args"), + |r| if r.macro_args.is_empty() { + None + } else { + Some(&r.macro_args) + }, + compare_property_list_of_quoted_string + ) + )? { + this_status = new_status; + message = new_message; + } Ok(DiffResult { status: this_status,