When we're parsing inlines and we hit
- a run of
*
or_
characters - a
[
or![
we insert a text node with the literal content, and add a pointer to this text node to the delimiter stack.
The delimiter stack is a doubly linked list. Each element contains a pointer to a text node, plus information about
- the type of delimiter (
[
,![
,*
,_
) - the number of delimiters,
- whether the delimiter is "active" (all are active to start), and
- whether the delimiter is a potential opener, a potential closer, or both.
When we hit a ]
character, we call the look_for_link_or_image
procedure (see below).
When we hit the end of the input, we call the process_emphasis
procedure (see below), with stack_bottom
= NULL.
Starting at the top of the delimiter stack, we look backwards
through the stack for a [
or ![
delimiter.
If we don't find one, we return a literal text node ]
.
If we do find one, but it's not active, we remove the inactive
delimiter from the stack, and return a literal text node ]
.
If we find one and it's active, then we parse ahead to see if we have an inline link/image, reference link/image, compact reference link/image, or shortcut reference link/image.
If we don't, then we remove the [
or ![
delimiter from the
delimiter stack and return a literal text node ]
.
If we do, then
-
We return a link or image node whose children are the inlines after the text node pointed to by the opening delimiter.
-
We run
process_emphasis
on these inlines, with the[
opener asstack_bottom
. -
We remove the opening delimiter.
-
If we have a link (and not an image), we also set all
[
delimiters before the opening delimiter to inactive. (This will prevent us from getting links within links.)
Parameter stack_bottom
sets a lower bound to how far we
descend in the delimiter stack. If it is NULL, we can
go all the way to the bottom. Otherwise, we stop before
visiting stack_bottom
.
Let current_position
point to the element on the delimiter
just above stack_bottom
(or the first element if stack_bottom
is NULL).
We keep track of the openers_bottom
for each delimiter
type (*
, _
). Initialize this to stack_bottom
.
Then we repeat the following until we run out of potential closers:
-
Move
current_position
forward in the delimiter stack (if needed) until we find the first potential closer with delimiter*
or_
. (This will be the potential closer closest to the beginning of the input -- the first one in parse order.) -
Now, look back in the stack (staying above
stack_bottom
and theopeners_bottom
for this delimiter type) for the first matching potential opener ("matching" means same delimiter). -
If one is found:
- Figure out whether we have emphasis or strong emphasis: if both closer and opener spans have length >= 2, we have strong, otherwise regular.
- Insert an emph or strong emph node accordingly, after the text node corresponding to the opener.
- Remove delimiters between opener and closer from the delimiter stack.
- Remove 1 (for regular emph) or 2 (for strong emph) delimiters
from the opening and closing text nodes. If they become empty
as a result, remove them and remove the corresponding element
of the delimiter stack. If the closing node is removed, reset
current_position
to the next element in the stack.
-
If none in found:
- Set
openers_bottom
to the element beforecurrent_position
. (We know that there are no openers for this kind of closer up to and including this point, so this puts a lower bound on future searches.) - If the closer at
current_position
is not a potential opener, remove it from the delimiter stack (since we know it can't be a closer either). - Advance
current_position
to the next element in the stack.
- Set
-
Repeat.
-
After we're done, remove all delimiters above
stack_bottom
from the delimiter stack.