From 8e357ed3b6f50f97198307df072925df641f9886 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 20:54:31 -0400 Subject: [PATCH 01/33] compare_properties section. --- src/compare/diff.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index b79d8ca..bc95af5 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -559,13 +559,28 @@ fn compare_section<'b, 's>( emacs: &'b Token<'s>, rust: &'b Section<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let this_status = DiffStatus::Good; + let mut this_status = DiffStatus::Good; let mut child_status = Vec::new(); - let message = None; + let mut message = None; - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; + + for diff in compare_properties!(emacs) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From 166e59b922d24a555b8391a5473eecfd368cf5b0 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 21:04:41 -0400 Subject: [PATCH 02/33] Implement a compare_property_numeric. --- src/compare/compare_field.rs | 34 ++++++++++++++++++++++++ src/compare/diff.rs | 50 ++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/compare/compare_field.rs b/src/compare/compare_field.rs index 8ee4557..9ea46c3 100644 --- a/src/compare/compare_field.rs +++ b/src/compare/compare_field.rs @@ -1,4 +1,5 @@ use std::fmt::Debug; +use std::str::FromStr; use super::diff::artificial_diff_scope; use super::diff::compare_ast_node; @@ -7,6 +8,7 @@ use super::diff::DiffStatus; use super::sexp::unquote; use super::sexp::Token; use super::util::get_property; +use super::util::get_property_numeric; use super::util::get_property_quoted_string; use super::util::get_property_unquoted_atom; use crate::types::AstNode; @@ -117,6 +119,38 @@ pub(crate) fn compare_property_unquoted_atom<'b, 's, 'x, R, RG: Fn(R) -> Option< } } +pub(crate) fn compare_property_numeric< + 'b, + 's, + 'x, + R, + RV: FromStr + PartialEq + Debug, + RG: Fn(R) -> Option, +>( + _source: &'s str, + emacs: &'b Token<'s>, + rust_node: R, + emacs_field: &'x str, + rust_value_getter: RG, +) -> Result, Box> +where + ::Err: std::error::Error, + ::Err: 's, +{ + let value = get_property_numeric::(emacs, emacs_field)?; + let rust_value = rust_value_getter(rust_node); + if rust_value != value { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, value, rust_value + )); + Ok(ComparePropertiesResult::SelfChange(this_status, message)) + } else { + Ok(ComparePropertiesResult::NoChange) + } +} + pub(crate) fn compare_property_list_of_quoted_string< 'b, 's, diff --git a/src/compare/diff.rs b/src/compare/diff.rs index bc95af5..e782676 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -10,6 +10,7 @@ use super::compare_field::compare_property_always_nil; use super::compare_field::compare_property_boolean; use super::compare_field::compare_property_list_of_ast_nodes; use super::compare_field::compare_property_list_of_quoted_string; +use super::compare_field::compare_property_numeric; use super::compare_field::compare_property_quoted_string; use super::compare_field::compare_property_unquoted_atom; use super::elisp_fact::ElispFact; @@ -594,6 +595,55 @@ fn compare_section<'b, 's>( .into()) } +fn new_compare_heading<'b, 's>( + source: &'s str, + emacs: &'b Token<'s>, + rust: &'b Heading<'s>, +) -> Result, Box> { + let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); + let mut message = None; + + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; + + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Required(":level"), + |r| Some(r.level), + compare_property_numeric + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } + } + + Ok(DiffResult { + status: this_status, + name: rust.get_elisp_name(), + message, + children: child_status, + rust_source: rust.get_source(), + emacs_token: emacs, + } + .into()) +} + fn compare_heading<'b, 's>( source: &'s str, emacs: &'b Token<'s>, From 65615c64d203af237b7a76fd39f19a81b32af59a Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 21:27:18 -0400 Subject: [PATCH 03/33] Implement a new compare_properties implementation of the heading comparison. --- src/compare/compare_field.rs | 39 +++++++++++++++++ src/compare/diff.rs | 81 ++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/src/compare/compare_field.rs b/src/compare/compare_field.rs index 9ea46c3..f6af4dc 100644 --- a/src/compare/compare_field.rs +++ b/src/compare/compare_field.rs @@ -230,6 +230,45 @@ pub(crate) fn compare_property_boolean<'b, 's, 'x, R, RG: Fn(R) -> bool>( } } +pub(crate) fn compare_property_single_ast_node< + 'b, + 's, + 'x: 'b + 's, + R, + RV: std::fmt::Debug, + RG: Fn(R) -> Option, +>( + source: &'s str, + emacs: &'b Token<'s>, + rust_node: R, + emacs_field: &'x str, + rust_value_getter: RG, +) -> Result, Box> +where + AstNode<'b, 's>: From, +{ + let value = get_property(emacs, emacs_field)?; + let rust_value = rust_value_getter(rust_node); + match (value, rust_value) { + (None, None) => {} + (None, rv @ Some(_)) | (Some(_), rv @ None) => { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, value, rv + )); + return Ok(ComparePropertiesResult::SelfChange(this_status, message)); + } + (Some(ev), Some(rv)) => { + let child_status: Vec> = + vec![compare_ast_node(source, ev, rv.into())?]; + let diff_scope = artificial_diff_scope(emacs_field, child_status)?; + return Ok(ComparePropertiesResult::DiffEntry(diff_scope)); + } + } + Ok(ComparePropertiesResult::NoChange) +} + pub(crate) fn compare_property_list_of_ast_nodes< 'b, 's, diff --git a/src/compare/diff.rs b/src/compare/diff.rs index e782676..16c62e0 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -12,6 +12,7 @@ use super::compare_field::compare_property_list_of_ast_nodes; use super::compare_field::compare_property_list_of_quoted_string; use super::compare_field::compare_property_numeric; use super::compare_field::compare_property_quoted_string; +use super::compare_field::compare_property_single_ast_node; use super::compare_field::compare_property_unquoted_atom; use super::elisp_fact::ElispFact; use super::elisp_fact::GetElispFact; @@ -621,6 +622,86 @@ fn new_compare_heading<'b, 's>( EmacsField::Required(":level"), |r| Some(r.level), compare_property_numeric + ), + ( + EmacsField::Required(":tags"), + |r| if r.tags.is_empty() { + None + } else { + Some(r.tags.iter()) + }, + compare_property_list_of_quoted_string + ), + ( + EmacsField::Required(":todo-keyword"), + |r| r.todo_keyword.as_ref().map(|(_, text)| text), + compare_property_quoted_string + ), + ( + EmacsField::Required(":todo-type"), + |r| r + .todo_keyword + .as_ref() + .map(|(todo_type, _)| todo_type) + .map(|todo_type| match todo_type { + TodoKeywordType::Todo => "todo", + TodoKeywordType::Done => "done", + }), + compare_property_unquoted_atom + ), + ( + EmacsField::Required(":title"), + |r| if r.title.is_empty() { + None + } else { + Some(r.title.iter()) + }, + compare_property_list_of_ast_nodes + ), + ( + EmacsField::Required(":priority"), + |r| r.priority_cookie, + compare_property_numeric + ), + ( + EmacsField::Required(":archivedp"), + |r| r.is_archived, + compare_property_boolean + ), + ( + EmacsField::Required(":commentedp"), + |r| r.is_comment, + compare_property_boolean + ), + ( + EmacsField::Required(":raw-value"), + |r| Some(r.get_raw_value()), + compare_property_quoted_string + ), + ( + EmacsField::Required(":footnote-section-p"), + |r| r.is_footnote_section, + compare_property_boolean + ), + ( + EmacsField::Required(":scheduled"), + |r| r.scheduled.as_ref(), + compare_property_single_ast_node + ), + ( + EmacsField::Required(":deadline"), + |r| r.deadline.as_ref(), + compare_property_single_ast_node + ), + ( + EmacsField::Required(":closed"), + |r| r.closed.as_ref(), + compare_property_single_ast_node + ), + ( + EmacsField::Required(":pre-blank"), + compare_identity, + compare_noop ) ) { match diff { From 33c53a14abe5f6ee3813b19df34486d3de6e02c7 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 21:32:29 -0400 Subject: [PATCH 04/33] Switch back to the old compare heading function until we support additional properties. --- src/compare/diff.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 16c62e0..687bda5 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -605,6 +605,8 @@ fn new_compare_heading<'b, 's>( let mut child_status = Vec::new(); let mut message = None; + // TODO: This needs to support additional properties from the property drawer + compare_children( source, emacs, @@ -684,17 +686,17 @@ fn new_compare_heading<'b, 's>( compare_property_boolean ), ( - EmacsField::Required(":scheduled"), + EmacsField::Optional(":scheduled"), |r| r.scheduled.as_ref(), compare_property_single_ast_node ), ( - EmacsField::Required(":deadline"), + EmacsField::Optional(":deadline"), |r| r.deadline.as_ref(), compare_property_single_ast_node ), ( - EmacsField::Required(":closed"), + EmacsField::Optional(":closed"), |r| r.closed.as_ref(), compare_property_single_ast_node ), From 7a38d1ead301c8692b3a86becdfa60a8c91b611b Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 21:35:35 -0400 Subject: [PATCH 05/33] compare_properties paragraph. --- src/compare/diff.rs | 47 +++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 687bda5..ff868fc 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -596,6 +596,7 @@ fn compare_section<'b, 's>( .into()) } +#[allow(dead_code)] fn new_compare_heading<'b, 's>( source: &'s str, emacs: &'b Token<'s>, @@ -1004,24 +1005,42 @@ fn compare_paragraph<'b, 's>( emacs: &'b Token<'s>, rust: &'b Paragraph<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From 409a92333ec94211167a95e14ee24f0aeca39911 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 21:42:07 -0400 Subject: [PATCH 06/33] compare_properties plain list. --- src/compare/diff.rs | 70 ++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index ff868fc..f37c596 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1059,43 +1059,53 @@ fn compare_plain_list<'b, 's>( emacs: &'b Token<'s>, rust: &'b PlainList<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - // Compare type - // :type is an unquoted atom of either descriptive, ordered, or unordered - let list_type = get_property_unquoted_atom(emacs, ":type")?; - match (list_type, &rust.list_type) { - (None, _) => panic!("Emacs returned a list with no type."), - (Some("unordered"), PlainListType::Unordered) => {} - (Some("ordered"), PlainListType::Ordered) => {} - (Some("descriptive"), PlainListType::Descriptive) => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "List type mismatch (emacs != rust) {:?} != {:?}", - list_type, rust.list_type - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":type"), + |r| Some(match r.list_type { + PlainListType::Unordered => "unordered", + PlainListType::Ordered => "ordered", + PlainListType::Descriptive => "descriptive", + }), + compare_property_unquoted_atom + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } } - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); - } - Ok(DiffResult { status: this_status, name: rust.get_elisp_name(), From f543caee00437c59799176946cfbcd00ae0a431b Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 21:54:29 -0400 Subject: [PATCH 07/33] compare_properties plain list item. --- .../greater_element/plain_list/checkbox.org | 3 + src/compare/diff.rs | 158 +++++++----------- 2 files changed, 62 insertions(+), 99 deletions(-) create mode 100644 org_mode_samples/greater_element/plain_list/checkbox.org diff --git a/org_mode_samples/greater_element/plain_list/checkbox.org b/org_mode_samples/greater_element/plain_list/checkbox.org new file mode 100644 index 0000000..e987168 --- /dev/null +++ b/org_mode_samples/greater_element/plain_list/checkbox.org @@ -0,0 +1,3 @@ +- [ ] Foo +- [-] Bar +- [X] Baz diff --git a/src/compare/diff.rs b/src/compare/diff.rs index f37c596..0a58bb7 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -83,8 +83,6 @@ use crate::types::Paragraph; use crate::types::PlainLink; use crate::types::PlainList; use crate::types::PlainListItem; -use crate::types::PlainListItemCounter; -use crate::types::PlainListItemPreBlank; use crate::types::PlainListType; use crate::types::PlainText; use crate::types::Planning; @@ -1121,108 +1119,70 @@ fn compare_plain_list_item<'b, 's>( source: &'s str, emacs: &'b Token<'s>, rust: &'b PlainListItem<'s>, -) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); +) -> Result, Box> { let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // Compare tag - let tag = get_property(emacs, ":tag")?; - match (tag, rust.tag.is_empty()) { - (None, true) => {} - (None, false) | (Some(_), true) => { - this_status = DiffStatus::Bad; - message = Some("Mismatched tags".to_owned()); - } - (Some(tag), false) => { - let tag_status = tag - .as_list()? - .iter() - .zip(rust.tag.iter()) - .map(|(emacs_child, rust_child)| { - compare_ast_node(source, emacs_child, rust_child.into()) - }) - .collect::, _>>()?; - child_status.push(artificial_diff_scope("tag", tag_status)?); - } - }; + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - // Compare contents - let contents_status = children - .iter() - .skip(2) - .zip(rust.children.iter()) - .map(|(emacs_child, rust_child)| compare_ast_node(source, emacs_child, rust_child.into())) - .collect::, _>>()?; - child_status.push(artificial_diff_scope("contents", contents_status)?); - - // Compare bullet - let bullet = get_property_quoted_string(emacs, ":bullet")? - .ok_or("Plain list items must have a :bullet.")?; - if bullet != rust.bullet { - this_status = DiffStatus::Bad; - message = Some(format!( - "Bullet mismatch (emacs != rust) {:?} != {:?}", - bullet, rust.bullet - )); - } - - // Compare counter - let counter = get_property_unquoted_atom(emacs, ":counter")?; - let counter: Option = counter - .map(|val| val.parse()) - .map_or(Ok(None), |r| r.map(Some))?; - match (counter, rust.counter) { - (None, None) => {} - (None, Some(_)) | (Some(_), None) => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Counter mismatch (emacs != rust) {:?} != {:?}", - counter, rust.counter - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Required(":tag"), + |r| if r.tag.is_empty() { + None + } else { + Some(r.tag.iter()) + }, + compare_property_list_of_ast_nodes + ), + ( + EmacsField::Required(":bullet"), + |r| Some(r.bullet), + compare_property_quoted_string + ), + ( + EmacsField::Required(":counter"), + |r| r.counter, + compare_property_numeric + ), + ( + EmacsField::Required(":checkbox"), + |r| r + .checkbox + .as_ref() + .map(|(checkbox_type, _)| checkbox_type) + .map(|checkbox_type| match checkbox_type { + CheckboxType::On => "on", + CheckboxType::Trans => "trans", + CheckboxType::Off => "off", + }), + compare_property_unquoted_atom + ), + ( + EmacsField::Required(":pre-blank"), + |r| Some(r.pre_blank), + compare_property_numeric + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } - (Some(e), Some(r)) if e != r => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Counter mismatch (emacs != rust) {:?} != {:?}", - counter, rust.counter - )); - } - (Some(_), Some(_)) => {} - }; - - // Compare checkbox - let checkbox = get_property(emacs, ":checkbox")? - .map(Token::as_atom) - .map_or(Ok(None), |r| r.map(Some))? - .unwrap_or("nil"); - match (checkbox, &rust.checkbox) { - ("nil", None) => {} - ("off", Some((CheckboxType::Off, _))) => {} - ("trans", Some((CheckboxType::Trans, _))) => {} - ("on", Some((CheckboxType::On, _))) => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Checkbox mismatch (emacs != rust) {:?} != {:?}", - checkbox, rust.checkbox - )); - } - }; - - // Compare pre-blank - // :pre-blank appears to count the line breaks between "::" and the contents in a descriptive list. Oddly enough it does not count the spaces so I'm not quite sure what the value is. - let pre_blank = get_property_unquoted_atom(emacs, ":pre-blank")?; - let pre_blank: Option = pre_blank - .map(|val| val.parse()) - .map_or(Ok(None), |r| r.map(Some))?; - if pre_blank.unwrap_or(0) != rust.pre_blank { - this_status = DiffStatus::Bad; - message = Some(format!( - "Pre-blank mismatch (emacs != rust) {:?} != {:?}", - pre_blank, rust.pre_blank - )); } Ok(DiffResult { From ca1b633a9f1ace09ac2d4664a48085ffb7122094 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 21:57:11 -0400 Subject: [PATCH 08/33] compare_properties quote block. --- src/compare/diff.rs | 46 +++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 0a58bb7..02ba10b 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1237,24 +1237,42 @@ fn compare_quote_block<'b, 's>( emacs: &'b Token<'s>, rust: &'b QuoteBlock<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From 9ab649ebd481899126efc8b7b744fb34ae310fd1 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 22:01:26 -0400 Subject: [PATCH 09/33] compare_properties special block. --- src/compare/diff.rs | 84 +++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 02ba10b..9f3266a 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1291,51 +1291,59 @@ fn compare_special_block<'b, 's>( emacs: &'b Token<'s>, rust: &'b SpecialBlock<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - // Compare type - let special_block_type = - get_property_quoted_string(emacs, ":type")?.ok_or("Special blocks should have a name.")?; - if special_block_type != rust.block_type { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - special_block_type, rust.block_type - )); - } - - // Compare parameters - let parameters = get_property_quoted_string(emacs, ":parameters")?; - match (parameters.as_ref(), rust.parameters) { - (None, None) => {} - (Some(emacs_parameters), Some(rust_parameters)) if emacs_parameters == rust_parameters => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Parameters mismatch (emacs != rust) {:?} != {:?}", - parameters, rust.parameters - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":type"), + |r| Some(r.block_type), + compare_property_quoted_string + ), + ( + EmacsField::Required(":parameters"), + |r| r.parameters, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":results"), + compare_identity, + compare_noop + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } } - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); - } - Ok(DiffResult { status: this_status, name: rust.get_elisp_name(), From 62926bb91d94ba1b89498adf91d4de23b26c65f5 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 22:28:32 -0400 Subject: [PATCH 10/33] compare_properties dynamic block. --- src/compare/diff.rs | 79 +++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 9f3266a..c5e4fb0 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1360,51 +1360,54 @@ fn compare_dynamic_block<'b, 's>( emacs: &'b Token<'s>, rust: &'b DynamicBlock<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - // Compare block-name - let block_name = get_property_quoted_string(emacs, ":block-name")? - .ok_or("Dynamic blocks should have a name.")?; - if block_name != rust.block_name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - block_name, rust.block_name - )); - } - - // Compare arguments - let parameters = get_property_quoted_string(emacs, ":arguments")?; - match (parameters.as_ref(), rust.parameters) { - (None, None) => {} - (Some(emacs_parameters), Some(rust_parameters)) if emacs_parameters == rust_parameters => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Parameters mismatch (emacs != rust) {:?} != {:?}", - parameters, rust.parameters - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":block-name"), + |r| Some(r.block_name), + compare_property_quoted_string + ), + ( + EmacsField::Required(":arguments"), + |r| r.parameters, + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } } - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); - } - Ok(DiffResult { status: this_status, name: rust.get_elisp_name(), From 4c89d6c813af9bba1704840607ba14262b6764cf Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 22:32:25 -0400 Subject: [PATCH 11/33] compare_properties footnote definition. --- src/compare/diff.rs | 68 ++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index c5e4fb0..fe8cd8a 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1424,36 +1424,52 @@ fn compare_footnote_definition<'b, 's>( emacs: &'b Token<'s>, rust: &'b FootnoteDefinition<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :pre-blank - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - // Compare label - let label = get_property_quoted_string(emacs, ":label")? - .ok_or("Footnote definitions should have a name.")?; - if label != rust.label { - this_status = DiffStatus::Bad; - message = Some(format!( - "Label mismatch (emacs != rust) {:?} != {:?}", - label, rust.label - )); - } - - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":label"), + |r| Some(r.label), + compare_property_quoted_string + ), + ( + EmacsField::Required(":pre-blank"), + compare_identity, + compare_noop + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From 926682d513254e78681064ad3aa53819c6690be2 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 22:36:15 -0400 Subject: [PATCH 12/33] compare_properties comment. --- src/compare/diff.rs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index fe8cd8a..859189a 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1484,24 +1484,34 @@ fn compare_footnote_definition<'b, 's>( } fn compare_comment<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b Comment<'s>, ) -> Result, Box> { - let child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // Compare value - let value = - get_property_quoted_string(emacs, ":value")?.ok_or("Comments should have a value.")?; - let rust_value = rust.get_value(); - if value != rust_value { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - value, rust_value - )); + assert_no_children(emacs, &mut this_status, &mut message)?; + + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Required(":value"), + |r| Some(r.get_value()), + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From 5b146d7c074de0305177f349f435e4593f2664b3 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 22:37:53 -0400 Subject: [PATCH 13/33] compare_properties drawer. --- src/compare/diff.rs | 62 +++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 859189a..8bacae3 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1530,35 +1530,47 @@ fn compare_drawer<'b, 's>( emacs: &'b Token<'s>, rust: &'b Drawer<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - // Compare drawer-name - let drawer_name = - get_property_quoted_string(emacs, ":drawer-name")?.ok_or("Drawers should have a name.")?; - if drawer_name != rust.drawer_name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Drawer name mismatch (emacs != rust) {:?} != {:?}", - drawer_name, rust.drawer_name - )); - } - - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":drawer-name"), + |r| Some(r.drawer_name), + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From d1184fa1d0a832b254917df484b660c59a5b00a1 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 22:42:02 -0400 Subject: [PATCH 14/33] compare_properties property drawer. --- src/compare/diff.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 8bacae3..00c09da 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1589,13 +1589,28 @@ fn compare_property_drawer<'b, 's>( emacs: &'b Token<'s>, rust: &'b PropertyDrawer<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; + let mut this_status = DiffStatus::Good; let mut child_status = Vec::new(); - let this_status = DiffStatus::Good; - let message = None; + let mut message = None; - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; + + for diff in compare_properties!(emacs) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From 7af5359e003959ebc1e62c3000472cd81855aa05 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 9 Oct 2023 22:45:32 -0400 Subject: [PATCH 15/33] compare_properties node property. --- src/compare/diff.rs | 48 +++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 00c09da..2857483 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1625,36 +1625,38 @@ fn compare_property_drawer<'b, 's>( } fn compare_node_property<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b NodeProperty<'s>, ) -> Result, Box> { - let child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // Compare key - let key = - get_property_quoted_string(emacs, ":key")?.ok_or("Node properties should have a key.")?; - if key != rust.property_name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Key mismatch (emacs != rust) {:?} != {:?}", - key, rust.property_name - )); - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare value - let value = get_property_quoted_string(emacs, ":value")?; - match (value.as_ref(), rust.value) { - (None, None) => {} - (Some(emacs_value), Some(rust_value)) if emacs_value == rust_value => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - value, rust.value - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Required(":key"), + |r| Some(r.property_name), + compare_property_quoted_string + ), + ( + EmacsField::Required(":value"), + |r| r.value, + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } } From 62815621e43c4681ec0b44f71ab9705ce9a12494 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 00:05:34 -0400 Subject: [PATCH 16/33] compare_properties table. --- src/compare/compare_field.rs | 54 ++++++++++++++++ src/compare/diff.rs | 118 +++++++++++++++-------------------- 2 files changed, 104 insertions(+), 68 deletions(-) diff --git a/src/compare/compare_field.rs b/src/compare/compare_field.rs index f6af4dc..3df2d7e 100644 --- a/src/compare/compare_field.rs +++ b/src/compare/compare_field.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeSet; use std::fmt::Debug; use std::str::FromStr; @@ -208,6 +209,59 @@ pub(crate) fn compare_property_list_of_quoted_string< Ok(ComparePropertiesResult::NoChange) } +pub(crate) fn compare_property_set_of_quoted_string< + 'a, + 'b, + 's, + 'x, + R, + RV: AsRef + std::fmt::Debug + Ord + 'a + ?Sized, + RI: Iterator, + RG: Fn(R) -> Option, +>( + _source: &'s str, + 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 empty = Vec::new(); + let value = value.unwrap_or(&empty); + let rust_value = rust_value_getter(rust_node); + let rust_value = if let Some(rust_value) = rust_value { + let slices: BTreeSet<&str> = rust_value.map(|rv| rv.as_ref()).collect(); + slices + } else { + BTreeSet::new() + }; + let value: Vec<&str> = value + .iter() + .map(|e| e.as_atom()) + .collect::, _>>()?; + let value: Vec = value + .into_iter() + .map(unquote) + .collect::, _>>()?; + let value: BTreeSet<&str> = value.iter().map(|e| e.as_str()).collect(); + let mismatched: Vec<_> = value + .symmetric_difference(&rust_value) + .map(|val| *val) + .collect(); + if !mismatched.is_empty() { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch. Mismatched values: {}", + emacs_field, + mismatched.join(", ") + )); + return Ok(ComparePropertiesResult::SelfChange(this_status, message)); + } + Ok(ComparePropertiesResult::NoChange) +} + pub(crate) fn compare_property_boolean<'b, 's, 'x, R, RG: Fn(R) -> bool>( _source: &'s str, emacs: &'b Token<'s>, diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 2857483..3159bcf 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -12,6 +12,7 @@ use super::compare_field::compare_property_list_of_ast_nodes; use super::compare_field::compare_property_list_of_quoted_string; use super::compare_field::compare_property_numeric; use super::compare_field::compare_property_quoted_string; +use super::compare_field::compare_property_set_of_quoted_string; use super::compare_field::compare_property_single_ast_node; use super::compare_field::compare_property_unquoted_atom; use super::elisp_fact::ElispFact; @@ -1676,80 +1677,61 @@ fn compare_table<'b, 's>( emacs: &'b Token<'s>, rust: &'b Table<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - // Compare formulas - // - // :tblfm is either nil or a list () filled with quoted strings containing the value for any tblfm keywords at the end of the table. - let emacs_formulas = get_property(emacs, ":tblfm")?; - if let Some(emacs_formulas) = emacs_formulas { - let emacs_formulas = emacs_formulas.as_list()?; - if emacs_formulas.len() != rust.formulas.len() { - this_status = DiffStatus::Bad; - message = Some(format!( - "Formulas do not match (emacs != rust): {:?} != {:?}", - emacs_formulas, rust.formulas - )) - } else { - let atoms = emacs_formulas - .into_iter() - .map(Token::as_atom) - .collect::, _>>()?; - let unquoted = atoms - .into_iter() - .map(unquote) - .collect::, _>>()?; - for kw in &rust.formulas { - if !unquoted.contains(kw.value) { - this_status = DiffStatus::Bad; - message = Some(format!("Could not find formula in emacs: {}", kw.value)) - } + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":tblfm"), + |r| if r.formulas.is_empty() { + None + } else { + Some(r.formulas.iter().map(|kw| kw.value)) + }, + compare_property_set_of_quoted_string + ), + ( + EmacsField::Optional(":type"), + |_| Some("org"), + compare_property_unquoted_atom + ), + ( + EmacsField::Required(":value"), + compare_identity, + compare_property_always_nil + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } - } else { - if !rust.formulas.is_empty() { - this_status = DiffStatus::Bad; - message = Some(format!( - "Formulas do not match (emacs != rust): {:?} != {:?}", - emacs_formulas, rust.formulas - )) - } - } - - // Compare type - let table_type = get_property_unquoted_atom(emacs, ":type")?.expect("Table should have a type"); - if table_type != "org" { - this_status = DiffStatus::Bad; - message = Some(format!( - "Table type mismatch (emacs != rust) {:?} != {:?}", - table_type, "org" - )); - } - - // Compare value - let value = get_property(emacs, ":value")?; - if value.is_some() { - // I don't know what :value is for, but it seems to always be nil. This is here to alert me to value being non-nil so I can investigate. - this_status = DiffStatus::Bad; - message = Some(format!("Non-nil value {:?}", value)) - } - - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); } Ok(DiffResult { From cf257443b08e329ef303ce0f1b4fc7e334b8bfe0 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 00:07:34 -0400 Subject: [PATCH 17/33] compare_properties table row. --- src/compare/diff.rs | 48 ++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 3159bcf..5b654ab 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1750,28 +1750,40 @@ fn compare_table_row<'b, 's>( emacs: &'b Token<'s>, rust: &'b TableRow<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // Compare type - let row_type = get_property_unquoted_atom(emacs, ":type")?; - let rust_row_type = rust.get_type(); - match (row_type, &rust_row_type) { - (Some("standard"), TableRowType::Standard) => {} - (Some("rule"), TableRowType::Rule) => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Type mismatch (emacs != rust) {:?} != {:?}", - row_type, rust_row_type - )); - } - } + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { - child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Required(":type"), + |r| Some(match r.get_type() { + TableRowType::Standard => "standard", + TableRowType::Rule => "rule", + }), + compare_property_unquoted_atom + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From 2215c32e57250ffafe86ff3c2466e77fea31781e Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 00:11:05 -0400 Subject: [PATCH 18/33] compare_properties table cell. --- src/compare/diff.rs | 29 +++++++++++++++++++++++------ src/parser/table.rs | 3 ++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 5b654ab..7509d36 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1798,16 +1798,33 @@ fn compare_table_row<'b, 's>( } fn compare_table_cell<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b TableCell<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let child_status = Vec::new(); - let this_status = DiffStatus::Good; - let message = None; + let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); + let mut message = None; - for (_emacs_child, _rust_child) in children.iter().skip(2).zip(rust.children.iter()) {} + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; + + for diff in compare_properties!(emacs) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } + } Ok(DiffResult { status: this_status, diff --git a/src/parser/table.rs b/src/parser/table.rs index ac0083d..f3b5a33 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -176,12 +176,13 @@ fn org_mode_table_cell<'b, 'g, 'r, 's>( let table_cell_set_object_matcher = parser_with_context!(table_cell_set_object)(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); + let (remaining, _) = space0(input)?; let (remaining, (children, _exit_contents)) = verify( many_till(table_cell_set_object_matcher, exit_matcher), |(children, exit_contents)| { !children.is_empty() || Into::<&str>::into(exit_contents).ends_with("|") }, - )(input)?; + )(remaining)?; let (remaining, _tail) = org_mode_table_cell_end(&parser_context, remaining)?; From 0d0b1b20510d432a294d690bae69036e6149b8ba Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 00:12:40 -0400 Subject: [PATCH 19/33] compare_properties verse block. --- src/compare/diff.rs | 48 ++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 7509d36..8b96c6e 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1838,27 +1838,47 @@ fn compare_table_cell<'b, 's>( } fn compare_verse_block<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b VerseBlock<'s>, ) -> Result, Box> { - let children = emacs.as_list()?; - let child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + compare_children( + source, + emacs, + &rust.children, + &mut child_status, + &mut this_status, + &mut message, + )?; - for (_emacs_child, _rust_child) in children.iter().skip(2).zip(rust.children.iter()) {} + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } + } Ok(DiffResult { status: this_status, From ec98e1c3c5f4605f4057e2e70ca692115ff76762 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 00:15:04 -0400 Subject: [PATCH 20/33] compare_properties comment block. --- src/compare/diff.rs | 52 ++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 8b96c6e..054c54e 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1892,39 +1892,51 @@ fn compare_verse_block<'b, 's>( } fn compare_comment_block<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b CommentBlock<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare value - let contents = get_property_quoted_string(emacs, ":value")?.unwrap_or(String::new()); - if contents != rust.contents { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - contents, rust.contents - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":value"), + |r| Some(r.contents), + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { status: this_status, name: rust.get_elisp_name(), message, - children: Vec::new(), + children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } From bdfa050ee3b9b53127282c8e5a90353709aaad23 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 00:43:02 -0400 Subject: [PATCH 21/33] compare_properties example block. --- src/compare/compare_field.rs | 116 +++++++++++++++++++ src/compare/diff.rs | 215 ++++++++++------------------------- src/parser/lesser_block.rs | 23 ++-- 3 files changed, 194 insertions(+), 160 deletions(-) diff --git a/src/compare/compare_field.rs b/src/compare/compare_field.rs index 3df2d7e..e6496fb 100644 --- a/src/compare/compare_field.rs +++ b/src/compare/compare_field.rs @@ -13,6 +13,10 @@ use super::util::get_property_numeric; use super::util::get_property_quoted_string; use super::util::get_property_unquoted_atom; use crate::types::AstNode; +use crate::types::CharOffsetInLine; +use crate::types::LineNumber; +use crate::types::RetainLabels; +use crate::types::SwitchNumberLines; #[derive(Debug)] pub(crate) enum EmacsField<'s> { @@ -376,3 +380,115 @@ where } Ok(ComparePropertiesResult::NoChange) } + +pub(crate) fn compare_property_number_lines< + 'b, + 's, + 'x, + 'y, + R, + RG: Fn(R) -> Option<&'y SwitchNumberLines>, +>( + _source: &'s str, + emacs: &'b Token<'s>, + rust_node: R, + emacs_field: &'x str, + rust_value_getter: RG, +) -> Result, Box> { + let number_lines = get_property(emacs, emacs_field)?; + let rust_value = rust_value_getter(rust_node); + match (number_lines, &rust_value) { + (None, None) => {} + (Some(number_lines), Some(rust_number_lines)) => { + let token_list = number_lines.as_list()?; + let number_type = token_list + .get(0) + .map(Token::as_atom) + .map_or(Ok(None), |r| r.map(Some))? + .ok_or(":number-lines should have a type.")?; + let number_value = token_list + .get(2) + .map(Token::as_atom) + .map_or(Ok(None), |r| r.map(Some))? + .map(|val| val.parse::()) + .map_or(Ok(None), |r| r.map(Some))? + .ok_or(":number-lines should have a value.")?; + match (number_type, number_value, rust_number_lines) { + ("new", emacs_val, SwitchNumberLines::New(rust_val)) if emacs_val == *rust_val => {} + ("continued", emacs_val, SwitchNumberLines::Continued(rust_val)) + if emacs_val == *rust_val => {} + _ => { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, number_lines, rust_value + )); + return Ok(ComparePropertiesResult::SelfChange(this_status, message)); + } + } + } + _ => { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, number_lines, rust_value + )); + return Ok(ComparePropertiesResult::SelfChange(this_status, message)); + } + }; + + Ok(ComparePropertiesResult::NoChange) +} + +pub(crate) fn compare_property_retain_labels<'b, 's, 'x, 'y, R, RG: Fn(R) -> &'y RetainLabels>( + _source: &'s str, + emacs: &'b Token<'s>, + rust_node: R, + emacs_field: &'x str, + rust_value_getter: RG, +) -> Result, Box> { + let rust_value = rust_value_getter(rust_node); + let retain_labels = get_property_unquoted_atom(emacs, ":retain-labels")?; + if let Some(retain_labels) = retain_labels { + if retain_labels == "t" { + match rust_value { + RetainLabels::Yes => {} + _ => { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, retain_labels, rust_value + )); + return Ok(ComparePropertiesResult::SelfChange(this_status, message)); + } + } + } else { + let retain_labels: CharOffsetInLine = get_property_numeric(emacs, ":retain-labels")?.expect("Cannot be None or else the earlier get_property_unquoted_atom would have been None."); + match (retain_labels, rust_value) { + (e, RetainLabels::Keep(r)) if e == *r => {} + _ => { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, retain_labels, rust_value + )); + return Ok(ComparePropertiesResult::SelfChange(this_status, message)); + } + } + } + } else { + match rust_value { + RetainLabels::No => {} + _ => { + let this_status = DiffStatus::Bad; + let message = Some(format!( + "{} mismatch (emacs != rust) {:?} != {:?}", + emacs_field, retain_labels, rust_value + )); + return Ok(ComparePropertiesResult::SelfChange(this_status, message)); + } + } + } + + Ok(ComparePropertiesResult::NoChange) +} diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 054c54e..cbc19f9 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -10,8 +10,10 @@ use super::compare_field::compare_property_always_nil; use super::compare_field::compare_property_boolean; use super::compare_field::compare_property_list_of_ast_nodes; use super::compare_field::compare_property_list_of_quoted_string; +use super::compare_field::compare_property_number_lines; use super::compare_field::compare_property_numeric; use super::compare_field::compare_property_quoted_string; +use super::compare_field::compare_property_retain_labels; use super::compare_field::compare_property_set_of_quoted_string; use super::compare_field::compare_property_single_ast_node; use super::compare_field::compare_property_unquoted_atom; @@ -1944,166 +1946,73 @@ fn compare_comment_block<'b, 's>( } fn compare_example_block<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b ExampleBlock<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare value - let contents = get_property_quoted_string(emacs, ":value")?.unwrap_or(String::new()); - if contents != rust.contents { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - contents, rust.contents - )); - } - - // Compare switches - let switches = get_property_quoted_string(emacs, ":switches")?; - match (switches.as_ref().map(String::as_str), rust.switches) { - (None, None) => {} - (Some(""), None) => {} - (None, Some("")) => { - unreachable!("The organic parser would return a None instead of an empty string."); - } - (Some(e), Some(r)) if e == r => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Switches mismatch (emacs != rust) {:?} != {:?}", - switches, rust.switches - )); - } - } - - // Compare number-lines - let number_lines = get_property(emacs, ":number-lines")?; - match (number_lines, &rust.number_lines) { - (None, None) => {} - (Some(number_lines), Some(rust_number_lines)) => { - let token_list = number_lines.as_list()?; - let number_type = token_list - .get(0) - .map(Token::as_atom) - .map_or(Ok(None), |r| r.map(Some))? - .ok_or(":number-lines should have a type.")?; - let number_value = token_list - .get(2) - .map(Token::as_atom) - .map_or(Ok(None), |r| r.map(Some))? - .map(|val| val.parse::()) - .map_or(Ok(None), |r| r.map(Some))? - .ok_or(":number-lines should have a value.")?; - match (number_type, number_value, rust_number_lines) { - ("new", emacs_val, SwitchNumberLines::New(rust_val)) if emacs_val == *rust_val => {} - ("continued", emacs_val, SwitchNumberLines::Continued(rust_val)) - if emacs_val == *rust_val => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Number lines mismatch (emacs != rust) {:?} != {:?}", - number_lines, rust.number_lines - )); - } + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":value"), + |r| Some(r.contents.as_str()), + compare_property_quoted_string + ), + ( + EmacsField::Required(":switches"), + |r| r.switches, + compare_property_quoted_string + ), + ( + EmacsField::Required(":number-lines"), + |r| r.number_lines.as_ref(), + compare_property_number_lines + ), + ( + EmacsField::Required(":preserve-indent"), + |r| r.preserve_indent, + compare_property_numeric + ), + ( + EmacsField::Required(":retain-labels"), + |r| &r.retain_labels, + compare_property_retain_labels + ), + ( + EmacsField::Required(":use-labels"), + |r| r.use_labels, + compare_property_boolean + ), + ( + EmacsField::Required(":label-fmt"), + |r| r.label_format, + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message } - } - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Number lines mismatch (emacs != rust) {:?} != {:?}", - number_lines, rust.number_lines - )); - } - }; - - // Compare preserve-indent - let preserve_indent: Option = - get_property_numeric(emacs, ":preserve-indent")?; - if preserve_indent != rust.preserve_indent { - this_status = DiffStatus::Bad; - message = Some(format!( - "Prserve indent mismatch (emacs != rust) {:?} != {:?}", - preserve_indent, rust.preserve_indent - )); - } - - // Compare retain-labels - // retain-labels is t by default, nil if -r is set, or a number if -k and -r is set. - let retain_labels = get_property_unquoted_atom(emacs, ":retain-labels")?; - if let Some(retain_labels) = retain_labels { - if retain_labels == "t" { - match rust.retain_labels { - RetainLabels::Yes => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Retain labels mismatch (emacs != rust) {:?} != {:?}", - retain_labels, rust.retain_labels - )); - } - } - } else { - let retain_labels: CharOffsetInLine = get_property_numeric(emacs, ":retain-labels")?.expect("Cannot be None or else the earlier get_property_unquoted_atom would have been None."); - match (retain_labels, &rust.retain_labels) { - (e, RetainLabels::Keep(r)) if e == *r => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Retain labels mismatch (emacs != rust) {:?} != {:?}", - retain_labels, rust.retain_labels - )); - } - } - } - } else { - match rust.retain_labels { - RetainLabels::No => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Retain labels mismatch (emacs != rust) {:?} != {:?}", - retain_labels, rust.retain_labels - )); - } - } - } - - // Compare use-labels - let use_labels = get_property_boolean(emacs, ":use-labels")?; - if use_labels != rust.use_labels { - this_status = DiffStatus::Bad; - message = Some(format!( - "Use labels mismatch (emacs != rust) {:?} != {:?}", - use_labels, rust.use_labels - )); - } - - // Compare label-fmt - let label_format = get_property_quoted_string(emacs, ":label-fmt")?; - match (label_format.as_ref(), rust.label_format) { - (None, None) => {} - (Some(emacs_label_format), Some(rust_label_format)) - if emacs_label_format == rust_label_format => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Label format mismatch (emacs != rust) {:?} != {:?}", - label_format, rust.label_format - )); + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } } @@ -2111,7 +2020,7 @@ fn compare_example_block<'b, 's>( status: this_status, name: rust.get_elisp_name(), message, - children: Vec::new(), + children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } diff --git a/src/parser/lesser_block.rs b/src/parser/lesser_block.rs index b849082..06e5de9 100644 --- a/src/parser/lesser_block.rs +++ b/src/parser/lesser_block.rs @@ -16,6 +16,7 @@ use nom::combinator::verify; use nom::multi::many0; use nom::multi::many_till; use nom::sequence::tuple; +use nom::InputTake; use super::keyword::affiliated_keyword; use super::org_source::OrgSource; @@ -160,7 +161,20 @@ pub(crate) fn example_block<'b, 'g, 'r, 's>( ) -> Res, ExampleBlock<'s>> { let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; let (remaining, _) = lesser_block_begin("example")(context, remaining)?; - let (remaining, parameters) = opt(tuple((space1, example_switches)))(remaining)?; + let (remaining, parameters) = opt(alt(( + map(tuple((space1, example_switches)), |(_, switches)| switches), + map(space1, |ws: OrgSource<'_>| { + let source = ws.take(0); + ExampleSrcSwitches { + source: source.into(), + number_lines: None, + retain_labels: RetainLabels::Yes, + preserve_indent: None, + use_labels: true, + label_format: None, + } + }), + )))(remaining)?; let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?; let lesser_block_end_specialized = lesser_block_end("example"); let contexts = [ @@ -174,7 +188,6 @@ pub(crate) fn example_block<'b, 'g, 'r, 's>( let parser_context = context.with_additional_node(&contexts[0]); let parser_context = parser_context.with_additional_node(&contexts[1]); let parser_context = parser_context.with_additional_node(&contexts[2]); - let parameters = parameters.map(|(_, parameters)| parameters); let (remaining, contents) = content(&parser_context, remaining)?; let (remaining, _end) = lesser_block_end_specialized(&parser_context, remaining)?; @@ -185,11 +198,7 @@ pub(crate) fn example_block<'b, 'g, 'r, 's>( let (switches, number_lines, preserve_indent, retain_labels, use_labels, label_format) = { if let Some(parameters) = parameters { ( - if parameters.source.len() == 0 { - None - } else { - Some(parameters.source) - }, + Some(parameters.source), parameters.number_lines, parameters.preserve_indent, parameters.retain_labels, From 0b1e06f0d51af95b7bcc7ba7b0d14738f1328ae3 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 01:07:41 -0400 Subject: [PATCH 22/33] compare_properties export block. --- src/compare/diff.rs | 69 ++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index cbc19f9..9e3cf05 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -2028,51 +2028,56 @@ fn compare_example_block<'b, 's>( } fn compare_export_block<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b ExportBlock<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare type - let export_type = get_property_quoted_string(emacs, ":type")?; - let rust_export_type = rust.get_export_type(); - if export_type != rust_export_type { - this_status = DiffStatus::Bad; - message = Some(format!( - "Export type mismatch (emacs != rust) {:?} != {:?}", - export_type, rust.export_type - )); - } - - // Compare value - let contents = get_property_quoted_string(emacs, ":value")?.unwrap_or(String::new()); - if contents != rust.contents { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - contents, rust.contents - )); - } - - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":type"), + |r| r.get_export_type(), + compare_property_quoted_string + ), + ( + EmacsField::Required(":value"), + |r| Some(r.contents.as_str()), + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { status: this_status, name: rust.get_elisp_name(), message, - children: Vec::new(), + children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } From ec755bae8b7234c3a5649a8b281cc938641343b0 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 01:13:09 -0400 Subject: [PATCH 23/33] compare_properties src block. --- src/compare/diff.rs | 255 ++++++++++++-------------------------------- 1 file changed, 70 insertions(+), 185 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 9e3cf05..9550869 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -37,7 +37,6 @@ use crate::types::AstNode; use crate::types::BabelCall; use crate::types::Bold; use crate::types::CenterBlock; -use crate::types::CharOffsetInLine; use crate::types::CheckboxType; use crate::types::Citation; use crate::types::CitationReference; @@ -74,7 +73,6 @@ use crate::types::Keyword; use crate::types::LatexEnvironment; use crate::types::LatexFragment; use crate::types::LineBreak; -use crate::types::LineNumber; use crate::types::LinkType; use crate::types::Minute; use crate::types::MinuteInner; @@ -97,7 +95,6 @@ use crate::types::RadioTarget; use crate::types::RegularLink; use crate::types::RepeaterType; use crate::types::RepeaterWarningDelayValueType; -use crate::types::RetainLabels; use crate::types::Section; use crate::types::SpecialBlock; use crate::types::SrcBlock; @@ -106,7 +103,6 @@ use crate::types::StatisticsCookie; use crate::types::StrikeThrough; use crate::types::Subscript; use crate::types::Superscript; -use crate::types::SwitchNumberLines; use crate::types::Table; use crate::types::TableCell; use crate::types::TableRow; @@ -2085,194 +2081,83 @@ fn compare_export_block<'b, 's>( } fn compare_src_block<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b SrcBlock<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare language - let language = get_property_quoted_string(emacs, ":language")?; - if language.as_ref().map(String::as_str) != rust.language { - this_status = DiffStatus::Bad; - message = Some(format!( - "Language mismatch (emacs != rust) {:?} != {:?}", - language, rust.language - )); - } - - // Compare value - let contents = get_property_quoted_string(emacs, ":value")?.unwrap_or(String::new()); - if contents != rust.contents { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - contents, rust.contents - )); - } - - // Compare switches - let switches = get_property_quoted_string(emacs, ":switches")?; - match (switches.as_ref().map(String::as_str), rust.switches) { - (None, None) => {} - (Some(""), None) => {} - (None, Some("")) => { - unreachable!("The organic parser would return a None instead of an empty string."); - } - (Some(e), Some(r)) if e == r => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Switches mismatch (emacs != rust) {:?} != {:?}", - switches, rust.switches - )); - } - } - - // Compare parameters - let parameters = get_property_quoted_string(emacs, ":parameters")?; - match (parameters.as_ref().map(String::as_str), rust.parameters) { - (None, None) => {} - (Some(""), None) => {} - (None, Some("")) => { - unreachable!("The organic parser would return a None instead of an empty string."); - } - (Some(e), Some(r)) if e == r => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Parameters mismatch (emacs != rust) {:?} != {:?}", - parameters, rust.parameters - )); - } - } - - // Compare number-lines - let number_lines = get_property(emacs, ":number-lines")?; - match (number_lines, &rust.number_lines) { - (None, None) => {} - (Some(number_lines), Some(rust_number_lines)) => { - let token_list = number_lines.as_list()?; - let number_type = token_list - .get(0) - .map(Token::as_atom) - .map_or(Ok(None), |r| r.map(Some))? - .ok_or(":number-lines should have a type.")?; - let number_value = token_list - .get(2) - .map(Token::as_atom) - .map_or(Ok(None), |r| r.map(Some))? - .map(|val| val.parse::()) - .map_or(Ok(None), |r| r.map(Some))? - .ok_or(":number-lines should have a value.")?; - match (number_type, number_value, rust_number_lines) { - ("new", emacs_val, SwitchNumberLines::New(rust_val)) if emacs_val == *rust_val => {} - ("continued", emacs_val, SwitchNumberLines::Continued(rust_val)) - if emacs_val == *rust_val => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Number lines mismatch (emacs != rust) {:?} != {:?}", - number_lines, rust.number_lines - )); - } + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":language"), + |r| r.language, + compare_property_quoted_string + ), + ( + EmacsField::Required(":value"), + |r| Some(r.contents.as_str()), + compare_property_quoted_string + ), + ( + EmacsField::Required(":switches"), + |r| r.switches, + compare_property_quoted_string + ), + ( + EmacsField::Required(":parameters"), + |r| r.parameters, + compare_property_quoted_string + ), + ( + EmacsField::Required(":number-lines"), + |r| r.number_lines.as_ref(), + compare_property_number_lines + ), + ( + EmacsField::Required(":preserve-indent"), + |r| r.preserve_indent, + compare_property_numeric + ), + ( + EmacsField::Required(":retain-labels"), + |r| &r.retain_labels, + compare_property_retain_labels + ), + ( + EmacsField::Required(":use-labels"), + |r| r.use_labels, + compare_property_boolean + ), + ( + EmacsField::Required(":label-fmt"), + |r| r.label_format, + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message } - } - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Number lines mismatch (emacs != rust) {:?} != {:?}", - number_lines, rust.number_lines - )); - } - }; - - // Compare preserve-indent - let preserve_indent: Option = - get_property_numeric(emacs, ":preserve-indent")?; - if preserve_indent != rust.preserve_indent { - this_status = DiffStatus::Bad; - message = Some(format!( - "Prserve indent mismatch (emacs != rust) {:?} != {:?}", - preserve_indent, rust.preserve_indent - )); - } - - // Compare retain-labels - // retain-labels is t by default, nil if -r is set, or a number if -k and -r is set. - let retain_labels = get_property_unquoted_atom(emacs, ":retain-labels")?; - if let Some(retain_labels) = retain_labels { - if retain_labels == "t" { - match rust.retain_labels { - RetainLabels::Yes => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Retain labels mismatch (emacs != rust) {:?} != {:?}", - retain_labels, rust.retain_labels - )); - } - } - } else { - let retain_labels: CharOffsetInLine = get_property_numeric(emacs, ":retain-labels")?.expect("Cannot be None or else the earlier get_property_unquoted_atom would have been None."); - match (retain_labels, &rust.retain_labels) { - (e, RetainLabels::Keep(r)) if e == *r => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Retain labels mismatch (emacs != rust) {:?} != {:?}", - retain_labels, rust.retain_labels - )); - } - } - } - } else { - match rust.retain_labels { - RetainLabels::No => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Retain labels mismatch (emacs != rust) {:?} != {:?}", - retain_labels, rust.retain_labels - )); - } - } - } - - // Compare use-labels - let use_labels = get_property_boolean(emacs, ":use-labels")?; - if use_labels != rust.use_labels { - this_status = DiffStatus::Bad; - message = Some(format!( - "Use labels mismatch (emacs != rust) {:?} != {:?}", - use_labels, rust.use_labels - )); - } - - // Compare label-fmt - let label_format = get_property_quoted_string(emacs, ":label-fmt")?; - match (label_format.as_ref(), rust.label_format) { - (None, None) => {} - (Some(emacs_label_format), Some(rust_label_format)) - if emacs_label_format == rust_label_format => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Label format mismatch (emacs != rust) {:?} != {:?}", - label_format, rust.label_format - )); + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } } @@ -2280,7 +2165,7 @@ fn compare_src_block<'b, 's>( status: this_status, name: rust.get_elisp_name(), message, - children: Vec::new(), + children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } From 384242af876172c54e09abca724515a99a35a1cf Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 01:19:14 -0400 Subject: [PATCH 24/33] compare_properties clock. --- src/compare/diff.rs | 71 +++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 9550869..bb65c33 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -2173,51 +2173,46 @@ fn compare_src_block<'b, 's>( } fn compare_clock<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b Clock<'s>, ) -> Result, Box> { - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // Compare value - let value = get_property(emacs, ":value")?; - match value { - Some(e) => { - let result = compare_ast_node(_source, e, (&rust.timestamp).into())?; - child_status.push(artificial_diff_scope("value", vec![result])?); - } - None => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - value, rust.timestamp - )); - } - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare duration - let duration = get_property_quoted_string(emacs, ":duration")?; - if duration.as_ref().map(String::as_str) != rust.duration { - this_status = DiffStatus::Bad; - message = Some(format!( - "Duration mismatch (emacs != rust) {:?} != {:?}", - duration, rust.duration - )); - } - - // Compare status - let status = get_property_unquoted_atom(emacs, ":status")?; - match (status, &rust.status) { - (Some("running"), ClockStatus::Running) => {} - (Some("closed"), ClockStatus::Closed) => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Status mismatch (emacs != rust) {:?} != {:?}", - status, rust.status - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Required(":value"), + |r| Some(&r.timestamp), + compare_property_single_ast_node + ), + ( + EmacsField::Required(":duration"), + |r| r.duration, + compare_property_quoted_string + ), + ( + EmacsField::Required(":status"), + |r| Some(match r.status { + ClockStatus::Running => "running", + ClockStatus::Closed => "closed", + }), + compare_property_unquoted_atom + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } } From d5396e311bbac008d60fb63b9144d6ca072193b2 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 01:22:16 -0400 Subject: [PATCH 25/33] compare_properties diary sexp. --- src/compare/diff.rs | 52 ++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index bb65c33..8d541f9 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -2228,39 +2228,51 @@ fn compare_clock<'b, 's>( } fn compare_diary_sexp<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b DiarySexp<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare value - let value = get_property_quoted_string(emacs, ":value")?; - if value.as_ref().map(String::as_str) != Some(rust.value) { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - value, rust.value - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":value"), + |r| Some(r.value), + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { status: this_status, name: rust.get_elisp_name(), message, - children: Vec::new(), + children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } From 0b465fe29018f4f7c36bf8e6755a9fc43a0b638d Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 01:24:11 -0400 Subject: [PATCH 26/33] compare_properties planning. --- src/compare/diff.rs | 77 +++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 48 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 8d541f9..762b435 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -2284,58 +2284,39 @@ fn compare_planning<'b, 's>( emacs: &'b Token<'s>, rust: &'b Planning<'s>, ) -> Result, Box> { - let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // Compare scheduled - let scheduled = get_property(emacs, ":scheduled")?; - match (scheduled, &rust.scheduled) { - (None, None) => {} - (None, Some(_)) | (Some(_), None) => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Scheduled mismatch (emacs != rust) {:?} != {:?}", - scheduled, rust.scheduled - )); - } - (Some(emacs_child), Some(rust_child)) => { - let result = compare_ast_node(source, emacs_child, rust_child.into())?; - child_status.push(artificial_diff_scope("scheduled", vec![result])?); - } - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare deadline - let deadline = get_property(emacs, ":deadline")?; - match (deadline, &rust.deadline) { - (None, None) => {} - (None, Some(_)) | (Some(_), None) => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Deadline mismatch (emacs != rust) {:?} != {:?}", - deadline, rust.deadline - )); - } - (Some(emacs_child), Some(rust_child)) => { - let result = compare_ast_node(source, emacs_child, rust_child.into())?; - child_status.push(artificial_diff_scope("deadline", vec![result])?); - } - } - - // Compare closed - let closed = get_property(emacs, ":closed")?; - match (closed, &rust.closed) { - (None, None) => {} - (None, Some(_)) | (Some(_), None) => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Closed mismatch (emacs != rust) {:?} != {:?}", - closed, rust.closed - )); - } - (Some(emacs_child), Some(rust_child)) => { - let result = compare_ast_node(source, emacs_child, rust_child.into())?; - child_status.push(artificial_diff_scope("closed", vec![result])?); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Required(":scheduled"), + |r| r.scheduled.as_ref(), + compare_property_single_ast_node + ), + ( + EmacsField::Required(":deadline"), + |r| r.deadline.as_ref(), + compare_property_single_ast_node + ), + ( + EmacsField::Required(":closed"), + |r| r.closed.as_ref(), + compare_property_single_ast_node + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } } From e40e3ff553bab9c87ae8a8638b2d58ab178de134 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 01:27:37 -0400 Subject: [PATCH 27/33] compare_properties fixed width area. --- src/compare/diff.rs | 53 ++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 762b435..9ac4c7a 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -2332,35 +2332,44 @@ fn compare_planning<'b, 's>( } fn compare_fixed_width_area<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b FixedWidthArea<'s>, ) -> Result, Box> { - let child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare value - let value = get_property_quoted_string(emacs, ":value")? - .ok_or("Fixed width area should have a value.")?; - let rust_value = rust.get_value(); - if value != rust_value { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - value, rust_value - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":value"), + |r| Some(r.get_value()), + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From fc104680eb850b4fcd263d95c6a436d1490728e7 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 01:29:00 -0400 Subject: [PATCH 28/33] compare_properties horizontal rule. --- src/compare/diff.rs | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 9ac4c7a..d6f8a73 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -2384,23 +2384,39 @@ fn compare_fixed_width_area<'b, 's>( } fn compare_horizontal_rule<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b HorizontalRule<'s>, ) -> Result, Box> { - let child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); + assert_no_children(emacs, &mut this_status, &mut message)?; + + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From c2222c9102ad402a17a5fb86f8e72bd955916a5d Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 01:32:36 -0400 Subject: [PATCH 29/33] compare_properties keyword. --- src/compare/diff.rs | 71 +++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index d6f8a73..adb509f 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -2431,48 +2431,49 @@ fn compare_horizontal_rule<'b, 's>( } fn compare_keyword<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b Keyword<'s>, ) -> Result, Box> { - let child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + assert_no_children(emacs, &mut this_status, &mut message)?; - let key = unquote( - get_property(emacs, ":key")? - .ok_or("Emacs keywords should have a :key")? - .as_atom()?, - )?; - if key != rust.key.to_uppercase() { - this_status = DiffStatus::Bad; - message = Some(format!( - "Mismatchs keyword keys (emacs != rust) {:?} != {:?}", - key, rust.key - )) - } - let value = unquote( - get_property(emacs, ":value")? - .ok_or("Emacs keywords should have a :value")? - .as_atom()?, - )?; - if value != rust.value { - this_status = DiffStatus::Bad; - message = Some(format!( - "Mismatchs keyword values (emacs != rust) {:?} != {:?}", - value, rust.value - )) + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":key"), + |r| Some(r.key.to_uppercase()), + compare_property_quoted_string + ), + ( + EmacsField::Required(":value"), + |r| Some(r.value), + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From 9f166278f4b5c1ff60e93754931321fb19b2ff14 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 01:36:48 -0400 Subject: [PATCH 30/33] compare_properties babel call. --- src/compare/diff.rs | 111 ++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 60 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index adb509f..a27fdfb 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -2488,73 +2488,64 @@ fn compare_keyword<'b, 's>( } fn compare_babel_call<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b BabelCall<'s>, ) -> Result, Box> { - let child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare value - let value = get_property_quoted_string(emacs, ":value")?.unwrap_or(String::new()); - if value != rust.value { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - value, rust.value - )) - } - - // Compare call - let call = get_property_quoted_string(emacs, ":call")?; - if call.as_ref().map(String::as_str) != rust.call { - this_status = DiffStatus::Bad; - message = Some(format!( - "Call mismatch (emacs != rust) {:?} != {:?}", - call, rust.call - )) - } - - // Compare arguments - let arguments = get_property_quoted_string(emacs, ":arguments")?; - if arguments.as_ref().map(String::as_str) != rust.arguments { - this_status = DiffStatus::Bad; - message = Some(format!( - "Arguments mismatch (emacs != rust) {:?} != {:?}", - arguments, rust.arguments - )) - } - - // Compare inside header - let inside_header = get_property_quoted_string(emacs, ":inside-header")?; - if inside_header.as_ref().map(String::as_str) != rust.inside_header { - this_status = DiffStatus::Bad; - message = Some(format!( - "Inside header mismatch (emacs != rust) {:?} != {:?}", - inside_header, rust.inside_header - )) - } - - // Compare end header - let end_header = get_property_quoted_string(emacs, ":end-header")?; - if end_header.as_ref().map(String::as_str) != rust.end_header { - this_status = DiffStatus::Bad; - message = Some(format!( - "End header mismatch (emacs != rust) {:?} != {:?}", - end_header, rust.end_header - )) + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":value"), + |r| Some(r.value), + compare_property_quoted_string + ), + ( + EmacsField::Required(":call"), + |r| r.call, + compare_property_quoted_string + ), + ( + EmacsField::Required(":arguments"), + |r| r.arguments, + compare_property_quoted_string + ), + ( + EmacsField::Required(":inside-header"), + |r| r.inside_header, + compare_property_quoted_string + ), + ( + EmacsField::Required(":end-header"), + |r| r.end_header, + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From 1a67aac502b20ab283f16f6fd3b796f129017aee Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 01:39:47 -0400 Subject: [PATCH 31/33] compare_properties latex environment. --- src/compare/diff.rs | 51 +++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index a27fdfb..3e644dd 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -2560,33 +2560,44 @@ fn compare_babel_call<'b, 's>( } fn compare_latex_environment<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b LatexEnvironment<'s>, ) -> Result, Box> { - let child_status = Vec::new(); let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // TODO: Compare :caption - // Compare name - let name = get_property_quoted_string(emacs, ":name")?; - if name.as_ref().map(String::as_str) != rust.name { - this_status = DiffStatus::Bad; - message = Some(format!( - "Name mismatch (emacs != rust) {:?} != {:?}", - name, rust.name - )); - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare value - let value = get_property_quoted_string(emacs, ":value")?; - if value.as_ref().map(String::as_str) != Some(rust.value) { - this_status = DiffStatus::Bad; - message = Some(format!( - "Value mismatch (emacs != rust) {:?} != {:?}", - value, rust.value - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Optional(":name"), + |r| r.name, + compare_property_quoted_string + ), + ( + EmacsField::Optional(":caption"), + compare_identity, + compare_noop + ), + ( + EmacsField::Required(":value"), + |r| Some(r.value), + compare_property_quoted_string + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), + } } Ok(DiffResult { From bdaf90af031ad4c9f9288a42d3706b9b040ebea5 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 02:05:31 -0400 Subject: [PATCH 32/33] compare_properties timestamp. --- src/compare/diff.rs | 443 +++++++++++++++++--------------------------- 1 file changed, 168 insertions(+), 275 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 3e644dd..bcdb2fe 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -26,9 +26,7 @@ use super::util::compare_children; use super::util::compare_standard_properties; use super::util::get_property; 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::compare_field::ComparePropertiesResult; use crate::compare::compare_field::EmacsField; use crate::compare::macros::compare_properties; @@ -47,7 +45,6 @@ use crate::types::Comment; use crate::types::CommentBlock; use crate::types::Date; use crate::types::DayOfMonth; -use crate::types::DayOfMonthInner; use crate::types::DiarySexp; use crate::types::Document; use crate::types::DocumentElement; @@ -65,7 +62,6 @@ use crate::types::GetStandardProperties; use crate::types::Heading; use crate::types::HorizontalRule; use crate::types::Hour; -use crate::types::HourInner; use crate::types::InlineBabelCall; use crate::types::InlineSourceBlock; use crate::types::Italic; @@ -75,9 +71,7 @@ use crate::types::LatexFragment; use crate::types::LineBreak; use crate::types::LinkType; use crate::types::Minute; -use crate::types::MinuteInner; use crate::types::Month; -use crate::types::MonthInner; use crate::types::NodeProperty; use crate::types::OrgMacro; use crate::types::Paragraph; @@ -94,7 +88,6 @@ use crate::types::RadioLink; use crate::types::RadioTarget; use crate::types::RegularLink; use crate::types::RepeaterType; -use crate::types::RepeaterWarningDelayValueType; use crate::types::Section; use crate::types::SpecialBlock; use crate::types::SrcBlock; @@ -119,7 +112,6 @@ use crate::types::Verbatim; use crate::types::VerseBlock; use crate::types::WarningDelayType; use crate::types::Year; -use crate::types::YearInner; #[derive(Debug)] pub enum DiffEntry<'b, 's> { @@ -4000,279 +3992,180 @@ fn compare_superscript<'b, 's>( } fn compare_timestamp<'b, 's>( - _source: &'s str, + source: &'s str, emacs: &'b Token<'s>, rust: &'b Timestamp<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); let mut message = None; - // Compare type - let timestamp_type = get_property_unquoted_atom(emacs, ":type")?; - match (timestamp_type, &rust.timestamp_type) { - (Some("diary"), TimestampType::Diary) => {} - (Some("active"), TimestampType::Active) => {} - (Some("inactive"), TimestampType::Inactive) => {} - (Some("active-range"), TimestampType::ActiveRange) => {} - (Some("inactive-range"), TimestampType::InactiveRange) => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Timestamp type mismatch (emacs != rust) {:?} != {:?}", - timestamp_type, rust.timestamp_type - )); - } - } + assert_no_children(emacs, &mut this_status, &mut message)?; - // Compare range-type - let range_type = get_property_unquoted_atom(emacs, ":range-type")?; - match (range_type, &rust.range_type) { - (Some("daterange"), TimestampRangeType::DateRange) => {} - (Some("timerange"), TimestampRangeType::TimeRange) => {} - (None, TimestampRangeType::None) => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Range type mismatch (emacs != rust) {:?} != {:?}", - range_type, rust.range_type - )); - } - } - - // Compare raw-value - let raw_value = get_property_quoted_string(emacs, ":raw-value")? - .ok_or("Timestamps should have a :raw-value.")?; - if raw_value != rust.get_raw_value() { - this_status = DiffStatus::Bad; - message = Some(format!( - "Raw value mismatch (emacs != rust) {:?} != {:?}", - raw_value, - rust.get_raw_value() - )); - } - - // Compare start - let year_start: Option = get_property_numeric(emacs, ":year-start")?; - let month_start: Option = get_property_numeric(emacs, ":month-start")?; - let day_of_month_start: Option = get_property_numeric(emacs, ":day-start")?; - let rust_year_start = rust.start.as_ref().map(Date::get_year).map(Year::get_value); - let rust_month_start = rust - .start - .as_ref() - .map(Date::get_month) - .map(Month::get_value); - let rust_day_of_month_start = rust - .start - .as_ref() - .map(Date::get_day_of_month) - .map(DayOfMonth::get_value); - if year_start != rust_year_start { - this_status = DiffStatus::Bad; - message = Some(format!( - "year start mismatch (emacs != rust) {:?} != {:?}", - year_start, rust_year_start - )); - } - if month_start != rust_month_start { - this_status = DiffStatus::Bad; - message = Some(format!( - "month start mismatch (emacs != rust) {:?} != {:?}", - month_start, rust_month_start - )); - } - if day_of_month_start != rust_day_of_month_start { - this_status = DiffStatus::Bad; - message = Some(format!( - "day of month start mismatch (emacs != rust) {:?} != {:?}", - day_of_month_start, rust_day_of_month_start - )); - } - - // Compare end - let year_end: Option = get_property_numeric(emacs, ":year-end")?; - let month_end: Option = get_property_numeric(emacs, ":month-end")?; - let day_of_month_end: Option = get_property_numeric(emacs, ":day-end")?; - let rust_year_end = rust.end.as_ref().map(Date::get_year).map(Year::get_value); - let rust_month_end = rust.end.as_ref().map(Date::get_month).map(Month::get_value); - let rust_day_of_month_end = rust - .end - .as_ref() - .map(Date::get_day_of_month) - .map(DayOfMonth::get_value); - if year_end != rust_year_end { - this_status = DiffStatus::Bad; - message = Some(format!( - "year end mismatch (emacs != rust) {:?} != {:?}", - year_end, rust_year_end - )); - } - if month_end != rust_month_end { - this_status = DiffStatus::Bad; - message = Some(format!( - "month end mismatch (emacs != rust) {:?} != {:?}", - month_end, rust_month_end - )); - } - if day_of_month_end != rust_day_of_month_end { - this_status = DiffStatus::Bad; - message = Some(format!( - "day of month end mismatch (emacs != rust) {:?} != {:?}", - day_of_month_end, rust_day_of_month_end - )); - } - - // Compare time start - let hour_start: Option = get_property_numeric(emacs, ":hour-start")?; - let minute_start: Option = get_property_numeric(emacs, ":minute-start")?; - let rust_hour_start = rust - .start_time - .as_ref() - .map(Time::get_hour) - .map(Hour::get_value); - let rust_minute_start = rust - .start_time - .as_ref() - .map(Time::get_minute) - .map(Minute::get_value); - if hour_start != rust_hour_start { - this_status = DiffStatus::Bad; - message = Some(format!( - "hour start mismatch (emacs != rust) {:?} != {:?}", - hour_start, rust_hour_start - )); - } - if minute_start != rust_minute_start { - this_status = DiffStatus::Bad; - message = Some(format!( - "minute start mismatch (emacs != rust) {:?} != {:?}", - minute_start, rust_minute_start - )); - } - - // Compare time end - let hour_end: Option = get_property_numeric(emacs, ":hour-end")?; - let minute_end: Option = get_property_numeric(emacs, ":minute-end")?; - let rust_hour_end = rust - .end_time - .as_ref() - .map(Time::get_hour) - .map(Hour::get_value); - let rust_minute_end = rust - .end_time - .as_ref() - .map(Time::get_minute) - .map(Minute::get_value); - if hour_end != rust_hour_end { - this_status = DiffStatus::Bad; - message = Some(format!( - "hour end mismatch (emacs != rust) {:?} != {:?}", - hour_end, rust_hour_end - )); - } - if minute_end != rust_minute_end { - this_status = DiffStatus::Bad; - message = Some(format!( - "minute end mismatch (emacs != rust) {:?} != {:?}", - minute_end, rust_minute_end - )); - } - - // Compare repeater - let repeater_type = get_property_unquoted_atom(emacs, ":repeater-type")?; - let repeater_value: Option = - get_property_numeric(emacs, ":repeater-value")?; - let repeater_unit = get_property_unquoted_atom(emacs, ":repeater-unit")?; - let rust_repeater_type = rust - .repeater - .as_ref() - .map(|repeater| &repeater.repeater_type); - let rust_repeater_value = rust.repeater.as_ref().map(|repeater| repeater.value); - let rust_repeater_unit = rust.repeater.as_ref().map(|repeater| &repeater.unit); - match (repeater_type, rust_repeater_type) { - (Some("cumulate"), Some(RepeaterType::Cumulative)) => {} - (Some("catch-up"), Some(RepeaterType::CatchUp)) => {} - (Some("restart"), Some(RepeaterType::Restart)) => {} - (None, None) => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Repeater type mismatch (emacs != rust) {:?} != {:?}", - repeater_type, rust_repeater_type - )); - } - } - if repeater_value != rust_repeater_value { - this_status = DiffStatus::Bad; - message = Some(format!( - "Repeater value mismatch (emacs != rust) {:?} != {:?}", - repeater_value, rust_repeater_value - )); - } - match (repeater_unit, rust_repeater_unit) { - (Some("hour"), Some(TimeUnit::Hour)) => {} - (Some("day"), Some(TimeUnit::Day)) => {} - (Some("week"), Some(TimeUnit::Week)) => {} - (Some("month"), Some(TimeUnit::Month)) => {} - (Some("year"), Some(TimeUnit::Year)) => {} - (None, None) => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Repeater unit mismatch (emacs != rust) {:?} != {:?}", - repeater_unit, rust_repeater_unit - )); - } - } - - // Compare warning_delay - let warning_delay_type = get_property_unquoted_atom(emacs, ":warning-type")?; - let warning_delay_value: Option = - get_property_numeric(emacs, ":warning-value")?; - let warning_delay_unit = get_property_unquoted_atom(emacs, ":warning-unit")?; - let rust_warning_delay_type = rust - .warning_delay - .as_ref() - .map(|warning_delay| &warning_delay.warning_delay_type); - let rust_warning_delay_value = rust - .warning_delay - .as_ref() - .map(|warning_delay| warning_delay.value); - let rust_warning_delay_unit = rust - .warning_delay - .as_ref() - .map(|warning_delay| &warning_delay.unit); - match (warning_delay_type, rust_warning_delay_type) { - (Some("all"), Some(WarningDelayType::All)) => {} - (Some("first"), Some(WarningDelayType::First)) => {} - (None, None) => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Warning delay type mismatch (emacs != rust) {:?} != {:?}", - warning_delay_type, rust_warning_delay_type - )); - } - } - if warning_delay_value != rust_warning_delay_value { - this_status = DiffStatus::Bad; - message = Some(format!( - "Warning delay value mismatch (emacs != rust) {:?} != {:?}", - warning_delay_value, rust_warning_delay_value - )); - } - match (warning_delay_unit, rust_warning_delay_unit) { - (Some("hour"), Some(TimeUnit::Hour)) => {} - (Some("day"), Some(TimeUnit::Day)) => {} - (Some("week"), Some(TimeUnit::Week)) => {} - (Some("month"), Some(TimeUnit::Month)) => {} - (Some("year"), Some(TimeUnit::Year)) => {} - (None, None) => {} - _ => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Warning delay unit mismatch (emacs != rust) {:?} != {:?}", - warning_delay_unit, rust_warning_delay_unit - )); + for diff in compare_properties!( + source, + emacs, + rust, + ( + EmacsField::Required(":type"), + |r| Some(match r.timestamp_type { + TimestampType::Diary => "diary", + TimestampType::Active => "active", + TimestampType::Inactive => "inactive", + TimestampType::ActiveRange => "active-range", + TimestampType::InactiveRange => "inactive-range", + }), + compare_property_unquoted_atom + ), + ( + EmacsField::Required(":range-type"), + |r| match r.range_type { + TimestampRangeType::DateRange => Some("daterange"), + TimestampRangeType::TimeRange => Some("timerange"), + TimestampRangeType::None => None, + }, + compare_property_unquoted_atom + ), + ( + EmacsField::Required(":raw-value"), + |r| Some(r.get_raw_value()), + compare_property_quoted_string + ), + ( + EmacsField::Required(":year-start"), + |r| r.start.as_ref().map(Date::get_year).map(Year::get_value), + compare_property_numeric + ), + ( + EmacsField::Required(":month-start"), + |r| r.start.as_ref().map(Date::get_month).map(Month::get_value), + compare_property_numeric + ), + ( + EmacsField::Required(":day-start"), + |r| r + .start + .as_ref() + .map(Date::get_day_of_month) + .map(DayOfMonth::get_value), + compare_property_numeric + ), + ( + EmacsField::Required(":year-end"), + |r| r.end.as_ref().map(Date::get_year).map(Year::get_value), + compare_property_numeric + ), + ( + EmacsField::Required(":month-end"), + |r| r.end.as_ref().map(Date::get_month).map(Month::get_value), + compare_property_numeric + ), + ( + EmacsField::Required(":day-end"), + |r| r + .end + .as_ref() + .map(Date::get_day_of_month) + .map(DayOfMonth::get_value), + compare_property_numeric + ), + ( + EmacsField::Required(":hour-start"), + |r| r + .start_time + .as_ref() + .map(Time::get_hour) + .map(Hour::get_value), + compare_property_numeric + ), + ( + EmacsField::Required(":minute-start"), + |r| r + .start_time + .as_ref() + .map(Time::get_minute) + .map(Minute::get_value), + compare_property_numeric + ), + ( + EmacsField::Required(":hour-end"), + |r| r.end_time.as_ref().map(Time::get_hour).map(Hour::get_value), + compare_property_numeric + ), + ( + EmacsField::Required(":minute-end"), + |r| r + .end_time + .as_ref() + .map(Time::get_minute) + .map(Minute::get_value), + compare_property_numeric + ), + ( + EmacsField::Optional(":repeater-type"), + |r| match r.repeater.as_ref().map(|repeater| &repeater.repeater_type) { + Some(RepeaterType::Cumulative) => Some("cumulate"), + Some(RepeaterType::CatchUp) => Some("catch-up"), + Some(RepeaterType::Restart) => Some("restart"), + None => None, + }, + compare_property_unquoted_atom + ), + ( + EmacsField::Optional(":repeater-unit"), + |r| match r.repeater.as_ref().map(|repeater| &repeater.unit) { + Some(TimeUnit::Hour) => Some("hour"), + Some(TimeUnit::Day) => Some("day"), + Some(TimeUnit::Week) => Some("week"), + Some(TimeUnit::Month) => Some("month"), + Some(TimeUnit::Year) => Some("year"), + None => None, + }, + compare_property_unquoted_atom + ), + ( + EmacsField::Optional(":repeater-value"), + |r| r.repeater.as_ref().map(|repeater| repeater.value), + compare_property_numeric + ), + ( + EmacsField::Optional(":warning-type"), + |r| match r + .warning_delay + .as_ref() + .map(|repeater| &repeater.warning_delay_type) + { + Some(WarningDelayType::All) => Some("all"), + Some(WarningDelayType::First) => Some("first"), + None => None, + }, + compare_property_unquoted_atom + ), + ( + EmacsField::Optional(":warning-unit"), + |r| match r.warning_delay.as_ref().map(|repeater| &repeater.unit) { + Some(TimeUnit::Hour) => Some("hour"), + Some(TimeUnit::Day) => Some("day"), + Some(TimeUnit::Week) => Some("week"), + Some(TimeUnit::Month) => Some("month"), + Some(TimeUnit::Year) => Some("year"), + None => None, + }, + compare_property_unquoted_atom + ), + ( + EmacsField::Optional(":warning-value"), + |r| r.warning_delay.as_ref().map(|repeater| repeater.value), + compare_property_numeric + ) + ) { + match diff { + ComparePropertiesResult::NoChange => {} + ComparePropertiesResult::SelfChange(new_status, new_message) => { + this_status = new_status; + message = new_message + } + ComparePropertiesResult::DiffEntry(diff_entry) => child_status.push(diff_entry), } } @@ -4280,7 +4173,7 @@ fn compare_timestamp<'b, 's>( status: this_status, name: rust.get_elisp_name(), message, - children: Vec::new(), + children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } From 534c5ded3cb8186cb785704805bf6a228f079036 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 02:07:36 -0400 Subject: [PATCH 33/33] Fix table type is required. --- src/compare/diff.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index bcdb2fe..f8eada8 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1704,7 +1704,7 @@ fn compare_table<'b, 's>( compare_property_set_of_quoted_string ), ( - EmacsField::Optional(":type"), + EmacsField::Required(":type"), |_| Some("org"), compare_property_unquoted_atom ),