Skip to content

Commit 877794a

Browse files
som-snytttgodzik
authored andcommitted
Improve SourceCode string printing
1 parent d942c7b commit 877794a

File tree

1 file changed

+65
-19
lines changed

1 file changed

+65
-19
lines changed

compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package scala.quoted
22
package runtime.impl.printers
33

4+
import dotty.tools.dotc.util.Chars
5+
46
import scala.annotation.switch
57

8+
import java.lang.StringBuilder
9+
610
/** Printer for fully elaborated representation of the source code */
711
object SourceCode {
812

@@ -97,7 +101,7 @@ object SourceCode {
97101
this += lineBreak() += "}"
98102
}
99103

100-
def result(): String = sb.result()
104+
def result(): String = sb.toString
101105

102106
private def lineBreak(): String = "\n" + (" " * indent)
103107
private def doubleLineBreak(): String = "\n\n" + (" " * indent)
@@ -438,7 +442,7 @@ object SourceCode {
438442
case _ =>
439443
inParens {
440444
printTree(term)
441-
this += (if (dotty.tools.dotc.util.Chars.isOperatorPart(sb.last)) " : " else ": ")
445+
this += (if Chars.isOperatorPart(sb.charAt(sb.length - 1)) then " : " else ": ")
442446
def printTypeOrAnnots(tpe: TypeRepr): Unit = tpe match {
443447
case AnnotatedType(tp, annot) if tp == term.tpe =>
444448
printAnnotation(annot)
@@ -957,8 +961,8 @@ object SourceCode {
957961

958962
}
959963

960-
inline private val qc = '\''
961-
inline private val qSc = '"'
964+
inline private val qc = "\'"
965+
inline private val qSc = "\""
962966

963967
def printConstant(const: Constant): this.type = const match {
964968
case UnitConstant() => this += highlightLiteral("()")
@@ -970,8 +974,8 @@ object SourceCode {
970974
case LongConstant(v) => this += highlightLiteral(v.toString + "L")
971975
case FloatConstant(v) => this += highlightLiteral(v.toString + "f")
972976
case DoubleConstant(v) => this += highlightLiteral(v.toString)
973-
case CharConstant(v) => this += highlightString(s"${qc}${escapedChar(v)}${qc}")
974-
case StringConstant(v) => this += highlightString(s"${qSc}${escapedString(v)}${qSc}")
977+
case CharConstant(v) => this += highlightString(escapedChar(v))
978+
case StringConstant(v) => this += highlightString(escapedString(v))
975979
case ClassOfConstant(v) =>
976980
this += "classOf"
977981
inSquare(printType(v))
@@ -1444,19 +1448,61 @@ object SourceCode {
14441448
private def +=(x: Char): this.type = { sb.append(x); this }
14451449
private def +=(x: String): this.type = { sb.append(x); this }
14461450

1447-
private def escapedChar(ch: Char): String = (ch: @switch) match {
1448-
case '\b' => "\\b"
1449-
case '\t' => "\\t"
1450-
case '\n' => "\\n"
1451-
case '\f' => "\\f"
1452-
case '\r' => "\\r"
1453-
case '"' => "\\\""
1454-
case '\'' => "\\\'"
1455-
case '\\' => "\\\\"
1456-
case _ => if ch.isControl then f"${"\\"}u${ch.toInt}%04x" else String.valueOf(ch).nn
1457-
}
1458-
1459-
private def escapedString(str: String): String = str flatMap escapedChar
1451+
private def escapedChar(ch: Char): String =
1452+
if requiresFormat(ch) then
1453+
val b = StringBuilder().append(qc)
1454+
escapedChar(b, ch)
1455+
b.append(qc).toString
1456+
else
1457+
qc + ch + qc
1458+
1459+
private def escapedChar(b: StringBuilder, c: Char): Unit =
1460+
def quadNibble(b: StringBuilder, x: Int, i: Int): Unit =
1461+
if i < 4 then
1462+
quadNibble(b, x >> 4, i + 1)
1463+
val n = x & 0xF
1464+
val c = if (n < 10) '0' + n else 'a' + (n - 10)
1465+
b.append(c.toChar)
1466+
val replace = (c: @switch) match
1467+
case '\b' => "\\b"
1468+
case '\t' => "\\t"
1469+
case '\n' => "\\n"
1470+
case '\f' => "\\f"
1471+
case '\r' => "\\r"
1472+
case '"' => "\\\""
1473+
case '\'' => "\\\'"
1474+
case '\\' => "\\\\"
1475+
case c =>
1476+
if c.isControl then
1477+
b.append("\\u")
1478+
quadNibble(b, c.toInt, 0)
1479+
else
1480+
b.append(c)
1481+
return
1482+
b.append(replace)
1483+
1484+
private def requiresFormat(c: Char): Boolean = (c: @switch) match
1485+
case '\b' | '\t' | '\n' | '\f' | '\r' | '"' | '\'' | '\\' => true
1486+
case c => c.isControl
1487+
1488+
private def escapedString(text: String): String =
1489+
def mustBuild: Boolean =
1490+
var i = 0
1491+
while i < text.length do
1492+
if requiresFormat(text.charAt(i)) then return true
1493+
i += 1
1494+
false
1495+
if mustBuild then
1496+
val b = StringBuilder(text.length + 16)
1497+
b.append(qSc)
1498+
var i = 0
1499+
while i < text.length do
1500+
escapedChar(b, text.charAt(i))
1501+
i += 1
1502+
b.append(qSc)
1503+
b.toString
1504+
else
1505+
qSc + text + qSc
14601506

14611507
private[this] val names = collection.mutable.Map.empty[Symbol, String]
14621508
private[this] val namesIndex = collection.mutable.Map.empty[String, Int]

0 commit comments

Comments
 (0)