# 内联结构

一旦解析完所有输入,将闭合所有开启的块。
然后我们“遍历树”,访问每个节点,并将段落和标题的原始字符串内容按内联解析。此时我们已经看到了所有链接引用定义,因此我们可以随时解析引用链接。

document
  block_quote
    paragraph
      str "Lorem ipsum dolor"
      softbreak
      str "sit amet."
    list (type=bullet tight=true bullet_char=-)
      list_item
        paragraph
          str "Qui "
          emph
            str "quodsi iracundia"
      list_item
        paragraph
          str "aliquando id"

注意第一段中的行尾 (opens new window)是如何被解析为softbreak的,并且第一个列表项中的星号已成为emph
一个解析嵌套强调和链接的算法。迄今为止,内联解析最棘手的部分是处理强调,加强的强调,链接和图像。 这是使用以下算法完成的。
当我们解析内联碰到以下符号时

  • 一系列 * 或者 _ 字符,
  • 一个 [ 或者 ![

我们插入一个带有这些符号作为文字内容的文本节点,然后我们将一个指向这个文本节点的指针添加到分隔符栈 (opens new window)
分隔符栈 (opens new window)是一个双向链表。每个元素都包含一个指向文本节点的指针,以及以下信息

  • 分隔符的类型 ([![*_)
  • 分隔符的数量
  • 分隔符是否启用(可以作为开启符号), 并且
  • 这些分隔符是否是潜在的开始符号或者关闭符号或者两者都是(取决于何种分隔符在其前或者在其后)。

当我们遇到] 时,调用 查找链接或图片 过程(见下文)。
当输入完成时,我们调用 解析强调 过程,此时 stack_bottom= NULL.
查找链接或图片在分隔符栈顶部开始,向后查找开启的 [![分隔符。

  • 如果找不到,则返回一个字面上的字符]
  • 如果找到,但是其未启用,则从栈中删除未启用的分隔符然后返回一个字面上的字符]
  • 如果找到并且其已启用,则继续解析查看是否有内联链接/图片,引用链接/图片,紧凑的的引用链接/图片,或者快捷的引用链接/图片
    • 如果没有,则移除栈中的开始分隔符,并返回一个字面上的字符]
    • 如果有
      • 返回一个链接或图像节点,其子节点是开始分隔符指向的文本节点后的内联内容
      • 在这些内联内容上运行 解析强调 ,将[作为stack_bottom
      • 移除开始分隔符
      • 如果我们有一个链接(且不是图像),我们还会在开始分隔符之前将所有[分隔符设置为未启用。(这将阻止我们在链接中获取链接。)

解析强调的变量stack_bottom设置了一个在 分隔符栈 (opens new window)中下行查找的下限。如果其值为 NULL,我们可以一直查到栈底,否则,我们将在stack_bottom之前停止。
current_position 指针指向 分隔符栈 (opens new window)上栈底之上的元素(或者是第一个元素,如果stack_bottom 值为 NULL)。
我们跟踪每个分隔符类型为(*_)的openers_bottom。以及每个结束分隔符路程的长度(3 取模)。将其初始化为stack_bottom
然后我们重复以下过程直到我们用完所有的闭合符号:

  • 在分隔符堆栈中向前移动current_position(如果需要),直到我们找到第一个具有分隔符*_的潜在闭合符号。(这将是距离输入开头最近的位置 – 按解析顺序的第一个。)
  • 现在,回顾堆栈(保持在stack_bottom和此分隔符类型的openers_bottom之上)匹配第一个潜在的开始符号(“匹配”意味着相同的分隔符)。
  • 如果找到一个:
    • 探明这是强调还是加强的强调,如果开始符号和闭合符号长度都 >= 2,则是加强的强调,否则就是强调
    • 在开始符号对应的文本节点之后,相应的插入一个强调或加强的强调节点
    • 在分隔符栈中移除开始符号和闭合符号中间所有的分隔符
    • 从开始和闭合文本节点中删除1(强调)或2(加强的强调)分隔符。 如果它们因此变为空,则删除它们并删除分隔符堆栈的相应元素。 如果关闭节点被移除,则将current_position重置为堆栈中的下一个元素
  • 如果没有找到:
    • openers_bottom设置为current_position之前的元素。(我们知道这种闭合符号并没有对应的开始符号,所以这对之后的搜索设置了一个下限。)
    • 如果current_position处的闭合符号不是潜在的开始符号,则将其从分隔符堆栈中移除(因为我们知道它也不能作为闭合符号)
    • current_position推进到堆栈中的下一个元素

完成之后,我们从分隔符堆栈中删除stack_bottom上面的所有分隔符。