When we're parsing inlines and we hit
*
or _
characters[
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
[
, ![
, *
, _
)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.
look_for_link_or_image
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 as stack_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.)
process_emphasis
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 the openers_bottom
for this delimiter type) for the first matching potential opener (“matching” means same delimiter).
If one is found:
current_position
to the next element in the stack.If none in found:
openers_bottom
to the element before current_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.)current_position
is not a potential opener, remove it from the delimiter stack (since we know it can't be a closer either).current_position
to the next element in the stack.Repeat.
After we're done, remove all delimiters above stack_bottom
from the delimiter stack.