From 8a61ff432543a29234193cd1f7c14abd3f3d31a0 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Wed, 2 Nov 2016 11:08:28 +0100 Subject: Move compiler and compiler tests to compiler dir --- .../src/dotty/tools/dotc/core/Decorators.scala | 185 +++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 compiler/src/dotty/tools/dotc/core/Decorators.scala (limited to 'compiler/src/dotty/tools/dotc/core/Decorators.scala') 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 + } +} + -- cgit v1.2.3