21b485c91b
Strip "Phase N", "SPEC §X.Y", and "v1.x" planning labels from comments across the Rust crates and editor layers now that those tracking artifacts are gone. Comments only — no logic, strings, or test names touched. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
229 lines
7.6 KiB
Rust
229 lines
7.6 KiB
Rust
//! 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: Visitor + ?Sized>(v: &mut V, node: &DocumentNode) {
|
|
for child in &node.children {
|
|
v.visit_block(child);
|
|
}
|
|
}
|
|
|
|
pub fn walk_block<V: Visitor + ?Sized>(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: Visitor + ?Sized>(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: Visitor + ?Sized>(v: &mut V, node: &ListNode) {
|
|
for item in &node.items {
|
|
v.visit_list_item(item);
|
|
}
|
|
}
|
|
|
|
pub fn walk_list_item<V: Visitor + ?Sized>(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: Visitor + ?Sized>(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: Visitor + ?Sized>(v: &mut V, node: &TableNode) {
|
|
for row in &node.rows {
|
|
v.visit_table_row(row);
|
|
}
|
|
}
|
|
|
|
pub fn walk_table_row<V: Visitor + ?Sized>(v: &mut V, node: &TableRowNode) {
|
|
for cell in &node.cells {
|
|
v.visit_table_cell(cell);
|
|
}
|
|
}
|