@@ -17,6 +17,8 @@ import scala.annotation.switch
17
17
import config .{Config , Feature }
18
18
import cc .*
19
19
20
+ import java .lang .StringBuilder
21
+
20
22
class PlainPrinter (_ctx : Context ) extends Printer {
21
23
22
24
/** The context of all public methods in Printer and subclasses.
@@ -668,22 +670,18 @@ class PlainPrinter(_ctx: Context) extends Printer {
668
670
669
671
def toText (denot : Denotation ): Text = toText(denot.symbol) ~ " /D"
670
672
671
- private def escapedChar (ch : Char ): String = (ch : @ switch) match {
672
- case '\b ' => " \\ b"
673
- case '\t ' => " \\ t"
674
- case '\n ' => " \\ n"
675
- case '\f ' => " \\ f"
676
- case '\r ' => " \\ r"
677
- case '"' => " \\\" "
678
- case '\' ' => " \\\' "
679
- case '\\ ' => " \\\\ "
680
- case _ => if ch.isControl then f " ${" \\ " }u ${ch.toInt}%04x " else String .valueOf(ch).nn
681
- }
673
+ private def escapedChar (ch : Char ): String =
674
+ if requiresFormat(ch) then
675
+ val b = StringBuilder ().append('\' ' )
676
+ escapedChar(b, ch)
677
+ b.append('\' ' ).toString
678
+ else
679
+ " '" + ch + " '"
682
680
683
681
def toText (const : Constant ): Text = const.tag match {
684
- case StringTag => stringText(" \" " + escapedString(const.value.toString) + " \" " )
682
+ case StringTag => stringText(escapedString(const.value.toString, quoted = true ) )
685
683
case ClazzTag => " classOf[" ~ toText(const.typeValue) ~ " ]"
686
- case CharTag => literalText(s " ' ${ escapedChar(const.charValue)} ' " )
684
+ case CharTag => literalText(escapedChar(const.charValue))
687
685
case LongTag => literalText(const.longValue.toString + " L" )
688
686
case DoubleTag => literalText(const.doubleValue.toString + " d" )
689
687
case FloatTag => literalText(const.floatValue.toString + " f" )
@@ -701,7 +699,57 @@ class PlainPrinter(_ctx: Context) extends Printer {
701
699
~ (if param.isTypeParam then " " else " : " )
702
700
~ toText(param.paramInfo)
703
701
704
- protected def escapedString (str : String ): String = str flatMap escapedChar
702
+ protected final def escapedString (str : String ): String = escapedString(str, quoted = false )
703
+
704
+ private def requiresFormat (c : Char ): Boolean = (c : @ switch) match
705
+ case '\b ' | '\t ' | '\n ' | '\f ' | '\r ' | '"' | '\' ' | '\\ ' => true
706
+ case c => c.isControl
707
+
708
+ private def escapedString (text : String , quoted : Boolean ): String =
709
+ def mustBuild : Boolean =
710
+ var i = 0
711
+ while i < text.length do
712
+ if requiresFormat(text.charAt(i)) then return true
713
+ i += 1
714
+ false
715
+ if mustBuild then
716
+ val b = StringBuilder (text.length + 16 )
717
+ if quoted then
718
+ b.append('"' )
719
+ var i = 0
720
+ while i < text.length do
721
+ escapedChar(b, text.charAt(i))
722
+ i += 1
723
+ if quoted then
724
+ b.append('"' )
725
+ b.toString
726
+ else if quoted then " \" " + text + " \" "
727
+ else text
728
+
729
+ private def escapedChar (b : StringBuilder , c : Char ): Unit =
730
+ def quadNibble (b : StringBuilder , x : Int , i : Int ): Unit =
731
+ if i < 4 then
732
+ quadNibble(b, x >> 4 , i + 1 )
733
+ val n = x & 0xF
734
+ val c = if (n < 10 ) '0' + n else 'a' + (n - 10 )
735
+ b.append(c.toChar)
736
+ val replace = (c : @ switch) match
737
+ case '\b ' => " \\ b"
738
+ case '\t ' => " \\ t"
739
+ case '\n ' => " \\ n"
740
+ case '\f ' => " \\ f"
741
+ case '\r ' => " \\ r"
742
+ case '"' => " \\\" "
743
+ case '\' ' => " \\\' "
744
+ case '\\ ' => " \\\\ "
745
+ case c =>
746
+ if c.isControl then
747
+ b.append(" \\ u" )
748
+ quadNibble(b, c.toInt, 0 )
749
+ else
750
+ b.append(c)
751
+ return
752
+ b.append(replace)
705
753
706
754
def dclsText (syms : List [Symbol ], sep : String ): Text = Text (syms map dclText, sep)
707
755
0 commit comments