aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-05-17 13:28:02 +0200
committerMartin Odersky <odersky@gmail.com>2013-05-17 13:28:02 +0200
commit94b9a2a0d083cca2ba1358582d8d6fd8143b0b31 (patch)
treee84279f763b7a241bf18c27c7227d66618936719 /src/dotty/tools/dotc
parentd2261b37cf23ccd04e9029f3556c2dc9e2bdf077 (diff)
downloaddotty-94b9a2a0d083cca2ba1358582d8d6fd8143b0b31.tar.gz
dotty-94b9a2a0d083cca2ba1358582d8d6fd8143b0b31.tar.bz2
dotty-94b9a2a0d083cca2ba1358582d8d6fd8143b0b31.zip
Refactored Printing architecture.
Split printers into several files. Added refined printing of trees. Changed Showable and generalized printing under a precedence.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/Constants.scala3
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala7
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala3
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala3
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala5
-rw-r--r--src/dotty/tools/dotc/core/Names.scala6
-rw-r--r--src/dotty/tools/dotc/core/Scopes.scala3
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala3
-rw-r--r--src/dotty/tools/dotc/core/Trees.scala16
-rw-r--r--src/dotty/tools/dotc/core/Types.scala3
-rw-r--r--src/dotty/tools/dotc/core/UntypedTrees.scala2
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala5
-rw-r--r--src/dotty/tools/dotc/parsing/package.scala3
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala356
-rw-r--r--src/dotty/tools/dotc/printing/Printer.scala91
-rw-r--r--src/dotty/tools/dotc/printing/Printers.scala540
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala372
-rw-r--r--src/dotty/tools/dotc/printing/Showable.scala15
-rw-r--r--src/dotty/tools/dotc/printing/Texts.scala20
-rw-r--r--src/dotty/tools/dotc/printing/package.scala17
20 files changed, 906 insertions, 567 deletions
diff --git a/src/dotty/tools/dotc/core/Constants.scala b/src/dotty/tools/dotc/core/Constants.scala
index cdfb62a18..b2949aae7 100644
--- a/src/dotty/tools/dotc/core/Constants.scala
+++ b/src/dotty/tools/dotc/core/Constants.scala
@@ -2,6 +2,7 @@ package dotty.tools.dotc
package core
import Types._, Symbols._, Contexts._
+import printing.Printer
object Constants {
@@ -189,7 +190,7 @@ object Constants {
def stringValue: String = value.toString
- def toText(implicit ctx: Context) = ctx.toText(this)
+ def toText(printer: Printer) = printer.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 e6bd5a843..d29f8834d 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -8,13 +8,14 @@ import Names._
import Phases._
import Types._
import Symbols._
-import TypeComparers._, printing.Printers._, NameOps._, SymDenotations._, util.Positions._
+import TypeComparers._, NameOps._, SymDenotations._, util.Positions._
import TypedTrees.tpd._, util.FreshNameCreator
import config.Settings._
import config.ScalaSettings
import reporting._
import collection.mutable
import collection.immutable.BitSet
+import printing._
import config.{Settings, Platform, JavaPlatform}
import language.implicitConversions
@@ -43,7 +44,7 @@ object Contexts {
with Substituters
with TypeOps
with Phases
- with printing.Printers
+ with Printers
with Symbols
with SymDenotations
with Reporting
@@ -378,7 +379,7 @@ object Contexts {
object Context {
/** Implicit conversion that injects all printer operations into a context */
- implicit def toPrinter(ctx: Context) = ctx.printer(ctx)
+ implicit def toPrinter(ctx: Context) = ctx.printer
/** implicit conversion that injects all ContextBase members into a context */
implicit def toBase(ctx: Context): ContextBase = ctx.base
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index 2f91aa59a..5e2da43e5 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._, printing.Texts._
+import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer
/** This object provides useful implicit decorators for types defined elsewhere */
object Decorators {
@@ -14,6 +14,7 @@ object Decorators {
def toTermName: TermName = termName(s)
def toEncodedTypeName = encodedTypeName(s)
def toEncodedTermName = encodedTermName(s)
+ def toText(printer: Printer): Text = Str(s)
}
/** Implements a findSymbol method on iterators of Symbols that
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index e30e230b1..97b25be00 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -10,6 +10,7 @@ import Symbols.NoSymbol
import Symbols._
import Types._, Periods._, Flags._, Transformers._
import printing.Texts._
+import printing.Printer
import io.AbstractFile
import Decorators.SymbolIteratorDecorator
@@ -288,7 +289,7 @@ object Denotations {
}
}
- def toText(implicit ctx: Context): Text = ctx.toText(this)
+ def toText(printer: Printer): Text = printer.toText(this)
}
/** An overloaded denotation consisting of the alternatives of both given denotations.
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 726b13af9..f22c2a0f2 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -362,7 +362,7 @@ object Flags {
/** Flags representing source modifiers */
final val ModifierFlags =
commonFlags(Private, Protected, Abstract, Final,
- Sealed, Case, Implicit, AbsOverride, Lazy)
+ Sealed, Case, Implicit, Override, AbsOverride, Lazy)
/** Flags representing access rights */
final val AccessFlags = Private | Protected | Local
@@ -434,6 +434,9 @@ object Flags {
/** Labeled private[this] */
final val PrivateLocal = allOf(Private, Local)
+ /** A local parameter */
+ final val ParamAndLocal = allOf(Param, Local)
+
/** Labeled protected[this] */
final val ProtectedLocal = allOf(Protected, Local)
diff --git a/src/dotty/tools/dotc/core/Names.scala b/src/dotty/tools/dotc/core/Names.scala
index c7fedbc4c..e5535cff3 100644
--- a/src/dotty/tools/dotc/core/Names.scala
+++ b/src/dotty/tools/dotc/core/Names.scala
@@ -3,6 +3,8 @@ package core
import scala.io.Codec
import util.NameTransformer
+import printing.{Showable, Texts, Printer}
+import Texts.Text
import Decorators._
import Contexts.Context
import collection.IndexedSeqOptimized
@@ -17,7 +19,7 @@ object Names {
/** A common class for things that can be turned into names.
* Instances are both names and strings, the latter via a decorator.
*/
- trait PreName extends Any {
+ trait PreName extends Any with Showable {
def toTypeName: TypeName
def toTermName: TermName
}
@@ -90,7 +92,7 @@ object Names {
override def toString =
if (length == 0) "" else new String(chrs, start, length)
- def show(implicit ctx: Context): String = ctx.nameString(this)
+ def toText(printer: Printer): Text = printer.toText(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/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala
index 426d5a51a..82ec0a30a 100644
--- a/src/dotty/tools/dotc/core/Scopes.scala
+++ b/src/dotty/tools/dotc/core/Scopes.scala
@@ -13,6 +13,7 @@ import Decorators._
import Contexts._
import Denotations._
import printing.Texts._
+import printing.Printer
import SymDenotations.NoDenotation
object Scopes {
@@ -108,7 +109,7 @@ object Scopes {
syms
}
- final def toText(implicit ctx: Context): Text = ctx.toText(this)
+ final def toText(printer: Printer): Text = printer.toText(this)
}
/** A subclass of Scope that defines methods for entering and
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 7d9fa9d44..b6efdcd36 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -11,6 +11,7 @@ import Decorators._
import Symbols._
import Contexts._
import SymDenotations._, printing.Texts._
+import printing.Printer
import Types._, Annotations._, util.Positions._, StdNames._, Trees._, NameOps._
import Denotations.{ Denotation, SingleDenotation, MultiDenotation }
import collection.mutable
@@ -382,7 +383,7 @@ object Symbols {
if (lastDenot == null) s"Naked$prefixString#$id"
else lastDenot.toString +"#"+id // !!! DEBUG
- def toText(implicit ctx: Context): Text = ctx.toText(this)
+ def toText(printer: Printer): Text = printer.toText(this)
def showLocated(implicit ctx: Context): String = ctx.locatedText(this).show
def showDcl(implicit ctx: Context): Text = ctx.dclText(this).show
diff --git a/src/dotty/tools/dotc/core/Trees.scala b/src/dotty/tools/dotc/core/Trees.scala
index f99e72196..9ac738929 100644
--- a/src/dotty/tools/dotc/core/Trees.scala
+++ b/src/dotty/tools/dotc/core/Trees.scala
@@ -8,6 +8,7 @@ import language.higherKinds
import collection.mutable
import collection.mutable.ArrayBuffer
import parsing.Tokens.Token
+import printing.Printer
import util.Stats
object Trees {
@@ -212,7 +213,7 @@ object Trees {
def orElse(that: => Tree[T]): Tree[T] =
if (this eq theEmptyTree) that else this
- override def toText(implicit ctx: Context) = ctx.toText(this)
+ override def toText(printer: Printer) = printer.toText(this)
override def hashCode(): Int = System.identityHashCode(this)
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
@@ -429,7 +430,7 @@ object Trees {
}
/** try block catch handler finally finalizer */
- case class Try[T >: Untyped](block: Tree[T], handler: Tree[T], finalizer: Tree[T])
+ case class Try[T >: Untyped](expr: Tree[T], handler: Tree[T], finalizer: Tree[T])
extends TermTree[T] {
type ThisTree[T >: Untyped] = Try[T]
}
@@ -531,11 +532,6 @@ object Trees {
type ThisTree[T >: Untyped] = DefDef[T]
}
- class ImplicitDefDef[T >: Untyped](mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T]) extends DefDef[T](mods, name, tparams, vparamss, tpt, rhs) {
- override def copy[T >: Untyped](mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T]) =
- new ImplicitDefDef[T](mods, name, tparams, vparamss, tpt, rhs)
- }
-
/** mods type name = rhs or
* mods type name >: lo <: hi, if rhs = TypeBoundsTree(lo, hi)
*/
@@ -769,9 +765,9 @@ object Trees {
case tree: Return[_] if (expr eq tree.expr) && (from eq tree.from) => tree
case _ => Return(expr, from).copyAttr(tree)
}
- def derivedTry(block: Tree[T], handler: Tree[T], finalizer: Tree[T]): Try[T] = tree match {
- case tree: Try[_] if (block eq tree.block) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree
- case _ => Try(block, handler, finalizer).copyAttr(tree)
+ def derivedTry(expr: Tree[T], handler: Tree[T], finalizer: Tree[T]): Try[T] = tree match {
+ case tree: Try[_] if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree
+ case _ => Try(expr, handler, finalizer).copyAttr(tree)
}
def derivedThrow(expr: Tree[T]): Throw[T] = tree match {
case tree: Throw[_] if (expr eq tree.expr) => tree
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 46b718968..ea3c9ca59 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -17,6 +17,7 @@ import Denotations._
import Periods._
import TypedTrees.tpd._, TypedTrees.TreeMapper, printing.Texts._
import transform.Erasure
+import printing.Printer
import scala.util.hashing.{ MurmurHash3 => hashing }
import collection.mutable
@@ -735,7 +736,7 @@ object Types {
*/
def signature(implicit ctx: Context): Signature = NotAMethod
- def toText(implicit ctx: Context): Text = ctx.toText(this, printing.Printers.GlobalPrec)
+ def toText(printer: Printer): Text = printer.toText(this)
// ----- hashing ------------------------------------------------------
diff --git a/src/dotty/tools/dotc/core/UntypedTrees.scala b/src/dotty/tools/dotc/core/UntypedTrees.scala
index 6fa830a45..80aeba77e 100644
--- a/src/dotty/tools/dotc/core/UntypedTrees.scala
+++ b/src/dotty/tools/dotc/core/UntypedTrees.scala
@@ -23,7 +23,7 @@ object UntypedTrees {
/** (vparams) => body */
case class SymbolLit(str: String) extends Tree
- case class InterpolatedString(id: TermName, stringParts: List[Tree], elems: List[Tree]) extends Tree
+ case class InterpolatedString(id: TermName, strings: List[Literal], elems: List[Tree]) extends Tree
case class Function(args: List[Tree], body: Tree) extends Tree
case class InfixOp(left: Tree, op: Name, right: Tree) extends Tree
case class PostfixOp(tree: Tree, op: Name) extends Tree
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index 1c9ce4b8a..5083ccf52 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -11,6 +11,7 @@ import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, Name
import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._
import util.Positions._, TypedTrees.tpd._, TypedTrees.TreeOps
import printing.Texts._
+import printing.Printer
import io.AbstractFile
import scala.reflect.internal.pickling.PickleFormat._
import Decorators._
@@ -24,8 +25,8 @@ object UnPickler {
class BadSignature(msg: String) extends RuntimeException(msg)
case class TempPolyType(tparams: List[Symbol], tpe: Type) extends UncachedGroundType {
- override def toText(implicit ctx: Context): Text =
- "[" ~ ctx.dclsText(tparams, ", ") ~ "]" ~ tpe.show
+ override def fallbackToText(printer: Printer): Text =
+ "[" ~ printer.dclsText(tparams, ", ") ~ "]" ~ printer.toText(tpe)
}
/** Temporary type for classinfos, will be decomposed on completion of the class */
diff --git a/src/dotty/tools/dotc/parsing/package.scala b/src/dotty/tools/dotc/parsing/package.scala
index b829bd313..0f64f9e1f 100644
--- a/src/dotty/tools/dotc/parsing/package.scala
+++ b/src/dotty/tools/dotc/parsing/package.scala
@@ -27,6 +27,7 @@ package object parsing {
}
def minPrec = 0
- def maxPrec = 10
+ def minInfixPrec = 1
+ def maxPrec = 11
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
new file mode 100644
index 000000000..274f78bee
--- /dev/null
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -0,0 +1,356 @@
+package dotty.tools.dotc
+package printing
+
+import core._
+import Texts._, Trees._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._
+import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation
+import StdNames.nme
+import UntypedTrees.untpd
+import java.lang.Integer.toOctalString
+import scala.annotation.switch
+
+class PlainPrinter(_ctx: Context) extends Printer {
+ protected[this] implicit val ctx = _ctx
+
+ protected def maxToTextRecursions = 100
+
+ protected final def controlled(op: => Text): Text =
+ if (ctx.toTextRecursions < maxToTextRecursions)
+ try {
+ ctx.toTextRecursions += 1
+ op
+ } finally {
+ ctx.toTextRecursions -= 1
+ }
+ else {
+ recursionLimitExceeeded()
+ "..."
+ }
+
+ protected def recursionLimitExceeeded() = {
+ ctx.warning("Exceeded recursion depth attempting to print type.")
+ (new Throwable).printStackTrace
+ }
+
+ /** Render elements alternating with `sep` string */
+ protected def toText(elems: Traversable[Showable], sep: String) =
+ Text(elems map (_ toText this), sep)
+
+ /** Render element within highest precedence */
+ protected def toTextLocal(elem: Showable): Text =
+ atPrec(DotPrec) { elem.toText(this) }
+
+ /** Render element within lowest precedence */
+ protected def toTextGlobal(elem: Showable): Text =
+ atPrec(GlobalPrec) { elem.toText(this) }
+
+ protected def toTextLocal(elems: Traversable[Showable], sep: String) =
+ atPrec(DotPrec) { toText(elems, sep) }
+
+ protected def toTextGlobal(elems: Traversable[Showable], sep: String) =
+ atPrec(GlobalPrec) { toText(elems, sep) }
+
+ /** 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
+ * "package", etc. The kind string, if non-empty, will be phrased relative
+ * to the name of the owner.
+ */
+ protected def hasMeaninglessName(sym: Symbol) = (
+ (sym is Param) && sym.owner.isSetter // x$1
+ || sym.isClassConstructor // this
+ || (sym.name == nme.PACKAGE) // package
+ )
+
+ def nameString(name: Name): String = name.toString + {
+ if (ctx.settings.debugNames.value)
+ if (name.isLocalName) "/L"
+ else if (name.isTypeName) "/T"
+ else "/V"
+ else ""
+ }
+
+ def toText(name: Name): Text = Str(nameString(name))
+
+ /** String representation of a name used in a refinement
+ * In refined printing this undoes type parameter expansion
+ */
+ protected def refinementNameString(tp: RefinedType) = nameString(tp.refinedName)
+
+ /** String representation of a refinement */
+ protected def toTextRefinement(rt: RefinedType) =
+ (refinementNameString(rt) ~ toTextRHS(rt.refinedInfo)).close
+
+ /** The longest sequence of refinement types, starting at given type
+ * and following parents.
+ */
+ private def refinementChain(tp: Type): List[Type] =
+ tp :: (tp match {
+ case RefinedType(parent, _) => refinementChain(parent)
+ case _ => Nil
+ })
+
+ def toText(tp: Type): Text = controlled {
+ tp match {
+ case tp: TypeType =>
+ toTextRHS(tp)
+ case tp: SingletonType =>
+ val pre = toTextPrefix(tp)
+ if (pre.lastLine.endsWith(".")) pre ~ "type"
+ else fullNameString(tp.typeSymbol.skipPackageObject) ~ ".type"
+ case TypeRef(pre, name) =>
+ toTextPrefix(pre) ~ nameString(tp.typeSymbol)
+ case tp: RefinedType =>
+ // return tp.toString // !!! DEBUG
+ val parent :: (refined: List[RefinedType]) =
+ refinementChain(tp).reverse
+ toTextLocal(parent) ~ "{" ~ Text(refined map toTextRefinement, "; ").close ~ "}"
+ case AndType(tp1, tp2) =>
+ changePrec(AndPrec) { toText(tp1) ~ " & " ~ toText(tp2) }
+ case OrType(tp1, tp2) =>
+ changePrec(OrPrec) { toText(tp1) ~ " | " ~ toText(tp2) }
+ case ErrorType =>
+ "<error>"
+ case WildcardType =>
+ "?"
+ case NoType =>
+ "<notype>"
+ case NoPrefix =>
+ "<noprefix>"
+ case tp: MethodType =>
+ def paramText(name: TermName, tp: Type) = toText(name) ~ ": " ~ toText(tp)
+ changePrec(GlobalPrec) {
+ (if (tp.isImplicit) "(implicit " else "(") ~
+ Text((tp.paramNames, tp.paramTypes).zipped map paramText, ", ") ~
+ ")" ~ toText(tp.resultType)
+ }
+ case tp: ExprType =>
+ changePrec(GlobalPrec) { "=> " ~ toText(tp.resultType) }
+ case tp: PolyType =>
+ def paramText(name: TypeName, bounds: TypeBounds) = toText(polyParamName(name)) ~ ": " ~ toText(bounds)
+ changePrec(GlobalPrec) {
+ "[" ~
+ Text((tp.paramNames, tp.paramBounds).zipped map paramText, ", ") ~
+ "]" ~ toText(tp.resultType)
+ }
+ case PolyParam(pt, n) =>
+ toText(polyParamName(pt.paramNames(n)))
+ case AnnotatedType(annot, tpe) =>
+ toTextLocal(tpe) ~ " " ~ toText(annot)
+ case _ =>
+ tp.fallbackToText(this)
+ }
+ }.close
+
+ protected def polyParamName(name: TypeName): TypeName = name
+
+ /** The name of the symbol without a unique id. Under refined printing,
+ * the decoded original name.
+ */
+ protected def simpleNameString(sym: Symbol): String = nameString(sym.name)
+
+ /** The unique id of symbol, after a # */
+ protected def idString(sym: Symbol): String =
+ if (ctx.settings.uniqid.value) "#" + sym.id else ""
+
+ def nameString(sym: Symbol): String = simpleNameString(sym) + idString(sym)
+
+ def fullNameString(sym: Symbol): String =
+ if (sym.isRoot || sym == NoSymbol || sym.owner.isEffectiveRoot)
+ nameString(sym)
+ else
+ fullNameString(sym.effectiveOwner.enclosingClass) + "." + nameString(sym)
+
+ protected def objectPrefix = "object "
+ protected def packagePrefix = "package "
+
+ protected def trimPrefix(text: Text) =
+ text.stripPrefix(objectPrefix).stripPrefix(packagePrefix)
+
+ /** The string representation of this type used as a prefix */
+ protected def toTextPrefix(tp: Type): Text = controlled {
+ tp match {
+ case tp @ TermRef(pre, name) =>
+ toTextPrefix(pre) ~ nameString(tp.symbol) ~ "."
+ case ThisType(cls) =>
+ nameString(cls) + ".this."
+ case SuperType(thistpe, _) =>
+ toTextPrefix(thistpe).map(_.replaceAll("""\bthis\.$""", "super."))
+ case tp @ ConstantType(value) =>
+ toTextLocal(tp.underlying) ~ "(" ~ toText(value) ~ ")."
+ case MethodParam(mt, idx) =>
+ nameString(mt.paramNames(idx)) + "."
+ case RefinedThis(_) =>
+ "this."
+ case NoPrefix =>
+ ""
+ case _ =>
+ trimPrefix(toTextLocal(tp)) ~ "#"
+ }
+ }
+
+ protected def isOmittablePrefix(sym: Symbol) =
+ (defn.UnqualifiedOwners contains sym) || isEmptyPrefix(sym)
+
+ protected def isEmptyPrefix(sym: Symbol) =
+ sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName
+
+ /** String representation of a definition's type following its name */
+ protected def toTextRHS(tp: Type): Text = controlled {
+ tp match {
+ case TypeBounds(lo, hi) =>
+ if (lo eq hi)
+ " = " ~ toText(lo)
+ else
+ (if (lo == defn.NothingType) Text() else " >: " ~ toText(lo)) ~
+ (if (hi == defn.AnyType) Text() else " <: " ~ toText(hi))
+ case ClassInfo(pre, cls, cparents, decls, optSelfType) =>
+ val preText = toTextLocal(pre)
+ val (tparams, otherDecls) = decls.toList partition treatAsTypeParam
+ val tparamsText =
+ if (tparams.isEmpty) Text() else ("[" ~ dclsText(tparams) ~ "]").close
+ val selfText =
+ if (optSelfType.exists)
+ "this: " ~ atPrec(InfixPrec) { toText(optSelfType) } ~ " =>"
+ else Text()
+ val parentsText = Text(cparents.map(p =>
+ toTextLocal(reconstituteParent(cls, p))), " with ")
+ val trueDecls = otherDecls.filterNot(treatAsTypeArg)
+ val declsText = if (trueDecls.isEmpty) Text() else dclsText(trueDecls)
+ tparamsText ~ " extends " ~ parentsText ~ "{" ~ selfText ~ declsText ~
+ "} at " ~ preText
+ case _ =>
+ ": " ~ toTextGlobal(tp)
+ }
+ }
+
+ protected def treatAsTypeParam(sym: Symbol): Boolean = false
+ protected def treatAsTypeArg(sym: Symbol): Boolean = false
+ protected def reconstituteParent(cls: ClassSymbol, parent: Type): Type = parent
+
+ /** String representation of symbol's kind. */
+ def kindString(sym: Symbol): String = {
+ val flags = sym.flagsUNSAFE
+ if (flags is PackageClass) "package class"
+ else if (flags is PackageVal) "package"
+ else if (sym.isPackageObject)
+ if (sym.isClass) "package object class"
+ else "package object"
+ else if (sym.isAnonymousClass) "anonymous class"
+ else if (flags is ModuleClass) "module class"
+ else if (flags is ModuleVal) "module"
+ else if (flags is ImplClass) "implementation class"
+ else if (flags is Trait) "trait"
+ else if (sym.isClass) "class"
+ else if (sym.isType) "type"
+ else if (sym.isGetter) "getter"
+ else if (sym.isSetter) "setter"
+ else if (flags is Lazy) "lazy value"
+ else if (flags is Mutable) "variable"
+ else if (sym.isClassConstructor && sym.isPrimaryConstructor) "primary constructor"
+ else if (sym.isClassConstructor) "constructor"
+ else if (sym.isSourceMethod) "method"
+ else if (sym.isTerm) "value"
+ else ""
+ }
+
+ /** String representation of symbol's definition key word */
+ protected def keyString(sym: Symbol): String = {
+ val flags = sym.flagsUNSAFE
+ if (flags is JavaInterface) "interface"
+ else if ((flags is Trait) && !(flags is ImplClass)) "trait"
+ else if (sym.isClass) "class"
+ else if (sym.isType) "type"
+ else if (flags is Mutable) "var"
+ else if (flags is Package) "package"
+ else if (flags is Module) "object"
+ else if (sym.isSourceMethod) "def"
+ else if (sym.isTerm && (!(flags is Param))) "val"
+ else ""
+ }
+
+ /** String representation of symbol's flags */
+ protected def toTextFlags(sym: Symbol): Text =
+ Text(sym.flags.flagStrings map stringToText, " ")
+
+ /** String representation of symbol's variance or "" if not applicable */
+ protected def varianceString(sym: Symbol): String = sym.variance match {
+ case -1 => "-"
+ case 1 => "+"
+ case _ => ""
+ }
+
+ def dclText(sym: Symbol): Text =
+ (toTextFlags(sym) ~~ keyString(sym) ~~
+ (varianceString(sym) ~ nameString(sym)) ~ toTextRHS(sym.info)).close
+
+ def toText(sym: Symbol): Text =
+ (kindString(sym) ~~ {
+ if (hasMeaninglessName(sym)) simpleNameString(sym.owner) + idString(sym)
+ else nameString(sym)
+ }).close
+
+ def locationText(sym: Symbol): Text = {
+ val owns = sym.effectiveOwner
+ if (owns.isClass && !isEmptyPrefix(owns)) " in " ~ toText(owns) else Text()
+ }
+
+ def locatedText(sym: Symbol): Text =
+ (toText(sym) ~ locationText(sym)).close
+
+ def toText(denot: Denotation): Text = toText(denot.symbol) ~ "/D"
+
+ @switch private def escapedChar(ch: Char): String = ch match {
+ case '\b' => "\\b"
+ case '\t' => "\\t"
+ case '\n' => "\\n"
+ case '\f' => "\\f"
+ case '\r' => "\\r"
+ case '"' => "\\\""
+ case '\'' => "\\\'"
+ case '\\' => "\\\\"
+ case _ => if (ch.isControl) "\\0" + toOctalString(ch) else String.valueOf(ch)
+ }
+
+ def toText(const: Constant): Text = const.tag match {
+ case StringTag => "\"" + escapedString(const.value.toString) + "\""
+ case ClazzTag => "classOf[" ~ toText(const.tpe) ~ "]"
+ case CharTag => s"'${escapedChar(const.charValue)}'"
+ case LongTag => const.longValue.toString + "L"
+ case EnumTag => const.symbolValue.name.toString
+ case _ => String.valueOf(const.value)
+ }
+
+ def toText(annot: Annotation): Text = s"@${annot.symbol.name}" // for now
+
+ protected def escapedString(str: String): String = str flatMap escapedChar
+
+ def dclsText(syms: List[Symbol], sep: String): Text = Text(syms map dclText, sep)
+
+ def toText(sc: Scope): Text =
+ ("Scope{" ~ dclsText(sc.toList) ~ "}").close
+
+ def toText[T >: Untyped](tree: Tree[T]): Text = {
+ tree match {
+ case node: Positioned =>
+ def toTextElem(elem: Any): Text = elem match {
+ case elem: Showable => elem.toText(this)
+ case elem: List[_] => "List(" ~ Text(elem map toTextElem, ",") ~ ")"
+ 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)
+ " | " ~ toText(tree.tpe.asInstanceOf[Type])
+ else
+ Text()
+
+ nodeName ~ "(" ~ elems ~ tpSuffix ~ ")" ~ node.pos.toString
+ case _ =>
+ tree.fallbackToText(this)
+ }
+ }.close // todo: override in refined printer
+}
+
diff --git a/src/dotty/tools/dotc/printing/Printer.scala b/src/dotty/tools/dotc/printing/Printer.scala
new file mode 100644
index 000000000..9ba3141f8
--- /dev/null
+++ b/src/dotty/tools/dotc/printing/Printer.scala
@@ -0,0 +1,91 @@
+package dotty.tools.dotc
+package printing
+
+import core._
+import Texts._, Trees._
+import Types.Type, Symbols.Symbol, Contexts.Context, Scopes.Scope, Constants.Constant,
+ Names.Name, Denotations.Denotation, Annotations.Annotation
+
+/** The base class of all printers
+ */
+abstract class Printer {
+
+ private[this] var prec: Precedence = GlobalPrec
+
+ /** The current precedence level */
+ def currentPrecedence = prec
+
+ /** Generate text using `op`, assuming a given precedence level `prec`. */
+ def atPrec(prec: Precedence)(op: => Text): Text = {
+ val outerPrec = this.prec
+ this.prec = prec
+ try op
+ finally this.prec = outerPrec
+ }
+
+ /** Generate text using `op`, assuming a given precedence level `prec`.
+ * If new level `prec` is lower than previous level, put text in parentheses.
+ */
+ def changePrec(prec: Precedence)(op: => Text): Text =
+ if (prec < this.prec) atPrec(prec) ("(" ~ op ~ ")") else atPrec(prec)(op)
+
+ /** 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 nameString(name: Name): String
+
+ /** 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 nameString(sym: Symbol): String
+
+ /** The fully qualified name of the symbol */
+ def fullNameString(sym: Symbol): String
+
+ /** The kind of the symbol */
+ def kindString(sym: Symbol): String
+
+ /** The name as a text */
+ def toText(name: Name): Text
+
+ /** 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 toText(sym: Symbol): Text
+
+ /** Textual representation of symbol's declaration */
+ def dclText(sym: Symbol): Text
+
+ /** If symbol's owner is a printable class C, the text "in C", otherwise "" */
+ def locationText(sym: Symbol): Text
+
+ /** Textual representation of symbol and its location */
+ def locatedText(sym: Symbol): Text
+
+ /** Textual representation of denotation */
+ def toText(denot: Denotation): Text
+
+ /** Textual representation of constant */
+ def toText(const: Constant): Text
+
+ /** Textual representation of annotation */
+ def toText(annot: Annotation): Text
+
+ /** Textual representation of type */
+ def toText(tp: Type): Text
+
+ /** Textual representation of all symbols in given list,
+ * using `dclText` for displaying each.
+ */
+ def dclsText(syms: List[Symbol], sep: String = "\n"): Text
+
+ /** Textual representation of all definitions in a scope using `dclText` for each */
+ def toText(sc: Scope): Text
+
+ /** Textual representation of tree */
+ def toText[T >: Untyped](tree: Tree[T]): Text
+}
+
diff --git a/src/dotty/tools/dotc/printing/Printers.scala b/src/dotty/tools/dotc/printing/Printers.scala
index 59e89ee9d..ba1cf83bb 100644
--- a/src/dotty/tools/dotc/printing/Printers.scala
+++ b/src/dotty/tools/dotc/printing/Printers.scala
@@ -1,545 +1,15 @@
package dotty.tools.dotc
package printing
-import core._
-import Types._, Symbols._, Contexts._, Scopes._, Names._, NameOps._, Flags._
-import Constants._, Annotations._, StdNames._, Denotations._, SymDenotations._, Trees._
-import Texts._
-import java.lang.Integer.toOctalString
-import scala.annotation.switch
-import parsing.{precedence, minPrec, maxPrec}
+import core.Contexts.Context
trait Printers { this: Context =>
- import Printers._
+ /** A creation method for printers, depending on debug option */
+ def printerFn = if (this.debug) plainPrinter else refinedPrinter
- def printer = if (this.debug) plainPrinter else refinedPrinter
+ /** A function creatung a printer */
+ def printer = printerFn(this)
}
-object Printers {
-
- class Precedence(val value: Int) extends AnyVal {
- def parenthesize(nested: Precedence)(text: Text) =
- if (nested.value < value) "(" ~ text ~ ")" else text
- }
-
- val DotPrec = new Precedence(maxPrec)
- val AndPrec = new Precedence(precedence(nme.raw.AMP))
- val OrPrec = new Precedence(precedence(nme.raw.BAR))
- val WithPrec = new Precedence(precedence(nme.WITHkw))
- val LeftArrowPrec = WithPrec
- val GlobalPrec = new Precedence(minPrec)
-
- abstract class Printer {
-
- /** 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 nameString(name: Name): String
-
- /** 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 nameString(sym: Symbol): String
-
- /** The fully qualified name of the symbol */
- def fullNameString(sym: Symbol): String
-
- /** The kind of the symbol */
- def kindString(sym: Symbol): String
-
- /** 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 toText(sym: Symbol): Text
-
- /** Textual representation of symbol's declaration */
- def dclText(sym: Symbol): Text
-
- /** If symbol's owner is a printable class C, the text "in C", otherwise "" */
- def locationText(sym: Symbol): Text
-
- /** Textual representation of symbol and its location */
- def locatedText(sym: Symbol): Text
-
- /** Textual representation of denotation */
- def toText(denot: Denotation): Text
-
- /** Textual representation of constant */
- def toText(const: Constant): Text
-
- /** Textual representation of annotation */
- def toText(annot: Annotation): Text
-
- /** Textual representation of type in context with given precedence */
- def toText(tp: Type, precedence: Precedence): Text
-
- /** Textual representation of all symbols in given list,
- * using `dclText` for displaying each.
- */
- def dclsText(syms: List[Symbol], sep: String = "\n"): Text
-
- /** Textual representation of all definitions in a scope using `dclText` for each */
- def toText(sc: Scope): Text
-
- /** Textual representation of tree */
- def toText[T >: Untyped](tree: Tree[T]): Text
- }
-
- class PlainPrinter(_ctx: Context) extends Printer {
- protected[this] implicit val ctx = _ctx
-
- def controlled(op: => Text): Text =
- if (ctx.toTextRecursions < maxToTextRecursions)
- try {
- ctx.toTextRecursions += 1
- op
- } finally {
- ctx.toTextRecursions -= 1
- }
- else {
- recursionLimitExceeeded()
- "..."
- }
-
- protected def recursionLimitExceeeded() = {
- ctx.warning("Exceeded recursion depth attempting to print type.")
- (new Throwable).printStackTrace
- }
-
- /** 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
- * "package", etc. The kind string, if non-empty, will be phrased relative
- * to the name of the owner.
- */
- protected def hasMeaninglessName(sym: Symbol) = (
- (sym is Param) && sym.owner.isSetter // x$1
- || sym.isClassConstructor // this
- || (sym.name == nme.PACKAGE) // package
- )
-
- def nameString(name: Name): String = name.toString + {
- if (ctx.settings.debugNames.value)
- if (name.isLocalName) "/L"
- else if (name.isTypeName) "/T"
- else "/V"
- else ""
- }
-
- /** String representation of a name used in a refinement
- * In refined printing this undoes type parameter expansion
- */
- protected def refinementNameString(tp: RefinedType) = nameString(tp.refinedName)
-
- /** String representation of a refinement */
- protected def toTextRefinement(rt: RefinedType) =
- (refinementNameString(rt) ~ toTextRHS(rt.refinedInfo)).close
-
- /** The longest sequence of refinement types, starting at given type
- * and following parents.
- */
- private def refinementChain(tp: Type): List[Type] =
- tp :: (tp match {
- case RefinedType(parent, _) => refinementChain(parent)
- case _ => Nil
- })
-
- def toText(tp: Type, prec: Precedence): Text = controlled {
- tp match {
- case tp: TypeType =>
- toTextRHS(tp)
- case tp: SingletonType =>
- val pre = toTextPrefix(tp)
- if (pre.lastLine.endsWith(".")) pre ~ "type"
- else fullNameString(tp.typeSymbol.skipPackageObject) ~ ".type"
- case TypeRef(pre, name) =>
- toTextPrefix(pre) ~ nameString(tp.typeSymbol)
- case tp: RefinedType =>
- // return tp.toString // !!! DEBUG
- val parent :: (refined: List[RefinedType]) =
- refinementChain(tp).reverse
- toTextLocal(parent) ~ "{" ~
- Text(refined.map(toTextRefinement), "; ").close ~ "}"
- case AndType(tp1, tp2) =>
- (prec parenthesize AndPrec) {
- toText(tp1, AndPrec) ~ " & " ~ toText(tp2, AndPrec)
- }
- case OrType(tp1, tp2) =>
- (prec parenthesize OrPrec) {
- toText(tp1, OrPrec) ~ " | " ~ toText(tp2, OrPrec)
- }
- case ErrorType =>
- "<error>"
- case WildcardType =>
- "?"
- case NoType =>
- "<notype>"
- case NoPrefix =>
- "<noprefix>"
- case tp: MethodType =>
- (prec parenthesize GlobalPrec) {
- (if (tp.isImplicit) "(implicit " else "(") ~
- Text(
- (tp.paramNames, tp.paramTypes).zipped
- .map((name, tp) => nameString(name) ~ ": " ~ toTextGlobal(tp)),
- ", ") ~
- ")" ~ toTextGlobal(tp.resultType)
- }
- case tp: ExprType =>
- (prec parenthesize GlobalPrec) {
- "=> " ~ toTextGlobal(tp.resultType)
- }
- case tp: PolyType =>
- (prec parenthesize GlobalPrec) {
- "[" ~
- Text(
- (tp.paramNames, tp.paramBounds).zipped
- .map((name, bounds) =>
- nameString(polyParamName(name)) ~ toTextGlobal(bounds)),
- ", ") ~
- "]" ~ toTextGlobal(tp.resultType)
- }
- case PolyParam(pt, n) =>
- nameString(polyParamName(pt.paramNames(n)))
- case AnnotatedType(annot, tpe) =>
- toTextLocal(tpe) ~ " " ~ toText(annot)
- }
- }.close
-
- protected def polyParamName(name: TypeName): TypeName = name
-
- /** Render type within highest precedence */
- protected def toTextLocal(tp: Type) = toText(tp, DotPrec)
-
- /** Render type within lowest precedence */
- protected def toTextGlobal(tp: Type) = toText(tp, GlobalPrec)
-
- /** The name of the symbol without a unique id. Under refined printing,
- * the decoded original name.
- */
- protected def simpleNameString(sym: Symbol): String = nameString(sym.name)
-
- /** The unique id of symbol, after a # */
- protected def idString(sym: Symbol): String =
- if (ctx.settings.uniqid.value) "#" + sym.id else ""
-
- def nameString(sym: Symbol): String = simpleNameString(sym) + idString(sym)
-
- def fullNameString(sym: Symbol): String =
- if (sym.isRoot || sym == NoSymbol || sym.owner.isEffectiveRoot)
- nameString(sym)
- else
- fullNameString(sym.effectiveOwner.enclosingClass) + "." + nameString(sym)
-
- protected def objectPrefix = "object "
- protected def packagePrefix = "package "
-
- protected def trimPrefix(text: Text) =
- text.stripPrefix(objectPrefix).stripPrefix(packagePrefix)
-
- /** The string representation of this type used as a prefix */
- protected def toTextPrefix(tp: Type): Text = controlled {
- tp match {
- case tp @ TermRef(pre, name) =>
- toTextPrefix(pre) ~ nameString(tp.symbol) ~ "."
- case ThisType(cls) =>
- nameString(cls) + ".this."
- case SuperType(thistpe, _) =>
- toTextPrefix(thistpe).map(_.replaceAll("""\bthis\.$""", "super."))
- case tp @ ConstantType(value) =>
- toTextLocal(tp.underlying) ~ "(" ~ toText(value) ~ ")."
- case MethodParam(mt, idx) =>
- nameString(mt.paramNames(idx)) + "."
- case RefinedThis(_) =>
- "this."
- case NoPrefix =>
- ""
- case _ =>
- trimPrefix(toTextLocal(tp)) ~ "#"
- }
- }
-
- protected def isOmittablePrefix(sym: Symbol) =
- (defn.UnqualifiedOwners contains sym) || isEmptyPrefix(sym)
-
- protected def isEmptyPrefix(sym: Symbol) =
- sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName
-
- /** String representation of a definition's type following its name */
- protected def toTextRHS(tp: Type): Text = controlled {
- tp match {
- case TypeBounds(lo, hi) =>
- if (lo eq hi)
- " = " ~ lo.toText
- else
- (if (lo == defn.NothingType) Text() else " >: " ~ lo.toText) ~
- (if (hi == defn.AnyType) Text() else " <: " ~ hi.toText)
- case ClassInfo(pre, cls, cparents, decls, optSelfType) =>
- val preText = toTextLocal(pre)
- val (tparams, otherDecls) = decls.toList partition treatAsTypeParam
- val tparamsText =
- if (tparams.isEmpty) Text() else ("[" ~ dclsText(tparams) ~ "]").close
- val selfText =
- if (optSelfType.exists)
- "this: " ~ toText(optSelfType, LeftArrowPrec) ~ " =>"
- else Text()
- val parentsText = Text(cparents.map(p =>
- toText(reconstituteParent(cls, p), WithPrec)), " with ")
- val trueDecls = otherDecls.filterNot(treatAsTypeArg)
- val declsText = if (trueDecls.isEmpty) Text() else dclsText(trueDecls)
- tparamsText ~ " extends " ~ parentsText ~ "{" ~ selfText ~ declsText ~
- "} at " ~ preText
- case _ =>
- ": " ~ toTextGlobal(tp)
- }
- }
-
- protected def treatAsTypeParam(sym: Symbol): Boolean = false
- protected def treatAsTypeArg(sym: Symbol): Boolean = false
- protected def reconstituteParent(cls: ClassSymbol, parent: Type): Type = parent
-
- /** String representation of symbol's kind. */
- def kindString(sym: Symbol): String = {
- val flags = sym.flagsUNSAFE
- if (flags is PackageClass) "package class"
- else if (flags is PackageVal) "package"
- else if (sym.isPackageObject)
- if (sym.isClass) "package object class"
- else "package object"
- else if (sym.isAnonymousClass) "anonymous class"
- else if (flags is ModuleClass) "module class"
- else if (flags is ModuleVal) "module"
- else if (flags is ImplClass) "implementation class"
- else if (flags is Trait) "trait"
- else if (sym.isClass) "class"
- else if (sym.isType) "type"
- else if (sym.isGetter) "getter"
- else if (sym.isSetter) "setter"
- else if (flags is Lazy) "lazy value"
- else if (flags is Mutable) "variable"
- else if (sym.isClassConstructor && sym.isPrimaryConstructor) "primary constructor"
- else if (sym.isClassConstructor) "constructor"
- else if (sym.isSourceMethod) "method"
- else if (sym.isTerm) "value"
- else ""
- }
-
- /** String representation of symbol's definition key word */
- protected def keyString(sym: Symbol): String = {
- val flags = sym.flagsUNSAFE
- if (flags is JavaInterface) "interface"
- else if ((flags is Trait) && !(flags is ImplClass)) "trait"
- else if (sym.isClass) "class"
- else if (sym.isType) "type"
- else if (flags is Mutable) "var"
- else if (flags is Package) "package"
- else if (flags is Module) "object"
- else if (sym.isSourceMethod) "def"
- else if (sym.isTerm && (!(flags is Param))) "val"
- else ""
- }
-
- /** String representation of symbol's flags */
- protected def toTextFlags(sym: Symbol): Text =
- Text(sym.flags.flagStrings map stringToText, " ")
-
- /** String representation of symbol's variance or "" if not applicable */
- protected def varianceString(sym: Symbol): String = sym.variance match {
- case -1 => "-"
- case 1 => "+"
- case _ => ""
- }
-
- def dclText(sym: Symbol): Text =
- (toTextFlags(sym) ~~ keyString(sym) ~~
- (varianceString(sym) ~ nameString(sym)) ~ toTextRHS(sym.info)).close
-
- def toText(sym: Symbol): Text =
- (kindString(sym) ~~ {
- if (hasMeaninglessName(sym)) simpleNameString(sym.owner) + idString(sym)
- else nameString(sym)
- }).close
-
- def locationText(sym: Symbol): Text = {
- val owns = sym.effectiveOwner
- if (owns.isClass && !isEmptyPrefix(owns)) " in " ~ toText(owns) else Text()
- }
-
- def locatedText(sym: Symbol): Text =
- (toText(sym) ~ locationText(sym)).close
-
- def toText(denot: Denotation): Text = toText(denot.symbol) ~ "/D"
-
- @switch private def escapedChar(ch: Char): String = ch match {
- case '\b' => "\\b"
- case '\t' => "\\t"
- case '\n' => "\\n"
- case '\f' => "\\f"
- case '\r' => "\\r"
- case '"' => "\\\""
- case '\'' => "\\\'"
- case '\\' => "\\\\"
- case _ => if (ch.isControl) "\\0" + toOctalString(ch) else String.valueOf(ch)
- }
-
- def toText(const: Constant): Text = const.tag match {
- case StringTag => "\"" + (const.value.toString flatMap escapedChar) + "\""
- 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 toText(annot: Annotation): Text = s"@${annot.symbol.name}" // for now
-
- def dclsText(syms: List[Symbol], sep: String): Text =
- if (sep == "\n") Text.lines(syms map dclText)
- else Text(syms map dclText, sep)
-
- def toText(sc: Scope): Text =
- ("Scope{" ~ dclsText(sc.toList) ~ "}").close
-
- def toText[T >: Untyped](tree: Tree[T]): Text = {
- tree match {
- case node: Positioned =>
- def toTextElem(elem: Any): Text = elem match {
- case elem: Showable => elem.toText
- case elem: List[_] => "List(" ~ Text(elem map toTextElem, ",") ~ ")"
- 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 ~ ")" ~ node.pos.toString
- case _ =>
- tree.toString: Text
- }
- }.close // todo: override in refined printer
- }
-
- class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
- override protected def recursionLimitExceeeded() = {}
-
- override def nameString(name: Name): String = name.toString
-
- override protected def simpleNameString(sym: Symbol): String = {
- var name = sym.originalName
- if (sym is ModuleClass) name = name.stripModuleClassSuffix
- name.decode.toString
- }
-
- 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 fullNameString(cls) + "."
- case tp @ TermRef(pre, name) =>
- val sym = tp.symbol
- if (sym.isPackageObject) return toTextPrefix(pre)
- if (isOmittablePrefix(sym)) return ""
- case _ =>
- }
- super.toTextPrefix(tp)
- }
-
- override protected def refinementNameString(tp: RefinedType): String = {
- val tsym = tp.member(tp.refinedName).symbol
- val name = tsym.originalName
- nameString(if (tsym is ExpandedTypeParam) name.asTypeName.unexpandedName() else name)
- }
-
- override def toText(tp: Type, prec: Precedence): Text = controlled {
- def toTextFunction(args: List[Type]): Text =
- (prec parenthesize GlobalPrec) {
- val argStr: Text =
- if (args.length == 2 &&
- !(defn.TupleClasses contains args.head.typeSymbol)) toText(args.head, LeftArrowPrec)
- else
- "(" ~ Text(args.init.map(toTextGlobal(_)), ", ") ~ ")"
- argStr ~ " => " ~ toTextGlobal(args.last)
- }
- def toTextTuple(args: List[Type]): Text =
- "(" ~ Text(args.map(toTextGlobal(_)), ", ") ~ ")"
- tp match {
- case tp: RefinedType =>
- val args = tp.typeArgs
- if (args.nonEmpty) {
- val tycon = tp.unrefine
- val cls = tycon.typeSymbol
- if (cls.typeParams.length == args.length) {
- 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 (toTextLocal(tycon) ~ "[" ~
- Text(args.map(toTextGlobal(_)), ", ") ~ "]").close
- }
- case tp @ TypeRef(pre, name) =>
- if (tp.symbol is TypeParam) return nameString(tp.symbol)
- case _ =>
- }
- super.toText(tp, prec)
- }
-
- override def toText[T >: Untyped](tree: Tree[T]): Text = toText(tree, GlobalPrec)
-
- def toText[T >: Untyped](tree: Tree[T], prec: Precedence): Text = ???
-
- override protected def polyParamName(name: TypeName): TypeName =
- name.unexpandedName()
-
- override protected def treatAsTypeParam(sym: Symbol): Boolean = sym is TypeParam
-
- override protected def treatAsTypeArg(sym: Symbol) =
- sym.isType && (sym is ProtectedLocal) &&
- (sym.allOverriddenSymbols exists (_ is TypeParam))
-
- override protected def reconstituteParent(cls: ClassSymbol, parent: Type): Type =
- (parent /: parent.classSymbol.typeParams) { (parent, tparam) =>
- val targSym = cls.decls.lookup(tparam.name)
- if (targSym.exists) RefinedType(parent, targSym.name, targSym.info)
- else parent
- }
-
- override def kindString(sym: Symbol) = {
- val flags = sym.flagsUNSAFE
- if (flags is Package) "package"
- else if (sym.isPackageObject) "package object"
- else if (flags is Module) "object"
- else if (flags is ImplClass) "class"
- else if (sym.isClassConstructor) "constructor"
- else super.kindString(sym)
- }
-
- override protected def keyString(sym: Symbol): String = {
- val flags = sym.flagsUNSAFE
- if (sym.isType && (flags is ExpandedTypeParam)) ""
- else super.keyString(sym)
- }
-
- override def toTextFlags(sym: Symbol) = {
- var flags = sym.flags
- if (flags is TypeParam) flags = flags &~ Protected
- Text(flags.flagStrings.filterNot(_.startsWith("<")) map stringToText, " ")
- }
-
- override def toText(denot: Denotation): Text = toText(denot.symbol)
- }
-
- final val maxToTextRecursions = 100
-
-}
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
new file mode 100644
index 000000000..88cc33c40
--- /dev/null
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -0,0 +1,372 @@
+package dotty.tools.dotc
+package printing
+
+import core._
+import Texts._, Trees._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._
+import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation
+import StdNames.nme
+import UntypedTrees.untpd
+import scala.annotation.switch
+
+class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
+ override protected def recursionLimitExceeeded() = {}
+
+ /** The closest enclosing DefDef, TypeDef, or ClassDef node */
+ private var currentOwner: Tree[_ >: Untyped] = EmptyTree()
+
+ def atOwner(owner: Tree[_ >: Untyped])(op: => Text): Text = {
+ val saved = owner
+ currentOwner = owner
+ try op
+ finally { currentOwner = saved }
+ }
+
+ override def nameString(name: Name): String = name.toString
+
+ override protected def simpleNameString(sym: Symbol): String = {
+ var name = sym.originalName
+ if (sym is ModuleClass) name = name.stripModuleClassSuffix
+ name.decode.toString
+ }
+
+ 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 fullNameString(cls) + "."
+ case tp @ TermRef(pre, name) =>
+ val sym = tp.symbol
+ if (sym.isPackageObject) return toTextPrefix(pre)
+ if (isOmittablePrefix(sym)) return ""
+ case _ =>
+ }
+ super.toTextPrefix(tp)
+ }
+
+ override protected def refinementNameString(tp: RefinedType): String = {
+ val tsym = tp.member(tp.refinedName).symbol
+ val name = tsym.originalName
+ nameString(if (tsym is ExpandedTypeParam) name.asTypeName.unexpandedName() else name)
+ }
+
+ override def toText(tp: Type): Text = controlled {
+ def toTextTuple(args: List[Type]): Text =
+ "(" ~ toTextGlobal(args, ", ") ~ ")"
+ def toTextFunction(args: List[Type]): Text =
+ changePrec(GlobalPrec) {
+ val argStr: Text =
+ if (args.length == 2 && !(defn.TupleClasses contains args.head.typeSymbol))
+ atPrec(InfixPrec) { toText(args.head) }
+ else
+ toTextTuple(args.init)
+ argStr ~ " => " ~ toText(args.last)
+ }
+ tp match {
+ case tp: RefinedType =>
+ val args = tp.typeArgs
+ if (args.nonEmpty) {
+ val tycon = tp.unrefine
+ val cls = tycon.typeSymbol
+ if (cls.typeParams.length == args.length) {
+ if (cls == defn.RepeatedParamClass) return toTextLocal(args.head) ~ "*"
+ if (cls == defn.ByNameParamClass) return "=> " ~ toText(args.head)
+ if (defn.FunctionClasses contains cls) return toTextFunction(args)
+ if (defn.TupleClasses contains cls) return toTextTuple(args)
+ }
+ return (toTextLocal(tycon) ~ "[" ~ toTextGlobal(args, ", ") ~ "]").close
+ }
+ case tp @ TypeRef(pre, name) =>
+ if (tp.symbol is TypeParam) return nameString(tp.symbol)
+ case _ =>
+ }
+ super.toText(tp)
+ }
+
+ override def toText[T >: Untyped](tree: Tree[T]): Text = {
+
+ def optDotPrefix(name: Name) = optText(name)(_ ~ ".")
+
+ def tparamsText(params: List[Tree[T]]): Text =
+ "[" ~ toText(params, ", ") ~ "]" provided params.nonEmpty
+
+ def addVparamssText[T >: Untyped](txt: Text, vparamss: List[List[ValDef[T]]]): Text =
+ (txt /: vparamss)((txt, vparams) => txt ~ "(" ~ toText(vparams, ", ") ~ ")")
+
+ def blockText[T >: Untyped](trees: List[Tree[T]]): Text =
+ "{" ~ toText(trees, "\n") ~ "}"
+
+ def caseBlockText[T >: Untyped](tree: Tree[T]): Text = tree match {
+ case Block(stats, expr) => toText(stats :+ expr, "\n")
+ case expr => toText(expr)
+ }
+
+ def forText(enums: List[Tree[T]], expr: Tree[T], sep: String): Text =
+ changePrec(GlobalPrec) { "for " ~ toText(enums, "; ") ~ sep ~ toText(expr) }
+
+ val txt: Text = tree match {
+ case id: BackquotedIdent[_] =>
+ "`" ~ toText(id.name) ~ "`"
+ case Ident(name) =>
+ toText(name)
+ case Select(qual, name) =>
+ toTextLocal(qual) ~ "." ~ toText(name)
+ case This(name) =>
+ optDotPrefix(name) ~ "this"
+ case Super(This(name), mix) =>
+ optDotPrefix(name) ~ "super" ~ optText(mix)("[" ~ _ ~ "]")
+ case Apply(fun, args) =>
+ toTextLocal(fun) ~ "(" ~ toTextGlobal(args, ", ") ~ ")"
+ case TypeApply(fun, args) =>
+ toTextLocal(fun) ~ "[" ~ toTextGlobal(args, ", ") ~ "]"
+ case Literal(c) =>
+ toText(c)
+ case New(tpt) =>
+ "new " ~ toTextLocal(tpt)
+ case Pair(l, r) =>
+ "(" ~ toTextGlobal(l) ~ ", " ~ toTextGlobal(r) ~ ")"
+ case Typed(l, tpt) =>
+ changePrec(InfixPrec) { toText(l) ~ ": " ~ toText(tpt) }
+ case NamedArg(name, arg) =>
+ toText(name) ~ " = " ~ toText(arg)
+ case Assign(lhs, rhs) =>
+ changePrec(GlobalPrec) { toTextLocal(lhs) ~ " = " ~ toText(rhs) }
+ case Block(stats, expr) =>
+ blockText(stats :+ expr)
+ case If(cond, thenp, elsep) =>
+ changePrec(GlobalPrec) {
+ "if " ~ toText(cond) ~ (" then" provided !cond.isInstanceOf[untpd.Parens]) ~~ toText(thenp) ~ optText(elsep)(" else " ~ _)
+ }
+ case Match(sel, cases) =>
+ if (sel.isEmpty) blockText(cases)
+ else changePrec(GlobalPrec) { toText(sel) ~ " match " ~ blockText(cases) }
+ case CaseDef(pat, guard, body) =>
+ "case " ~ toText(pat) ~ optText(guard)("if " ~ _) ~ " => " ~ caseBlockText(body)
+ case Return(expr, from) =>
+ changePrec(GlobalPrec) { "return " ~ toText(expr) }
+ case Try(expr, handler, finalizer) =>
+ changePrec(GlobalPrec) {
+ "try " ~ toText(expr) ~ optText(handler)(" catch " ~ _) ~ optText(finalizer)(" finally " ~ _)
+ }
+ case Throw(expr) =>
+ changePrec(GlobalPrec) {
+ "throw " ~ toText(expr)
+ }
+ case SeqLiteral(elempt, elems) =>
+ "[" ~ toTextGlobal(elems, ",") ~ "]"
+ case TypeTree(orig) =>
+ if (tree.hasType) toText(tree.typeOpt) else toText(orig)
+ case SingletonTypeTree(ref) =>
+ toTextLocal(ref) ~ ".type"
+ case SelectFromTypeTree(qual, name) =>
+ toTextLocal(qual) ~ "#" ~ toText(name)
+ case AndTypeTree(l, r) =>
+ changePrec(AndPrec) { toText(l) ~ " & " ~ toText(r) }
+ case OrTypeTree(l, r) =>
+ changePrec(OrPrec) { toText(l) ~ " | " ~ toText(r) }
+ case RefinedTypeTree(tpt, refines) =>
+ toTextLocal(tpt) ~ " " ~ blockText(refines)
+ case AppliedTypeTree(tpt, args) =>
+ toTextLocal(tpt) ~ "(" ~ toTextGlobal(args, ", ") ~ ")"
+ case TypeBoundsTree(lo, hi) =>
+ optText(lo)(" >: " ~ _) ~ optText(hi)(" <: " ~ _)
+ case Bind(name, body) =>
+ changePrec(InfixPrec) { toText(name) ~ " @ " ~ toText(body) }
+ case Alternative(trees) =>
+ changePrec(OrPrec) { toText(trees, " | ") }
+ case UnApply(fun, args) =>
+ toTextLocal(fun) ~ "(" ~ toTextGlobal(args, ", ") ~ ")"
+ case ValDef(mods, name, tpt, rhs) =>
+ toText(mods, if (mods is Mutable) "var" else "val") ~~ toText(name) ~
+ optText(tpt)(": " ~ _) ~ optText(rhs)(" = " ~ _)
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ atOwner(tree) {
+ val first = toText(mods, "def") ~~ toText(name) ~ tparamsText(tparams)
+ addVparamssText(first, vparamss) ~ optText(tpt)(": " ~ _) ~ optText(rhs)(" = " ~ _)
+ }
+ case TypeDef(mods, name, tparams, rhs) =>
+ atOwner(tree) {
+ val rhsText = rhs match {
+ case TypeBoundsTree(_, _) => toText(rhs)
+ case _ => optText(rhs)(" = " ~ _)
+ }
+ toText(mods, "type") ~~ toText(name) ~ tparamsText(tparams) ~ rhsText
+ }
+ case Template(DefDef(mods, _, _, vparamss, _, _), parents, self, stats) =>
+ val prefix: Text =
+ if (vparamss.isEmpty) ""
+ else {
+ var modsText = toText(mods, "")
+ if (mods.hasAnnotations && !mods.hasFlags) modsText = modsText ~~ " this"
+ addVparamssText(modsText, vparamss) ~ " extends"
+ }
+ val parentsText = toTextLocal(parents, "with")
+ val selfText = optText(self)(" " ~ _ ~ " => ")
+ val bodyText: Text = stats match {
+ case Nil =>
+ assert(self.isEmpty)
+ ""
+ case EmptyTree() :: Nil =>
+ "{" ~ selfText ~ "}"
+ case stats =>
+ "{" ~ selfText ~ toTextGlobal(stats, "\n") ~ "}"
+ }
+ prefix ~~ parentsText ~~ bodyText
+ case ClassDef(mods, name, tparams, impl) =>
+ atOwner(tree) {
+ toText(mods, if (mods is Trait) "trait" else "class") ~~
+ toText(name) ~ tparamsText(tparams) ~ toText(impl)
+ }
+ case Import(expr, selectors) =>
+ def selectorText(sel: UntypedTree): Text = sel match {
+ case Pair(l, r) => toTextGlobal(l) ~ " => " ~ toTextGlobal(r)
+ case _ => toTextGlobal(sel)
+ }
+ val selectorsText: Text = selectors match {
+ case Ident(name) :: Nil => toText(name)
+ case _ => "{" ~ Text(selectors map selectorText, ", ") ~ "}"
+ }
+ "import " ~ toTextLocal(expr) ~ "." ~ selectorsText
+ case PackageDef(pid, stats) =>
+ val statsText = stats match {
+ case (pdef: PackageDef[_]) :: Nil => toText(pdef)
+ case _ => toTextGlobal(stats, "\n")
+ }
+ val bodyText =
+ if (currentPrecedence == TopLevelPrec) "\n" ~ statsText else " {" ~ statsText ~ "}"
+ "package " ~ toTextLocal(pid) ~ bodyText
+ case Annotated(annot, arg) =>
+ toTextLocal(arg) ~ " @" ~ toTextLocal(annot)
+ case EmptyTree() =>
+ "<empty>"
+ case SharedTree(shared) =>
+ toText(shared)
+ case untpd.TypedSplice(t) =>
+ toText(t)
+ case untpd.ModuleDef(mods, name, impl) =>
+ toText(mods, "object") ~~ toText(name) ~ " extends " ~ toText(impl)
+ case untpd.SymbolLit(str) =>
+ "'" + str
+ case untpd.InterpolatedString(id, strings, elems) =>
+ def interleave(strs: List[Text], elems: List[Text]): Text = ((strs, elems): @unchecked) match {
+ case (Nil, Nil) => ""
+ case (str :: Nil, Nil) => str
+ case (str :: strs1, elem :: elems1) => str ~ elem ~ interleave(strs1, elems1)
+ }
+ val strTexts = strings map (str => Str(escapedString(str.const.stringValue)))
+ val elemsTexts = elems map (elem => "{" ~ toTextGlobal(elem) ~ "}")
+ toText(id) ~ "\"" ~ interleave(strTexts, elemsTexts) ~ "\""
+ case untpd.Function(args, body) =>
+ var implicitSeen: Boolean = false
+ def argToText(arg: untpd.Tree) = arg match {
+ case ValDef(mods, name, tpt, _) =>
+ val implicitText =
+ if ((mods is Implicit) && !implicitSeen) { implicitSeen = true; "implicit " }
+ else ""
+ implicitText ~ toText(name) ~ optText(tpt)(": " ~ _)
+ case _ =>
+ toText(arg)
+ }
+ val argsText = args match {
+ case (arg @ ValDef(_, _, tpt, _)) :: Nil if tpt.isEmpty => argToText(arg)
+ case _ => "(" ~ Text(args map argToText, ", ") ~ ")"
+ }
+ changePrec(GlobalPrec) {
+ argsText ~ " => " ~ toText(body)
+ }
+ case untpd.InfixOp(l, op, r) =>
+ val opPrec = parsing.precedence(op)
+ changePrec(opPrec) { toText(l) ~ " " ~ toText(op) ~ " " ~ toText(r) }
+ case untpd.PostfixOp(l, op) =>
+ changePrec(InfixPrec) { toText(l) ~ " " ~ toText(op) }
+ case untpd.PrefixOp(op, r) =>
+ changePrec(DotPrec) { toText(op) ~ " " ~ toText(r) }
+ case untpd.Parens(t) =>
+ "(" ~ toTextGlobal(t) ~ ")"
+ case untpd.Tuple(ts) =>
+ "(" ~ toTextGlobal(ts, ", ") ~ ")"
+ case untpd.WhileDo(cond, body) =>
+ changePrec(GlobalPrec) { "while " ~ toText(cond) ~ " do " ~ toText(body) }
+ case untpd.DoWhile(cond, body) =>
+ changePrec(GlobalPrec) { "do " ~ toText(body) ~ " while " ~ toText(cond) }
+ case untpd.ForYield(enums, expr) =>
+ forText(enums, expr, " yield ")
+ case untpd.ForDo(enums, expr) =>
+ forText(enums, expr, " do ")
+ case untpd.GenFrom(pat, expr) =>
+ toText(pat) ~ " <- " ~ toText(expr)
+ case untpd.GenAlias(pat, expr) =>
+ toText(pat) ~ " = " ~ toText(expr)
+ case untpd.ContextBounds(bounds, cxBounds) =>
+ (toText(bounds) /: cxBounds) {(t, cxb) =>
+ t ~ " : " ~ toText(cxb)
+ }
+ case untpd.PatDef(mods, pats, tpt, rhs) =>
+ toText(mods, "val") ~~ toText(pats, ", ") ~ optText(tpt)(": " ~ _) ~
+ optText(rhs)(" = " ~ _)
+ case _ =>
+ tree.fallbackToText(this)
+ }
+ tree match {
+ case Block(_, _) | Template(_, _, _, _) => txt
+ case _ => txt.close
+ }
+ }
+
+ def optText(name: Name)(encl: Text => Text): Text =
+ if (name.isEmpty) "" else encl(toText(name))
+
+ def optText[T >: Untyped](tree: Tree[T])(encl: Text => Text): Text =
+ if (tree.isEmpty) "" else encl(toText(tree))
+
+ def toText[T >: Untyped](mods: Modifiers[T], kw: String): Text = {
+ def annotText(annot: Tree[T]) = "@" ~ toTextLocal(annot)
+ def suppressKw = currentOwner match {
+ case _: ClassDef[_] => mods is ParamAndLocal
+ case _ => mods is Param
+ }
+ val flagMask = if (suppressKw) ModifierFlags &~ Private else ModifierFlags
+ val modsText: Text = (mods.flags & flagMask).toString
+ Text(mods.annotations.map(annotText), " ") ~~ modsText ~~ (kw provided !suppressKw)
+ }
+
+ override protected def polyParamName(name: TypeName): TypeName =
+ name.unexpandedName()
+
+ override protected def treatAsTypeParam(sym: Symbol): Boolean = sym is TypeParam
+
+ override protected def treatAsTypeArg(sym: Symbol) =
+ sym.isType && (sym is ProtectedLocal) &&
+ (sym.allOverriddenSymbols exists (_ is TypeParam))
+
+ override protected def reconstituteParent(cls: ClassSymbol, parent: Type): Type =
+ (parent /: parent.classSymbol.typeParams) { (parent, tparam) =>
+ val targSym = cls.decls.lookup(tparam.name)
+ if (targSym.exists) RefinedType(parent, targSym.name, targSym.info)
+ else parent
+ }
+
+ override def kindString(sym: Symbol) = {
+ val flags = sym.flagsUNSAFE
+ if (flags is Package) "package"
+ else if (sym.isPackageObject) "package object"
+ else if (flags is Module) "object"
+ else if (flags is ImplClass) "class"
+ else if (sym.isClassConstructor) "constructor"
+ else super.kindString(sym)
+ }
+
+ override protected def keyString(sym: Symbol): String = {
+ val flags = sym.flagsUNSAFE
+ if (sym.isType && (flags is ExpandedTypeParam)) ""
+ else super.keyString(sym)
+ }
+
+ override def toTextFlags(sym: Symbol) = {
+ var flags = sym.flags
+ if (flags is TypeParam) flags = flags &~ Protected
+ Text(flags.flagStrings.filterNot(_.startsWith("<")) map stringToText, " ")
+ }
+
+ override def toText(denot: Denotation): Text = toText(denot.symbol)
+}
diff --git a/src/dotty/tools/dotc/printing/Showable.scala b/src/dotty/tools/dotc/printing/Showable.scala
index 73d320019..cb65193e6 100644
--- a/src/dotty/tools/dotc/printing/Showable.scala
+++ b/src/dotty/tools/dotc/printing/Showable.scala
@@ -5,10 +5,19 @@ import core._
import Contexts._, Texts._, Decorators._
-trait Showable {
+trait Showable extends Any {
- def toText(implicit ctx: Context): Text
+ /** The text representation of this showable element.
+ * This normally dispatches to a pattern matching
+ * method in Printers.
+ */
+ def toText(printer: Printer): Text
- def show(implicit ctx: Context): String = toText.show
+ /** A fallback text representation, if the pattern matching
+ * in Printers does not have a case for this showable element
+ */
+ def fallbackToText(printer: Printer): Text = toString
+ /** The string representation of this showable element. */
+ def show(implicit ctx: Context): String = toText(ctx.printer).show
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/printing/Texts.scala b/src/dotty/tools/dotc/printing/Texts.scala
index 2ff4edc9a..8c214f5f0 100644
--- a/src/dotty/tools/dotc/printing/Texts.scala
+++ b/src/dotty/tools/dotc/printing/Texts.scala
@@ -1,5 +1,6 @@
package dotty.tools.dotc
package printing
+import core.Contexts.Context
object Texts {
@@ -128,15 +129,28 @@ object Texts {
def over (that: Text) =
if (this.isVertical) Vertical(that :: this.relems)
else Vertical(that :: this :: Nil)
+
+ def provided(pred: => Boolean) = if (pred) this else Str("")
}
object Text {
+
+ /** The empty text */
def apply(): Text = Str("")
+
+ /** A concatenation of elements in `xs` and interspersed with
+ * separator strings `sep`.
+ */
def apply(xs: Traversable[Text], sep: String = " "): Text = {
- val ys = xs filterNot (_.isEmpty)
- if (ys.isEmpty) Str("")
- else ys reduce (_ ~ sep ~ _)
+ if (sep == "\n") lines(xs)
+ else {
+ val ys = xs filterNot (_.isEmpty)
+ if (ys.isEmpty) Str("")
+ else ys reduce (_ ~ sep ~ _)
+ }
}
+
+ /** The given texts `xs`, each on a separate line */
def lines(xs: Traversable[Text]) = Vertical(xs.toList.reverse)
}
diff --git a/src/dotty/tools/dotc/printing/package.scala b/src/dotty/tools/dotc/printing/package.scala
new file mode 100644
index 000000000..814eb2ad0
--- /dev/null
+++ b/src/dotty/tools/dotc/printing/package.scala
@@ -0,0 +1,17 @@
+package dotty.tools.dotc
+
+import core.StdNames.nme
+import parsing.{precedence, minPrec, maxPrec, minInfixPrec}
+
+package object printing {
+
+ type Precedence = Int
+
+ val DotPrec = parsing.maxPrec
+ val AndPrec = parsing.precedence(nme.raw.AMP)
+ val OrPrec = parsing.precedence(nme.raw.BAR)
+ val InfixPrec = parsing.minInfixPrec
+ val GlobalPrec = parsing.minPrec
+ val TopLevelPrec = parsing.minPrec - 1
+
+}