aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-03-20 17:39:32 +0100
committerMartin Odersky <odersky@gmail.com>2013-03-20 17:39:32 +0100
commit5ac2104e688409e24785cfe62cdc7e8ef0bc6428 (patch)
tree0d48205fa5b50c25e240d77d4fb0e26c4b6c9b36 /src
parent53e0a8a9227820e47e33f1e0b1d91819aec917c4 (diff)
downloaddotty-5ac2104e688409e24785cfe62cdc7e8ef0bc6428.tar.gz
dotty-5ac2104e688409e24785cfe62cdc7e8ef0bc6428.tar.bz2
dotty-5ac2104e688409e24785cfe62cdc7e8ef0bc6428.zip
Pretty-printing improvements.
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/config/ScalaSettings.scala1
-rw-r--r--src/dotty/tools/dotc/config/Settings.scala2
-rw-r--r--src/dotty/tools/dotc/core/Constants.scala2
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala3
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala6
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala3
-rw-r--r--src/dotty/tools/dotc/core/Names.scala3
-rw-r--r--src/dotty/tools/dotc/core/Printers.scala368
-rw-r--r--src/dotty/tools/dotc/core/Scopes.scala3
-rw-r--r--src/dotty/tools/dotc/core/Showable.scala9
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala3
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala15
-rw-r--r--src/dotty/tools/dotc/core/Trees.scala2
-rw-r--r--src/dotty/tools/dotc/core/Types.scala4
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala8
-rw-r--r--src/dotty/tools/dotc/util/Text.scala108
-rw-r--r--src/test/showClass.scala28
17 files changed, 315 insertions, 253 deletions
diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala
index 483e163bf..1eeae8453 100644
--- a/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -33,6 +33,7 @@ class ScalaSettings extends Settings.SettingGroup {
val usejavacp = BooleanSetting("-usejavacp", "Utilize the java.class.path in classpath resolution.")
val verbose = BooleanSetting("-verbose", "Output messages about what the compiler is doing.")
val version = BooleanSetting("-version", "Print product version and exit.")
+ val pageWidth = IntSetting("-pagewidth", "Set page width", 80)
val jvmargs = PrefixSetting("-J<flag>", "-J", "Pass <flag> directly to the runtime system.")
val defines = PrefixSetting("-Dproperty=value", "-D", "Pass -Dproperty=value directly to the runtime system.")
diff --git a/src/dotty/tools/dotc/config/Settings.scala b/src/dotty/tools/dotc/config/Settings.scala
index adac2ecfd..96b047ede 100644
--- a/src/dotty/tools/dotc/config/Settings.scala
+++ b/src/dotty/tools/dotc/config/Settings.scala
@@ -230,7 +230,7 @@ object Settings {
def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String): Setting[String] =
publish(Setting(name, descr, default, helpArg, choices))
- def IntSetting(name: String, descr: String, default: Int, range: Seq[Int]): Setting[Int] =
+ def IntSetting(name: String, descr: String, default: Int, range: Seq[Int] = Nil): Setting[Int] =
publish(Setting(name, descr, default, choices = range))
def MultiStringSetting(name: String, helpArg: String, descr: String): Setting[List[String]] =
diff --git a/src/dotty/tools/dotc/core/Constants.scala b/src/dotty/tools/dotc/core/Constants.scala
index 9dd5a2627..0b4f51cf2 100644
--- a/src/dotty/tools/dotc/core/Constants.scala
+++ b/src/dotty/tools/dotc/core/Constants.scala
@@ -189,7 +189,7 @@ object Constants {
def stringValue: String = value.toString
- def show(implicit ctx: Context) = ctx.show(this)
+ def toText(implicit ctx: Context) = ctx.toText(this)
def typeValue: Type = value.asInstanceOf[Type]
def symbolValue: Symbol = value.asInstanceOf[Symbol]
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index 6874cd74c..2759d1079 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -256,6 +256,7 @@ object Contexts {
.withSetting(settings.debug, true)
.withSetting(settings.Ylogcp, true)
.withSetting(settings.printtypes, true)
+ .withSetting(settings.pageWidth, 120)
/** The symbol loaders */
val loaders = new SymbolLoaders
@@ -334,7 +335,7 @@ object Contexts {
// Printers state
/** Number of recursive invocations of a show method on cuyrrent stack */
- private[core] var showRecursions = 0
+ private[core] var toTextRecursions = 0
// Reporters state
private[dotc] var indent = 0
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index dd93b216c..2d6526c26 100644
--- a/src/dotty/tools/dotc/core/Decorators.scala
+++ b/src/dotty/tools/dotc/core/Decorators.scala
@@ -3,7 +3,7 @@ package core
import annotation.tailrec
import Symbols._
-import Contexts._, Names._, Phases._
+import Contexts._, Names._, Phases._, util.Texts._
/** This object provides useful implicit decorators for types defined elsewhere */
object Decorators {
@@ -71,6 +71,10 @@ object Decorators {
}
}
+ implicit class TextToString(val text: Text) extends AnyVal {
+ def show(implicit ctx: Context) = text.mkString(ctx.settings.pageWidth.value)
+ }
+
/** Implements a test whether a list of strings representing phases contains
* a given phase. The test returns true if the given phase starts with
* one of the names in the list of strings.
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index a3b48926e..24008ab63 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -9,6 +9,7 @@ import Names.TypeName
import Symbols.NoSymbol
import Symbols._
import Types._, Periods._, Flags._, Transformers._
+import util.Texts._
import io.AbstractFile
import Decorators.SymbolIteratorDecorator
@@ -276,7 +277,7 @@ object Denotations {
}
}
- def show(implicit ctx: Context): String = ctx.show(this)
+ def toText(implicit ctx: Context): Text = ctx.toText(this)
}
/** An overloaded denotation consisting of the alternatives of both given denotations.
diff --git a/src/dotty/tools/dotc/core/Names.scala b/src/dotty/tools/dotc/core/Names.scala
index 8a345fcc8..b61f5ee06 100644
--- a/src/dotty/tools/dotc/core/Names.scala
+++ b/src/dotty/tools/dotc/core/Names.scala
@@ -33,7 +33,6 @@ object Names {
*/
abstract class Name extends DotClass
with PreName
- with Showable
with Seq[Char]
with IndexedSeqOptimized[Char, Name] {
@@ -82,7 +81,7 @@ object Names {
override def toString = new String(chrs, start, length)
- def show(implicit ctx: Context): String = ctx.show(this)
+ def show(implicit ctx: Context): String = ctx.nameString(this)
/** Write to UTF8 representation of this name to given character array.
* Start copying to index `to`. Return index of next free byte in array.
diff --git a/src/dotty/tools/dotc/core/Printers.scala b/src/dotty/tools/dotc/core/Printers.scala
index a8059e6c4..e6b2288ab 100644
--- a/src/dotty/tools/dotc/core/Printers.scala
+++ b/src/dotty/tools/dotc/core/Printers.scala
@@ -3,6 +3,7 @@ package core
import Types._, Symbols._, Contexts._, Scopes._, Names._, NameOps._, Flags._
import Constants._, Annotations._, StdNames._, Denotations._, Trees._
+import util.Texts._
import java.lang.Integer.toOctalString
import scala.annotation.switch
@@ -17,8 +18,8 @@ trait Printers { this: Context =>
object Printers {
class Precedence(val value: Int) extends AnyVal {
- def parenthesize(nested: Precedence)(str: String) =
- if (nested.value < value) "(" + str + ")" else str
+ def parenthesize(nested: Precedence)(text: Text) =
+ if (nested.value < value) "(" ~ text ~ ")" else text
}
val DotPrec = new Precedence(4)
@@ -30,71 +31,73 @@ object Printers {
abstract class Printer {
- /** Show name with namespace suffix: /L for local names,
- * /V for other term names, /T for type names
+ /** The name, possibley with with namespace suffix if debugNames is set:
+ * /L for local names, /V for other term names, /T for type names
*/
- def show(name: Name): String
+ def nameString(name: Name): String
- /** Show type in context with given precedence */
- def show(tp: Type, precedence: Precedence): String
-
- /** Show name of symbol.
- * If !settings.debug shows original name and
- * translates expansions of operators back to operator symbol.
+ /** The name of the given symbol.
+ * If !settings.debug, the original name where
+ * expansions of operators are translated back to operator symbol.
* E.g. $eq => =.
* If settings.uniqid, adds id.
*/
- def showName(sym: Symbol): String
+ def nameString(sym: Symbol): String
- /** Show fully qualified name of symbol */
- def showFullName(sym: Symbol): String
+ /** The fully qualified name of the symbol */
+ def fullNameString(sym: Symbol): String
- /** Show kind of symbol */
- def showKind(sym: Symbol): String
+ /** The kind of the symbol */
+ def kindString(sym: Symbol): String
- /** String representation, including symbol's kind e.g., "class Foo", "method Bar".
+ /** Textual representation, including symbol's kind e.g., "class Foo", "method Bar".
* If hasMeaninglessName is true, uses the owner's name to disambiguate identity.
*/
- def show(sym: Symbol): String
+ def toText(sym: Symbol): Text
+
+ /** Textual representation of symbol's declaration */
+ def dclText(sym: Symbol): Text
- /** Show symbol's declaration */
- def showDcl(sym: Symbol): String
+ /** If symbol's owner is a printable class C, the text "in C", otherwise "" */
+ def locationText(sym: Symbol): Text
- /** If symbol's owner is a printable class C, the string "in C", otherwise "" */
- def showLocation(sym: Symbol): String
+ /** Textual representation of symbol and its location */
+ def locatedText(sym: Symbol): Text
- /** Show symbol and its location */
- def showLocated(sym: Symbol): String
+ /** Textual representation of denotation */
+ def toText(denot: Denotation): Text
- /** Show denotation */
- def show(denot: Denotation): String
+ /** Textual representation of constant */
+ def toText(const: Constant): Text
- /** Show constant */
- def show(const: Constant): String
+ /** Textual representation of annotation */
+ def toText(annot: Annotation): Text
- /** Show annotation */
- def show(annot: Annotation): String
+ /** Textual representation of type in context with given precedence */
+ def toText(tp: Type, precedence: Precedence): Text
- /** Show all symbols in given list separated by `sep`, using `showDcl` for each */
- def showDcls(syms: List[Symbol], sep: String): String
+ /** Textual representation of all symbols in given list,
+ * using `dclText` for displaying each.
+ */
+ def dclsText(syms: List[Symbol], sep: String = "\n"): Text
- /** Show all definitions in a scope using `showDcl` for each */
- def show(sc: Scope): String
+ /** Textual representation of all definitions in a scope using `dclText` for each */
+ def toText(sc: Scope): Text
- /** Show tree */
- def show[T](tree: Tree[T]): String
+ /** Textual representation of tree */
+ def toText[T](tree: Tree[T]): Text
}
class PlainPrinter(_ctx: Context) extends Printer {
protected[this] implicit val ctx = _ctx
- def controlled(op: => String): String =
- if (ctx.showRecursions < maxShowRecursions)
+ def controlled(op: => Text): Text =
+ if (ctx.toTextRecursions < maxToTextRecursions)
try {
- ctx.showRecursions += 1
+ ctx.toTextRecursions += 1
op
} finally {
- ctx.showRecursions -= 1
+ ctx.toTextRecursions -= 1
}
else {
recursionLimitExceeeded()
@@ -106,9 +109,6 @@ object Printers {
(new Throwable).printStackTrace
}
- /** Concatenate strings separated by spaces */
- protected def compose(ss: String*) = ss.filter(_.nonEmpty).mkString(" ")
-
/** If the name of the symbol's owner should be used when you care about
* seeing an interesting name: in such cases this symbol is e.g. a method
* parameter with a synthetic name, a constructor named "this", an object
@@ -121,7 +121,7 @@ object Printers {
|| (sym.name == nme.PACKAGE) // package
)
- def show(name: Name): String = name.toString + {
+ def nameString(name: Name): String = name.toString + {
if (ctx.settings.debugNames.value)
if (name.isLocalName) "/L"
else if (name.isTypeName) "/T"
@@ -132,11 +132,11 @@ object Printers {
/** String representation of a name used in a refinement
* In refined printing this undoes type parameter expansion
*/
- protected def showRefinementName(tp: RefinedType) = show(tp.refinedName)
+ protected def refinementNameString(tp: RefinedType) = nameString(tp.refinedName)
/** String representation of a refinement */
- protected def showRefinement(rt: RefinedType) =
- showRefinementName(rt) + showRHS(rt.refinedInfo)
+ protected def toTextRefinement(rt: RefinedType) =
+ (refinementNameString(rt) ~ toTextRHS(rt.refinedInfo)).close
/** The longest sequence of refinement types, starting at given type
* and following parents.
@@ -147,28 +147,29 @@ object Printers {
case _ => Nil
})
- def show(tp: Type, prec: Precedence): String = controlled {
+ def toText(tp: Type, prec: Precedence): Text = controlled {
tp match {
case tp: TypeType =>
- showRHS(tp)
+ toTextRHS(tp)
case tp: SingletonType =>
- val str = showPrefix(tp)
- if (str.endsWith(".")) str + "type"
- else showFullName(tp.typeSymbol.skipPackageObject) + ".type"
+ val pre = toTextPrefix(tp)
+ if (pre.lastLine.endsWith(".")) pre ~ "type"
+ else fullNameString(tp.typeSymbol.skipPackageObject) ~ ".type"
case TypeRef(pre, name) =>
- showPrefix(pre) + showName(tp.typeSymbol)
+ toTextPrefix(pre) ~ nameString(tp.typeSymbol)
case tp: RefinedType =>
// return tp.toString // !!! DEBUG
- val parent :: refined = refinementChain(tp).reverse
- showLocal(parent) +
- refined.asInstanceOf[List[RefinedType]].map(showRefinement).mkString("{", "; ", "}")
+ val parent :: (refined: List[RefinedType]) =
+ refinementChain(tp).reverse
+ toTextLocal(parent) ~ "{" ~
+ Text(refined.map(toTextRefinement), "; ").close ~ "}"
case AndType(tp1, tp2) =>
(prec parenthesize AndPrec) {
- show(tp1, AndPrec) + "&" + show(tp2, AndPrec)
+ toText(tp1, AndPrec) ~ "&" ~ toText(tp2, AndPrec)
}
case OrType(tp1, tp2) =>
(prec parenthesize OrPrec) {
- show(tp1, OrPrec) + "|" + show(tp2, OrPrec)
+ toText(tp1, OrPrec) ~ "|" ~ toText(tp2, OrPrec)
}
case ErrorType =>
"<error>"
@@ -180,76 +181,81 @@ object Printers {
"<noprefix>"
case tp: MethodType =>
(prec parenthesize GlobalPrec) {
- val openStr = if (tp.isImplicit) "(implicit " else "("
+ (if (tp.isImplicit) "(implicit " else "(") ~
+ Text(
(tp.paramNames, tp.paramTypes).zipped
- .map((name, tp) => show(name) + ": " + showGlobal(tp))
- .mkString(openStr, ", ", ")" + showGlobal(tp.resultType))
+ .map((name, tp) => nameString(name) ~ ": " ~ toTextGlobal(tp)),
+ ", ") ~
+ ")" ~ toTextGlobal(tp.resultType)
}
case tp: ExprType =>
(prec parenthesize GlobalPrec) {
- "=> " + showGlobal(tp.resultType)
+ "=> " ~ toTextGlobal(tp.resultType)
}
case tp: PolyType =>
(prec parenthesize GlobalPrec) {
- (tp.paramNames, tp.paramBounds).zipped
- .map((name, bounds) => show(name) + showGlobal(bounds))
- .mkString("[", ", ", "]" + showGlobal(tp.resultType))
+ "[" ~
+ Text(
+ (tp.paramNames, tp.paramBounds).zipped
+ .map((name, bounds) => nameString(name) ~ toTextGlobal(bounds)),
+ ", ") ~
+ "]" ~ toTextGlobal(tp.resultType)
}
case PolyParam(pt, n) =>
- show(pt.paramNames(n))
+ nameString(pt.paramNames(n))
case AnnotatedType(annot, tpe) =>
- showLocal(tpe) + " " + show(annot)
+ toTextLocal(tpe) ~ " " ~ toText(annot)
}
- }
+ }.close
- /** Show type within highest precedence */
- protected def showLocal(tp: Type) = show(tp, DotPrec)
+ /** Render type within highest precedence */
+ protected def toTextLocal(tp: Type) = toText(tp, DotPrec)
- /** Show type within lowest precedence */
- protected def showGlobal(tp: Type) = show(tp, GlobalPrec)
+ /** Render type within lowest precedence */
+ protected def toTextGlobal(tp: Type) = toText(tp, GlobalPrec)
- /** Show name of symbol without unique id. Under refined printing,
- * shows decoded original name.
+ /** The name of the symbol without a unique id. Under refined printing,
+ * the decoded original name.
*/
- protected def showSimpleName(sym: Symbol) = show(sym.name)
+ protected def simpleNameString(sym: Symbol): String = nameString(sym.name)
- /** Show unique id of symbol, after a # */
- protected def showId(sym: Symbol) =
+ /** The unique id of symbol, after a # */
+ protected def idString(sym: Symbol): String =
if (ctx.settings.uniqid.value) "#" + sym.id else ""
- def showName(sym: Symbol): String = showSimpleName(sym) + showId(sym)
+ def nameString(sym: Symbol): String = simpleNameString(sym) + idString(sym)
- def showFullName(sym: Symbol): String =
+ def fullNameString(sym: Symbol): String =
if (sym.isRoot || sym == NoSymbol || sym.owner.isEffectiveRoot)
- showName(sym)
+ nameString(sym)
else
- showFullName(sym.effectiveOwner.enclosingClass) + "." + showName(sym)
+ fullNameString(sym.effectiveOwner.enclosingClass) + "." + nameString(sym)
protected def objectPrefix = "object "
protected def packagePrefix = "package "
- protected def trimPrefix(str: String) =
- str.stripPrefix(objectPrefix).stripPrefix(packagePrefix)
+ protected def trimPrefix(text: Text) =
+ text.stripPrefix(objectPrefix).stripPrefix(packagePrefix)
/** The string representation of this type used as a prefix */
- protected def showPrefix(tp: Type): String = controlled {
+ protected def toTextPrefix(tp: Type): Text = controlled {
tp match {
case tp @ TermRef(pre, name) =>
- showPrefix(pre) + showName(tp.symbol) + "."
+ toTextPrefix(pre) ~ nameString(tp.symbol) ~ "."
case ThisType(cls) =>
- showName(cls) + ".this."
+ nameString(cls) + ".this."
case SuperType(thistpe, _) =>
- showPrefix(thistpe).replaceAll("""\bthis\.$""", "super.")
+ toTextPrefix(thistpe).map(_.replaceAll("""\bthis\.$""", "super."))
case tp @ ConstantType(value) =>
- showLocal(tp.underlying) + "(" + show(value) + ")."
+ toTextLocal(tp.underlying) ~ "(" ~ toText(value) ~ ")."
case MethodParam(mt, idx) =>
- show(mt.paramNames(idx)) + "."
+ nameString(mt.paramNames(idx)) + "."
case RefinedThis(_) =>
"this."
case NoPrefix =>
""
case _ =>
- trimPrefix(showLocal(tp)) + "#"
+ trimPrefix(toTextLocal(tp)) ~ "#"
}
}
@@ -260,31 +266,31 @@ object Printers {
sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName
/** String representation of a definition's type following its name */
- protected def showRHS(tp: Type): String = controlled {
+ protected def toTextRHS(tp: Type): Text = controlled {
tp match {
case TypeBounds(lo, hi) =>
if (lo eq hi)
- " = " + lo.show
+ " = " ~ lo.toText
else
- (if (lo == defn.NothingType) "" else " >: " + lo.show) +
- (if (hi == defn.AnyType) "" else " <: " + hi.show)
+ (if (lo == defn.NothingType) Text() else " >: " ~ lo.toText) ~
+ (if (hi == defn.AnyType) Text() else " <: " ~ hi.toText)
case ClassInfo(pre, cdenot, cparents, decls, optSelfType) =>
- val preStr = showLocal(pre)
- val selfStr =
- if (optSelfType.exists) s"this: ${show(optSelfType, LeftArrowPrec)} =>"
- else ""
- val parentsStr = cparents.map(show(_, WithPrec)).mkString(" with ")
- val declsStr =
- if (decls.isEmpty) ""
- else "\n " + showDcls(decls.toList, "\n ")
- s""" extends $parentsStr { $selfStr$declsStr
- |} at $preStr""".stripMargin
- case _ => ": " + showGlobal(tp)
+ val preText = toTextLocal(pre)
+ val selfText =
+ if (optSelfType.exists)
+ "this: " ~ toText(optSelfType, LeftArrowPrec) ~ " =>"
+ else Text()
+ val parentsText = Text(cparents.map(toText(_, WithPrec)), " with ")
+ val declsText = if (decls.isEmpty) Text() else dclsText(decls.toList)
+ "extends " ~ parentsText ~ "{" ~ selfText ~ declsText ~
+ "} at " ~ preText
+ case _ =>
+ ": " ~ toTextGlobal(tp)
}
}
- /** Show kind of symbol */
- def showKind(sym: Symbol) =
+ /** String representation of symbol's kind. */
+ def kindString(sym: Symbol): String =
if (sym is PackageClass) "package class"
else if (sym is PackageVal) "package"
else if (sym.isPackageObject)
@@ -308,7 +314,7 @@ object Printers {
else ""
/** String representation of symbol's definition key word */
- protected def showKey(sym: Symbol): String =
+ protected def keyString(sym: Symbol): String =
if (sym is JavaInterface) "interface"
else if (sym is (Trait, butNot = ImplClass)) "trait"
else if (sym.isClass) "class"
@@ -321,35 +327,35 @@ object Printers {
else ""
/** String representation of symbol's flags */
- protected def showFlags(sym: Symbol) = sym.flags.toString
+ protected def toTextFlags(sym: Symbol): Text =
+ Text(sym.flags.flagStrings map stringToText, " ")
/** String representation of symbol's variance or "" if not applicable */
- protected def showVariance(sym: Symbol) = sym.variance match {
+ protected def varianceString(sym: Symbol): String = sym.variance match {
case -1 => "-"
case 1 => "+"
case _ => ""
}
- def showDcl(sym: Symbol): String = compose(
- showFlags(sym),
- showKey(sym),
- showVariance(sym) + showName(sym) + showRHS(sym.info))
+ def dclText(sym: Symbol): Text =
+ (toTextFlags(sym) ~~ keyString(sym) ~~
+ (varianceString(sym) ~ nameString(sym)) ~ toTextRHS(sym.info)).close
- def show(sym: Symbol): String = compose(
- showKind(sym),
- if (hasMeaninglessName(sym)) showSimpleName(sym.owner) + showId(sym)
- else showName(sym)
- )
+ def toText(sym: Symbol): Text =
+ (kindString(sym) ~~ {
+ if (hasMeaninglessName(sym)) simpleNameString(sym.owner) + idString(sym)
+ else nameString(sym)
+ }).close
- def showLocation(sym: Symbol): String = {
+ def locationText(sym: Symbol): Text = {
val owns = sym.effectiveOwner
- if (owns.isClass && !isEmptyPrefix(owns)) "in "+show(owns) else ""
+ if (owns.isClass && !isEmptyPrefix(owns)) "in " ~ toText(owns) else Text()
}
- def showLocated(sym: Symbol): String =
- show(sym) + showLocation(sym)
+ def locatedText(sym: Symbol): Text =
+ (toText(sym) ~ locationText(sym)).close
- def show(denot: Denotation): String = show(denot.symbol) + "/D"
+ def toText(denot: Denotation): Text = toText(denot.symbol) ~ "/D"
@switch private def escapedChar(ch: Char): String = ch match {
case '\b' => "\\b"
@@ -363,82 +369,87 @@ object Printers {
case _ => if (ch.isControl) "\\0" + toOctalString(ch) else String.valueOf(ch)
}
- def show(const: Constant) = const.tag match {
+ def toText(const: Constant): Text = const.tag match {
case StringTag => "\"" + (const.value.toString flatMap escapedChar) + "\""
- case ClazzTag => s"classOf[${const.tpe.show}]"
+ case ClazzTag => "classOf[" ~ const.tpe.toText ~ "]"
case CharTag => s"'${escapedChar(const.charValue)}'"
case LongTag => const.longValue.toString + "L"
case EnumTag => const.symbolValue.name.toString
case _ => String.valueOf(const.value)
}
- def show(annot: Annotation): String = s"@${annot.symbol.name}" // for now
+ def toText(annot: Annotation): Text = s"@${annot.symbol.name}" // for now
- def showDcls(syms: List[Symbol], sep: String): String =
- syms map (_.showDcl) mkString sep
+ def dclsText(syms: List[Symbol], sep: String): Text =
+ if (sep == "\n") Text.lines(syms map dclText)
+ else Text(syms map dclText, sep)
- def show(sc: Scope): String =
- "Scope{\n" + showDcls(sc.toList, ";\n ") + "\n}"
+ def toText(sc: Scope): Text =
+ ("Scope{" ~ dclsText(sc.toList) ~ "}").close
- def show[T](tree: Tree[T]): String = tree match {
- case node: Product =>
- def showElem(elem: Any) = elem match {
- case elem: Showable => elem.show
- case elem => elem.toString
- }
- val nodeName = node.productPrefix
- val elems = node.productIterator.map(showElem).mkString(", ")
- val tpSuffix =
- if (ctx.settings.printtypes.value && tree.hasType)
- s" | ${tree.tpe.asInstanceOf[Type].show}"
- else
- ""
-
- s"$nodeName($elems$tpSuffix)"
- case _ =>
- tree.toString
- } // todo: override in refined printer
+ def toText[T](tree: Tree[T]): Text = {
+ tree match {
+ case node: Product =>
+ def toTextElem(elem: Any): Text = elem match {
+ case elem: Showable => elem.toText
+ case elem => elem.toString
+ }
+ val nodeName = node.productPrefix
+ val elems =
+ Text(node.productIterator.map(toTextElem).toList, ", ")
+ val tpSuffix =
+ if (ctx.settings.printtypes.value && tree.hasType)
+ " | " ~ tree.tpe.asInstanceOf[Type].toText
+ else
+ Text()
+
+ nodeName ~ "(" ~ elems ~ tpSuffix ~ ")"
+ case _ =>
+ tree.toString: Text
+ }
+ }.close // todo: override in refined printer
}
class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
override protected def recursionLimitExceeeded() = {}
- override def show(name: Name): String = name.toString
+ override def nameString(name: Name): String = name.toString
- override protected def showSimpleName(sym: Symbol) = sym.originalName.decode
+ override protected def simpleNameString(sym: Symbol) = sym.originalName.decode
- override def showPrefix(tp: Type): String = controlled {
+ override def toTextPrefix(tp: Type): Text = controlled {
tp match {
case ThisType(cls) =>
if (cls.isAnonymousClass) return "this."
if (isOmittablePrefix(cls)) return ""
- if (cls is ModuleClass) return showFullName(cls) + "."
+ if (cls is ModuleClass) return fullNameString(cls) + "."
case tp @ TermRef(pre, name) =>
val sym = tp.symbol
- if (sym.isPackageObject) return showPrefix(pre)
+ if (sym.isPackageObject) return toTextPrefix(pre)
if (isOmittablePrefix(sym)) return ""
case _ =>
}
- super.showPrefix(tp)
+ super.toTextPrefix(tp)
}
- override protected def showRefinementName(tp: RefinedType): String = {
+ override protected def refinementNameString(tp: RefinedType): String = {
val tsym = tp.member(tp.refinedName).symbol
val name = tsym.originalName
- show(if (tsym is ExpandedTypeParam) name.asTypeName.unexpandedName() else name)
+ nameString(if (tsym is ExpandedTypeParam) name.asTypeName.unexpandedName() else name)
}
- override def show(tp: Type, prec: Precedence): String = controlled {
- def showFunction(args: List[Type]): String =
+ override def toText(tp: Type, prec: Precedence): Text = controlled {
+ def toTextFunction(args: List[Type]): Text =
(prec parenthesize GlobalPrec) {
- val argStr =
+ val argStr: Text =
if (args.length == 2 &&
- !(defn.TupleClasses contains args.head.typeSymbol)) show(args.head, LeftArrowPrec)
- else args.init.map(showGlobal(_)).mkString("(", ", ", ")")
- argStr + " => " + showGlobal(args.last)
+ !(defn.TupleClasses contains args.head.typeSymbol)) toText(args.head, LeftArrowPrec)
+ else
+ "(" ~ Text(args.init.map(toTextGlobal(_)), ", ") ~ ")"
+ argStr ~ " => " ~ toTextGlobal(args.last)
}
- def showTuple(args: List[Type]): String =
- args.map(showGlobal(_)).mkString("(", ", ", ")")
+ def toTextTuple(args: List[Type]): Text =
+ "(" ~ Text(args.map(toTextGlobal(_)), ", ") ~ ")"
try {
tp match {
case tp: RefinedType =>
@@ -447,36 +458,37 @@ object Printers {
val tycon = tp.unrefine
val cls = tycon.typeSymbol
if (cls.typeParams.length == args.length) {
- if (cls == defn.RepeatedParamClass) return showLocal(args.head) + "*"
- if (cls == defn.ByNameParamClass) return "=> " + showGlobal(args.head)
- if (defn.FunctionClasses contains cls) return showFunction(args)
- if (defn.TupleClasses contains cls) return showTuple(args)
+ if (cls == defn.RepeatedParamClass) return toTextLocal(args.head) ~ "*"
+ if (cls == defn.ByNameParamClass) return "=> " ~ toTextGlobal(args.head)
+ if (defn.FunctionClasses contains cls) return toTextFunction(args)
+ if (defn.TupleClasses contains cls) return toTextTuple(args)
}
- return showLocal(tycon) + args.map(showGlobal(_)).mkString("[", ", ", "]")
+ return toTextLocal(tycon) ~ "[" ~
+ Text(args.map(toTextGlobal(_)), ", ") ~ "]"
}
case _ =>
}
} catch {
case ex: CyclicReference =>
- "<cylic reference during display>" + super.show(tp, prec)
+ "<cylic reference during display>" ~ super.toText(tp, prec)
}
- super.show(tp, prec)
+ super.toText(tp, prec)
}
- override def showKind(sym: Symbol) =
+ override def kindString(sym: Symbol) =
if (sym is Package) "package"
else if (sym.isPackageObject) "package object"
else if (sym is Module) "object"
else if (sym is ImplClass) "class"
else if (sym.isClassConstructor) "constructor"
- else super.showKind(sym)
+ else super.kindString(sym)
- override def showFlags(sym: Symbol) =
- sym.flags.flagStrings.filterNot(_.startsWith("<")).mkString(" ")
+ override def toTextFlags(sym: Symbol) =
+ Text(sym.flags.flagStrings.filterNot(_.startsWith("<")) map stringToText, " ")
- override def show(denot: Denotation): String = show(denot.symbol)
+ override def toText(denot: Denotation): Text = toText(denot.symbol)
}
- final val maxShowRecursions = 100
+ final val maxToTextRecursions = 100
}
diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala
index cddf2e990..2d9df1962 100644
--- a/src/dotty/tools/dotc/core/Scopes.scala
+++ b/src/dotty/tools/dotc/core/Scopes.scala
@@ -12,6 +12,7 @@ import Periods._
import Decorators._
import Contexts._
import Denotations._
+import util.Texts._
import SymDenotations.NoDenotation
object Scopes {
@@ -110,7 +111,7 @@ object Scopes {
/** Cast this scope to a mutable scope */
final def openForMutations: MutableScope = this.asInstanceOf[MutableScope]
- final def show(implicit ctx: Context): String = ctx.show(this)
+ final def toText(implicit ctx: Context): Text = ctx.toText(this)
}
/** A subclass of Scope that defines methods for entering and
diff --git a/src/dotty/tools/dotc/core/Showable.scala b/src/dotty/tools/dotc/core/Showable.scala
index 770b3c818..54a25506a 100644
--- a/src/dotty/tools/dotc/core/Showable.scala
+++ b/src/dotty/tools/dotc/core/Showable.scala
@@ -1,9 +1,12 @@
-package dotty.tools.dotc.core
+package dotty.tools.dotc
+package core
-import Contexts._
+import Contexts._, util.Texts._, Decorators._
trait Showable {
- def show(implicit ctx: Context): String
+ def toText(implicit ctx: Context): Text
+
+ def show(implicit ctx: Context): String = toText.show
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 3f37c41f5..d5ccfb74a 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -991,7 +991,8 @@ object SymDenotations {
if (file != null) (s" in $file", file.toString)
else ("", "the signature")
cctx.error(
- s"""|bad symbolic reference. A signature$location refers to ${cctx.fresh.withDebug.show(denot.name)}
+ s"""|bad symbolic reference. A signature$location refers to
+ |${cctx.fresh.withSetting(cctx.settings.debugNames, true).nameString(denot.name)}
|in ${denot.owner.showKind} ${denot.owner.showFullName} which is not available.
|It may be completely missing from the current classpath, or the version on
|the classpath might be incompatible with the version used when compiling $src.""".stripMargin)
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 089d41be7..d39dabe1d 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -10,7 +10,7 @@ import java.lang.AssertionError
import Decorators._
import Symbols._
import Contexts._
-import SymDenotations._
+import SymDenotations._, util.Texts._
import Types._, Annotations._, Positions._, StdNames._, Trees._
import Denotations.{ Denotation, SingleDenotation, MultiDenotation }
import collection.mutable
@@ -376,12 +376,13 @@ object Symbols {
if (lastDenot == null) s"Naked$prefixString#$id"
else lastDenot.toString
- def show(implicit ctx: Context): String = ctx.show(this)
- def showLocated(implicit ctx: Context): String = ctx.showLocated(this)
- def showDcl(implicit ctx: Context): String = ctx.showDcl(this)
- def showKind(implicit ctx: Context): String = ctx.showKind(this)
- def showName(implicit ctx: Context): String = ctx.showName(this)
- def showFullName(implicit ctx: Context): String = ctx.showFullName(this)
+ def toText(implicit ctx: Context): Text = ctx.toText(this)
+
+ def showLocated(implicit ctx: Context): String = ctx.locatedText(this).show
+ def showDcl(implicit ctx: Context): Text = ctx.dclText(this).show
+ def showKind(implicit ctx: Context): String = ctx.kindString(this)
+ def showName(implicit ctx: Context): String = ctx.nameString(this)
+ def showFullName(implicit ctx: Context): String = ctx.fullNameString(this)
}
type TermSymbol = Symbol { type ThisName = TermName }
diff --git a/src/dotty/tools/dotc/core/Trees.scala b/src/dotty/tools/dotc/core/Trees.scala
index bc3d83aa1..5fcab4de7 100644
--- a/src/dotty/tools/dotc/core/Trees.scala
+++ b/src/dotty/tools/dotc/core/Trees.scala
@@ -100,7 +100,7 @@ object Trees {
/** Is this tree either the empty tree or the empty ValDef? */
def isEmpty: Boolean = false
- override def show(implicit ctx: Context) = ctx.show(this)
+ override def toText(implicit ctx: Context) = ctx.toText(this)
override def hashCode(): Int = System.identityHashCode(this)
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 297f58cd5..252901b17 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -15,7 +15,7 @@ import SymDenotations._
import Decorators._
import Denotations._
import Periods._
-import TypedTrees.tpd._, TypedTrees.TreeMapper
+import TypedTrees.tpd._, TypedTrees.TreeMapper, util.Texts._
import transform.Erasure
import scala.util.hashing.{ MurmurHash3 => hashing }
import collection.mutable
@@ -663,7 +663,7 @@ object Types {
*/
def signature(implicit ctx: Context): Signature = NotAMethod
- def show(implicit ctx: Context): String = ctx.show(this, Printers.GlobalPrec)
+ def toText(implicit ctx: Context): Text = ctx.toText(this, Printers.GlobalPrec)
// ----- hashing ------------------------------------------------------
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index f7ee0d05c..2f7bcc94d 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -10,8 +10,10 @@ import java.lang.Double.longBitsToDouble
import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._
import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._
import Positions._, TypedTrees.tpd._, TypedTrees.TreeOps
+import util.Texts._
import io.AbstractFile
import scala.reflect.internal.pickling.PickleFormat._
+import Decorators._
import scala.collection.{ mutable, immutable }
import scala.collection.mutable.ListBuffer
import scala.annotation.switch
@@ -22,8 +24,8 @@ object UnPickler {
class BadSignature(msg: String) extends RuntimeException(msg)
case class TempPolyType(tparams: List[Symbol], tpe: Type) extends UncachedGroundType {
- override def show(implicit ctx: Context): String =
- s"[${ctx.showDcls(tparams, ", ")}]${tpe.show}"
+ override def toText(implicit ctx: Context): Text =
+ "[" ~ ctx.dclsText(tparams, ", ") ~ "]" ~ tpe.show
}
/** Temporary type for classinfos, will be decomposed on completion of the class */
@@ -529,7 +531,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
if (tp1 existsPart isBound) {
val tp2 = tp1.subst(boundSyms, boundSyms map (_ => defn.AnyType))
cctx.warning(s"""failure to eliminate existential
- |original type : $tp forSome {${cctx.showDcls(boundSyms, "; ")}}
+ |original type : $tp forSome {${cctx.dclsText(boundSyms, "; ").show}
|reduces to : $tp1
|type used instead: $tp2
|proceed at own risk.""".stripMargin)
diff --git a/src/dotty/tools/dotc/util/Text.scala b/src/dotty/tools/dotc/util/Text.scala
index a63f36b83..251274371 100644
--- a/src/dotty/tools/dotc/util/Text.scala
+++ b/src/dotty/tools/dotc/util/Text.scala
@@ -4,33 +4,40 @@ import language.implicitConversions
object Texts {
- class Text {
+ abstract class Text {
protected def indentMargin = 2
- protected def pageWidth = 80
def relems: List[Text]
def isEmpty: Boolean = this match {
case Str(s) => s.isEmpty
case Fluid(relems) => relems forall (_.isEmpty)
- case Rigid(relems) => relems.isEmpty
+ case Vertical(relems) => relems.isEmpty
}
- def isRigid = isInstanceOf[Rigid]
+ def isVertical = isInstanceOf[Vertical]
+ def isClosed = isVertical || isInstanceOf[Closed]
+ def isFluid = isInstanceOf[Fluid]
+ def isSplittable = isFluid && !isClosed
- def fitsIn(width: Int): Boolean = this match {
+ def close = new Closed(relems)
+
+ def remaining(width: Int): Int = this match {
case Str(s) =>
- s.length <= width
- case Fluid(Str(s) :: prevs) =>
- s.length < width && Fluid(prevs).fitsIn(width - s.length)
- case Rigid(_) =>
- false
+ width - s.length
+ case Fluid(Nil) =>
+ width
+ case Fluid(last :: prevs) =>
+ val r = last remaining width
+ if (r < 0) r else Fluid(prevs) remaining r
+ case Vertical(_) =>
+ -1
}
- def lastLineWidth: Int = this match {
- case Str(s) => s.length
- case _ => relems.head.lastLineWidth
+ def lastLine: String = this match {
+ case Str(s) => s
+ case _ => relems.head.lastLine
}
def appendToLastLine(that: Text): Text = that match {
@@ -44,80 +51,103 @@ object Texts {
}
private def appendIndented(that: Text)(width: Int): Text =
- Rigid(that.layout(width - indentMargin).indented :: this.relems)
+ Vertical(that.layout(width - indentMargin).indented :: this.relems)
- private def append(width: Int)(that: Text): Text =
+ private def append(width: Int)(that: Text): Text = {
if (this.isEmpty) that.layout(width)
else if (that.isEmpty) this
- else if (that.isRigid) appendIndented(that)(width)
- else if (this.isRigid) Fluid(that.layout(width) :: this.relems)
- else if (that.fitsIn(width - this.lastLineWidth)) appendToLastLine(that)
+ else if (that.isVertical) appendIndented(that)(width)
+ else if (this.isVertical) Fluid(that.layout(width) :: this.relems)
+ else if (that.remaining(width - lastLine.length) >= 0) appendToLastLine(that)
+ else if (that.isSplittable) (this /: that.relems.reverse)(_.append(width)(_))
else appendIndented(that)(width)
+ }
def layout(width: Int): Text = this match {
case Str(_) =>
this
case Fluid(relems) =>
((Str(""): Text) /: relems.reverse)(_.append(width)(_))
- case Rigid(relems) =>
- Rigid(relems map (_ layout width))
+ case Vertical(relems) =>
+ Vertical(relems map (_ layout width))
+ }
+
+ def map(f: String => String): Text = this match {
+ case Str(s) => Str(f(s))
+ case Fluid(relems) => Fluid(relems map (_ map f))
+ case Vertical(relems) => Vertical(relems map (_ map f))
+ }
+
+ def stripPrefix(pre: String): Text = this match {
+ case Str(s) =>
+ if (s.startsWith(pre)) s drop pre.length else s
+ case Fluid(relems) =>
+ val elems = relems.reverse
+ val head = elems.head.stripPrefix(pre)
+ if (head eq elems.head) this else Fluid((head :: elems.tail).reverse)
+ case Vertical(relems) =>
+ val elems = relems.reverse
+ val head = elems.head.stripPrefix(pre)
+ if (head eq elems.head) this else Vertical((head :: elems.tail).reverse)
}
private def indented: Text = this match {
case Str(s) => Str((" " * indentMargin) + s)
case Fluid(relems) => Fluid(relems map (_.indented))
- case Rigid(relems) => Rigid(relems map (_.indented))
+ case Vertical(relems) => Vertical(relems map (_.indented))
}
def print(sb: StringBuilder): Unit = this match {
case Str(s) =>
sb.append(s)
- case txt: CompoundText =>
+ case _ =>
var follow = false
- for (elem <- txt.relems.reverse) {
+ for (elem <- relems.reverse) {
if (follow) sb.append("\n")
elem.print(sb)
follow = true
}
}
- def show: String =
- layout(pageWidth).showRaw
-
- def showRaw: String = {
+ def mkString(width: Int): String = {
val sb = new StringBuilder
- print(sb)
+ layout(width).print(sb)
sb.toString
}
- def +++ (that: Text) =
+ def ~ (that: Text) =
if (this.isEmpty) that
else if (that.isEmpty) this
else Fluid(that :: this :: Nil)
+ def ~~ (that: Text) =
+ if (this.isEmpty) that
+ else if (that.isEmpty) this
+ else Fluid(that :: Str(" ") :: this :: Nil)
+
def over (that: Text) =
- if (this.isRigid) Rigid(that :: this.relems)
- else Rigid(that :: this :: Nil)
+ if (this.isVertical) Vertical(that :: this.relems)
+ else Vertical(that :: this :: Nil)
}
object Text {
- def apply(xs: Traversable[Text], sep: String): Text = {
+ def apply(): Text = Str("")
+ def apply(xs: Traversable[Text], sep: String = " "): Text = {
val ys = xs filterNot (_.isEmpty)
if (ys.isEmpty) Str("")
- else ys reduce (_ +++ sep +++ _)
+ else ys reduce (_ ~ sep ~ _)
}
- }
-
- abstract class CompoundText extends Text {
- def relems: List[Text]
+ def lines(xs: Traversable[Text]) = Vertical(xs.toList.reverse)
}
case class Str(s: String) extends Text {
override def relems: List[Text] = List(this)
}
- case class Rigid(relems: List[Text]) extends CompoundText
- case class Fluid(relems: List[Text]) extends CompoundText
+ case class Vertical(relems: List[Text]) extends Text
+ case class Fluid(relems: List[Text]) extends Text
+
+ class Closed(relems: List[Text]) extends Fluid(relems)
implicit def stringToText(s: String): Text = Str(s)
} \ No newline at end of file
diff --git a/src/test/showClass.scala b/src/test/showClass.scala
index e7e01ae84..a7896c733 100644
--- a/src/test/showClass.scala
+++ b/src/test/showClass.scala
@@ -11,15 +11,20 @@ object showClass {
println(s"showing $path")
val cls = ctx.requiredClass(path.toTypeName)
println(s"showing $path -> ${cls.denot}")
+ println((cls.toText ~ cls.info.toText).show)
+/*
val info = cls.info
info match {
case ClassInfo(pre, c, cps, decls, optSelfType) =>
println(s"prefix = ${pre.show}")
println(s"self = ${c.show}")
println(s"parents = ${cps.map(_.show).mkString(",")}")
+ println(s"showClass $path") // !!! DEBUG
println(s"decls = ${decls.show}")
println(s"selftype = ${optSelfType.show}")
+ println(s"type-params = ${info.typeParams}")
}
+*/
}
def main(args: Array[String]) = {
@@ -30,17 +35,18 @@ object showClass {
for (arg <- args) showClass(arg)
- showClass("java.lang.Class")
- showClass("scala.Boolean")
- showClass("scala.Array")
- showClass("scala.math.Ordering")
- showClass("scala.collection.Traversable")
- showClass("scala.collection.LinearSeqLike")
- showClass("scala.collection.immutable.List")
- showClass("scala.collection.TraversableLike")
- showClass("scala.collection.immutable.Seq")
- showClass("scala.collection.MapLike")
- //showClass("dotty.tools.dotc.core.Types")
+// showClass("java.lang.Class")
+// showClass("scala.Boolean")
+// showClass("scala.Array")
+// showClass("scala.math.Ordering")
+// showClass("scala.collection.Traversable")
+// showClass("scala.collection.LinearSeqLike")
+// showClass("scala.collection.immutable.List")
+ showClass("scala.collection.TraversableLike")
+// showClass("scala.collection.immutable.Seq")
+// showClass("scala.collection.MapLike")
+// showClass("scala.Function1")
+// showClass("dotty.tools.dotc.core.Types")
println("done")
}
} \ No newline at end of file