Skip to main content

arity_parser/
syntax.rs

1use rowan::Language;
2
3pub mod ptr;
4
5pub use ptr::NodePtr;
6
7#[allow(non_camel_case_types)]
8#[derive(
9    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
10)]
11#[repr(u16)]
12pub enum SyntaxKind {
13    ROOT,
14    BINARY_EXPR,
15    ASSIGNMENT_EXPR,
16    PAREN_EXPR,
17    IF_EXPR,
18    FOR_EXPR,
19    WHILE_EXPR,
20    REPEAT_EXPR,
21    FUNCTION_EXPR,
22    BLOCK_EXPR,
23    UNARY_EXPR,
24    IDENT,
25    INT,
26    FLOAT,
27    STRING,
28    COMMENT,
29    TILDE,
30    USER_OP,
31    LBRACK,
32    RBRACK,
33    LBRACK2,
34    RBRACK2,
35    PLUS,
36    MINUS,
37    STAR,
38    SLASH,
39    CARET,
40    PIPE,
41    COLON,
42    COLON2,
43    COLON3,
44    DOLLAR,
45    AT,
46    SEMICOLON,
47    COMMA,
48    OR,
49    OR2,
50    AND,
51    AND2,
52    EQUAL2,
53    NOT_EQUAL,
54    BANG,
55    LESS_THAN,
56    LESS_THAN_OR_EQUAL,
57    GREATER_THAN,
58    GREATER_THAN_OR_EQUAL,
59    LPAREN,
60    RPAREN,
61    IF_KW,
62    ELSE_KW,
63    FOR_KW,
64    WHILE_KW,
65    REPEAT_KW,
66    FUNCTION_KW,
67    IN_KW,
68    LBRACE,
69    RBRACE,
70    WHITESPACE,
71    NEWLINE,
72    ASSIGN_LEFT,
73    SUPER_ASSIGN,
74    ASSIGN_RIGHT,
75    SUPER_ASSIGN_RIGHT,
76    ASSIGN_EQ,
77    CALL_EXPR,
78    SUBSET_EXPR,
79    SUBSET2_EXPR,
80    ARG_LIST,
81    ARG,
82    ERROR,
83    COMPLEX,
84    QUESTION,
85    WALRUS,
86    // Roxygen tokens (leaves). A roxygen line (`#'` …) is sub-tokenized so its
87    // structure lives in the CST; the texts of these tokens tile the line's
88    // bytes exactly (losslessness).
89    ROXYGEN_MARKER,
90    ROXYGEN_AT,
91    ROXYGEN_TAG_NAME,
92    ROXYGEN_TAG_ARG,
93    ROXYGEN_TEXT,
94    // Roxygen protected-span leaves: inline markup carved out of a `ROXYGEN_TEXT`
95    // run so the formatter can treat each as an atomic unit during prose reflow
96    // (and a future linter can resolve the code references inside them). Each
97    // holds its whole span, delimiters included, so the run still tiles exactly.
98    ROXYGEN_CODE,
99    ROXYGEN_RD_MACRO,
100    ROXYGEN_MD_LINK,
101    // Roxygen nodes.
102    ROXYGEN_BLOCK,
103    /// Reserved: the legacy physical-line node. No longer emitted since the
104    /// CST re-model (a roxygen block now owns logical content --- sections and
105    /// paragraphs --- with `#'` markers and newlines threaded in as trivia, the
106    /// way rowan/rust-analyzer trees attach whitespace). Kept in the enum so the
107    /// `as u16` discriminants of the later variants stay stable.
108    ROXYGEN_LINE,
109    ROXYGEN_TAG,
110    // Inline Rd-macro structure. A `ROXYGEN_RD_MACRO` is materialized as a *node*
111    // (not a leaf) whose children carve the macro into its parts so the CST models
112    // what `tools::parse_Rd` parses: `\code{\link{x}}` becomes nested macro nodes,
113    // not flat text. These leaves tile the macro span exactly (losslessness).
114    ROXYGEN_RD_MACRO_NAME,  // the `\name` head (backslash included)
115    ROXYGEN_RD_MACRO_OPT,   // a `[...]` option group (e.g. `\link[pkg]{x}`)
116    ROXYGEN_RD_MACRO_DELIM, // a `{` or `}` content delimiter
117    ROXYGEN_RD_MACRO_VERB,  // verbatim content of a VERB macro (`\url`, `\verb`, …)
118    // Roxygen logical-content nodes (the CST re-model). A block's children are
119    // `ROXYGEN_SECTION`s (the intro prose, then one per `@tag`); a section's prose
120    // is grouped into `ROXYGEN_PARAGRAPH`s between blank-line separators. Markers,
121    // the marker→content whitespace, and inter-line newlines live as trivia leaves
122    // threaded into the enclosing node.
123    ROXYGEN_SECTION,
124    ROXYGEN_PARAGRAPH,
125    // Markdown inline leaves, emitted **only** under a resolved `@md` block mode
126    // (Rd-first, markdown-second). Like the other protected-span leaves they hold
127    // their whole span (delimiters included) so the run tiles exactly, but their
128    // *kind* is what records the resolved mode: in non-markdown mode `*x*` and
129    // `` `x` `` stay literal `ROXYGEN_TEXT`/`ROXYGEN_CODE`, so the CST (and the
130    // projected Rd) differ by mode. The projector maps emphasis/strong to
131    // `\emph`/`\strong`, and a code span to `\code` or `\verb` per roxygen2's
132    // R-parseability rule. Appended here (not beside `ROXYGEN_CODE`) to keep the
133    // earlier variants' `as u16` discriminants stable.
134    ROXYGEN_MD_EMPH,
135    ROXYGEN_MD_STRONG,
136    ROXYGEN_MD_CODE,
137    /// A markdown list item's leading marker (`-`/`*`/`+` or `1.`/`1)`), emitted
138    /// **only** under a resolved `@md` block mode and only at a line's content
139    /// start. Like the other markdown leaves it holds its literal source (the
140    /// bullet/number punctuation, *without* the trailing space, so a marker that
141    /// does not form a list — see the CommonMark interrupt rule — chunks for
142    /// reflow exactly as the plain text it stands in for). The projector maps the
143    /// enclosing `ROXYGEN_MD_LIST` to `\itemize`/`\enumerate` and each item to a
144    /// name-only `\item`.
145    ROXYGEN_MD_LIST_MARKER,
146    // Markdown block-list nodes (resolved `@md` mode only). A `ROXYGEN_MD_LIST`
147    // groups consecutive `ROXYGEN_MD_LIST_ITEM`s; each item owns its marker leaf
148    // and inline content. `#'` markers, the marker→content whitespace, and
149    // inter-line newlines are threaded in as trivia (losslessness), the way the
150    // block Rd macros thread them.
151    ROXYGEN_MD_LIST,
152    ROXYGEN_MD_LIST_ITEM,
153    /// A markdown image `![alt](url "title")`, emitted **only** under a resolved
154    /// `@md` block mode. Like the other markdown leaves it holds its whole span
155    /// (delimiters included) so the run tiles exactly. The projector maps it to
156    /// `\figure{url}{title}`, wrapping the figure in `\if{html}{…}`/`\if{pdf}{…}`
157    /// per roxygen2's extension-keyed `get_image_format` rule. Appended last to
158    /// keep the earlier variants' `as u16` discriminants stable.
159    ROXYGEN_MD_IMAGE,
160    /// A markdown fenced code block (resolved `@md` mode only): a
161    /// `ROXYGEN_MD_FENCE` opener leaf, the verbatim code lines, and a
162    /// `ROXYGEN_MD_FENCE` closer leaf, with the `#'` markers, marker→content
163    /// whitespace, and inter-line newlines threaded in as trivia (losslessness),
164    /// the way the block Rd macros and markdown lists thread them. The projector
165    /// maps it to roxygen2's `\if{html}{\out{<div…>}} \preformatted{…}
166    /// \if{html}{\out{</div>}}` triple. Appended last to keep the earlier
167    /// variants' `as u16` discriminants stable.
168    ROXYGEN_MD_CODE_BLOCK,
169    /// A fenced-code-block delimiter line (3+ backticks plus an optional info
170    /// string), a leaf inside a `ROXYGEN_MD_CODE_BLOCK`.
171    ROXYGEN_MD_FENCE,
172    /// A raw inline-HTML tag (`<img …>`, `</span>`), emitted **only** under a
173    /// resolved `@md` block mode. Like the other markdown leaves it holds its
174    /// whole span so the run tiles exactly. The projector maps it to roxygen2's
175    /// `\if{html}{\out{<tag>}}` (`mdxml_html_inline`). Appended last to keep the
176    /// earlier variants' `as u16` discriminants stable.
177    ROXYGEN_MD_HTML,
178    /// A markdown **HTML block** (resolved `@md` mode only): a run of `#'` lines
179    /// opened by a CommonMark HTML-block start (condition 6 — a block-level tag at
180    /// line start) and continuing to the next blank line, with the `#'` markers,
181    /// marker→content whitespace, and inter-line newlines threaded in as trivia
182    /// (losslessness), the way the fenced code block threads them. Its line content
183    /// is verbatim `ROXYGEN_TEXT`; the projector reconstructs the block text and
184    /// maps it to roxygen2's `\if{html}{\out{…}}` (`mdxml_html_block`). Appended
185    /// last to keep the earlier variants' `as u16` discriminants stable.
186    ROXYGEN_MD_HTML_BLOCK,
187    /// A raw markdown emphasis-delimiter run leaf (`*`, `**`, `_`, …), emitted
188    /// only under a resolved `@md` block mode. The lexer carves the maximal same-
189    /// char run neutrally; the inline pass (`parser::roxygen::inline`) resolves
190    /// matched runs into `ROXYGEN_MD_EMPH`/`ROXYGEN_MD_STRONG` **nodes** (now node
191    /// kinds, not leaves), whose opener/closer delimiters are themselves
192    /// `ROXYGEN_MD_DELIM` leaves, and leaves an unmatched run as a literal
193    /// `ROXYGEN_MD_DELIM` leaf (projected as plain text). Appended last to keep the
194    /// earlier variants' `as u16` discriminants stable.
195    ROXYGEN_MD_DELIM,
196    /// A GFM **table** (resolved `@md` mode only): a header row, a delimiter row
197    /// (`|---|:--:|`) whose cell count matches the header, and zero or more body
198    /// rows, with the `#'` markers, marker→content whitespace, and inter-line
199    /// newlines threaded in as trivia (losslessness), the way the fenced code block
200    /// and HTML block thread them. Its line content is verbatim `ROXYGEN_TEXT` (and,
201    /// for the delimiter row, whatever inline leaves the lexer carved); the
202    /// projector reconstructs the rows and cells from the node text and maps them to
203    /// roxygen2's `\tabular{<align>}{… \tab … \cr}`. Appended last to keep the
204    /// earlier variants' `as u16` discriminants stable.
205    ROXYGEN_MD_TABLE,
206    /// A markdown ATX **heading** line (resolved `@md` mode only): a single line
207    /// whose content is `#{1,6}` followed by a space/tab or the line end, holding
208    /// the `#'` marker (trivia) and the verbatim `ROXYGEN_TEXT` heading leaf. The
209    /// projector reads the level and title from the node text and hoists it into an
210    /// Rd `\section` (level 1) / `\subsection` (level >= 2) out of the enclosing
211    /// `@description`/`@details`. Appended last to keep the earlier variants'
212    /// `as u16` discriminants stable.
213    ROXYGEN_MD_HEADING,
214    /// A markdown **block quote** (resolved `@md` mode only): a run of consecutive
215    /// `#'` lines each opening with `>` (after up to three spaces), with the `#'`
216    /// markers, marker→content whitespace, and inter-line newlines threaded in as
217    /// trivia (losslessness), the way the HTML block threads them. Its line content
218    /// is verbatim `ROXYGEN_TEXT`. roxygen2 does not support block quotes: it warns
219    /// and renders the node's *flattened plain text* (`escape_comment(xml_text)`),
220    /// which the projector reproduces (strip each `>` marker, flatten the inner
221    /// markdown, concatenate with no separator). Appended last to keep the earlier
222    /// variants' `as u16` discriminants stable.
223    ROXYGEN_MD_BLOCK_QUOTE,
224    /// A markdown **thematic break** (resolved `@md` mode only): a single line whose
225    /// whole content is a CommonMark thematic break (`***`/`---`/`___`, three or more
226    /// of one character with optional spaces between, up to three leading spaces),
227    /// holding the `#'` marker (trivia) and the verbatim break leaf. roxygen2 has no
228    /// thematic-break support: it warns and renders the empty `escape_comment(xml_text)`
229    /// (a thematic break has no text), so the break contributes nothing and the
230    /// surrounding paragraphs coalesce. The projector drops it in `section_body_parts`.
231    /// Appended last to keep the earlier variants' `as u16` discriminants stable.
232    ROXYGEN_MD_THEMATIC_BREAK,
233    /// A markdown **indented code block** resolved under `@md` mode: a run of
234    /// prose lines each indented four or more columns past roxygen2's stripped
235    /// `#'` prefix (a CommonMark indented code block), with interior blank lines,
236    /// holding the `#'` markers (trivia) and the verbatim code leaves. roxygen2
237    /// renders it exactly like a fenced code block — the three-atom
238    /// `\if{html}{\out{<div…>}}` / `\preformatted{…}` / `\if{html}{\out{</div>}}`
239    /// sequence — but with a bare `sourceCode` class and each line's indentation
240    /// stripped (see `serialize_md_indented_code`). Appended last to keep the
241    /// earlier variants' `as u16` discriminants stable.
242    ROXYGEN_MD_INDENTED_CODE,
243}
244
245impl SyntaxKind {
246    /// Number of distinct kinds, sized to the last variant. Used to allocate
247    /// dispatch tables indexed by `kind as usize` (see the linter's single-walk
248    /// rule dispatch). Stays correct as long as `ROXYGEN_MD_INDENTED_CODE` remains
249    /// the last variant.
250    pub const COUNT: usize = SyntaxKind::ROXYGEN_MD_INDENTED_CODE as usize + 1;
251
252    /// A roxygen line's bytes are carried by these leaf tokens, which stand in
253    /// for the single `COMMENT` token a non-roxygen comment line uses.
254    pub fn is_roxygen_token(self) -> bool {
255        matches!(
256            self,
257            SyntaxKind::ROXYGEN_MARKER
258                | SyntaxKind::ROXYGEN_AT
259                | SyntaxKind::ROXYGEN_TAG_NAME
260                | SyntaxKind::ROXYGEN_TAG_ARG
261                | SyntaxKind::ROXYGEN_TEXT
262                | SyntaxKind::ROXYGEN_CODE
263                | SyntaxKind::ROXYGEN_RD_MACRO
264                | SyntaxKind::ROXYGEN_MD_LINK
265                | SyntaxKind::ROXYGEN_MD_CODE
266                | SyntaxKind::ROXYGEN_MD_LIST_MARKER
267                | SyntaxKind::ROXYGEN_MD_IMAGE
268                | SyntaxKind::ROXYGEN_MD_FENCE
269                | SyntaxKind::ROXYGEN_MD_HTML
270                | SyntaxKind::ROXYGEN_MD_DELIM
271        )
272    }
273
274    /// The prose / inline-markup roxygen content elements: plain text plus the
275    /// protected spans (inline code, Rd macro, markdown link/code/list-marker/…)
276    /// and the resolved emphasis/strong **nodes**. The `SyntaxKind`-side
277    /// counterpart of [`crate::parser::lexer::RoxygenRole::Content`]; the single
278    /// list the formatter derives "is this a prose element" from. Includes the
279    /// `ROXYGEN_MD_EMPH`/`ROXYGEN_MD_STRONG` nodes (the inline pass's output) so the
280    /// formatter treats a resolved span as one atomic prose chunk.
281    pub fn is_roxygen_prose_content(self) -> bool {
282        matches!(
283            self,
284            SyntaxKind::ROXYGEN_TEXT
285                | SyntaxKind::ROXYGEN_CODE
286                | SyntaxKind::ROXYGEN_RD_MACRO
287                | SyntaxKind::ROXYGEN_MD_LINK
288                | SyntaxKind::ROXYGEN_MD_EMPH
289                | SyntaxKind::ROXYGEN_MD_STRONG
290                | SyntaxKind::ROXYGEN_MD_CODE
291                | SyntaxKind::ROXYGEN_MD_LIST_MARKER
292                | SyntaxKind::ROXYGEN_MD_IMAGE
293                | SyntaxKind::ROXYGEN_MD_FENCE
294                | SyntaxKind::ROXYGEN_MD_HTML
295                | SyntaxKind::ROXYGEN_MD_DELIM
296        )
297    }
298}
299
300impl From<SyntaxKind> for rowan::SyntaxKind {
301    fn from(kind: SyntaxKind) -> Self {
302        Self(kind as u16)
303    }
304}
305
306#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
307pub enum RLanguage {}
308
309impl Language for RLanguage {
310    type Kind = SyntaxKind;
311
312    fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
313        match raw.0 {
314            0 => SyntaxKind::ROOT,
315            1 => SyntaxKind::BINARY_EXPR,
316            2 => SyntaxKind::ASSIGNMENT_EXPR,
317            3 => SyntaxKind::PAREN_EXPR,
318            4 => SyntaxKind::IF_EXPR,
319            5 => SyntaxKind::FOR_EXPR,
320            6 => SyntaxKind::WHILE_EXPR,
321            7 => SyntaxKind::REPEAT_EXPR,
322            8 => SyntaxKind::FUNCTION_EXPR,
323            9 => SyntaxKind::BLOCK_EXPR,
324            10 => SyntaxKind::UNARY_EXPR,
325            11 => SyntaxKind::IDENT,
326            12 => SyntaxKind::INT,
327            13 => SyntaxKind::FLOAT,
328            14 => SyntaxKind::STRING,
329            15 => SyntaxKind::COMMENT,
330            16 => SyntaxKind::TILDE,
331            17 => SyntaxKind::USER_OP,
332            18 => SyntaxKind::LBRACK,
333            19 => SyntaxKind::RBRACK,
334            20 => SyntaxKind::LBRACK2,
335            21 => SyntaxKind::RBRACK2,
336            22 => SyntaxKind::PLUS,
337            23 => SyntaxKind::MINUS,
338            24 => SyntaxKind::STAR,
339            25 => SyntaxKind::SLASH,
340            26 => SyntaxKind::CARET,
341            27 => SyntaxKind::PIPE,
342            28 => SyntaxKind::COLON,
343            29 => SyntaxKind::COLON2,
344            30 => SyntaxKind::COLON3,
345            31 => SyntaxKind::DOLLAR,
346            32 => SyntaxKind::AT,
347            33 => SyntaxKind::SEMICOLON,
348            34 => SyntaxKind::COMMA,
349            35 => SyntaxKind::OR,
350            36 => SyntaxKind::OR2,
351            37 => SyntaxKind::AND,
352            38 => SyntaxKind::AND2,
353            39 => SyntaxKind::EQUAL2,
354            40 => SyntaxKind::NOT_EQUAL,
355            41 => SyntaxKind::BANG,
356            42 => SyntaxKind::LESS_THAN,
357            43 => SyntaxKind::LESS_THAN_OR_EQUAL,
358            44 => SyntaxKind::GREATER_THAN,
359            45 => SyntaxKind::GREATER_THAN_OR_EQUAL,
360            46 => SyntaxKind::LPAREN,
361            47 => SyntaxKind::RPAREN,
362            48 => SyntaxKind::IF_KW,
363            49 => SyntaxKind::ELSE_KW,
364            50 => SyntaxKind::FOR_KW,
365            51 => SyntaxKind::WHILE_KW,
366            52 => SyntaxKind::REPEAT_KW,
367            53 => SyntaxKind::FUNCTION_KW,
368            54 => SyntaxKind::IN_KW,
369            55 => SyntaxKind::LBRACE,
370            56 => SyntaxKind::RBRACE,
371            57 => SyntaxKind::WHITESPACE,
372            58 => SyntaxKind::NEWLINE,
373            59 => SyntaxKind::ASSIGN_LEFT,
374            60 => SyntaxKind::SUPER_ASSIGN,
375            61 => SyntaxKind::ASSIGN_RIGHT,
376            62 => SyntaxKind::SUPER_ASSIGN_RIGHT,
377            63 => SyntaxKind::ASSIGN_EQ,
378            64 => SyntaxKind::CALL_EXPR,
379            65 => SyntaxKind::SUBSET_EXPR,
380            66 => SyntaxKind::SUBSET2_EXPR,
381            67 => SyntaxKind::ARG_LIST,
382            68 => SyntaxKind::ARG,
383            69 => SyntaxKind::ERROR,
384            70 => SyntaxKind::COMPLEX,
385            71 => SyntaxKind::QUESTION,
386            72 => SyntaxKind::WALRUS,
387            73 => SyntaxKind::ROXYGEN_MARKER,
388            74 => SyntaxKind::ROXYGEN_AT,
389            75 => SyntaxKind::ROXYGEN_TAG_NAME,
390            76 => SyntaxKind::ROXYGEN_TAG_ARG,
391            77 => SyntaxKind::ROXYGEN_TEXT,
392            78 => SyntaxKind::ROXYGEN_CODE,
393            79 => SyntaxKind::ROXYGEN_RD_MACRO,
394            80 => SyntaxKind::ROXYGEN_MD_LINK,
395            81 => SyntaxKind::ROXYGEN_BLOCK,
396            82 => SyntaxKind::ROXYGEN_LINE,
397            83 => SyntaxKind::ROXYGEN_TAG,
398            84 => SyntaxKind::ROXYGEN_RD_MACRO_NAME,
399            85 => SyntaxKind::ROXYGEN_RD_MACRO_OPT,
400            86 => SyntaxKind::ROXYGEN_RD_MACRO_DELIM,
401            87 => SyntaxKind::ROXYGEN_RD_MACRO_VERB,
402            88 => SyntaxKind::ROXYGEN_SECTION,
403            89 => SyntaxKind::ROXYGEN_PARAGRAPH,
404            90 => SyntaxKind::ROXYGEN_MD_EMPH,
405            91 => SyntaxKind::ROXYGEN_MD_STRONG,
406            92 => SyntaxKind::ROXYGEN_MD_CODE,
407            93 => SyntaxKind::ROXYGEN_MD_LIST_MARKER,
408            94 => SyntaxKind::ROXYGEN_MD_LIST,
409            95 => SyntaxKind::ROXYGEN_MD_LIST_ITEM,
410            96 => SyntaxKind::ROXYGEN_MD_IMAGE,
411            97 => SyntaxKind::ROXYGEN_MD_CODE_BLOCK,
412            98 => SyntaxKind::ROXYGEN_MD_FENCE,
413            99 => SyntaxKind::ROXYGEN_MD_HTML,
414            100 => SyntaxKind::ROXYGEN_MD_HTML_BLOCK,
415            101 => SyntaxKind::ROXYGEN_MD_DELIM,
416            102 => SyntaxKind::ROXYGEN_MD_TABLE,
417            103 => SyntaxKind::ROXYGEN_MD_HEADING,
418            104 => SyntaxKind::ROXYGEN_MD_BLOCK_QUOTE,
419            105 => SyntaxKind::ROXYGEN_MD_THEMATIC_BREAK,
420            106 => SyntaxKind::ROXYGEN_MD_INDENTED_CODE,
421            _ => SyntaxKind::ERROR,
422        }
423    }
424
425    fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
426        kind.into()
427    }
428}
429
430pub type SyntaxNode = rowan::SyntaxNode<RLanguage>;
431pub type SyntaxToken = rowan::SyntaxToken<RLanguage>;
432pub type SyntaxElement = rowan::SyntaxElement<RLanguage>;