From a8737940687c190c53cda7831940995855c8880a Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 14:58:18 -0400 Subject: [PATCH 1/5] Starting a compare properties document function. --- src/compare/diff.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++ src/compare/util.rs | 33 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index f8eada8..154bf31 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -23,6 +23,7 @@ use super::sexp::unquote; use super::sexp::Token; use super::util::assert_no_children; use super::util::compare_children; +use super::util::compare_children_iter; use super::util::compare_standard_properties; use super::util::get_property; use super::util::get_property_boolean; @@ -438,6 +439,63 @@ pub fn compare_document<'b, 's>( } fn _compare_document<'b, 's>( + source: &'s str, + emacs: &'b Token<'s>, + rust: &'b Document<'s>, +) -> Result, Box> { + let mut this_status = DiffStatus::Good; + let mut child_status = Vec::new(); + let mut message = None; + + // compare_children_iter( + // source, + // emacs, + // rust.zeroth_section + // .iter() + // .map(Into::::into) + // .chain(rust.children.iter().map(Into::::into)), + // &mut child_status, + // &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 { + status: this_status, + name: rust.get_elisp_name(), + message, + children: child_status, + rust_source: rust.get_source(), + emacs_token: emacs, + } + .into()) +} + +fn _old_compare_document<'b, 's>( _source: &'s str, emacs: &'b Token<'s>, rust: &'b Document<'s>, diff --git a/src/compare/util.rs b/src/compare/util.rs index 28f7bad..e3e02d5 100644 --- a/src/compare/util.rs +++ b/src/compare/util.rs @@ -284,6 +284,39 @@ where Ok(()) } +pub(crate) fn compare_children_iter< + 'b, + 's, + 'x, + RC: 'x, + RI: Iterator + ExactSizeIterator, +>( + source: &'s str, + emacs: &'b Token<'s>, + rust_children: RI, + child_status: &mut Vec>, + this_status: &mut DiffStatus, + message: &mut Option, +) -> Result<(), Box> +where + AstNode<'b, 's>: From<&'x RC>, +{ + let emacs_children = emacs.as_list()?; + let emacs_children_length = emacs_children.len() - 2; + if emacs_children_length != rust_children.len() { + *this_status = DiffStatus::Bad; + *message = Some(format!( + "Child length mismatch (emacs != rust) {:?} != {:?}", + emacs_children_length, + rust_children.len() + )); + } + for (emacs_child, rust_child) in emacs_children.iter().skip(2).zip(rust_children) { + child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); + } + Ok(()) +} + pub(crate) fn assert_no_children<'b, 's>( emacs: &'b Token<'s>, this_status: &mut DiffStatus, From ee5ed17c20f3ef157439d41453a324643ac7e4b8 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 15:19:42 -0400 Subject: [PATCH 2/5] Implement ExactSizeIterator for DocumentIter. --- src/compare/diff.rs | 19 ++++++++----------- src/compare/util.rs | 10 ++-------- src/iter/ast_node_iter.rs | 37 +++++++++++++++++++++++++++++-------- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 154bf31..838b0e2 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -447,17 +447,14 @@ fn _compare_document<'b, 's>( let mut child_status = Vec::new(); let mut message = None; - // compare_children_iter( - // source, - // emacs, - // rust.zeroth_section - // .iter() - // .map(Into::::into) - // .chain(rust.children.iter().map(Into::::into)), - // &mut child_status, - // &mut this_status, - // &mut message, - // )?; + compare_children_iter( + source, + emacs, + rust.into_iter(), + &mut child_status, + &mut this_status, + &mut message, + )?; for diff in compare_properties!( source, diff --git a/src/compare/util.rs b/src/compare/util.rs index e3e02d5..47dd8e5 100644 --- a/src/compare/util.rs +++ b/src/compare/util.rs @@ -284,13 +284,7 @@ where Ok(()) } -pub(crate) fn compare_children_iter< - 'b, - 's, - 'x, - RC: 'x, - RI: Iterator + ExactSizeIterator, ->( +pub(crate) fn compare_children_iter<'b, 's, RC, RI: Iterator + ExactSizeIterator>( source: &'s str, emacs: &'b Token<'s>, rust_children: RI, @@ -299,7 +293,7 @@ pub(crate) fn compare_children_iter< message: &mut Option, ) -> Result<(), Box> where - AstNode<'b, 's>: From<&'x RC>, + AstNode<'b, 's>: From, { let emacs_children = emacs.as_list()?; let emacs_children_length = emacs_children.len() - 2; diff --git a/src/iter/ast_node_iter.rs b/src/iter/ast_node_iter.rs index 1c4210d..851666e 100644 --- a/src/iter/ast_node_iter.rs +++ b/src/iter/ast_node_iter.rs @@ -202,14 +202,35 @@ impl<'r, 's> AstNodeIter<'r, 's> { } } -multi_field_iter!( - Document<'s>, - DocumentIter, - zeroth_section, - std::option::Iter<'r, Section<'s>>, - children, - std::slice::Iter<'r, Heading<'s>> -); +pub struct DocumentIter<'r, 's> { + zeroth_section: std::option::Iter<'r, Section<'s>>, + children: std::slice::Iter<'r, Heading<'s>>, +} +impl<'r, 's> Iterator for DocumentIter<'r, 's> { + type Item = AstNode<'r, 's>; + fn next(&mut self) -> Option { + self.zeroth_section + .next() + .map(Into::::into) + .or_else(|| self.children.next().map(Into::::into)) + } + + fn size_hint(&self) -> (usize, Option) { + let size = self.zeroth_section.len() + self.children.len(); + (size, Some(size)) + } +} +impl<'r, 's> ExactSizeIterator for DocumentIter<'r, 's> {} +impl<'r, 's> IntoIterator for &'r Document<'s> { + type Item = AstNode<'r, 's>; + type IntoIter = DocumentIter<'r, 's>; + fn into_iter(self) -> Self::IntoIter { + DocumentIter { + zeroth_section: self.zeroth_section.iter(), + children: self.children.iter(), + } + } +} multi_field_iter!( Heading<'s>, HeadingIter, From b7f7876706740d85a68c8d4d283486da1ddd4b93 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 15:23:04 -0400 Subject: [PATCH 3/5] Impl ExactSizeIterator for multi_field_iter. --- src/iter/macros.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/iter/macros.rs b/src/iter/macros.rs index f428249..18a265d 100644 --- a/src/iter/macros.rs +++ b/src/iter/macros.rs @@ -79,8 +79,15 @@ $fieldname: $innertype, .or_else(|| self.$fieldname.next().map(Into::::into)) ),* } + + fn size_hint(&self) -> (usize, Option) { + let size = self.$firstfieldname.len()$( + self.$fieldname.len() ),*; + (size, Some(size)) + } } + impl<'r, 's> ExactSizeIterator for $itertype<'r, 's> {} + impl<'r, 's> IntoIterator for &'r $astnodetype { type Item = AstNode<'r, 's>; From c578bb45af3c2b1c5e7f302f6adcfbff4891bf48 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 15:27:03 -0400 Subject: [PATCH 4/5] Implement ExactSizeIterator for the other node types. --- src/iter/ast_node_iter.rs | 37 ++++++++----------------------------- src/iter/macros.rs | 13 +++++++++++++ 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/iter/ast_node_iter.rs b/src/iter/ast_node_iter.rs index 851666e..1c4210d 100644 --- a/src/iter/ast_node_iter.rs +++ b/src/iter/ast_node_iter.rs @@ -202,35 +202,14 @@ impl<'r, 's> AstNodeIter<'r, 's> { } } -pub struct DocumentIter<'r, 's> { - zeroth_section: std::option::Iter<'r, Section<'s>>, - children: std::slice::Iter<'r, Heading<'s>>, -} -impl<'r, 's> Iterator for DocumentIter<'r, 's> { - type Item = AstNode<'r, 's>; - fn next(&mut self) -> Option { - self.zeroth_section - .next() - .map(Into::::into) - .or_else(|| self.children.next().map(Into::::into)) - } - - fn size_hint(&self) -> (usize, Option) { - let size = self.zeroth_section.len() + self.children.len(); - (size, Some(size)) - } -} -impl<'r, 's> ExactSizeIterator for DocumentIter<'r, 's> {} -impl<'r, 's> IntoIterator for &'r Document<'s> { - type Item = AstNode<'r, 's>; - type IntoIter = DocumentIter<'r, 's>; - fn into_iter(self) -> Self::IntoIter { - DocumentIter { - zeroth_section: self.zeroth_section.iter(), - children: self.children.iter(), - } - } -} +multi_field_iter!( + Document<'s>, + DocumentIter, + zeroth_section, + std::option::Iter<'r, Section<'s>>, + children, + std::slice::Iter<'r, Heading<'s>> +); multi_field_iter!( Heading<'s>, HeadingIter, diff --git a/src/iter/macros.rs b/src/iter/macros.rs index 18a265d..3f9333b 100644 --- a/src/iter/macros.rs +++ b/src/iter/macros.rs @@ -11,8 +11,15 @@ macro_rules! children_iter { fn next(&mut self) -> Option { self.next.next().map(Into::::into) } + + fn size_hint(&self) -> (usize, Option) { + let size = self.next.len(); + (size, Some(size)) + } } + impl<'r, 's> ExactSizeIterator for $itertype<'r, 's> {} + impl<'r, 's> IntoIterator for &'r $astnodetype { type Item = AstNode<'r, 's>; @@ -42,8 +49,14 @@ macro_rules! empty_iter { fn next(&mut self) -> Option { None } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } } + impl<'r, 's> ExactSizeIterator for $itertype<'r, 's> {} + impl<'r, 's> IntoIterator for &'r $astnodetype { type Item = AstNode<'r, 's>; From 585b1d2b74d765d96ce5422f1b0b140cf6463c48 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 10 Oct 2023 15:30:27 -0400 Subject: [PATCH 5/5] compare_properties for document. --- src/compare/diff.rs | 124 +++----------------------------------------- 1 file changed, 8 insertions(+), 116 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 838b0e2..911d192 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -460,15 +460,15 @@ fn _compare_document<'b, 's>( source, emacs, rust, - // ( - // EmacsField::Optional(":name"), - // |r| r.name, - // compare_property_quoted_string - // ), ( - EmacsField::Optional(":caption"), - compare_identity, - compare_noop + EmacsField::Required(":path"), + |r| r.path.as_ref().map(|p| p.to_str()).flatten(), + compare_property_quoted_string + ), + ( + EmacsField::Required(":CATEGORY"), + |r| r.category.as_ref(), + compare_property_quoted_string ) ) { match diff { @@ -492,114 +492,6 @@ fn _compare_document<'b, 's>( .into()) } -fn _old_compare_document<'b, 's>( - _source: &'s str, - emacs: &'b Token<'s>, - rust: &'b Document<'s>, -) -> Result, Box> { - let children = emacs.as_list()?; - let mut child_status = Vec::new(); - let mut this_status = DiffStatus::Good; - let mut message = None; - - // Compare :path - // :path is a quoted string to the absolute path of the document. - let document_path = get_property_quoted_string(emacs, ":path")?; - let rust_document_path = rust.path.as_ref().map(|p| p.to_str()).flatten(); - match ( - document_path.as_ref().map(|s| s.as_str()), - rust_document_path, - ) { - (None, None) => {} - (None, Some(_)) | (Some(_), None) => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Path mismatch (emacs != rust) {:?} != {:?}", - document_path, rust_document_path - )); - } - (Some(e), Some(r)) if e != r => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Path mismatch (emacs != rust) {:?} != {:?}", - document_path, rust_document_path - )); - } - (Some(_), Some(_)) => {} - }; - - // Compare category - // :CATEGORY is specified either from "#+CATEGORY:" or it is the file name without the ".org" extension. - let category = get_property_quoted_string(emacs, ":CATEGORY")?; - match (category.as_ref(), rust.category.as_ref()) { - (None, None) => {} - (None, Some(_)) | (Some(_), None) => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Category mismatch (emacs != rust) {:?} != {:?}", - category, rust.category - )); - } - (Some(e), Some(r)) if e != r => { - this_status = DiffStatus::Bad; - message = Some(format!( - "Category mismatch (emacs != rust) {:?} != {:?}", - category, rust.category - )); - } - (Some(_), Some(_)) => {} - }; - - // Skipping "org-data" and its properties - for (i, token) in children.iter().skip(2).enumerate() { - let section_or_headline = token.as_list()?; - let first_cell = section_or_headline - .first() - .ok_or("Should have at least one child.")? - .as_atom()?; - if first_cell == "section" { - if i != 0 { - return Err("Section cannot be after the first child of document.".into()); - } - child_status.push(compare_ast_node( - rust.source, - token, - rust.zeroth_section - .as_ref() - .ok_or("No corresponding zeroth-section")? - .into(), - )?); - } else if first_cell == "headline" { - let corresponding_heading = rust - .children - .iter() - .nth(i - rust.zeroth_section.as_ref().map(|_| 1).unwrap_or(0)) - .ok_or("Should have a corresponding heading.")?; - child_status.push(compare_ast_node( - rust.source, - token, - corresponding_heading.into(), - )?); - } else { - return Err(format!( - "Document should only contain sections and headlines, found: {}", - first_cell - ) - .into()); - } - } - - 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_section<'b, 's>( source: &'s str, emacs: &'b Token<'s>,