@@ -202,19 +202,42 @@ defimpl Inspect, for: BitString do
202202 else
203203 << byte :: size ( 8 ) , h :: binary >> = head
204204 t = << h :: binary , t :: binary >>
205- escape ( t , char , << binary :: binary , octify ( byte ) :: binary >> )
205+ escape ( t , char , << binary :: binary , escape_char ( byte ) :: binary >> )
206206 end
207207 end
208208 defp escape ( << h , t :: binary >> , char , binary ) do
209- escape ( t , char , << binary :: binary , octify ( h ) :: binary >> )
209+ escape ( t , char , << binary :: binary , escape_char ( h ) :: binary >> )
210210 end
211211 defp escape ( << >> , _char , binary ) , do: binary
212212
213+
214+ @ doc false
215+ # also used by Regex
216+ def escape_char ( char ) when char in ?\0 00 .. ?\3 77 ,
217+ do: octify ( char )
218+
219+ def escape_char ( char ) , do: hexify ( char )
220+
213221 defp octify ( byte ) do
214222 << hi :: size ( 2 ) , mi :: size ( 3 ) , lo :: size ( 3 ) >> = << byte >>
215223 << ?\\ , ?0 + hi , ?0 + mi , ?0 + lo >>
216224 end
217225
226+ defp hexify ( char ) when char < 0x10000 do
227+ << a :: 4 , b :: 4 , c :: 4 , d :: 4 >> = << char :: size ( 16 ) >>
228+ << ?\\ , ?x , ?{ , to_hex ( a ) , to_hex ( b ) , to_hex ( c ) , to_hex ( d ) , ?} >>
229+ end
230+
231+ defp hexify ( char ) when char < 0x1000000 do
232+ << a :: 4 , b :: 4 , c :: 4 , d :: 4 , e :: 4 , f :: 4 >> = << char :: size ( 24 ) >>
233+ << ?\\ , ?x , ?{ , to_hex ( a ) , to_hex ( b ) , to_hex ( c ) ,
234+ to_hex ( d ) , to_hex ( e ) , to_hex ( f ) , ?} >>
235+ end
236+
237+ defp to_hex ( c ) when c in 0 .. 9 , do: ?0 + c
238+ defp to_hex ( c ) when c in 10 .. 15 , do: ?a + c - 10
239+
240+
218241 defp append ( << h , t :: binary >> , binary ) , do: append ( t , << binary :: binary , h >> )
219242 defp append ( << >> , binary ) , do: binary
220243
@@ -419,9 +442,57 @@ defimpl Inspect, for: Float do
419442end
420443
421444defimpl Inspect , for: Regex do
422- def inspect ( regex , opts ) do
423- concat [ "~r" , to_doc ( regex . source , opts ) , regex . opts ]
445+ def inspect ( regex , _opts ) do
446+ delim = ?/
447+ concat [ "~r" ,
448+ << delim , escape ( regex . source , delim ) :: binary , delim >> ,
449+ regex . opts ]
424450 end
451+
452+
453+ defp escape ( bin , term ) ,
454+ do: escape ( bin , << >> , term )
455+
456+ defp escape ( << ?\\ , term >> <> rest , buf , term ) ,
457+ do: escape ( rest , buf <> << ?\\ , term >> , term )
458+
459+ defp escape ( << term >> <> rest , buf , term ) ,
460+ do: escape ( rest , buf <> << ?\\ , term >> , term )
461+
462+ # the list of characters is from `String.printable?` impl
463+ # minus characters treated specially by regex: \s, \d, \b, \e
464+
465+ defp escape ( << ?\n >> <> rest , buf , term ) ,
466+ do: escape ( rest , << buf :: binary , ?\\ , ?n >> , term )
467+
468+ defp escape ( << ?\r >> <> rest , buf , term ) ,
469+ do: escape ( rest , << buf :: binary , ?\\ , ?r >> , term )
470+
471+ defp escape ( << ?\t >> <> rest , buf , term ) ,
472+ do: escape ( rest , << buf :: binary , ?\\ , ?t >> , term )
473+
474+ defp escape ( << ?\v >> <> rest , buf , term ) ,
475+ do: escape ( rest , << buf :: binary , ?\\ , ?v >> , term )
476+
477+ defp escape ( << ?\f >> <> rest , buf , term ) ,
478+ do: escape ( rest , << buf :: binary , ?\\ , ?f >> , term )
479+
480+ defp escape ( << ?\a >> <> rest , buf , term ) ,
481+ do: escape ( rest , << buf :: binary , ?\\ , ?a >> , term )
482+
483+ defp escape ( << c :: utf8 >> <> rest , buf , term ) do
484+ charstr = << c :: utf8 >>
485+ if String . printable? ( charstr ) and not c in [ ?\d , ?\b , ?\e ] do
486+ escape ( rest , buf <> charstr , term )
487+ else
488+ escape ( rest , buf <> Inspect.BitString . escape_char ( c ) , term )
489+ end
490+ end
491+
492+ defp escape ( << c >> <> rest , buf , term ) ,
493+ do: escape ( rest , << buf :: binary , Inspect.BitString . escape_char ( c ) >> , term )
494+
495+ defp escape ( << >> , buf , _ ) , do: buf
425496end
426497
427498defimpl Inspect , for: Function do
0 commit comments