@@ -81,9 +81,9 @@ Its fields are as follows:
81
81
styled string, as markup structures are absorbed.
82
82
- `point::Int`, the current index in `content`.
83
83
- `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
85
85
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 .
87
87
- `errors::Vector`, any errors raised during parsing. We collect them instead of immediately throwing
88
88
so that we can list as many issues as possible at once, instead of forcing the author of the invalid
89
89
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
100
100
offset:: Int
101
101
point:: Int
102
102
escape:: Bool
103
- interpolated :: Bool
103
+ interpolations :: Int
104
104
const errors:: Vector
105
105
end
106
106
@@ -111,7 +111,7 @@ function State(content::AbstractString, mod::Union{Module, Nothing}=nothing)
111
111
Vector{Tuple{Int, Int, Union{Symbol, Expr, Pair{Symbol, Any}}}}[], # active_styles
112
112
Tuple{UnitRange{Int}, Union{Symbol, Expr, Pair{Symbol, Any}}}[], # pending_styles
113
113
0 , 1 , # offset, point
114
- false , false , # escape, interpolated
114
+ false , 0 , # escape, interpolations
115
115
NamedTuple{(:message , :position , :hint ), # errors
116
116
Tuple{AnnotatedString{String}, <: Union{Int, Nothing} , String}}[])
117
117
end
@@ -311,7 +311,7 @@ function interpolated!(state::State, i::Int, _)
311
311
state. offset -= ncodeunits (' $' )
312
312
addpart! (state, i, esc (expr), nexti)
313
313
state. point = nexti + state. offset
314
- state. interpolated = true
314
+ state. interpolations += 1
315
315
end
316
316
317
317
"""
@@ -511,7 +511,7 @@ function read_inlineface!(state::State, i::Int, char::Char, newstyles)
511
511
elseif isnextchar (state, ' $' ) && ismacro (state)
512
512
expr, _ = readexpr! (state)
513
513
lastchar = last (popfirst! (state. s))
514
- state. interpolated = true
514
+ state. interpolations += 1
515
515
needseval = true
516
516
esc (expr)
517
517
else
@@ -525,7 +525,7 @@ function read_inlineface!(state::State, i::Int, char::Char, newstyles)
525
525
if isnextchar (state, ' $' ) && ismacro (state)
526
526
expr, _ = readexpr! (state)
527
527
lastchar = last (popfirst! (state. s))
528
- state. interpolated = true
528
+ state. interpolations += 1
529
529
needseval = true
530
530
ustyle = esc (expr)
531
531
else
@@ -639,7 +639,7 @@ function read_inlineface!(state::State, i::Int, char::Char, newstyles)
639
639
val = if ismacro (state) && isnextchar (state, ' $' )
640
640
expr, _ = readexpr! (state)
641
641
lastchar = last (popfirst! (state. s))
642
- state. interpolated = true
642
+ state. interpolations += 1
643
643
needseval = true
644
644
esc (expr)
645
645
elseif key == :font
@@ -766,7 +766,7 @@ function read_face_or_keyval!(state::State, i::Int, char::Char, newstyles)
766
766
# this isn't the 'last' char yet, but it will be
767
767
key = if ismacro (state) && last (peek (state. s)) == ' $'
768
768
expr, _ = readexpr! (state)
769
- state. interpolated = true
769
+ state. interpolations += 1
770
770
needseval = true
771
771
esc (expr)
772
772
else
@@ -788,7 +788,7 @@ function read_face_or_keyval!(state::State, i::Int, char::Char, newstyles)
788
788
read_curlywrapped! (state)
789
789
elseif ismacro (state) && nextchar == ' $'
790
790
expr, _ = readexpr! (state)
791
- state. interpolated = true
791
+ state. interpolations += 1
792
792
needseval = true
793
793
esc (expr)
794
794
else
868
868
Merge contiguous identical annotations in `str`.
869
869
"""
870
870
function annotatedstring_optimize! (s:: AnnotatedString )
871
+ length (s. annotations) <= 1 && return s
871
872
last_seen = Dict {Pair{Symbol, Any}, Int} ()
872
873
i = 1
873
874
while i <= length (s. annotations)
@@ -988,7 +989,9 @@ macro styled_str(raw_content::String)
988
989
run_state_machine! (state)
989
990
if ! isempty (state. errors)
990
991
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)
992
995
:(annotatedstring ($ (state. parts... )) |> annotatedstring_optimize!)
993
996
else
994
997
annotatedstring (map (Base. Fix1 (hygienic_eval, state), state. parts)... ) |> annotatedstring_optimize!
0 commit comments