Skip to main content

varar_core/
ast.rs

1//! AST node types produced by the scanner/structurer — port of `ast.ts` /
2//! `Ast.java`. Pure data; the sealed `Block`/`TableOrFence` interfaces become
3//! Rust enums (exhaustive `match` replaces `instanceof`). Immutability is by
4//! construction (owned fields, no mutation) — Java's `List.copyOf` defensive
5//! copies have no Rust analog.
6
7use crate::span::Span;
8
9/// Maps a block-text offset to its source offset (both UTF-16).
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub struct SegmentOffset {
12    pub text_offset: usize,
13    pub source_offset: usize,
14}
15
16impl SegmentOffset {
17    pub fn new(text_offset: usize, source_offset: usize) -> SegmentOffset {
18        SegmentOffset {
19            text_offset,
20            source_offset,
21        }
22    }
23}
24
25/// A markdown heading (`#`..`######`); `level` is 1–6.
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub struct Heading {
28    pub level: usize,
29    pub text: String,
30    pub span: Span,
31}
32
33/// A markdown paragraph.
34#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct Paragraph {
36    pub text: String,
37    pub span: Span,
38    pub segment_map: Vec<SegmentOffset>,
39}
40
41/// A single list item (`-`/`*` or numbered).
42#[derive(Clone, Debug, PartialEq, Eq)]
43pub struct ListItem {
44    pub text: String,
45    pub span: Span,
46    pub segment_map: Vec<SegmentOffset>,
47    pub ordered: bool,
48    pub marker_span: Span,
49}
50
51/// A markdown blockquote (`>`).
52#[derive(Clone, Debug, PartialEq, Eq)]
53pub struct Blockquote {
54    pub text: String,
55    pub span: Span,
56    pub segment_map: Vec<SegmentOffset>,
57}
58
59/// One row of a table: `cells` and `cell_spans` are parallel, same-length.
60#[derive(Clone, Debug, PartialEq, Eq)]
61pub struct Row {
62    pub cells: Vec<String>,
63    pub cell_spans: Vec<Span>,
64    pub span: Span,
65}
66
67/// A markdown table: a header [`Row`] plus zero or more data rows.
68#[derive(Clone, Debug, PartialEq, Eq)]
69pub struct Table {
70    pub span: Span,
71    pub header: Row,
72    pub rows: Vec<Row>,
73}
74
75/// A fenced code block; `info` is the text after the opening fence.
76#[derive(Clone, Debug, PartialEq, Eq)]
77pub struct Fence {
78    pub span: Span,
79    pub info: String,
80    pub body: String,
81    pub body_span: Span,
82}
83
84/// A thematic break (`---`/`***`/`___`).
85#[derive(Clone, Copy, Debug, PartialEq, Eq)]
86pub struct ThematicBreak {
87    pub span: Span,
88}
89
90/// A markdown block node — the closed union the structurer matches over.
91#[derive(Clone, Debug, PartialEq, Eq)]
92pub enum Block {
93    Heading(Heading),
94    Paragraph(Paragraph),
95    ListItem(ListItem),
96    Blockquote(Blockquote),
97    Table(Table),
98    Fence(Fence),
99    ThematicBreak(ThematicBreak),
100}
101
102impl Block {
103    /// The block's source span (exhaustive over the union).
104    pub fn span(&self) -> Span {
105        match self {
106            Block::Heading(h) => h.span,
107            Block::Paragraph(p) => p.span,
108            Block::ListItem(l) => l.span,
109            Block::Blockquote(b) => b.span,
110            Block::Table(t) => t.span,
111            Block::Fence(f) => f.span,
112            Block::ThematicBreak(t) => t.span,
113        }
114    }
115}
116
117/// The block kinds that may appear as a [`Doc`] orphan attachment (`Table | Fence`).
118#[derive(Clone, Debug, PartialEq, Eq)]
119pub enum TableOrFence {
120    Table(Table),
121    Fence(Fence),
122}
123
124/// One matched example: the heading scope above it (outer→inner) plus its body
125/// blocks (first is the candidate primary block, then any trailing attachments).
126#[derive(Clone, Debug, PartialEq, Eq)]
127pub struct Example {
128    pub scope_stack: Vec<String>,
129    pub span: Span,
130    pub body: Vec<Block>,
131    /// True when a heading or thematic break (`---`) sits between this candidate
132    /// and the previous one — i.e. a syntactic delimiter separates them (also
133    /// true for the first candidate). The planner uses it to decide grouping: a
134    /// matching candidate with this false merges into the open example rather
135    /// than starting a new one. See ADR 0012.
136    pub preceded_by_delimiter: bool,
137}
138
139/// A parsed source file: its matched examples plus unattached table/fence blocks.
140#[derive(Clone, Debug, PartialEq, Eq)]
141pub struct Doc {
142    pub path: String,
143    pub source: String,
144    pub examples: Vec<Example>,
145    pub orphan_attachments: Vec<TableOrFence>,
146}