Sourceror.get_range/1 with a correction for one upstream quirk that would
otherwise corrupt a survivor's reported location.
The escaped-delimiter under-count in sigils and interpolated strings.
Sourceror computes a sigil's end column from the stored content length
(range.ex get_end_pos_for_interpolation_segments/3, String.length of the
<<>> segments). The tokenizer keeps a sigil's content raw — \n/\\/\t
stay two-character sequences — except it collapses an escaped closing
delimiter (\/ → / in ~r/…/, \} → } in ~r{…}), so the stored content
is one byte shorter per such escape and the range falls short by that many
columns. A textual patch over the short range leaves the sigil's tail in place —
and when the mutation only drops a trailing flag (~r/…/u → ~r/…/,
RegexLiteral), the patch lands exactly on the dropped u and the diff shows
no change at all (a survivor with an empty diff). get/1 adds back one
column per collapsed closing delimiter. (Escaped delimiters before the last
interpolation are already accounted for — their absolute closing position is
baked into the segment metadata — so only the trailing binary segments are
counted; an opening delimiter escape \{ keeps its backslash and never
collapses, so only the closing char is counted.)
The same collapse hits the interpolated string family — "a\"#{x}\"b" and
its charlist / quoted-atom cousins also range from segment lengths, and the
tokenizer collapses \" → " (or \' → ') there too, so an escaped quote
after the last interpolation shortens the range and the patch leaves the
original closing quote behind (toast("…\"#{x}\".") mutated to "" renders
as toast(""")). get/1 applies the same trailing-segment count to those
three container shapes. Non-interpolated strings are immune (their raw content
keeps the backslash), and heredocs never escape their fence, so only the
quote-delimited (non-heredoc), single-line, interpolated forms are corrected.
Only Mutare.Report reads the range, so the quirk is invisible at runtime:
the metamutant is built from the AST, never the range. It corrupts only a
surviving mutant's rendered location — the human diff, and the endColumn the
machine reporters emit (Mutare.Report.Json / Mutare.Report.Sarif).
See NOTES "Sourceror range".
Summary
Functions
Like Sourceror.get_range/1, correcting the sigil/interpolated-string under-count.
Functions
@spec get(Macro.t()) :: Sourceror.Range.t() | nil
Like Sourceror.get_range/1, correcting the sigil/interpolated-string under-count.