Skip to content

Commit 9f19b05

Browse files
committed
Improve SourceCode string printing
1 parent e2c4ec1 commit 9f19b05

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

+65-19
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))
@@ -1445,19 +1449,61 @@ object SourceCode {
14451449
private def +=(x: Char): this.type = { sb.append(x); this }
14461450
private def +=(x: String): this.type = { sb.append(x); this }
14471451

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

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

0 commit comments

Comments
 (0)