83 lines
2.8 KiB
Rust
83 lines
2.8 KiB
Rust
#[derive(Debug)]
|
|
pub(crate) enum EmacsField<'s> {
|
|
Required(&'s str),
|
|
Optional(&'s str),
|
|
}
|
|
|
|
/// Create iterators for ast nodes where it only has to iterate over children
|
|
macro_rules! compare_properties {
|
|
($emacs:expr, $($emacs_field:expr, $rust_value:expr, $compare_fn: ident),+) => {
|
|
{
|
|
let mut this_status = DiffStatus::Good;
|
|
let mut message: Option<String> = 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
|
|
));
|
|
}
|
|
|
|
$(
|
|
let emacs_name = match $emacs_field {
|
|
EmacsField::Required(name) => {
|
|
name
|
|
},
|
|
EmacsField::Optional(name) => {
|
|
name
|
|
},
|
|
};
|
|
let result = $compare_fn($emacs, emacs_name, $rust_value)?;
|
|
match result {
|
|
Some((DiffStatus::Good, _)) => unreachable!("No comparison functions should return Some() when DiffStatus is good."),
|
|
Some((status, msg)) => {
|
|
this_status = status;
|
|
message = msg;
|
|
},
|
|
_ => {}
|
|
}
|
|
),+
|
|
|
|
match this_status {
|
|
DiffStatus::Good => {
|
|
let result: Result<_, Box<dyn std::error::Error>> = Ok(None);
|
|
result
|
|
},
|
|
_ => {
|
|
Ok(Some((this_status, message)))
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
pub(crate) use compare_properties;
|