diff options
Diffstat (limited to 'src/dotty/tools/dotc/printing/PlainPrinter.scala')
-rw-r--r-- | src/dotty/tools/dotc/printing/PlainPrinter.scala | 500 |
1 files changed, 0 insertions, 500 deletions
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala deleted file mode 100644 index 15c382bb0..000000000 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ /dev/null @@ -1,500 +0,0 @@ -package dotty.tools.dotc -package printing - -import core._ -import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._, Denotations._ -import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation -import StdNames.{nme, tpnme} -import ast.Trees._, ast._ -import config.Config -import java.lang.Integer.toOctalString -import config.Config.summarizeDepth -import scala.annotation.switch - -class PlainPrinter(_ctx: Context) extends Printer { - protected[this] implicit def ctx: Context = _ctx.addMode(Mode.Printing) - - private var openRecs: List[RecType] = Nil - - protected def maxToTextRecursions = 100 - - protected final def controlled(op: => Text): Text = - if (ctx.toTextRecursions < maxToTextRecursions && ctx.toTextRecursions < maxSummarized) - try { - ctx.toTextRecursions += 1 - op - } finally { - ctx.toTextRecursions -= 1 - } - else { - if (ctx.toTextRecursions >= maxToTextRecursions) - recursionLimitExceeded() - "..." - } - - protected def recursionLimitExceeded() = { - ctx.warning("Exceeded recursion depth attempting to print.") - if (ctx.debug) Thread.dumpStack() - } - - /** If true, tweak output so it is the same before and after pickling */ - protected def homogenizedView: Boolean = ctx.settings.YtestPickler.value - - def homogenize(tp: Type): Type = - if (homogenizedView) - tp match { - case tp: ThisType if tp.cls.is(Package) && !tp.cls.isEffectiveRoot => - ctx.requiredPackage(tp.cls.fullName).termRef - case tp: TypeVar if tp.isInstantiated => - homogenize(tp.instanceOpt) - case AndType(tp1, tp2) => - homogenize(tp1) & homogenize(tp2) - case OrType(tp1, tp2) => - homogenize(tp1) | homogenize(tp2) - case tp: SkolemType => - homogenize(tp.info) - case tp: LazyRef => - homogenize(tp.ref) - case HKApply(tycon, args) => - tycon.dealias.appliedTo(args) - case _ => - tp - } - else tp - - private def selfRecName(n: Int) = s"z$n" - - /** 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.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 - - protected def argText(arg: Type): Text = arg match { - case arg: TypeBounds => "_" ~ toTextGlobal(arg) - case _ => toTextGlobal(arg) - } - - /** The longest sequence of refinement types, starting at given type - * and following parents. - */ - private def refinementChain(tp: Type): List[Type] = - tp :: (tp match { - case tp: RefinedType => refinementChain(tp.parent.stripTypeVar) - case _ => Nil - }) - - def toText(tp: Type): Text = controlled { - homogenize(tp) match { - case tp: TypeType => - toTextRHS(tp) - case tp: TermRef - if !tp.denotationIsCurrent && !homogenizedView || // always print underyling when testing picklers - tp.symbol.is(Module) || - tp.symbol.name.isImportName => - toTextRef(tp) ~ ".type" - case tp: TermRef if tp.denot.isOverloaded => - "<overloaded " ~ toTextRef(tp) ~ ">" - case tp: SingletonType => - toTextLocal(tp.underlying) ~ "(" ~ toTextRef(tp) ~ ")" - case tp: TypeRef => - toTextPrefix(tp.prefix) ~ selectionString(tp) - case tp: RefinedType => - val parent :: (refined: List[RefinedType @unchecked]) = - refinementChain(tp).reverse - toTextLocal(parent) ~ "{" ~ Text(refined map toTextRefinement, "; ").close ~ "}" - case tp: RecType => - try { - openRecs = tp :: openRecs - "{" ~ selfRecName(openRecs.length) ~ " => " ~ toTextGlobal(tp.parent) ~ "}" - } - finally openRecs = openRecs.tail - case AndType(tp1, tp2) => - changePrec(AndPrec) { toText(tp1) ~ " & " ~ toText(tp2) } - case OrType(tp1, tp2) => - changePrec(OrPrec) { toText(tp1) ~ " | " ~ toText(tp2) } - case ErrorType => - "<error>" - case tp: WildcardType => - if (tp.optBounds.exists) "(?" ~ toTextRHS(tp.bounds) ~ ")" else "?" - 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(variance: Int, name: Name, bounds: TypeBounds): Text = - varianceString(variance) ~ name.toString ~ toText(bounds) - changePrec(GlobalPrec) { - "[" ~ Text((tp.variances, tp.paramNames, tp.paramBounds).zipped.map(paramText), ", ") ~ - "] => " ~ toTextGlobal(tp.resultType) - } - case tp: PolyParam => - polyParamNameString(tp) ~ polyHash(tp.binder) - case AnnotatedType(tpe, annot) => - toTextLocal(tpe) ~ " " ~ toText(annot) - case HKApply(tycon, args) => - toTextLocal(tycon) ~ "[" ~ Text(args.map(argText), ", ") ~ "]" - case tp: TypeVar => - if (tp.isInstantiated) - toTextLocal(tp.instanceOpt) ~ "^" // debug for now, so that we can see where the TypeVars are. - else { - val constr = ctx.typerState.constraint - val bounds = - if (constr.contains(tp)) constr.fullBounds(tp.origin)(ctx.addMode(Mode.Printing)) - else TypeBounds.empty - if (ctx.settings.YshowVarBounds.value) "(" ~ toText(tp.origin) ~ "?" ~ toText(bounds) ~ ")" - else toText(tp.origin) - } - case tp: LazyRef => - "LazyRef(" ~ toTextGlobal(tp.ref) ~ ")" // TODO: only print this during debug mode? - case _ => - tp.fallbackToText(this) - } - }.close - - protected def polyParamNameString(name: TypeName): String = name.toString - - protected def polyParamNameString(param: PolyParam): String = polyParamNameString(param.binder.paramNames(param.paramNum)) - - /** 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) - - /** If -uniqid is set, the hashcode of the polytype, after a # */ - protected def polyHash(pt: PolyType): Text = - if (ctx.settings.uniqid.value) "#" + pt.hashCode else "" - - /** If -uniqid is set, 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) // + "<" + (if (sym.exists) sym.owner else "") + ">" - - def fullNameString(sym: Symbol): String = - if (sym.isRoot || sym == NoSymbol || sym.owner.isEffectiveRoot) - nameString(sym) - else - fullNameString(fullNameOwner(sym)) + "." + nameString(sym) - - protected def fullNameOwner(sym: Symbol): Symbol = sym.effectiveOwner.enclosingClass - - protected def objectPrefix = "object " - protected def packagePrefix = "package " - - protected def trimPrefix(text: Text) = - text.stripPrefix(objectPrefix).stripPrefix(packagePrefix) - - protected def selectionString(tp: NamedType) = { - val sym = if (homogenizedView) tp.symbol else tp.currentSymbol - if (sym.exists) nameString(sym) else nameString(tp.name) - } - - /** The string representation of this type used as a prefix */ - protected def toTextRef(tp: SingletonType): Text = controlled { - tp match { - case tp: TermRef => - toTextPrefix(tp.prefix) ~ selectionString(tp) - case tp: ThisType => - nameString(tp.cls) + ".this" - case SuperType(thistpe: SingletonType, _) => - toTextRef(thistpe).map(_.replaceAll("""\bthis$""", "super")) - case SuperType(thistpe, _) => - "Super(" ~ toTextGlobal(thistpe) ~ ")" - case tp @ ConstantType(value) => - toText(value) - case MethodParam(mt, idx) => - nameString(mt.paramNames(idx)) - case tp: RecThis => - val idx = openRecs.reverse.indexOf(tp.binder) - if (idx >= 0) selfRecName(idx + 1) - else "{...}.this" // TODO move underlying type to an addendum, e.g. ... z3 ... where z3: ... - case tp: SkolemType => - if (homogenizedView) toText(tp.info) else tp.repr - } - } - - /** The string representation of this type used as a prefix */ - protected def toTextPrefix(tp: Type): Text = controlled { - homogenize(tp) match { - case NoPrefix => "" - case tp: SingletonType => toTextRef(tp) ~ "." - case tp => trimPrefix(toTextLocal(tp)) ~ "#" - } - } - - protected def isOmittablePrefix(sym: Symbol): Boolean = - defn.UnqualifiedOwnerTypes.exists(_.symbol == sym) || isEmptyPrefix(sym) - - protected def isEmptyPrefix(sym: Symbol): Boolean = - sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName - - /** String representation of a definition's type following its name, - * if symbol is completed, "?" otherwise. - */ - protected def toTextRHS(optType: Option[Type]): Text = optType match { - case Some(tp) => toTextRHS(tp) - case None => "?" - } - - /** String representation of a definition's type following its name */ - protected def toTextRHS(tp: Type): Text = controlled { - homogenize(tp) match { - case tp @ TypeBounds(lo, hi) => - if (lo eq hi) { - val eql = - if (tp.variance == 1) " =+ " - else if (tp.variance == -1) " =- " - else " = " - eql ~ toText(lo) - } - else - (if (lo isRef defn.NothingClass) Text() else " >: " ~ toText(lo)) ~ - (if (hi isRef defn.AnyClass) Text() else " <: " ~ toText(hi)) - case tp @ ClassInfo(pre, cls, cparents, decls, selfInfo) => - val preText = toTextLocal(pre) - val (tparams, otherDecls) = decls.toList partition treatAsTypeParam - val tparamsText = - if (tparams.isEmpty) Text() else ("[" ~ dclsText(tparams) ~ "]").close - val selfText: Text = selfInfo match { - case NoType => Text() - case sym: Symbol if !sym.isCompleted => "this: ? =>" - case _ => "this: " ~ atPrec(InfixPrec) { toText(tp.selfType) } ~ " =>" - } - val trueDecls = otherDecls.filterNot(treatAsTypeArg) - val declsText = - if (trueDecls.isEmpty || !ctx.settings.debug.value) Text() - else dclsText(trueDecls) - tparamsText ~ " extends " ~ toTextParents(tp.parents) ~ "{" ~ selfText ~ declsText ~ - "} at " ~ preText - case tp => - ": " ~ toTextGlobal(tp) - } - } - - protected def toTextParents(parents: List[Type]): Text = Text(parents.map(toTextLocal), " with ") - - protected def treatAsTypeParam(sym: Symbol): Boolean = false - protected def treatAsTypeArg(sym: Symbol): Boolean = false - - /** 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.is(Method)) "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 JavaTrait) "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 is Method) "def" - else if (sym.isTerm && (!(flags is Param))) "val" - else "" - } - - /** String representation of symbol's flags */ - protected def toTextFlags(sym: Symbol): Text = - Text(sym.flagsUNSAFE.flagStrings map stringToText, " ") - - /** String representation of symbol's variance or "" if not applicable */ - protected def varianceString(sym: Symbol): String = varianceString(sym.variance) - - protected def varianceString(v: Int): String = v match { - case -1 => "-" - case 1 => "+" - case _ => "" - } - - def annotsText(sym: Symbol): Text = Text(sym.annotations.map(toText)) - - def dclText(sym: Symbol): Text = dclTextWithInfo(sym, sym.unforcedInfo) - - def dclText(d: SingleDenotation): Text = dclTextWithInfo(d.symbol, Some(d.info)) - - private def dclTextWithInfo(sym: Symbol, info: Option[Type]): Text = - (toTextFlags(sym) ~~ keyString(sym) ~~ - (varianceString(sym) ~ nameString(sym)) ~ toTextRHS(info)).close - - def toText(sym: Symbol): Text = - (kindString(sym) ~~ { - if (sym.isAnonymousClass) toText(sym.info.parents, " with ") ~ "{...}" - else if (hasMeaninglessName(sym)) simpleNameString(sym.owner) + idString(sym) - else nameString(sym) - }).close - - def locationText(sym: Symbol): Text = - if (!sym.exists) "" - else { - val ownr = sym.effectiveOwner - if (ownr.isClass && !isEmptyPrefix(ownr)) " in " ~ toText(ownr) else Text() - } - - def locatedText(sym: Symbol): Text = - (toText(sym) ~ locationText(sym)).close - - def extendedLocationText(sym: Symbol): Text = - if (!sym.exists) "" - else { - def recur(ownr: Symbol, innerLocation: String): Text = { - def nextOuter(innerKind: String): Text = - recur(ownr.effectiveOwner, - if (!innerLocation.isEmpty) innerLocation - else s" in an anonymous $innerKind") - def showLocation(ownr: Symbol, where: String): Text = - innerLocation ~ " " ~ where ~ " " ~ toText(ownr) - if (ownr.isAnonymousClass) nextOuter("class") - else if (ownr.isAnonymousFunction) nextOuter("function") - else if (isEmptyPrefix(ownr)) "" - else if (ownr.isLocalDummy) showLocation(ownr.owner, "locally defined in") - else if (ownr.isTerm && !ownr.is(Module | Method)) showLocation(ownr, "in the initalizer of") - else showLocation(ownr, "in") - } - recur(sym.owner, "") - } - - 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.typeValue.classSymbol) ~ "]" - 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.typeOpt) - else - Text() - - nodeName ~ "(" ~ elems ~ tpSuffix ~ ")" ~ node.pos.toString - case _ => - tree.fallbackToText(this) - } - }.close // todo: override in refined printer - - private var maxSummarized = Int.MaxValue - - def summarized[T](depth: Int)(op: => T): T = { - val saved = maxSummarized - maxSummarized = ctx.toTextRecursions + depth - try op - finally maxSummarized = depth - } - - def summarized[T](op: => T): T = summarized(summarizeDepth)(op) - - def plain = this -} - |