aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/Decorators.scala
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-11-02 11:08:28 +0100
committerGuillaume Martres <smarter@ubuntu.com>2016-11-22 01:35:07 +0100
commit8a61ff432543a29234193cd1f7c14abd3f3d31a0 (patch)
treea8147561d307af862c295cfc8100d271063bb0dd /compiler/src/dotty/tools/dotc/core/Decorators.scala
parent6a455fe6da5ff9c741d91279a2dc6fe2fb1b472f (diff)
downloaddotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.gz
dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.bz2
dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.zip
Move compiler and compiler tests to compiler dir
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core/Decorators.scala')
-rw-r--r--compiler/src/dotty/tools/dotc/core/Decorators.scala185
1 files changed, 185 insertions, 0 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Decorators.scala b/compiler/src/dotty/tools/dotc/core/Decorators.scala
new file mode 100644
index 000000000..a105741f5
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/core/Decorators.scala
@@ -0,0 +1,185 @@
+package dotty.tools.dotc
+package core
+
+import annotation.tailrec
+import Symbols._
+import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer, printing.Showable
+import util.Positions.Position, util.SourcePosition
+import collection.mutable.ListBuffer
+import dotty.tools.dotc.transform.TreeTransforms._
+import ast.tpd._
+import scala.language.implicitConversions
+import printing.Formatting._
+
+/** This object provides useful implicit decorators for types defined elsewhere */
+object Decorators {
+
+ /** Turns Strings into PreNames, adding toType/TermName methods */
+ implicit class StringDecorator(val s: String) extends AnyVal with PreName {
+ def toTypeName: TypeName = typeName(s)
+ def toTermName: TermName = termName(s)
+ def toText(printer: Printer): Text = Str(s)
+ }
+
+ /** Implements a findSymbol method on iterators of Symbols that
+ * works like find but avoids Option, replacing None with NoSymbol.
+ */
+ implicit class SymbolIteratorDecorator(val it: Iterator[Symbol]) extends AnyVal {
+ final def findSymbol(p: Symbol => Boolean): Symbol = {
+ while (it.hasNext) {
+ val sym = it.next
+ if (p(sym)) return sym
+ }
+ NoSymbol
+ }
+ }
+
+ final val MaxFilterRecursions = 1000
+
+ /** Implements filterConserve, zipWithConserve methods
+ * on lists that avoid duplication of list nodes where feasible.
+ */
+ implicit class ListDecorator[T](val xs: List[T]) extends AnyVal {
+
+ final def mapconserve[U](f: T => U): List[U] = {
+ @tailrec
+ def loop(mapped: ListBuffer[U], unchanged: List[U], pending: List[T]): List[U] =
+ if (pending.isEmpty) {
+ if (mapped eq null) unchanged
+ else mapped.prependToList(unchanged)
+ } else {
+ val head0 = pending.head
+ val head1 = f(head0)
+
+ if (head1.asInstanceOf[AnyRef] eq head0.asInstanceOf[AnyRef])
+ loop(mapped, unchanged, pending.tail)
+ else {
+ val b = if (mapped eq null) new ListBuffer[U] else mapped
+ var xc = unchanged
+ while (xc ne pending) {
+ b += xc.head
+ xc = xc.tail
+ }
+ b += head1
+ val tail0 = pending.tail
+ loop(b, tail0.asInstanceOf[List[U]], tail0)
+ }
+ }
+ loop(null, xs.asInstanceOf[List[U]], xs)
+ }
+
+ /** Like `xs filter p` but returns list `xs` itself - instead of a copy -
+ * if `p` is true for all elements and `xs` is not longer
+ * than `MaxFilterRecursions`.
+ */
+ def filterConserve(p: T => Boolean): List[T] = {
+ def loop(xs: List[T], nrec: Int): List[T] = xs match {
+ case Nil => xs
+ case x :: xs1 =>
+ if (nrec < MaxFilterRecursions) {
+ val ys1 = loop(xs1, nrec + 1)
+ if (p(x))
+ if (ys1 eq xs1) xs else x :: ys1
+ else
+ ys1
+ } else xs filter p
+ }
+ loop(xs, 0)
+ }
+
+ /** Like `(xs, ys).zipped.map(f)`, but returns list `xs` itself
+ * - instead of a copy - if function `f` maps all elements of
+ * `xs` to themselves. Also, it is required that `ys` is at least
+ * as long as `xs`.
+ */
+ def zipWithConserve[U](ys: List[U])(f: (T, U) => T): List[T] =
+ if (xs.isEmpty) xs
+ else {
+ val x1 = f(xs.head, ys.head)
+ val xs1 = xs.tail.zipWithConserve(ys.tail)(f)
+ if ((x1.asInstanceOf[AnyRef] eq xs.head.asInstanceOf[AnyRef]) &&
+ (xs1 eq xs.tail)) xs
+ else x1 :: xs1
+ }
+
+ def foldRightBN[U](z: => U)(op: (T, => U) => U): U = xs match {
+ case Nil => z
+ case x :: xs1 => op(x, xs1.foldRightBN(z)(op))
+ }
+
+ final def hasSameLengthAs[U](ys: List[U]): Boolean = {
+ @tailrec def loop(xs: List[T], ys: List[U]): Boolean =
+ if (xs.isEmpty) ys.isEmpty
+ else ys.nonEmpty && loop(xs.tail, ys.tail)
+ loop(xs, ys)
+ }
+
+ /** Union on lists seen as sets */
+ def | (ys: List[T]): List[T] = xs ++ (ys filterNot (xs contains _))
+
+ /** Intersection on lists seen as sets */
+ def & (ys: List[T]): List[T] = xs filter (ys contains _)
+ }
+
+ implicit class ListOfListDecorator[T](val xss: List[List[T]]) extends AnyVal {
+ def nestedMap[U](f: T => U): List[List[U]] = xss map (_ map f)
+ def nestedMapconserve[U](f: T => U): List[List[U]] = xss mapconserve (_ mapconserve f)
+ }
+
+ implicit class TextToString(val text: Text) extends AnyVal {
+ def show(implicit ctx: Context) = text.mkString(ctx.settings.pageWidth.value)
+ }
+
+ /** Test whether a list of strings representing phases contains
+ * a given phase. See [[config.CompilerCommand#explainAdvanced]] for the
+ * exact meaning of "contains" here.
+ */
+ implicit class PhaseListDecorator(val names: List[String]) extends AnyVal {
+ def containsPhase(phase: Phase): Boolean = phase match {
+ case phase: TreeTransformer => phase.miniPhases.exists(containsPhase)
+ case _ =>
+ names exists { name =>
+ name == "all" || {
+ val strippedName = name.stripSuffix("+")
+ val logNextPhase = name ne strippedName
+ phase.phaseName.startsWith(strippedName) ||
+ (logNextPhase && phase.prev.phaseName.startsWith(strippedName))
+ }
+ }
+ }
+ }
+
+ implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition = {
+ def recur(inlinedCalls: List[Tree], pos: Position): SourcePosition = inlinedCalls match {
+ case inlinedCall :: rest =>
+ sourceFile(inlinedCall).atPos(pos).withOuter(recur(rest, inlinedCall.pos))
+ case empty =>
+ ctx.source.atPos(pos)
+ }
+ recur(enclosingInlineds, pos)
+ }
+
+ implicit class StringInterpolators(val sc: StringContext) extends AnyVal {
+
+ /** General purpose string formatting */
+ def i(args: Any*)(implicit ctx: Context): String =
+ new StringFormatter(sc).assemble(args)
+
+ /** Formatting for error messages: Like `i` but suppress follow-on
+ * error messages after the first one if some of their arguments are "non-sensical".
+ */
+ def em(args: Any*)(implicit ctx: Context): String =
+ new ErrorMessageFormatter(sc).assemble(args)
+
+ /** Formatting with added explanations: Like `em`, but add explanations to
+ * give more info about type variables and to disambiguate where needed.
+ */
+ def ex(args: Any*)(implicit ctx: Context): String =
+ explained2(implicit ctx => em(args: _*))
+
+ /** Formatter that adds syntax highlighting to all interpolated values */
+ def hl(args: Any*)(implicit ctx: Context): String =
+ new SyntaxFormatter(sc).assemble(args).stripMargin
+ }
+}
+