@@ -81,9 +81,9 @@ Its fields are as follows:
8181 styled string, as markup structures are absorbed.
8282- `point::Int`, the current index in `content`.
8383- `escape::Bool`, whether the last character seen was an escape character.
84- - `interpolated::Bool `, whether any interpolated values have been seen. Knowing whether or not
84+ - `interpolations::Int `, how many interpolated values have been seen. Knowing whether or not
8585 anything needs to be evaluated allows the resulting string to be computed at macroexpansion time,
86- when possible.
86+ when possible, and knowing how many allows for some micro-optimisations .
8787- `errors::Vector`, any errors raised during parsing. We collect them instead of immediately throwing
8888 so that we can list as many issues as possible at once, instead of forcing the author of the invalid
8989 styled markup to resolve each issue one at a time. This is expected to be populated by invocations of
@@ -100,7 +100,7 @@ mutable struct State
100100 offset:: Int
101101 point:: Int
102102 escape:: Bool
103- interpolated :: Bool
103+ interpolations :: Int
104104 const errors:: Vector
105105end
106106
@@ -111,7 +111,7 @@ function State(content::AbstractString, mod::Union{Module, Nothing}=nothing)
111111 Vector{Tuple{Int, Int, Union{Symbol, Expr, Pair{Symbol, Any}}}}[], # active_styles
112112 Tuple{UnitRange{Int}, Union{Symbol, Expr, Pair{Symbol, Any}}}[], # pending_styles
113113 0 , 1 , # offset, point
114- false , false , # escape, interpolated
114+ false , 0 , # escape, interpolations
115115 NamedTuple{(:message , :position , :hint ), # errors
116116 Tuple{AnnotatedString{String}, <: Union{Int, Nothing} , String}}[])
117117end
@@ -311,7 +311,7 @@ function interpolated!(state::State, i::Int, _)
311311 state. offset -= ncodeunits (' $' )
312312 addpart! (state, i, esc (expr), nexti)
313313 state. point = nexti + state. offset
314- state. interpolated = true
314+ state. interpolations += 1
315315end
316316
317317"""
@@ -511,7 +511,7 @@ function read_inlineface!(state::State, i::Int, char::Char, newstyles)
511511 elseif isnextchar (state, ' $' ) && ismacro (state)
512512 expr, _ = readexpr! (state)
513513 lastchar = last (popfirst! (state. s))
514- state. interpolated = true
514+ state. interpolations += 1
515515 needseval = true
516516 esc (expr)
517517 else
@@ -525,7 +525,7 @@ function read_inlineface!(state::State, i::Int, char::Char, newstyles)
525525 if isnextchar (state, ' $' ) && ismacro (state)
526526 expr, _ = readexpr! (state)
527527 lastchar = last (popfirst! (state. s))
528- state. interpolated = true
528+ state. interpolations += 1
529529 needseval = true
530530 ustyle = esc (expr)
531531 else
@@ -639,7 +639,7 @@ function read_inlineface!(state::State, i::Int, char::Char, newstyles)
639639 val = if ismacro (state) && isnextchar (state, ' $' )
640640 expr, _ = readexpr! (state)
641641 lastchar = last (popfirst! (state. s))
642- state. interpolated = true
642+ state. interpolations += 1
643643 needseval = true
644644 esc (expr)
645645 elseif key == :font
@@ -766,7 +766,7 @@ function read_face_or_keyval!(state::State, i::Int, char::Char, newstyles)
766766 # this isn't the 'last' char yet, but it will be
767767 key = if ismacro (state) && last (peek (state. s)) == ' $'
768768 expr, _ = readexpr! (state)
769- state. interpolated = true
769+ state. interpolations += 1
770770 needseval = true
771771 esc (expr)
772772 else
@@ -788,7 +788,7 @@ function read_face_or_keyval!(state::State, i::Int, char::Char, newstyles)
788788 read_curlywrapped! (state)
789789 elseif ismacro (state) && nextchar == ' $'
790790 expr, _ = readexpr! (state)
791- state. interpolated = true
791+ state. interpolations += 1
792792 needseval = true
793793 esc (expr)
794794 else
868868Merge contiguous identical annotations in `str`.
869869"""
870870function annotatedstring_optimize! (s:: AnnotatedString )
871+ length (s. annotations) <= 1 && return s
871872 last_seen = Dict {Pair{Symbol, Any}, Int} ()
872873 i = 1
873874 while i <= length (s. annotations)
@@ -988,7 +989,9 @@ macro styled_str(raw_content::String)
988989 run_state_machine! (state)
989990 if ! isempty (state. errors)
990991 throw (MalformedStylingMacro (state. content, state. errors))
991- elseif state. interpolated
992+ elseif state. interpolations == 1 && length (state. parts) == 1
993+ :(annotatedstring ($ (first (state. parts))))
994+ elseif ! iszero (state. interpolations)
992995 :(annotatedstring ($ (state. parts... )) |> annotatedstring_optimize!)
993996 else
994997 annotatedstring (map (Base. Fix1 (hygienic_eval, state), state. parts)... ) |> annotatedstring_optimize!
0 commit comments