Skip to content

AST Structure

The SevenMark parser produces an Abstract Syntax Tree (AST) composed of Element nodes. This page documents the element types, expression system, and supporting types.

Element Enum

Every parsed node is a variant of the Element enum. Elements are grouped by category:

Basic Text

VariantDescription
TextPlain text content
CommentComment block (not rendered)
EscapeEscaped character (\*, \[, etc.)
ErrorUnparseable content (error recovery)

Text Styles

VariantDescription
Bold**text**
Italic*text*
Underline__text__
Strikethrough~~text~~
Superscript^^text^^
Subscript,,text,,

All text style variants share the same TextStyleElement structure with span, parameters, and children fields.

Block Elements

VariantDescription
LiteralRaw content block {{{ text }}}
StyledStyled block {{{ #param text }}}
TableTable structure {{{#table ...}}}
ListOrdered/unordered list {{{#list ...}}}
FoldCollapsible section {{{#fold ...}}}
BlockQuoteQuote block {{{#quote ...}}}
CodeCode block `{{{#code
...
}}}`
TeXMath expression `{{{#tex
...
}}}`
CssCSS block `{{{#css
...
}}}`
RubyRuby annotation {{{#ruby ...}}}
FootnoteFootnote definition {{{#fn ...}}}

Line Elements

VariantDescription
HeaderHeading (#, ##, ..., ######)
HLineHorizontal rule (---)
SoftBreakSingle newline (paragraph continues)
HardBreakDouble newline (paragraph break)

Wiki Elements

VariantDescription
IncludeInclude another document {{{#include ...}}}
CategoryCategory assignment {{{#category ...}}}
RedirectPage redirect {{{#redirect ...}}}
DefineVariable definition {{{#define ...}}}
IfConditional block {{{#if ...}}}

Media Elements

VariantDescription
MediaMedia element [[#file="..." ...]], [[#url="..." ...]]
ExternalMediaExternal embed [[#youtube ...]], [[#spotify ...]], etc.

Macros

VariantDescription
VariableVariable reference [var(name)]
MentionUser/discussion mention <@uuid> or <#uuid>
TimeNowCurrent time [now]
DateCurrent date [date]
DateTimeCurrent date and time [datetime]
DdayD-day counter [dday(date)]
PageCountPage count [pagecount] or [pagecount(namespace)]
AgeAge calculation [age(date)]
AnchorNamed anchor [anchor(name)]
NullNo-op macro [null]
ClearFloat clear macro [clear]
FootnoteRefFootnote list macro [fn]

Common Element Fields

Most elements share these fields:

rust
struct SomeElement {
    pub span: Span,           // byte offsets (start, end)
    pub parameters: Parameters, // #key="value" pairs
    pub children: Vec<Element>, // nested elements
}

Span

rust
pub struct Span {
    pub start: usize,  // start byte offset in source
    pub end: usize,    // end byte offset in source
}

Every element records its position in the source text via Span. When serialized with the include_locations feature, these appear in JSON output.

Parameters

rust
pub struct Parameter {
    pub span: Span,
    pub key: String,
    pub value: Vec<Element>,  // parsed value (may contain macros)
}

pub type Parameters = IndexMap<String, Parameter>;

Parameters are stored as an IndexMap keyed by parameter name. This preserves the order they appeared in the source while still supporting efficient keyed lookup. Keys may contain Unicode letters, digits, underscore, and hyphen. Values are parsed AST fragments rather than raw strings, so macros like [var(name)] can appear inside parameter values.

Expression Enum (Conditionals)

The {{{#if}}} element uses an expression tree for its condition:

VariantDescription
OrLogical OR (||)
AndLogical AND (&&)
NotLogical NOT (!)
ComparisonComparison (==, !=, >, <, >=, <=)
FunctionCallType conversion (int(), len(), str())
StringLiteralQuoted string value
NumberLiteralInteger value
BoolLiteraltrue or false
Nullnull literal
GroupParenthesized sub-expression
ElementEmbedded AST element (e.g., [var(name)])

Operators

Comparison operators:

KindSyntax
Equal==
NotEqual!=
GreaterThan>
LessThan<
GreaterEqual>=
LessEqual<=

Logical operators:

KindSyntax
Or||
And&&
Not!

Table Types

Tables have a multi-level type hierarchy to support conditional rows and cells:

TableElement
  └── children: Vec<TableRowItem>
        ├── Row(TableRowElement)
        │     └── children: Vec<TableCellItem>
        │           ├── Cell(TableCellElement)
        │           └── Conditional(ConditionalTableCells)
        └── Conditional(ConditionalTableRows)

TableElement

rust
pub struct TableElement {
    pub span: Span,
    pub parameters: Parameters,
    pub children: Vec<TableRowItem>,
}

TableRowItem

rust
pub enum TableRowItem {
    Row(TableRowElement),
    Conditional(ConditionalTableRows),
}

TableCellItem

rust
pub enum TableCellItem {
    Cell(TableCellElement),
    Conditional(ConditionalTableCells),
}

List Types

Lists follow a similar pattern to tables for conditional support:

ListElement
  └── children: Vec<ListContentItem>
        ├── Item(ListItemElement)
        └── Conditional(ConditionalListItems)

ListElement

rust
pub struct ListElement {
    pub span: Span,
    pub kind: String,           // list type ("1", "a", "A", "i", "I")
    pub parameters: Parameters,
    pub children: Vec<ListContentItem>,
}

ListContentItem

rust
pub enum ListContentItem {
    Item(ListItemElement),
    Conditional(ConditionalListItems),
}

Mention Types

rust
pub enum MentionType {
    Discussion,  // <#uuid>
    User,        // <@uuid>
}

JSON Serialization Example

Given this input:

sevenmark
# Hello **World**

A paragraph with *italic* text.

The serialized AST (simplified) looks like:

json
[
  {
    "Header": {
      "level": 1,
      "children": [
        { "Text": { "value": "Hello " } },
        { "Bold": { "children": [{ "Text": { "value": "World" } }] } }
      ]
    }
  },
  { "HardBreak": {} },
  {
    "Text": { "value": "A paragraph with " }
  },
  {
    "Italic": {
      "children": [{ "Text": { "value": "italic" } }]
    }
  },
  {
    "Text": { "value": " text." }
  }
]

Each element is serialized as an object with the variant name as key. The Span fields only appear when the include_locations feature is enabled.