//! Open-recursion AST visitor. //! //! Each `visit_*` method has a default body that calls the corresponding //! `walk_*` free function, which in turn dispatches back into the trait. //! Override any method to short-circuit or augment traversal — call the //! matching `walk_*` from your override to keep descending. //! //! Pattern follows `rustc`'s and `syn`'s visitors. //! //! Read-only for now. A `VisitorMut` flavor can be added when transformations //! become relevant. use super::block::{ BlockNode, BlockquoteNode, CommentNode, DefinitionItemNode, DefinitionListNode, ErrorNode, HeadingNode, HorizontalRuleNode, ListItemNode, ListNode, MathBlockNode, ParagraphNode, PreformattedNode, TableCellNode, TableNode, TableRowNode, TagNode, }; use super::inline::{ BoldItalicNode, BoldNode, CodeNode, ColorNode, InlineNode, ItalicNode, KeywordNode, MathInlineNode, StrikethroughNode, SubscriptNode, SuperscriptNode, TextNode, }; use super::link::{ExternalLinkNode, RawUrlNode, TransclusionNode, WikiLinkNode}; use super::DocumentNode; pub trait Visitor { // Top level fn visit_document(&mut self, node: &DocumentNode) { walk_document(self, node); } // Block dispatch fn visit_block(&mut self, node: &BlockNode) { walk_block(self, node); } // Inline dispatch fn visit_inline(&mut self, node: &InlineNode) { walk_inline(self, node); } // Block leaves and recursive block nodes fn visit_heading(&mut self, node: &HeadingNode) { for child in &node.children { self.visit_inline(child); } } fn visit_paragraph(&mut self, node: &ParagraphNode) { for child in &node.children { self.visit_inline(child); } } fn visit_horizontal_rule(&mut self, _node: &HorizontalRuleNode) {} fn visit_blockquote(&mut self, node: &BlockquoteNode) { for child in &node.children { self.visit_block(child); } } fn visit_preformatted(&mut self, _node: &PreformattedNode) {} fn visit_math_block(&mut self, _node: &MathBlockNode) {} fn visit_list(&mut self, node: &ListNode) { walk_list(self, node); } fn visit_list_item(&mut self, node: &ListItemNode) { walk_list_item(self, node); } fn visit_definition_list(&mut self, node: &DefinitionListNode) { for item in &node.items { self.visit_definition_item(item); } } fn visit_definition_item(&mut self, node: &DefinitionItemNode) { walk_definition_item(self, node); } fn visit_table(&mut self, node: &TableNode) { walk_table(self, node); } fn visit_table_row(&mut self, node: &TableRowNode) { walk_table_row(self, node); } fn visit_table_cell(&mut self, node: &TableCellNode) { for child in &node.children { self.visit_inline(child); } } fn visit_comment(&mut self, _node: &CommentNode) {} fn visit_tag(&mut self, _node: &TagNode) {} fn visit_error(&mut self, _node: &ErrorNode) {} // Inline leaves and recursive inline nodes fn visit_text(&mut self, _node: &TextNode) {} fn visit_bold(&mut self, node: &BoldNode) { for child in &node.children { self.visit_inline(child); } } fn visit_italic(&mut self, node: &ItalicNode) { for child in &node.children { self.visit_inline(child); } } fn visit_bold_italic(&mut self, node: &BoldItalicNode) { for child in &node.children { self.visit_inline(child); } } fn visit_strikethrough(&mut self, node: &StrikethroughNode) { for child in &node.children { self.visit_inline(child); } } fn visit_code(&mut self, _node: &CodeNode) {} fn visit_superscript(&mut self, node: &SuperscriptNode) { for child in &node.children { self.visit_inline(child); } } fn visit_subscript(&mut self, node: &SubscriptNode) { for child in &node.children { self.visit_inline(child); } } fn visit_math_inline(&mut self, _node: &MathInlineNode) {} fn visit_keyword(&mut self, _node: &KeywordNode) {} fn visit_color(&mut self, node: &ColorNode) { for child in &node.children { self.visit_inline(child); } } fn visit_wiki_link(&mut self, node: &WikiLinkNode) { if let Some(desc) = &node.description { for child in desc { self.visit_inline(child); } } } fn visit_external_link(&mut self, node: &ExternalLinkNode) { if let Some(desc) = &node.description { for child in desc { self.visit_inline(child); } } } fn visit_transclusion(&mut self, _node: &TransclusionNode) {} fn visit_raw_url(&mut self, _node: &RawUrlNode) {} } pub fn walk_document(v: &mut V, node: &DocumentNode) { for child in &node.children { v.visit_block(child); } } pub fn walk_block(v: &mut V, node: &BlockNode) { match node { BlockNode::Heading(n) => v.visit_heading(n), BlockNode::Paragraph(n) => v.visit_paragraph(n), BlockNode::HorizontalRule(n) => v.visit_horizontal_rule(n), BlockNode::Blockquote(n) => v.visit_blockquote(n), BlockNode::Preformatted(n) => v.visit_preformatted(n), BlockNode::MathBlock(n) => v.visit_math_block(n), BlockNode::List(n) => v.visit_list(n), BlockNode::DefinitionList(n) => v.visit_definition_list(n), BlockNode::Table(n) => v.visit_table(n), BlockNode::Comment(n) => v.visit_comment(n), BlockNode::Tag(n) => v.visit_tag(n), BlockNode::Error(n) => v.visit_error(n), } } pub fn walk_inline(v: &mut V, node: &InlineNode) { match node { InlineNode::Text(n) => v.visit_text(n), InlineNode::Bold(n) => v.visit_bold(n), InlineNode::Italic(n) => v.visit_italic(n), InlineNode::BoldItalic(n) => v.visit_bold_italic(n), InlineNode::Strikethrough(n) => v.visit_strikethrough(n), InlineNode::Code(n) => v.visit_code(n), InlineNode::Superscript(n) => v.visit_superscript(n), InlineNode::Subscript(n) => v.visit_subscript(n), InlineNode::MathInline(n) => v.visit_math_inline(n), InlineNode::Keyword(n) => v.visit_keyword(n), InlineNode::Color(n) => v.visit_color(n), InlineNode::WikiLink(n) => v.visit_wiki_link(n), InlineNode::ExternalLink(n) => v.visit_external_link(n), InlineNode::Transclusion(n) => v.visit_transclusion(n), InlineNode::RawUrl(n) => v.visit_raw_url(n), } } pub fn walk_list(v: &mut V, node: &ListNode) { for item in &node.items { v.visit_list_item(item); } } pub fn walk_list_item(v: &mut V, node: &ListItemNode) { for child in &node.children { v.visit_inline(child); } if let Some(sublist) = &node.sublist { v.visit_list(sublist); } } pub fn walk_definition_item(v: &mut V, node: &DefinitionItemNode) { if let Some(term) = &node.term { for child in term { v.visit_inline(child); } } for definition in &node.definitions { for child in definition { v.visit_inline(child); } } } pub fn walk_table(v: &mut V, node: &TableNode) { for row in &node.rows { v.visit_table_row(row); } } pub fn walk_table_row(v: &mut V, node: &TableRowNode) { for cell in &node.cells { v.visit_table_cell(cell); } }