+ # Get the token kind at `pos`.
+ fun token_at(text: Text, pos: Int): Token do
+ var c0: Char
+ var c1: Char
+ var c2: Char
+
+ if pos > 0 then
+ c0 = text[pos - 1]
+ else
+ c0 = ' '
+ end
+ var c = text[pos]
+
+ if pos + 1 < text.length then
+ c1 = text[pos + 1]
+ else
+ c1 = ' '
+ end
+ if pos + 2 < text.length then
+ c2 = text[pos + 2]
+ else
+ c2 = ' '
+ end
+
+ var loc
+ if no_location then
+ loc = null
+ else
+ loc = new MDLocation(
+ current_loc.line_start,
+ current_loc.column_start + pos,
+ current_loc.line_start,
+ current_loc.column_start + pos)
+ end
+
+ if c == '*' then
+ if c1 == '*' then
+ if c0 != ' ' or c2 != ' ' then
+ return new TokenStrongStar(loc, pos, c)
+ else
+ return new TokenEmStar(loc, pos, c)
+ end
+ end
+ if c0 != ' ' or c1 != ' ' then
+ return new TokenEmStar(loc, pos, c)
+ else
+ return new TokenNone(loc, pos, c)
+ end
+ else if c == '_' then
+ if c1 == '_' then
+ if c0 != ' ' or c2 != ' ' then
+ return new TokenStrongUnderscore(loc, pos, c)
+ else
+ return new TokenEmUnderscore(loc, pos, c)
+ end
+ end
+ if ext_mode then
+ if (c0.is_letter or c0.is_digit) and c0 != '_' and
+ (c1.is_letter or c1.is_digit) then
+ return new TokenNone(loc, pos, c)
+ else
+ return new TokenEmUnderscore(loc, pos, c)
+ end
+ end
+ if c0 != ' ' or c1 != ' ' then
+ return new TokenEmUnderscore(loc, pos, c)
+ else
+ return new TokenNone(loc, pos, c)
+ end
+ else if c == '!' then
+ if c1 == '[' then return new TokenImage(loc, pos, c)
+ return new TokenNone(loc, pos, c)
+ else if c == '[' then
+ return new TokenLink(loc, pos, c)
+ else if c == ']' then
+ return new TokenNone(loc, pos, c)
+ else if c == '`' then
+ if c1 == '`' then
+ return new TokenCodeDouble(loc, pos, c)
+ else
+ return new TokenCodeSingle(loc, pos, c)
+ end
+ else if c == '\\' then
+ if c1 == '\\' or c1 == '[' or c1 == ']' or c1 == '(' or c1 == ')' or c1 == '{' or c1 == '}' or c1 == '#' or c1 == '"' or c1 == '\'' or c1 == '.' or c1 == '<' or c1 == '>' or c1 == '*' or c1 == '+' or c1 == '-' or c1 == '_' or c1 == '!' or c1 == '`' or c1 == '~' or c1 == '^' then
+ return new TokenEscape(loc, pos, c)
+ else
+ return new TokenNone(loc, pos, c)
+ end
+ else if c == '<' then
+ return new TokenHTML(loc, pos, c)
+ else if c == '&' then
+ return new TokenEntity(loc, pos, c)
+ else
+ if ext_mode then
+ if c == '~' and c1 == '~' then
+ return new TokenStrike(loc, pos, c)
+ end
+ end
+ return new TokenNone(loc, pos, c)
+ end
+ end
+
+ # Find the position of a `token` in `self`.
+ fun find_token(text: Text, start: Int, token: Token): Int do
+ var pos = start
+ while pos < text.length do
+ if token_at(text, pos).is_same_type(token) then
+ return pos
+ end
+ pos += 1
+ end
+ return -1
+ end
+
+ # Location used for next parsed token.
+ #
+ # This location can be changed by the emitter to adjust with `\n` found
+ # in the input.
+ private fun current_loc: MDLocation do return emitter.current_loc