|
| 1 | +package dotty.tools |
| 2 | +package repl |
| 3 | + |
| 4 | +import dotc.ast.Trees.{ Untyped, Tree } |
| 5 | +import dotc.core.Annotations.Annotation |
| 6 | +import dotc.core.Constants.Constant |
| 7 | +import dotc.core.Contexts.Context |
| 8 | +import dotc.core.Denotations.{ Denotation, MultiDenotation, SingleDenotation } |
| 9 | +import dotc.core.Flags._ |
| 10 | +import dotc.core.TypeApplications.{ AnyAppliedType, EtaExpansion } |
| 11 | +import dotc.core.Names._ |
| 12 | +import dotc.core.NameOps._ |
| 13 | +import dotc.core.StdNames._ |
| 14 | +import dotc.core.Decorators._ |
| 15 | +import dotc.core.Scopes.Scope |
| 16 | +import dotc.core.Symbols.{ Symbol, ClassSymbol, defn } |
| 17 | +import dotc.core.SymDenotations.NoDenotation |
| 18 | +import dotc.core.Types._ |
| 19 | +import dotc.printing.Texts._ |
| 20 | +import dotc.printing.{ GlobalPrec, DotPrec, Printer, PlainPrinter } |
| 21 | +import dotc.typer.Implicits.SearchResult |
| 22 | +import dotc.typer.ImportInfo |
| 23 | + |
| 24 | +class UserFacingPrinter(_ctx: Context) extends PlainPrinter(_ctx) { |
| 25 | + |
| 26 | + private def panic(msg: String): Nothing = throw new AssertionError(msg) |
| 27 | + |
| 28 | + private[this] def getPkgCls(path: String) = |
| 29 | + _ctx.requiredPackage(path).moduleClass.asClass |
| 30 | + |
| 31 | + private lazy val collectionPkg = getPkgCls("scala.collection") |
| 32 | + private lazy val immutablePkg = getPkgCls("scala.collection.immutable") |
| 33 | + private lazy val scalaPkg = defn.ScalaPackageClass |
| 34 | + private lazy val javaLangPkg = defn.JavaLangPackageVal.moduleClass.asClass |
| 35 | + |
| 36 | + def standardPkg(pkgSym: Symbol) = pkgSym match { |
| 37 | + case `scalaPkg` | `collectionPkg` | `immutablePkg` | `javaLangPkg` => true |
| 38 | + case _ => false |
| 39 | + } |
| 40 | + |
| 41 | + def wrappedName(pkgSym: Symbol) = |
| 42 | + pkgSym.name.toTermName == nme.EMPTY_PACKAGE || |
| 43 | + pkgSym.name.isReplWrapperName |
| 44 | + |
| 45 | + def wellKnownPkg(pkgSym: Symbol) = standardPkg(pkgSym) || wrappedName(pkgSym) |
| 46 | + |
| 47 | + override protected def keyString(sym: Symbol): String = { |
| 48 | + val flags = sym.flags |
| 49 | + if (flags is Package) "" |
| 50 | + else if (sym.isPackageObject) "package object" |
| 51 | + else if (flags.is(Module) && flags.is(Case)) "case object" |
| 52 | + else if (sym.isClass && flags.is(Case)) "case class" |
| 53 | + else if (flags.is(Lazy)) "lazy val" |
| 54 | + else if (flags is Module) "object" |
| 55 | + else if (sym.isTerm && !flags.is(Param) && flags.is(Implicit)) "implicit val" |
| 56 | + else super.keyString(sym) |
| 57 | + } |
| 58 | + |
| 59 | + override def nameString(name: Name): String = |
| 60 | + if (name.isReplAssignName) name.decode.toString.takeWhile(_ != '$') |
| 61 | + else name.decode.toString |
| 62 | + |
| 63 | + override def toText(sym: Symbol): Text = |
| 64 | + if (sym.name.isReplAssignName) nameString(sym.name) |
| 65 | + else keyString(sym) ~~ nameString(sym.name.stripModuleClassSuffix) |
| 66 | + |
| 67 | + override def dclText(sym: Symbol): Text = |
| 68 | + toText(sym) ~ { |
| 69 | + if (sym.is(Method)) toText(sym.info) |
| 70 | + else if (sym.isClass) "" |
| 71 | + else if (sym.isType && sym.info.isInstanceOf[TypeAlias]) " =" ~~ toText(sym.info) |
| 72 | + else if (sym.isType) "" |
| 73 | + else { |
| 74 | + ":" ~~ toText(sym.info) |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + override def toText(denot: Denotation): Text = denot match { |
| 79 | + case NoDenotation => |
| 80 | + panic("NoDenotation encountered in UserFacingPrinter") |
| 81 | + case denot: MultiDenotation => |
| 82 | + panic("MultiDenotation not allowed in UserFacingPrinter") |
| 83 | + case _ => |
| 84 | + toText(denot.symbol) |
| 85 | + } |
| 86 | + |
| 87 | + override def toText(const: Constant): Text = Str(const.value.toString) |
| 88 | + |
| 89 | + override def toText(tp: Type): Text = tp match { |
| 90 | + case tp: AnnotatedType => toText(tp.tpe) ~~ toText(tp.annot) |
| 91 | + case tp: ConstantType => toText(tp.value) |
| 92 | + case tp: TypeAlias => toText(tp.underlying) |
| 93 | + case ExprType(result) => ":" ~~ toText(result) |
| 94 | + case TypeBounds(lo, hi) => |
| 95 | + { if (lo != defn.NothingType) toText(lo) ~~ ">: _" else Str("_") } ~~ |
| 96 | + { if (hi != defn.AnyType) "<:" ~~ toText(hi) else Text() } |
| 97 | + case tp: TypeRef => tp.info match { |
| 98 | + case TypeAlias(alias) => toText(alias) |
| 99 | + case _ => toText(tp.info) |
| 100 | + } |
| 101 | + case tp: ParamRef => { |
| 102 | + val name = tp.paramName.unexpandedName.invariantName.toString |
| 103 | + if (tp.isInstanceOf[TermParamRef]) name ~ ".type" |
| 104 | + else name |
| 105 | + } |
| 106 | + case EtaExpansion(tycon) => toText(tycon) |
| 107 | + case PolyType(params, res) => |
| 108 | + "[" ~ Fluid(params.map(tl => toText(tl.paramRef)).intersperse(Str(", "))) ~ "]" ~ toText(res) |
| 109 | + case tp: MethodType => { |
| 110 | + def paramText(name: TermName, tp: Type) = toText(name) ~ ": " ~ toText(tp) |
| 111 | + changePrec(GlobalPrec) { |
| 112 | + (if (tp.isImplicit) "(implicit " else "(") ~ |
| 113 | + Text((tp.paramNames, tp.paramInfos).zipped map paramText, ", ") ~ |
| 114 | + (if (tp.resultType.isInstanceOf[MethodType]) ")" else "): ") ~ |
| 115 | + toText(tp.resultType) |
| 116 | + } |
| 117 | + } |
| 118 | + case AnyAppliedType(tycon, args) => { |
| 119 | + def toTextInfixType(tycon: Type, args: List[Type]): Text = { |
| 120 | + // TODO: blatant copy from `RefinedPrinter` |
| 121 | + val l :: r :: Nil = args |
| 122 | + val isRightAssoc = tycon.typeSymbol.name.endsWith(":") |
| 123 | + val leftArg = if (isRightAssoc && l.isInfixType) "(" ~ toText(l) ~ ")" else toText(l) |
| 124 | + val rightArg = if (!isRightAssoc && r.isInfixType) "(" ~ toText(r) ~ ")" else toText(r) |
| 125 | + leftArg ~~ atPrec(DotPrec) { tycon.toText(this) } ~~ rightArg |
| 126 | + } |
| 127 | + if (tp.isInfixType) toTextInfixType(tycon, args) |
| 128 | + else { |
| 129 | + toText(tycon) ~ "[" ~ Fluid(args.reverse.map(toText).intersperse(Str(", "))) ~ "]" |
| 130 | + } |
| 131 | + } |
| 132 | + case tp: ClassInfo => { |
| 133 | + if (wellKnownPkg(tp.cls.owner)) |
| 134 | + nameString(tp.cls.name) |
| 135 | + else { |
| 136 | + def printPkg(sym: ClassSymbol): Text = |
| 137 | + if (sym.owner == defn.RootClass || wrappedName(sym.owner)) |
| 138 | + nameString(sym.name.stripModuleClassSuffix) |
| 139 | + else |
| 140 | + printPkg(sym.owner.asClass) ~ "." ~ toText(sym) |
| 141 | + |
| 142 | + printPkg(tp.cls.owner.asClass) ~ "." ~ nameString(tp.cls.name) |
| 143 | + } |
| 144 | + } |
| 145 | + } |
| 146 | + |
| 147 | + override lazy val plain = new PlainPrinter(_ctx) |
| 148 | +} |
0 commit comments