@@ -68,6 +68,28 @@ introducing type instability.
6868"""
6969const NONE_TOKEN = Token(K" " , 0 , 0 ), UInt32(0 )
7070
71+ """
72+ @sometoken(args...)
73+
74+ Return the first of `args` that is not `NONE_TOKEN`, finally returning
75+ `NONE_TOKEN` only if all arguments are `NONE_TOKEN`.
76+ """
77+ macro sometoken(args... )
78+ expr = :(NONE_TOKEN)
79+ for arg in reverse(args)
80+ val = gensym(" tok" )
81+ expr = quote
82+ $ val = $ (esc(arg))
83+ if $ val != NONE_TOKEN
84+ $ val
85+ else
86+ $ expr
87+ end
88+ end
89+ end
90+ expr
91+ end
92+
7193function lexnext(state:: LexerState , bytes:: DenseVector{UInt8} , start:: UInt32 )
7294 linestart, newlines = @inline skipnewlines(bytes, start)
7395 if start == 1 && state. lastelement != K" <paragraph"
@@ -141,10 +163,19 @@ function lexnext_element(state::LexerState, bytes::DenseVector{UInt8},
141163 end
142164 elseif chr == UInt8(' [' ) && pos == linestart
143165 fndef = lex_footnotedef(state, bytes, pos)
144- if fndef != NONE_TOKEN && K" footnote_definition" ∈ state. ctx
145- Token(K" >footnote_definition" , start - 0x1 , start - 0x1 ), start
166+ if fndef != NONE_TOKEN
167+ if K" footnote_definition" ∈ state. ctx
168+ Token(K" >footnote_definition" , start - 0x1 , start - 0x1 ), start
169+ else
170+ fndef
171+ end
146172 else
147- fndef
173+ fnref = lex_footnoteref(state, bytes, pos)
174+ if fnref != NONE_TOKEN
175+ Token(K" <paragraph" , pos, pos), pos
176+ else
177+ NONE_TOKEN
178+ end
148179 end
149180 elseif chr == UInt8(' |' ) && K" table" ∈ state. restriction
150181 Token(K" <table" , pos, pos), pos
@@ -199,13 +230,12 @@ function lexnext_object(state::LexerState, bytes::DenseVector{UInt8},
199230 elseif chr ∈ (UInt8(' *' ), UInt8(' /' ), UInt8(' _' ), UInt8(' =' ), UInt8(' ~' ), UInt8(' +' ))
200231 lex_markup(state, bytes, pos)
201232 elseif chr == UInt8(' \\ ' )
202- tok = lex_entity(state, bytes, pos)
203- if tok == NONE_TOKEN
204- tok = lex_latexfrag(state, bytes, pos)
205- end
206- tok
233+ @sometoken(lex_entity(state, bytes, pos),
234+ lex_latexfrag(state, bytes, pos))
207235 elseif chr == UInt8(' @' )
208236 lex_exportsnippet(state, bytes, pos)
237+ elseif chr == UInt8(' [' ) && hasprefix(bytes, pos + 0x1 , " fn:" )
238+ lex_footnoteref(state, bytes, pos)
209239 else
210240 NONE_TOKEN
211241 end
@@ -286,15 +316,14 @@ function lex_item(state::LexerState, bytes::DenseVector{UInt8}, linestart::UInt3
286316end
287317
288318function lex_hashplus(state:: LexerState , bytes:: DenseVector{UInt8} , pos:: UInt32 )
289- blk = lex_block(state, bytes, pos)
290- blk != NONE_TOKEN && return blk
291- blk = lex_dynamicblock(state, bytes, pos)
292- blk != NONE_TOKEN && return blk
293- if K" keyword" in state. restriction
294- blk = lex_keyword(state, bytes, pos)
295- blk != NONE_TOKEN && return blk
296- end
297- NONE_TOKEN
319+ @sometoken(
320+ lex_block(state, bytes, pos),
321+ lex_dynamicblock(state, bytes, pos),
322+ if K" keyword" ∈ state. restriction
323+ lex_keyword(state, bytes, pos)
324+ else
325+ NONE_TOKEN
326+ end )
298327end
299328
300329function lex_block((; ctx):: LexerState , bytes:: DenseVector{UInt8} , start:: UInt32 )
@@ -606,7 +635,19 @@ function lex_exportsnippet(::LexerState, bytes::DenseVector{UInt8}, pos::UInt32)
606635 Token(settag(K" export_snippet" , langtag), pos, closepos), closepos + 0x1
607636end
608637
609- # TODO : Footnote references
638+ function lex_footnoteref(:: LexerState , bytes:: DenseVector{UInt8} , pos:: UInt32 )
639+ refend = skipbalanced(bytes, pos, ' [' => ' ]' )
640+ iszero(refend) && return NONE_TOKEN
641+ nameend = skipwords(bytes, pos + ncodeunits(" [fn:" ) % UInt32, (' -' , ' _' ))
642+ fnkind = if bytes[nameend] == UInt8(' ]' )
643+ 0x01 # label
644+ elseif bytes[nameend] == UInt8(' :' )
645+ 0x02 + UInt8(nameend > pos + ncodeunits(" [fn:" ) % UInt32)
646+ else
647+ return NONE_TOKEN
648+ end
649+ Token(settag(K" footnote_reference" , fnkind), pos, refend - 0x1 ), refend
650+ end
610651
611652# TODO : Citations
612653
0 commit comments