Skip to content

Commit 1d79ae2

Browse files
Merge pull request #3523 from dotty-staging/print-lines
Add -print-lines
2 parents da25dcd + 8a50320 commit 1d79ae2

File tree

5 files changed

+71
-25
lines changed

5 files changed

+71
-25
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ class ScalaSettings extends Settings.SettingGroup {
4343
val rewrite = OptionSetting[Rewrites]("-rewrite", "When used in conjunction with -language:Scala2 rewrites sources to migrate to new syntax")
4444
val silentWarnings = BooleanSetting("-nowarn", "Silence all warnings.")
4545
val fromTasty = BooleanSetting("-from-tasty", "Compile classes from tasty in classpath. The arguments are used as class names.")
46+
47+
/** Decompiler settings */
4648
val printTasty = BooleanSetting("-print-tasty", "Prints the raw tasty when decompiling.")
49+
val printLines = BooleanSetting("-print-lines", "Show source code line numbers.")
4750

4851
/** -X "Advanced" settings
4952
*/

compiler/src/dotty/tools/dotc/core/Decorators.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ object Decorators {
143143
}
144144

145145
implicit class TextToString(val text: Text) extends AnyVal {
146-
def show(implicit ctx: Context) = text.mkString(ctx.settings.pageWidth.value)
146+
def show(implicit ctx: Context) = text.mkString(ctx.settings.pageWidth.value, ctx.settings.printLines.value)
147147
}
148148

149149
/** Test whether a list of strings representing phases contains

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@ import config.Config
1616
import transform.SymUtils._
1717
import scala.annotation.switch
1818
import language.implicitConversions
19+
import dotty.tools.dotc.util.SourcePosition
20+
1921

2022
class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
2123

2224
/** A stack of enclosing DefDef, TypeDef, or ClassDef, or ModuleDefs nodes */
2325
private[this] var enclosingDef: untpd.Tree = untpd.EmptyTree
2426
private[this] var myCtx: Context = _ctx
2527
private[this] var printPos = ctx.settings.Yprintpos.value
28+
private[this] val printLines = ctx.settings.printLines.value
2629
override protected[this] implicit def ctx: Context = myCtx
2730

2831
def withEnclosingDef(enclDef: Tree[_ >: Untyped])(op: => Text): Text = {
@@ -287,9 +290,17 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
287290
if (ctx.settings.uniqid.value && tree.hasType && tree.symbol.exists) s"#${tree.symbol.id}" else ""
288291
}
289292

290-
def nameIdText(tree: untpd.NameTree): Text =
291-
if (tree.hasType && tree.symbol.exists) nameString(tree.symbol)
293+
def nameIdText(tree: untpd.NameTree): Text = {
294+
if (tree.hasType && tree.symbol.exists) {
295+
val str: Text = nameString(tree.symbol)
296+
tree match {
297+
case tree: RefTree => withPos(str, tree.pos)
298+
case tree: MemberDef => withPos(str, tree.namePos)
299+
case _ => str
300+
}
301+
}
292302
else toText(tree.name) ~ idText(tree)
303+
}
293304

294305
def toTextTemplate(impl: Template, ofNew: Boolean = false): Text = {
295306
val Template(constr @ DefDef(_, tparams, vparamss, _, _), parents, self, _) = impl
@@ -343,7 +354,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
343354
tree.typeOpt match {
344355
case tp: NamedType if name != nme.WILDCARD =>
345356
val pre = if (tp.symbol is JavaStatic) tp.prefix.widen else tp.prefix
346-
toTextPrefix(pre) ~ selectionString(tp)
357+
toTextPrefix(pre) ~ withPos(selectionString(tp), tree.pos)
347358
case _ =>
348359
toText(name)
349360
}
@@ -365,8 +376,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
365376
toTextLocal(fun) ~ "[" ~ toTextGlobal(args, ", ") ~ "]"
366377
case Literal(c) =>
367378
tree.typeOpt match {
368-
case ConstantType(tc) => toText(tc)
369-
case _ => toText(c)
379+
case ConstantType(tc) => withPos(toText(tc), tree.pos)
380+
case _ => withPos(toText(c), tree.pos)
370381
}
371382
case New(tpt) =>
372383
"new " ~ {
@@ -517,7 +528,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
517528
case SymbolLit(str) =>
518529
"'" + str
519530
case InterpolatedString(id, segments) =>
520-
def strText(str: Literal) = Str(escapedString(str.const.stringValue))
531+
def strText(str: Literal) = withPos(escapedString(str.const.stringValue), tree.pos)
521532
def segmentText(segment: Tree) = segment match {
522533
case Thicket(List(str: Literal, expr)) => strText(str) ~ "{" ~ toTextGlobal(expr) ~ "}"
523534
case str: Literal => strText(str)
@@ -694,4 +705,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
694705
}
695706

696707
override def plain = new PlainPrinter(_ctx)
708+
709+
private def withPos(txt: Text, pos: SourcePosition): Text = {
710+
if (!printLines || !pos.exists) txt
711+
else txt match {
712+
case Str(s, _) => Str(s, LineRange(pos.line, pos.endLine))
713+
case _ => txt
714+
}
715+
}
697716
}

compiler/src/dotty/tools/dotc/printing/Texts.scala

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package dotty.tools.dotc
22
package printing
3-
import core.Contexts.Context
43
import language.implicitConversions
54

65
object Texts {
@@ -12,7 +11,7 @@ object Texts {
1211
def relems: List[Text]
1312

1413
def isEmpty: Boolean = this match {
15-
case Str(s) => s.isEmpty
14+
case Str(s, _) => s.isEmpty
1615
case Fluid(relems) => relems forall (_.isEmpty)
1716
case Vertical(relems) => relems.isEmpty
1817
}
@@ -25,7 +24,7 @@ object Texts {
2524
def close = new Closed(relems)
2625

2726
def remaining(width: Int): Int = this match {
28-
case Str(s) =>
27+
case Str(s, _) =>
2928
width - s.length
3029
case Fluid(Nil) =>
3130
width
@@ -37,15 +36,15 @@ object Texts {
3736
}
3837

3938
def lastLine: String = this match {
40-
case Str(s) => s
39+
case Str(s, _) => s
4140
case _ => relems.head.lastLine
4241
}
4342

4443
def appendToLastLine(that: Text): Text = that match {
45-
case Str(s2) =>
44+
case Str(s2, lines1) =>
4645
this match {
47-
case Str(s1) => Str(s1 + s2)
48-
case Fluid(Str(s1) :: prev) => Fluid(Str(s1 + s2) :: prev)
46+
case Str(s1, lines2) => Str(s1 + s2, lines1 union lines2)
47+
case Fluid(Str(s1, lines2) :: prev) => Fluid(Str(s1 + s2, lines1 union lines2) :: prev)
4948
case Fluid(relems) => Fluid(that :: relems)
5049
}
5150
case Fluid(relems) =>
@@ -66,7 +65,7 @@ object Texts {
6665
}
6766

6867
def layout(width: Int): Text = this match {
69-
case Str(_) =>
68+
case Str(s, _) =>
7069
this
7170
case Fluid(relems) =>
7271
((Str(""): Text) /: relems.reverse)(_.append(width)(_))
@@ -75,13 +74,13 @@ object Texts {
7574
}
7675

7776
def map(f: String => String): Text = this match {
78-
case Str(s) => Str(f(s))
77+
case Str(s, lines) => Str(f(s), lines)
7978
case Fluid(relems) => Fluid(relems map (_ map f))
8079
case Vertical(relems) => Vertical(relems map (_ map f))
8180
}
8281

8382
def stripPrefix(pre: String): Text = this match {
84-
case Str(s) =>
83+
case Str(s, _) =>
8584
if (s.startsWith(pre)) s drop pre.length else s
8685
case Fluid(relems) =>
8786
val elems = relems.reverse
@@ -94,26 +93,40 @@ object Texts {
9493
}
9594

9695
private def indented: Text = this match {
97-
case Str(s) => Str((" " * indentMargin) + s)
96+
case Str(s, lines) => Str((" " * indentMargin) + s, lines)
9897
case Fluid(relems) => Fluid(relems map (_.indented))
9998
case Vertical(relems) => Vertical(relems map (_.indented))
10099
}
101100

102-
def print(sb: StringBuilder): Unit = this match {
103-
case Str(s) =>
101+
def print(sb: StringBuilder, numberWidth: Int): Unit = this match {
102+
case Str(s, lines) =>
103+
if (numberWidth != 0) {
104+
val ln = lines.show
105+
val pad = (numberWidth - ln.length - 1)
106+
assert(pad >= 0)
107+
sb.append(" " * pad)
108+
sb.append(ln)
109+
sb.append("|")
110+
}
104111
sb.append(s)
105112
case _ =>
106113
var follow = false
107114
for (elem <- relems.reverse) {
108115
if (follow) sb.append("\n")
109-
elem.print(sb)
116+
elem.print(sb, numberWidth)
110117
follow = true
111118
}
112119
}
113120

114-
def mkString(width: Int): String = {
121+
def maxLine: Int = this match {
122+
case Str(_, lines) => lines.end
123+
case _ => (-1 /: relems)((acc, relem) => acc max relem.maxLine)
124+
}
125+
126+
def mkString(width: Int, withLineNumbers: Boolean): String = {
115127
val sb = new StringBuilder
116-
layout(width).print(sb)
128+
val numberWidth = if (withLineNumbers) (2 * maxLine.toString.length) + 2 else 0
129+
layout(width - numberWidth).print(sb, numberWidth)
117130
sb.toString
118131
}
119132

@@ -155,7 +168,7 @@ object Texts {
155168
def lines(xs: Traversable[Text]) = Vertical(xs.toList.reverse)
156169
}
157170

158-
case class Str(s: String) extends Text {
171+
case class Str(s: String, lineRange: LineRange = EmptyLineRange) extends Text {
159172
override def relems: List[Text] = List(this)
160173
}
161174

@@ -165,4 +178,15 @@ object Texts {
165178
class Closed(relems: List[Text]) extends Fluid(relems)
166179

167180
implicit def stringToText(s: String): Text = Str(s)
181+
182+
/** Inclusive line range */
183+
case class LineRange(start: Int, end: Int) {
184+
def union(that: LineRange): LineRange = LineRange(start min that.start, end max that.end)
185+
def show: String =
186+
if (start == end) (start + 1).toString
187+
else if (start < end) s"${start + 1}-${end + 1}"
188+
else "" // empty range
189+
}
190+
191+
object EmptyLineRange extends LineRange(Int.MaxValue, Int.MinValue)
168192
}

compiler/src/dotty/tools/repl/package.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ package object repl {
2222
def showUser(implicit ctx: Context): String = {
2323
val printer = new UserFacingPrinter(ctx)
2424
val text = printer.dclText(s)
25-
text.mkString(ctx.settings.pageWidth.value)
25+
text.mkString(ctx.settings.pageWidth.value, ctx.settings.printLines.value)
2626
}
2727
}
2828

0 commit comments

Comments
 (0)