aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-03-04 12:23:10 +0100
committerMartin Odersky <odersky@gmail.com>2016-03-12 16:08:36 +0100
commit12d895587444d5d59e7d75dfaf7b85deb61e99e0 (patch)
treee8f880f79911366d448ff6cc6cdb82fdd846ac6a
parentc1e263bebf7e73239e7faa3e48d75a0a7df45d76 (diff)
downloaddotty-12d895587444d5d59e7d75dfaf7b85deb61e99e0.tar.gz
dotty-12d895587444d5d59e7d75dfaf7b85deb61e99e0.tar.bz2
dotty-12d895587444d5d59e7d75dfaf7b85deb61e99e0.zip
Better encapsulation
No more leaking ofMove PatchedFiles in a settings option. Move all patch classes into a `Rewrites` object.
-rw-r--r--src/dotty/tools/dotc/Driver.scala1
-rw-r--r--src/dotty/tools/dotc/Run.scala4
-rw-r--r--src/dotty/tools/dotc/config/ScalaSettings.scala4
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala2
-rw-r--r--src/dotty/tools/dotc/rewrite/Patches.scala87
-rw-r--r--src/dotty/tools/dotc/rewrite/Rewrites.scala96
6 files changed, 101 insertions, 93 deletions
diff --git a/src/dotty/tools/dotc/Driver.scala b/src/dotty/tools/dotc/Driver.scala
index a989ad218..887274fa8 100644
--- a/src/dotty/tools/dotc/Driver.scala
+++ b/src/dotty/tools/dotc/Driver.scala
@@ -5,7 +5,6 @@ import config.CompilerCommand
import core.Contexts.{Context, ContextBase}
import util.DotClass
import reporting._
-import rewrite.Patches
import scala.util.control.NonFatal
/** Run the Dotty compiler.
diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala
index aba7a002d..ee808323a 100644
--- a/src/dotty/tools/dotc/Run.scala
+++ b/src/dotty/tools/dotc/Run.scala
@@ -8,7 +8,7 @@ import io.PlainFile
import util.{SourceFile, NoSource, Stats, SimpleMap}
import reporting.Reporter
import transform.TreeChecker
-import rewrite.Patches
+import rewrite.Rewrites
import java.io.{BufferedWriter, OutputStreamWriter}
import scala.reflect.io.VirtualFile
import scala.util.control.NonFatal
@@ -65,7 +65,7 @@ class Run(comp: Compiler)(implicit ctx: Context) {
foreachUnit(printTree)
ctx.informTime(s"$phase ", start)
}
- if (!ctx.reporter.hasErrors) Patches.writeBack()
+ if (!ctx.reporter.hasErrors) Rewrites.writeBack()
}
private def printTree(ctx: Context) = {
diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala
index cdbf6ec50..a10165be2 100644
--- a/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -2,7 +2,7 @@ package dotty.tools.dotc
package config
import PathResolver.Defaults
-import rewrite.Patches
+import rewrite.Rewrites
class ScalaSettings extends Settings.SettingGroup {
@@ -50,7 +50,7 @@ class ScalaSettings extends Settings.SettingGroup {
val d = StringSetting("-d", "directory|jar", "destination for generated classfiles.", ".")
val nospecialization = BooleanSetting("-no-specialization", "Ignore @specialize annotations.")
val language = MultiStringSetting("-language", "feature", "Enable one or more language features.")
- val rewrite = OptionSetting[Patches.PatchedFiles]("-rewrite", "When used in conjunction with -language:Scala2 rewrites sources to migrate to new syntax")
+ val rewrite = OptionSetting[Rewrites]("-rewrite", "When used in conjunction with -language:Scala2 rewrites sources to migrate to new syntax")
/** -X "Advanced" settings
*/
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index 47b0ae22d..d5ce455f3 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -21,7 +21,7 @@ import Constants._
import ScriptParsers._
import annotation.switch
import util.DotClass
-import rewrite.Patches.patch
+import rewrite.Rewrites.patch
object Parsers {
diff --git a/src/dotty/tools/dotc/rewrite/Patches.scala b/src/dotty/tools/dotc/rewrite/Patches.scala
deleted file mode 100644
index 7513ec7fa..000000000
--- a/src/dotty/tools/dotc/rewrite/Patches.scala
+++ /dev/null
@@ -1,87 +0,0 @@
-package dotty.tools.dotc
-package rewrite
-
-import util.{SourceFile, Positions}
-import Positions.Position
-import core.Contexts.{Context, FreshContext}
-import collection.mutable
-
-object Patches {
-
- private case class Patch(pos: Position, replacement: String) {
- def delta = replacement.length - (pos.end - pos.start)
- }
-
- class PatchedFiles extends mutable.HashMap[SourceFile, Patches]
-
- /** If -rewrite is set, record a patch that replaces the range
- * given by `pos` in `source` by `replacement`
- */
- def patch(source: SourceFile, pos: Position, replacement: String)(implicit ctx: Context): Unit =
- ctx.settings.rewrite.value match {
- case Some(pfs: PatchedFiles) =>
- pfs.get(source) match {
- case Some(ps) =>
- ps.addPatch(pos, replacement)
- case None =>
- pfs(source) = new Patches(source)
- patch(source, pos, replacement)
- }
- case _ =>
- }
-
- /** If -rewrite is set, apply all patches and overwrite patched source files.
- */
- def writeBack()(implicit ctx: Context) =
- ctx.settings.rewrite.value match {
- case Some(pfs: PatchedFiles) =>
- for (source <- pfs.keys) {
- ctx.println(s"[patched file ${source.file.path}]")
- pfs(source).writeBack()
- }
- case _ =>
- }
-}
-
-class Patches(source: SourceFile) {
- import Patches._
-
- private val pbuf = new mutable.ListBuffer[Patch]()
-
- def addPatch(pos: Position, replacement: String): Unit =
- pbuf += Patch(pos, replacement)
-
- def apply(cs: Array[Char]): Array[Char] = {
- val delta = pbuf.map(_.delta).sum
- val patches = pbuf.toList.sortBy(_.pos.start)
- patches.iterator.sliding(2, 1).foreach(ps =>
- assert(ps(0).pos.end <= ps(1).pos.start, s"overlapping patches: ${ps(0)} and ${ps(1)}"))
- val ds = new Array[Char](cs.length + delta)
- def loop(ps: List[Patch], inIdx: Int, outIdx: Int): Unit = {
- def copy(upTo: Int): Int = {
- val untouched = upTo - inIdx
- Array.copy(cs, inIdx, ds, outIdx, untouched)
- outIdx + untouched
- }
- ps match {
- case patch @ Patch(pos, replacement) :: ps1 =>
- val outNew = copy(pos.start)
- replacement.copyToArray(ds, outNew)
- loop(ps1, pos.end, outNew + replacement.length)
- case Nil =>
- val outNew = copy(cs.length)
- assert(outNew == ds.length, s"$outNew != ${ds.length}")
- }
- }
- loop(patches, 0, 0)
- ds
- }
-
- def writeBack(): Unit = {
- val out = source.file.output
- val chars = apply(source.content)
- val bytes = new String(chars).getBytes
- out.write(bytes)
- out.close()
- }
-} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/rewrite/Rewrites.scala b/src/dotty/tools/dotc/rewrite/Rewrites.scala
new file mode 100644
index 000000000..27dafebcf
--- /dev/null
+++ b/src/dotty/tools/dotc/rewrite/Rewrites.scala
@@ -0,0 +1,96 @@
+package dotty.tools.dotc
+package rewrite
+
+import util.{SourceFile, Positions}
+import Positions.Position
+import core.Contexts.{Context, FreshContext}
+import collection.mutable
+
+/** Handles rewriting of Scala2 files to Dotty */
+object Rewrites {
+ private class PatchedFiles extends mutable.HashMap[SourceFile, Patches]
+
+ private case class Patch(pos: Position, replacement: String) {
+ def delta = replacement.length - (pos.end - pos.start)
+ }
+
+ private class Patches(source: SourceFile) {
+ private val pbuf = new mutable.ListBuffer[Patch]()
+
+ def addPatch(pos: Position, replacement: String): Unit =
+ pbuf += Patch(pos, replacement)
+
+ def apply(cs: Array[Char]): Array[Char] = {
+ val delta = pbuf.map(_.delta).sum
+ val patches = pbuf.toList.sortBy(_.pos.start)
+ patches.iterator.sliding(2, 1).foreach(ps =>
+ assert(ps(0).pos.end <= ps(1).pos.start, s"overlapping patches: ${ps(0)} and ${ps(1)}"))
+ val ds = new Array[Char](cs.length + delta)
+ def loop(ps: List[Patch], inIdx: Int, outIdx: Int): Unit = {
+ def copy(upTo: Int): Int = {
+ val untouched = upTo - inIdx
+ Array.copy(cs, inIdx, ds, outIdx, untouched)
+ outIdx + untouched
+ }
+ ps match {
+ case patch @ Patch(pos, replacement) :: ps1 =>
+ val outNew = copy(pos.start)
+ replacement.copyToArray(ds, outNew)
+ loop(ps1, pos.end, outNew + replacement.length)
+ case Nil =>
+ val outNew = copy(cs.length)
+ assert(outNew == ds.length, s"$outNew != ${ds.length}")
+ }
+ }
+ loop(patches, 0, 0)
+ ds
+ }
+
+ def writeBack(): Unit = {
+ val out = source.file.output
+ val chars = apply(source.content)
+ val bytes = new String(chars).getBytes
+ out.write(bytes)
+ out.close()
+ }
+ }
+
+ /** If -rewrite is set, record a patch that replaces the range
+ * given by `pos` in `source` by `replacement`
+ */
+ def patch(source: SourceFile, pos: Position, replacement: String)(implicit ctx: Context): Unit =
+ ctx.settings.rewrite.value match {
+ case Some(rewrites: Rewrites) =>
+ rewrites.patched.get(source) match {
+ case Some(ps) =>
+ ps.addPatch(pos, replacement)
+ case None =>
+ rewrites.patched(source) = new Patches(source)
+ patch(source, pos, replacement)
+ }
+ case _ =>
+ }
+
+ /** If -rewrite is set, apply all patches and overwrite patched source files.
+ */
+ def writeBack()(implicit ctx: Context) =
+ ctx.settings.rewrite.value match {
+ case Some(rewrites: Rewrites) =>
+ for (source <- rewrites.patched.keys) {
+ ctx.println(s"[patched file ${source.file.path}]")
+ rewrites.patched(source).writeBack()
+ }
+ case _ =>
+ }
+}
+
+/** A completely encapsulated class representing rewrite state, used
+ * as an optional setting.
+ */
+class Rewrites {
+ import Rewrites._
+ private val patched = new PatchedFiles
+}
+
+
+