///|
#warnings("-unused_field")
//! Core data structures for the parser: items and allocations.
// `span` and `use_count` are carried over even though this port omits the
// HTML renderer / broken-link callback that consumes them.
/// Index types into `Allocations` arrays.
struct Item {
/// A tree node item; spans a byte range of the source.
mut start : Int
mut end : Int
mut body : ItemBody
}
///|
impl Default for Item with fn default() -> Item {
{ start: 0, end: 0, body: Root }
}
///|
/// The body of a tree node.
priv enum ItemBody {
// These are possible inline items, need to be resolved in second pass.
// repeats, can_open, can_close
MaybeEmphasis(Int, Bool, Bool)
// can_open, can_close, brace context
MaybeMath(Bool, Bool, Int)
// quote byte, can_open, can_close
MaybeSmartQuote(Byte, Bool, Bool)
MaybeCode(Int, Bool) // number of backticks, preceded by backslash
MaybeHtml
MaybeLinkOpen
// bool indicates whether or not the preceding section could be a reference
MaybeLinkClose(Bool)
MaybeImage
// These are inline items after resolution.
Emphasis
Strong
Strikethrough
Highlight
Superscript
Subscript
Math(Int, Bool) // true for display math
Code(Int)
Link(Int)
Image(Int)
FootnoteReference(Int)
TaskListMarker(Bool)
// These are also inline items.
InlineHtml
OwnedInlineHtml(Int)
SynthesizeText(Int)
SynthesizeChar(Char)
Html
Text(Bool) // backslash_escaped
SoftBreak
// true = is backlash
HardBreak(Bool)
// Dummy node at the top of the tree - should not be used otherwise!
Root
// These are block items.
Paragraph
TightParagraph
Rule
Heading(HeadingLevel, Int?) // heading level
FencedCodeBlock(Int)
IndentCodeBlock
HtmlBlock
BlockQuote(BlockQuoteKind?)
Container(Int, ContainerKind, Int) // (fence length, kind, descriptor)
List(Bool, Byte, Int64) // is_tight, list character, list start index
ListItem(Int) // indent level
FootnoteDefinition(Int)
MetadataBlock(MetadataBlockKind)
// Definition lists
DefinitionList(Bool) // is_tight
MaybeDefinitionListTitle
DefinitionListTitle
DefinitionListDefinition(Int)
// Tables
Table(Int)
TableHead
TableRow
TableCell
}
///|
fn item_body_is_maybe_inline(body : ItemBody) -> Bool {
match body {
MaybeEmphasis(_, _, _)
| MaybeMath(_, _, _)
| MaybeSmartQuote(_, _, _)
| MaybeCode(_, _)
| MaybeHtml
| MaybeLinkOpen
| MaybeLinkClose(_)
| MaybeImage => true
_ => false
}
}
///|
fn item_body_is_inline(body : ItemBody) -> Bool {
match body {
MaybeEmphasis(_, _, _)
| MaybeMath(_, _, _)
| MaybeSmartQuote(_, _, _)
| MaybeCode(_, _)
| MaybeHtml
| MaybeLinkOpen
| MaybeLinkClose(_)
| MaybeImage
| Emphasis
| Strong
| Strikethrough
| Highlight
| Math(_, _)
| Code(_)
| Link(_)
| Image(_)
| FootnoteReference(_)
| TaskListMarker(_)
| InlineHtml
| OwnedInlineHtml(_)
| SynthesizeText(_)
| SynthesizeChar(_)
| Html
| Text(_)
| SoftBreak
| HardBreak(_) => true
_ => false
}
}
///|
/// Contains the destination URL, title and source span of a reference definition.
priv struct LinkDef {
dest : String
title : String?
_span : (Int, Int)
}
///|
/// Contains the destination URL, title and source span of a footnote definition.
priv struct FootnoteDef {
mut _use_count : Int
}
///|
/// Used by the heading attributes extension.
priv struct HeadingAttributes {
id : String?
classes : Array[String]
attrs : Array[(String, String?)]
}
///|
/// Allocations of owned strings, links, alignments and headings.
struct Allocations {
refdefs : Map[String, LinkDef]
footdefs : Map[String, FootnoteDef]
links : Array[(LinkType, String, String, String)]
cows : Array[String]
alignments : Array[Array[Alignment]]
headings : Array[HeadingAttributes]
}
///|
fn allocations_new() -> Allocations {
{
refdefs: Map([], capacity=0),
footdefs: Map([], capacity=0),
links: [],
cows: [],
alignments: [],
headings: [],
}
}
///|
fn Allocations::allocate_cow(self : Allocations, cow : String) -> Int {
let ix = self.cows.length()
self.cows.push(cow)
ix
}
///|
fn Allocations::allocate_link(
self : Allocations,
ty : LinkType,
url : String,
title : String,
id : String,
) -> Int {
let ix = self.links.length()
self.links.push((ty, url, title, id))
ix
}
///|
fn Allocations::allocate_alignment(
self : Allocations,
alignment : Array[Alignment],
) -> Int {
let ix = self.alignments.length()
self.alignments.push(alignment)
ix
}
///|
fn Allocations::allocate_heading(
self : Allocations,
attrs : HeadingAttributes,
) -> Int {
let ix = self.headings.length()
self.headings.push(attrs)
ix + 1
}
///|
fn Allocations::take_cow(self : Allocations, ix : Int) -> String {
let v = self.cows[ix]
self.cows[ix] = ""
v
}
///|
fn Allocations::take_link(
self : Allocations,
ix : Int,
) -> (LinkType, String, String, String) {
let v = self.links[ix]
self.links[ix] = (ShortcutUnknown, "", "", "")
v
}
///|
fn Allocations::take_alignment(
self : Allocations,
ix : Int,
) -> Array[Alignment] {
let v = self.alignments[ix]
self.alignments[ix] = []
v
}
///|
fn Allocations::heading_at(self : Allocations, ix : Int) -> HeadingAttributes {
self.headings[ix - 1]
}