summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/interactive/CompilerControl.scala63
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala84
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Picklers.scala113
-rw-r--r--src/compiler/scala/tools/nsc/io/JSON.scala512
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala15
-rw-r--r--src/compiler/scala/tools/nsc/util/Pickler.scala316
-rw-r--r--src/compiler/scala/tools/nsc/util/Replay.scala59
-rw-r--r--src/compiler/scala/tools/nsc/util/WorkScheduler.scala2
-rw-r--r--src/library/scala/collection/Iterator.scala4
9 files changed, 1110 insertions, 58 deletions
diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
index 87eace3a24..4a4808b28e 100644
--- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
+++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
@@ -18,6 +18,36 @@ trait CompilerControl { self: Global =>
override def toString = "reload "+sources
}
+ class AskTypeAtItem(val pos: Position, response: Response[Tree]) extends WorkItem {
+ def apply() = self.getTypedTreeAt(pos, response)
+ override def toString = "typeat "+pos.source+" "+pos.show
+ }
+
+ class AskTypeItem(val source: SourceFile, val forceReload: Boolean, response: Response[Tree]) extends WorkItem {
+ def apply() = self.getTypedTree(source, forceReload, response)
+ override def toString = "typecheck"
+ }
+
+ class AskLastTypeItem(val source: SourceFile, response: Response[Tree]) extends WorkItem {
+ def apply() = self.getLastTypedTree(source, response)
+ override def toString = "reconcile"
+ }
+
+ class AskTypeCompletionItem(val pos: Position, response: Response[List[Member]]) extends WorkItem {
+ def apply() = self.getTypeCompletion(pos, response)
+ override def toString = "type completion "+pos.source+" "+pos.show
+ }
+
+ class AskScopeCompletionItem(val pos: Position, response: Response[List[Member]]) extends WorkItem {
+ def apply() = self.getScopeCompletion(pos, response)
+ override def toString = "scope completion "+pos.source+" "+pos.show
+ }
+
+ class AskToDoFirstItem(val source: SourceFile) extends WorkItem {
+ def apply() = moveToFront(List(source))
+ override def toString = "dofirst "+source
+ }
+
/** Info given for every member found by completion
*/
abstract class Member {
@@ -108,53 +138,34 @@ trait CompilerControl { self: Global =>
/** Set sync var `response` to the smallest fully attributed tree that encloses position `pos`.
*/
def askTypeAt(pos: Position, response: Response[Tree]) =
- scheduler postWorkItem new WorkItem {
- def apply() = self.getTypedTreeAt(pos, response)
- override def toString = "typeat "+pos.source+" "+pos.show
- }
+ scheduler postWorkItem new AskTypeAtItem(pos, response)
/** Set sync var `response` to the fully attributed & typechecked tree contained in `source`.
*/
def askType(source: SourceFile, forceReload: Boolean, response: Response[Tree]) =
- scheduler postWorkItem new WorkItem {
- def apply() = self.getTypedTree(source, forceReload, response)
- override def toString = "typecheck"
- }
+ scheduler postWorkItem new AskTypeItem(source, forceReload, response)
/** Set sync var `response` to the last fully attributed & typechecked tree produced from `source`.
* If no such tree exists yet, do a normal askType(source, false, response)
*/
def askLastType(source: SourceFile, response: Response[Tree]) =
- scheduler postWorkItem new WorkItem {
- def apply() = self.getLastTypedTree(source, response)
- override def toString = "reconcile"
- }
+ scheduler postWorkItem new AskLastTypeItem(source, response)
/** Set sync var `response' to list of members that are visible
* as members of the tree enclosing `pos`, possibly reachable by an implicit.
*/
def askTypeCompletion(pos: Position, response: Response[List[Member]]) =
- scheduler postWorkItem new WorkItem {
- def apply() = self.getTypeCompletion(pos, response)
- override def toString = "type completion "+pos.source+" "+pos.show
- }
+ scheduler postWorkItem new AskTypeCompletionItem(pos, response)
/** Set sync var `response' to list of members that are visible
* as members of the scope enclosing `pos`.
*/
def askScopeCompletion(pos: Position, response: Response[List[Member]]) =
- scheduler postWorkItem new WorkItem {
- def apply() = self.getScopeCompletion(pos, response)
- override def toString = "scope completion "+pos.source+" "+pos.show
- }
+ scheduler postWorkItem new AskScopeCompletionItem(pos, response)
/** Ask to do unit first on present and subsequent type checking passes */
- def askToDoFirst(f: SourceFile) = {
- scheduler postWorkItem new WorkItem {
- def apply() = moveToFront(List(f))
- override def toString = "dofirst "+f
- }
- }
+ def askToDoFirst(f: SourceFile) =
+ scheduler postWorkItem new AskToDoFirstItem(f)
/** Cancel current compiler run and start a fresh one where everything will be re-typechecked
* (but not re-loaded).
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index e106ad1f9d..9c14f80a9e 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -1,17 +1,19 @@
package scala.tools.nsc
package interactive
-import java.io.{ PrintWriter, StringWriter }
+import java.io.{ PrintWriter, StringWriter, FileReader, FileWriter }
import scala.collection.mutable
import mutable.{LinkedHashMap, SynchronizedMap,LinkedHashSet, SynchronizedSet}
import scala.concurrent.SyncVar
import scala.util.control.ControlThrowable
import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.util.{SourceFile, Position, RangePosition, NoPosition, WorkScheduler}
+import scala.tools.nsc.util.{SourceFile, Position, RangePosition, NoPosition, WorkScheduler, LogReplay, Logger, Replayer, NullLogger}
import scala.tools.nsc.reporters._
import scala.tools.nsc.symtab._
import scala.tools.nsc.ast._
+import scala.tools.nsc.io.JSON._
+import scala.tools.nsc.util.Pickler._
/** The main class of the presentation compiler in an interactive environment such as an IDE
*/
@@ -20,7 +22,8 @@ class Global(settings: Settings, reporter: Reporter)
with CompilerControl
with RangePositions
with ContextTrees
- with RichCompilationUnits {
+ with RichCompilationUnits
+ with Picklers {
self =>
import definitions._
@@ -28,6 +31,18 @@ self =>
val debugIDE: Boolean = settings.YpresentationDebug.value
val verboseIDE: Boolean = settings.YpresentationVerbose.value
+ private def replayName = settings.YpresentationReplay.value
+ private def logName = settings.YpresentationLog.value
+
+ lazy val log =
+ if (replayName != "") new Replayer(new FileReader(replayName))
+ else if (logName != "") new Logger(new FileWriter(logName))
+ else NullLogger
+
+// import log.logreplay
+
+ def logreplay[T](label: String, x: T): T = x
+
/** Print msg only when debugIDE is true. */
@inline final def debugLog(msg: => String) =
if (debugIDE) println(msg)
@@ -82,7 +97,7 @@ self =>
*/
override def signalDone(context: Context, old: Tree, result: Tree) {
def integrateNew() {
- // Don't think this is needed anymore, let's see if we can remove
+ // still needed?
context.unit.body = new TreeReplacer(old, result) transform context.unit.body
}
if (activeLocks == 0) { // can we try to avoid that condition (?)
@@ -165,6 +180,9 @@ self =>
// ----------------- Polling ---------------------------------------
+ var moreWorkAtNode: Int = -1
+ var nodesSeen = 0
+
/** Called from runner thread and signalDone:
* Poll for interrupts and execute them immediately.
* Then, poll for exceptions and execute them.
@@ -182,28 +200,46 @@ self =>
pollForWork()
case _ =>
}
- if (pendingResponse.isCancelled)
- throw CancelException
- scheduler.pollThrowable() match {
- case Some(ex @ FreshRunReq) =>
- newTyperRun()
- minRunId = currentRunId
- if (outOfDate) throw ex
- else outOfDate = true
- case Some(ex: Throwable) => throw ex
- case _ =>
+
+ def nodeWithWork(): Option[Int] = {
+ nodesSeen += 1
+ if (scheduler.moreWork || pendingResponse.isCancelled) Some(nodesSeen) else None
}
- scheduler.nextWorkItem() match {
- case Some(action) =>
- try {
- debugLog("picked up work item: "+action)
- action()
- debugLog("done with work item: "+action)
- } finally {
- debugLog("quitting work item: "+action)
- }
+
+ logreplay("atnode", nodeWithWork()) match {
+ case Some(id) =>
+ assert(id >= nodesSeen)
+ moreWorkAtNode = id
case None =>
}
+
+ if (nodesSeen == moreWorkAtNode) {
+
+ if (logreplay("cancelled", pendingResponse.isCancelled)) {
+ throw CancelException
+ }
+
+ logreplay("exception thrown", scheduler.pollThrowable()) match {
+ case Some(ex @ FreshRunReq) =>
+ newTyperRun()
+ minRunId = currentRunId
+ if (outOfDate) throw ex
+ else outOfDate = true
+ case Some(ex: Throwable) => throw ex
+ case _ =>
+ }
+ logreplay("workitem", scheduler.nextWorkItem()) match {
+ case Some(action) =>
+ try {
+ debugLog("picked up work item: "+action)
+ action()
+ debugLog("done with work item: "+action)
+ } finally {
+ debugLog("quitting work item: "+action)
+ }
+ case None =>
+ }
+ }
}
def debugInfo(source : SourceFile, start : Int, length : Int): String = {
@@ -291,13 +327,11 @@ self =>
// remove any files in first that are no longer maintained by presentation compiler (i.e. closed)
allSources = allSources filter (s => unitOfFile contains (s.file))
- informIDE("Parsing %d files.".format(allSources.size))
for (s <- allSources) {
val unit = unitOf(s)
if (unit.status == NotLoaded) parse(unit)
}
- informIDE("Typechecking %d files.".format(allSources.size))
for (s <- allSources) {
val unit = unitOf(s)
if (!unit.isUpToDate) typeCheck(unit)
diff --git a/src/compiler/scala/tools/nsc/interactive/Picklers.scala b/src/compiler/scala/tools/nsc/interactive/Picklers.scala
new file mode 100644
index 0000000000..79b1921642
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interactive/Picklers.scala
@@ -0,0 +1,113 @@
+package scala.tools.nsc
+package interactive
+
+import util.{SourceFile, BatchSourceFile}
+import io.{AbstractFile, PlainFile}
+
+import util.{Pickler, CondPickler, Position, RangePosition, NoPosition, OffsetPosition, TransparentPosition}
+import util.Pickler._
+import collection.mutable
+
+trait Picklers { self: Global =>
+
+ lazy val freshRunReq = obj(FreshRunReq)
+ lazy val shutdownReq = obj(ShutdownReq)
+
+ def defaultThrowable[T <: Throwable]: CondPickler[T] = anyJavaInstance[T] cond { _ => true }
+
+ implicit lazy val throwable: Pickler[Throwable] =
+ freshRunReq | shutdownReq | defaultThrowable
+
+ implicit def abstractFile: Pickler[AbstractFile] =
+ pkl[String]
+ .wrapped[AbstractFile] { new PlainFile(_) } { _.path }
+ .asClass (classOf[PlainFile])
+
+ private val sourceFilesSeen = new mutable.HashMap[AbstractFile, Array[Char]] {
+ override def default(key: AbstractFile) = Array()
+ }
+
+ type Diff = (Int /*start*/, Int /*end*/, Array[Char] /*replacement*/)
+
+ def delta(f: AbstractFile, cs: Array[Char]): Diff = {
+ val bs = sourceFilesSeen(f)
+ var start = 0
+ while (start < bs.length && start < cs.length && bs(start) == cs(start)) start += 1
+ var end = bs.length
+ var end2 = cs.length
+ while (end > start && end2 > start && bs(end - 1) == cs(end2 - 1)) { end -= 1; end2 -= 1 }
+ sourceFilesSeen(f) = cs
+ (start, end, cs.slice(start, end2))
+ }
+
+ def patch(f: AbstractFile, d: Diff): Array[Char] = {
+ val (start, end, replacement) = d
+ val patched = sourceFilesSeen(f).patch(start, replacement, end - start)
+ sourceFilesSeen(f) = patched
+ patched
+ }
+
+ implicit lazy val sourceFile: Pickler[SourceFile] =
+ (pkl[AbstractFile] ~ pkl[Diff]).wrapped[SourceFile] {
+ case f ~ d => new BatchSourceFile(f, patch(f, d))
+ } {
+ f => f.file ~ delta(f.file, f.content)
+ }.asClass (classOf[BatchSourceFile])
+
+ lazy val offsetPosition: CondPickler[OffsetPosition] =
+ (pkl[SourceFile] ~ pkl[Int])
+ .wrapped { case x ~ y => new OffsetPosition(x, y) } { p => p.source ~ p.point }
+ .asClass (classOf[OffsetPosition])
+
+ lazy val rangePosition: CondPickler[RangePosition] =
+ (pkl[SourceFile] ~ pkl[Int] ~ pkl[Int] ~ pkl[Int])
+ .wrapped { case source ~ start ~ point ~ end => new RangePosition(source, start, point, end) } { p => p.source ~ p.start ~ p.point ~ p.end }
+ .asClass (classOf[RangePosition])
+
+ lazy val transparentPosition: CondPickler[TransparentPosition] =
+ (pkl[SourceFile] ~ pkl[Int] ~ pkl[Int] ~ pkl[Int])
+ .wrapped { case source ~ start ~ point ~ end => new TransparentPosition(source, start, point, end) } { p => p.source ~ p.start ~ p.point ~ p.end }
+ .asClass (classOf[TransparentPosition])
+
+ lazy val noPosition = obj(NoPosition)
+
+ implicit lazy val position: Pickler[Position] = transparentPosition | rangePosition | offsetPosition | noPosition
+
+ implicit def reloadItem: CondPickler[ReloadItem] =
+ pkl[List[SourceFile]]
+ .wrapped { ReloadItem(_, new Response) } { _.sources }
+ .asClass (classOf[ReloadItem])
+
+ implicit def askTypeAtItem: CondPickler[AskTypeAtItem] =
+ pkl[Position]
+ .wrapped { new AskTypeAtItem(_, new Response) } { _.pos }
+ .asClass (classOf[AskTypeAtItem])
+
+ implicit def askTypeItem: CondPickler[AskTypeItem] =
+ (pkl[SourceFile] ~ pkl[Boolean])
+ .wrapped { case source ~ forceReload => new AskTypeItem(source, forceReload, new Response) } { w => w.source ~ w.forceReload }
+ .asClass (classOf[AskTypeItem])
+
+ implicit def askLastTypeItem: CondPickler[AskLastTypeItem] =
+ pkl[SourceFile]
+ .wrapped { new AskLastTypeItem(_, new Response) } { _.source }
+ .asClass (classOf[AskLastTypeItem])
+
+ implicit def askTypeCompletionItem: CondPickler[AskTypeCompletionItem] =
+ pkl[Position]
+ .wrapped { new AskTypeCompletionItem(_, new Response) } { _.pos }
+ .asClass (classOf[AskTypeCompletionItem])
+
+ implicit def askScopeCompletionItem: CondPickler[AskScopeCompletionItem] =
+ pkl[Position]
+ .wrapped { new AskScopeCompletionItem(_, new Response) } { _.pos }
+ .asClass (classOf[AskScopeCompletionItem])
+
+ implicit def askToDoFirstItem: CondPickler[AskToDoFirstItem] =
+ pkl[SourceFile]
+ .wrapped { new AskToDoFirstItem(_) } { _.source }
+ .asClass (classOf[AskToDoFirstItem])
+
+ implicit def action: Pickler[() => Unit] =
+ reloadItem | askTypeAtItem | askTypeItem | askLastTypeItem | askTypeCompletionItem | askScopeCompletionItem | askToDoFirstItem
+}
diff --git a/src/compiler/scala/tools/nsc/io/JSON.scala b/src/compiler/scala/tools/nsc/io/JSON.scala
new file mode 100644
index 0000000000..c4584f762a
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/JSON.scala
@@ -0,0 +1,512 @@
+package scala.tools.nsc.io
+
+import java.io.{Reader, Writer, StringReader, StringWriter}
+import scala.collection.mutable.{Buffer, ArrayBuffer}
+import scala.math.BigInt
+
+object JSON {
+
+ class MalformedInput(val rdr: JReader, val msg: String) extends Exception("Malformed JSON input at "+rdr.tokenPos+": "+msg)
+
+ class PrettyWriter(wr: Writer) extends Writer {
+ protected val indentStep = " "
+ private var indent = 0
+ private def newLine() {
+ wr.write('\n')
+ wr.write(indentStep * indent)
+ }
+ def close() = wr.close()
+ def flush() = wr.flush()
+ def write(str: Array[Char], off: Int, len: Int): Unit = {
+ if (off < str.length && off < len) {
+ str(off) match {
+ case '{' | '[' =>
+ indent += 1
+ wr.write(str(off))
+ newLine()
+ wr.write(str, off + 1, len - 1)
+ case '}' | ']' =>
+ wr.write(str, off, len)
+ indent -= 1
+ case ',' =>
+ wr.write(',')
+ newLine()
+ wr.write(str, off + 1, len - 1)
+ case ':' =>
+ wr.write(':')
+ wr.write(' ')
+ wr.write(str, off + 1, len - 1)
+ case _ =>
+ wr.write(str, off, len)
+ }
+ } else {
+ wr.write(str, off, len)
+ }
+ }
+ override def toString = wr.toString
+ }
+
+ object JReader {
+
+ type Token = Int
+
+ val STRING = 1
+ val INTEGER = 2
+ val FLOAT = 3
+ val LBRACE = 4
+ val RBRACE = 5
+ val LBRACKET = 6
+ val RBRACKET = 7
+ val COMMA = 8
+ val COLON = 9
+ val TRUE = 10
+ val FALSE = 11
+ val NULL = 12
+ val EOF = 13
+
+ def show(token: Token) = token match {
+ case STRING => "string literal"
+ case INTEGER => "integer literal"
+ case FLOAT => "floating point literal"
+ case LBRACE => "'{'"
+ case RBRACE => "'}'"
+ case LBRACKET => "'['"
+ case RBRACKET => "']'"
+ case COMMA => "','"
+ case COLON => "':'"
+ case TRUE => "'true'"
+ case FALSE => "'false'"
+ case NULL => "'null'"
+ case EOF => "<end of input>"
+ }
+
+ private def toUDigit(ch: Int): Char = {
+ val d = ch & 0xF
+ (if (d < 10) d + '0' else d - 10 + 'A').toChar
+ }
+
+ private def addToStr(buf: StringBuilder, ch: Char) {
+ ch match {
+ case '"' => buf ++= "\\\""
+ case '\b' => buf ++= "\\b"
+ case '\f' => buf ++= "\\f"
+ case '\n' => buf ++= "\\n"
+ case '\r' => buf ++= "\\r"
+ case '\t' => buf ++= "\\t"
+ case '\\' => buf ++= "\\\\"
+ case _ =>
+ if (' ' <= ch && ch < 128) buf += ch
+ else buf ++= "\\u" += toUDigit(ch >>> 12) += toUDigit(ch >>> 8) += toUDigit(ch >>> 4) += toUDigit(ch)
+ }
+ }
+
+ def quoted(str: String): String = {
+ val buf = new StringBuilder += '\"'
+ str foreach (addToStr(buf, _))
+ buf += '\"'
+ buf.toString
+ }
+
+ private val BUF_SIZE = 2 << 16
+ }
+
+ import JReader._
+
+ abstract class JIterator[T] extends BufferedIterator[T] {
+ def reader: Option[JReader]
+ }
+
+ class JReader(rd: Reader) {
+
+ var ch: Char = 0
+ var pos: Long = 0
+ var token: Token = 0
+ var tokenPos: Long = 0
+ private var atEOF: Boolean = false
+
+ private val buf = new Array[Char](BUF_SIZE)
+ private var nread: Int = 0
+ private var bp = 0
+
+ def nextChar() {
+ if (!atEOF) {
+ if (bp == nread) {
+ nread = rd.read(buf)
+ bp = 0
+ if (nread <= 0) { ch = 0; atEOF = true; return }
+ }
+ ch = buf(bp)
+ bp += 1
+ pos += 1
+ }
+ }
+
+ def acceptChar(c: Char) = if (ch == c) nextChar() else error("'"+c+"' expected")
+
+ val sb = new StringBuilder
+
+ def putChar() {
+ sb += ch; nextChar()
+ }
+
+ def putAcceptString(str: String) {
+ str foreach acceptChar
+ sb ++= str
+ }
+
+ def nextToken() {
+ sb.clear()
+ while (!atEOF && ch <= ' ') nextChar()
+ tokenPos = pos - 1
+ if (atEOF) token = EOF
+ else ch match {
+ case '{' => putChar(); token = LBRACE
+ case '}' => putChar(); token = RBRACE
+ case '[' => putChar(); token = LBRACKET
+ case ']' => putChar(); token = RBRACKET
+ case ',' => putChar(); token = COMMA
+ case ':' => putChar(); token = COLON
+ case 't' => putAcceptString("true"); token = TRUE
+ case 'f' => putAcceptString("false"); token = FALSE
+ case 'n' => putAcceptString("null"); token = NULL
+ case '"' => getString()
+ case '-' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => getNumber()
+ case _ => error("illegal string literal character: '"+ch+"'")
+ }
+ println("["+showCurrent+"]")
+ }
+
+ def getString() {
+ def udigit() = {
+ nextChar()
+ if ('0' <= ch && ch <= '9') ch - '9'
+ else if ('A' <= ch && ch <= 'F') ch - 'A' + 10
+ else if ('a' <= ch && ch <= 'f') ch - 'a' + 10
+ else error("illegal unicode escape character: '"+ch+"'")
+ }
+ val delim = ch
+ nextChar()
+ while (ch != delim && ch >= ' ') {
+ if (ch == '\\') {
+ nextChar()
+ ch match {
+ case '\'' => sb += '\''
+ case '"' => sb += '"'
+ case '\\' => sb += '\\'
+ case '/' => sb += '/'
+ case 'b' => sb += '\b'
+ case 'f' => sb += '\f'
+ case 'n' => sb += '\n'
+ case 'r' => sb += '\r'
+ case 't' => sb += '\t'
+ case 'u' => sb += (udigit() << 12 | udigit() << 8 | udigit() << 4 | udigit()).toChar
+ case _ => error("illegal escape character: '"+ch+"'")
+ }
+ nextChar()
+ } else {
+ putChar()
+ }
+ }
+ acceptChar(delim)
+ token = STRING
+ }
+
+ def getNumber() {
+ def digit() =
+ if ('0' <= ch && ch <= '9') putChar()
+ else error("<digit> expected")
+ def digits() =
+ do { digit() } while ('0' <= ch && ch <= '9')
+ token = INTEGER
+ if (ch == '-') putChar()
+ if (ch == '0') digit()
+ else digits()
+ if (ch == '.') {
+ token = FLOAT
+ putChar()
+ digits()
+ }
+ if (ch == 'e' || ch == 'E') {
+ token = FLOAT
+ putChar()
+ if (ch == '+' || ch == '-') putChar()
+ digits()
+ }
+ }
+
+ def accept(t: Token) =
+ if (token == t) nextToken()
+ else error(show(t)+" expected, but "+showCurrent+" found")
+
+ def headValue(): JValue = token match {
+ case STRING => JString(tokenStr)
+ case INTEGER =>
+ try {
+ JLong(tokenStr.toLong)
+ } catch {
+ case ex: NumberFormatException => JInteger(BigInt(tokenStr))
+ }
+ case FLOAT => JDouble(tokenStr.toDouble)
+ case LBRACE => new JObject(this)
+ case LBRACKET => new JArray(this)
+ case TRUE => JTrue
+ case FALSE => JFalse
+ case NULL => JNull
+ case t => error("unexpected: "+showCurrent)
+ }
+
+ def nextValue(): JValue = {
+ val result = headValue()
+ nextToken()
+ result
+ }
+
+ def iterator: JIterator[JValue] =
+ new JTopLevel(this).inputIterator
+
+ def tokenStr = sb.toString
+
+ def showCurrent() = token match {
+ case STRING => "string literal "+quoted(tokenStr)
+ case INTEGER => "integer literal "+tokenStr
+ case FLOAT => "floating point literal "+tokenStr
+ case _ => show(token)
+ }
+
+ def error(msg: String) = throw new MalformedInput(this, msg)
+
+ nextChar()
+ nextToken()
+ }
+
+ abstract class JElement {
+ def isComplete: Boolean
+ def doneReading()
+ def readFully(): this.type
+ def write(wr: Writer)
+ }
+
+ case class J_: (label: String, value: JValue) extends JElement {
+ def isComplete = value.isComplete
+ def doneReading() = value.doneReading()
+ def readFully() = { value.readFully(); this }
+ def write(wr: Writer) { wr.write(quoted(label)); wr.write(":"); value.write(wr) }
+ override def toString = label+" J_: "+value
+ }
+
+ abstract class JValue extends JElement {
+ def J_: (label: String) = new J_: (label, this)
+ }
+
+ abstract class JContainer[T <: JElement](closingToken: Token,
+ elems: T*) extends JValue {
+ protected var input: Option[JReader] = None
+ private var prevInput = input
+
+ val contents: Buffer[T] = new ArrayBuffer[T] ++= elems
+
+ protected def readElement(rdr: JReader): T
+
+ val inputIterator = new JIterator[T] {
+ var last: Option[T] = None
+ var lastIsNext: Boolean = false
+ def hasNext: Boolean =
+ lastIsNext || {
+ input match {
+ case None => false
+ case Some(rdr) =>
+ closeLast()
+ rdr.token != closingToken
+ }
+ }
+ def head: T =
+ if (lastIsNext) last.get
+ else input match {
+ case None => Iterator.empty.next
+ case Some(rdr) =>
+ closeLast()
+ if (last.isDefined) rdr.accept(COMMA)
+ val x = readElement(rdr)
+ last = Some(x)
+ lastIsNext = true
+ x
+ }
+ def next(): T = {
+ val result = head
+ lastIsNext = false
+ println("next: "+result)
+ result
+ }
+ def closeLast(): Unit = last match {
+ case Some(elem) => elem.doneReading()
+ case _ =>
+ }
+ def reader = input orElse prevInput
+ }
+
+ def isComplete: Boolean = !inputIterator.hasNext
+
+ def doneReading() {
+ require(isComplete)
+ input match {
+ case None => // already closed
+ case Some(rdr) =>
+ inputIterator.closeLast()
+ println("done reading: "+rdr.showCurrent)
+ rdr.accept(closingToken)
+ prevInput = input
+ input = None
+ }
+ }
+
+ def readFully() = {
+ contents ++= inputIterator map (_.readFully())
+ doneReading()
+ this
+ }
+
+ def skip() {
+ inputIterator foreach { _ => () }
+ doneReading()
+ }
+
+ protected def writeContents(wr: Writer) {
+ var first = true
+ for (elem <- contents) {
+ if (first) first = false else wr.write(",")
+ elem.write(wr)
+ }
+ }
+
+ }
+
+ class JObject(elems: J_: *) extends JContainer(RBRACE, elems: _*) {
+ def this(in: JReader) = { this(); input = Some(in) }
+ protected def readElement(rdr: JReader): J_: = {
+ if (rdr.token == STRING) {
+ val label = rdr.tokenStr
+ rdr.nextToken(); rdr.accept(COLON)
+ label J_: rdr.nextValue()
+ } else {
+ rdr.error("string literal expected, but "+rdr.tokenStr+" found")
+ }
+ }
+
+ def write(wr: Writer) {
+ wr.write("{")
+ writeContents(wr)
+ wr.write("}")
+ }
+
+ override def toString = contents.mkString("{", ",", "}")
+ override def hashCode = contents.hashCode + 17
+ override def equals(other: Any) = other match {
+ case that: JObject => this.contents == that.contents
+ case _ => false
+ }
+ }
+
+ class JArray(elems: JValue*) extends JContainer(RBRACKET, elems: _*) {
+ def this(in: JReader) = { this(); input = Some(in) }
+ protected val closingToken = RBRACKET
+ protected def readElement(rdr: JReader): JValue = rdr.nextValue()
+
+ def write(wr: Writer) {
+ wr.write("[")
+ writeContents(wr)
+ wr.write("]")
+ }
+
+ override def toString = contents.mkString("[", ",", "]")
+ override def hashCode = contents.hashCode + 19
+ override def equals(other: Any) = other match {
+ case that: JArray => this.contents == that.contents
+ case _ => false
+ }
+ }
+
+ class JTopLevel(elems: JValue*) extends JContainer(EOF, elems: _*) {
+ def this(in: JReader) = { this(); input = Some(in) }
+ protected val closingToken = EOF
+ protected def readElement(rdr: JReader): JValue = rdr.nextValue()
+
+ def write(wr: Writer) {
+ writeContents(wr)
+ }
+
+ override def toString = contents.mkString(",")
+ override def hashCode = contents.hashCode + 23
+ override def equals(other: Any) = other match {
+ case that: JTopLevel => this.contents == that.contents
+ case _ => false
+ }
+ }
+
+ object JObject {
+ def apply(elems: J_: *) = new JObject(elems: _*)
+ def unapplySeq(x: JObject): Some[Seq[J_:]] = Some(x.contents)
+ }
+
+ object JArray {
+ def apply(elems: JValue*) = new JArray(elems: _*)
+ def unapplySeq(x: JArray): Some[Seq[JValue]] = Some(x.contents)
+ }
+
+ abstract class JAtom extends JValue {
+ def isComplete = true
+ def doneReading() {}
+ def readFully() = this
+ }
+
+ case class JInteger(value: BigInt) extends JAtom {
+ def write(wr: Writer) { wr.write(value.toString) }
+ }
+
+ case class JLong(value: Long) extends JAtom {
+ def write(wr: Writer) { wr.write(value.toString) }
+ }
+
+ case class JDouble(value: Double) extends JAtom {
+ def write(wr: Writer) { wr.write(value.toString) }
+ }
+
+ case class JString(value: String) extends JAtom {
+ def write(wr: Writer) { wr.write(quoted(value)) }
+ }
+
+ case object JTrue extends JAtom {
+ def write(wr: Writer) { wr.write("true") }
+ }
+
+ case object JFalse extends JAtom {
+ def write(wr: Writer) { wr.write("false") }
+ }
+
+ case object JNull extends JAtom {
+ def write(wr: Writer) { wr.write("null") }
+ }
+}
+
+object Test extends Application {
+ import JSON._
+ val obj = JObject(
+ "a" J_: JArray(JLong(1), JDouble(2.0), JInteger(BigInt("12345678901234567890"))),
+ "b" J_: JString("I am a \t String \n on two lines"),
+ "c" J_: JObject("t" J_: JTrue, "f" J_: JFalse),
+ "d" J_: JNull,
+ "e" J_: JArray(),
+ "f" J_: JObject()
+ )
+ val sw = new PrettyWriter(new StringWriter())
+ obj.write(sw)
+ sw.close()
+ val s = sw.toString
+ println("written: "+s)
+ var sr = new JReader(new StringReader(s))
+ val it = sr.iterator
+ val r = it.head.readFully()
+ it.next()
+ println("read: "+r)
+ assert(!it.hasNext, it.next()+"/"+sr.showCurrent+"/"+r)
+ assert(obj == r)
+}
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 627fdac2d0..f9d0d4034c 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -145,13 +145,20 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings {
val noSelfCheck = BooleanSetting ("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.")
val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes")
- val YpresentationVerbose = BooleanSetting("-YpresentationVerbose", "Print information about presentation compiler tasks.")
- val YpresentationDebug = BooleanSetting("-Ypresentation-debug", "Enable debugging output for the presentation compiler.")
-
- // Warnings
+ /**
+ * Warnings
+ */
val Ywarndeadcode = BooleanSetting ("-Ywarn-dead-code", "Emit warnings for dead code")
/**
+ * IDE-specific settings
+ */
+ val YpresentationVerbose = BooleanSetting("-Ypresentation-verbose", "Print information about presentation compiler tasks.")
+ val YpresentationDebug = BooleanSetting("-Ypresentation-debug", "Enable debugging output for the presentation compiler.")
+
+ val YpresentationLog = StringSetting("-Ypresentation-log", "file", "Log presentation comnpiler events into file", "")
+ val YpresentationReplay = StringSetting("-Ypresentation-replay", "file", "Replay presentation comnpiler events from file", "")
+ /**
* "fsc-specific" settings.
*/
val fscShutdown = BooleanSetting ("-shutdown", "Shutdown the fsc daemon")
diff --git a/src/compiler/scala/tools/nsc/util/Pickler.scala b/src/compiler/scala/tools/nsc/util/Pickler.scala
new file mode 100644
index 0000000000..ef9fcb4c92
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/util/Pickler.scala
@@ -0,0 +1,316 @@
+package scala.tools.nsc.util
+
+import scala.tools.nsc.io.JSON._
+import annotation.unchecked
+
+abstract class Pickler[T] {
+
+ import Pickler._
+
+ def pickle(x: T): Pickled
+ def unpickle(it: PickleIterator): Result[T]
+
+ def ~ [U] (that: => Pickler[U]): Pickler[T ~ U] = seq(this, that)
+
+ def labelled(label: String): Pickler[T] = Pickler.labelled(label, this)
+ def wrapped [U] (in: T => U)(out: U => T): Pickler[U] = wrap(this)(in)(out)
+ def cond(p: Any => Boolean): CondPickler[T] = conditional(this, p)
+ def asClass[U <: T](c: Class[U]): CondPickler[T] = this labelled c.getName cond (c isInstance _)
+}
+
+object Pickler {
+
+ var debugMode = false
+
+ type Pickled = JValue
+ type PickleIterator = JIterator[Pickled]
+
+ abstract class Result[+T] {
+ def map[U](f: T => U): Result[U] = this match {
+ case Success(x) => Success(f(x))
+ case f: Failure => f
+ }
+ def flatMap[U](f: T => Result[U]): Result[U] = this match {
+ case Success(x) => f(x)
+ case f: Failure => f
+ }
+ def orElse[U >: T](alt: => Result[U]): Result[U] = this match {
+ case Success(x) => this
+ case f: Failure => alt
+ }
+ }
+
+ case class Success[T](result: T) extends Result[T]
+
+ class Failure(msg: => String, it: PickleIterator) extends Result[Nothing] {
+ override def toString = it.reader match {
+ case Some(rdr) => "Failure at "+rdr.tokenPos+": "+msg
+ case None => "Failure: "+msg
+ }
+ }
+
+ def errorExpected(msg: String, it: PickleIterator) =
+ new Failure("expected: "+msg+"\n" +
+ "found : "+(if (it.hasNext) it.head.toString else "<end of input>"),
+ it)
+
+ def valueIterator(x: JValue): PickleIterator = {
+ val xArray = x match {
+ case arr: JArray => arr
+ case _ => new JArray(x)
+ }
+ xArray.inputIterator
+ }
+
+ def unpickleLabelled[T](it: PickleIterator, label: String)
+ (unpickleBinding: (PickleIterator, String) => Result[T]): Result[T] = {
+ def err(it: PickleIterator) = errorExpected("{"+label+": ?}", it)
+ if (it.hasNext)
+ it.head match {
+ case jo: JObject =>
+ val it2 = jo.inputIterator
+ if (it2.hasNext)
+ it2.head match {
+ case name J_: rhs if (label == "?" || label == name) =>
+ it2.next()
+ val result = unpickleBinding(valueIterator(rhs), name)
+ it.next()
+ result
+ case _ =>
+ err(it)
+ }
+ else err(it)
+ case _ =>
+ err(it)
+ }
+ else
+ err(it)
+ }
+
+ def labelled[T](label: String, p: Pickler[T]): Pickler[T] = new Pickler[T] {
+ def pickle(x: T): Pickled =
+ JObject(label J_: p.pickle(x))
+ def unpickle(it: PickleIterator): Result[T] =
+ unpickleLabelled(it, label) { (rit, name) => p unpickle rit }
+ }
+
+ def wrap[S, T](p: Pickler[S])(in: S => T)(out: T => S) = new Pickler[T] {
+ def pickle(x: T) = p.pickle(out(x))
+ def unpickle(it: PickleIterator) = p.unpickle(it) map in
+ }
+
+ def conditional[T](p: Pickler[T], cond: Any => Boolean) = new CondPickler[T](cond) {
+ def pickle(x: T) = p.pickle(x)
+ def unpickle(it: PickleIterator) = p.unpickle(it)
+ }
+
+ def seq[T, U](p: Pickler[T], q: => Pickler[U]) = new Pickler[T ~ U] {
+ private def toSeq(x: JValue): Seq[JValue] = x match {
+ case JArray(elems @ _*) => elems
+ case _ => Vector(x)
+ }
+ lazy val qq = q
+ def pickle(x: T ~ U) =
+ JArray(toSeq(p pickle x.fst) ++ toSeq(qq pickle x.snd): _*)
+ def unpickle(it: PickleIterator) =
+ for (x <- p.unpickle(it); y <- qq.unpickle(it)) yield x ~ y
+ }
+
+ def rep[T](implicit p: Pickler[T]): Pickler[Seq[T]] = new Pickler[Seq[T]] {
+ def pickle(xs: Seq[T]): Pickled = JArray(xs map p.pickle: _*)
+ def unpickle(it: PickleIterator): Result[Seq[T]] =
+ if (it.hasNext)
+ for {
+ first <- p.unpickle(it)
+ rest <- rep(p).unpickle(it)
+ } yield first +: rest
+ else Success(Seq())
+ }
+
+ def either[T, U <: T, V <: T](p: CondPickler[U], q: CondPickler[V]) =
+ new CondPickler[T](x => p.canPickle(x) || q.canPickle(x)) {
+ override def tryPickle(x: Any) = p.tryPickle(x) orElse q.tryPickle(x)
+ def pickle(x: T): Pickled = tryPickle(x) getOrElse {
+ throw new Error("no pickler found for a "+x.asInstanceOf[AnyRef].getClass.getName)
+ }
+ def unpickle(it: PickleIterator) = p.unpickle(it) orElse q.unpickle(it)
+ }
+
+ def obj[T <: AnyRef](x: T): CondPickler[T] =
+ unit.wrapped { _ => x } { x => () } labelled x.getClass.getName cond (x eq _.asInstanceOf[AnyRef])
+
+ def pkl[T: Pickler] = implicitly[Pickler[T]]
+
+ def anyJavaInstance[T <: AnyRef]: Pickler[T] = new Pickler[T] {
+ def pickle(x: T) = JObject(x.getClass.getName J_: JArray())
+ def unpickle(it: PickleIterator): Result[T] =
+ unpickleLabelled(it, "?") { (rit, name) => Success(Class.forName(name).newInstance().asInstanceOf[T]) }
+ }
+
+ def nullable[T >: Null](p: Pickler[T]): Pickler[T] = new Pickler[T] {
+ def pickle(x: T) = if (x == null) JNull else p.pickle(x)
+ def unpickle(it: PickleIterator): Result[T] =
+ if (it.hasNext && it.head == JNull) Success(null)
+ else p.unpickle(it)
+ }
+
+ case class ~[S, T](fst: S, snd: T)
+
+ class TildeDecorator[S](x: S) {
+ def ~ [T](y: T): S ~ T = new ~ (x, y)
+ }
+
+ implicit def tildeDecorator[S](x: S): TildeDecorator[S] = new TildeDecorator(x)
+
+ implicit def fromTilde[T1, T2, R](f: (T1, T2) => R): T1 ~ T2 => R = { case x1 ~ x2 => f(x1, x2) }
+
+ implicit def toTilde[T1, T2, S](f: S => Option[(T1, T2)]): S => T1 ~ T2 = { x => (f(x): @unchecked) match { case Some((x1, x2)) => x1 ~ x2 } }
+
+ private def jsonValue[T](it: PickleIterator, kind: String)
+ (matcher: PartialFunction[JValue, T]): Result[T] =
+ if (it.hasNext && matcher.isDefinedAt(it.head)) Success(matcher(it.next()))
+ else errorExpected(kind+" value", it)
+
+ implicit def bigint: Pickler[BigInt] = new Pickler[BigInt] {
+ def pickle(x: BigInt): Pickled = JInteger(x)
+ def unpickle(it: PickleIterator): Result[BigInt] = jsonValue(it, "integer") { case JInteger(x) => x }
+ }
+
+ implicit def long: Pickler[Long] = new Pickler[Long] {
+ def pickle(x: Long): Pickled = JLong(x)
+ def unpickle(it: PickleIterator): Result[Long] = jsonValue(it, "long") { case JLong(x) => x }
+ }
+
+ implicit def double: Pickler[Double] = new Pickler[Double] {
+ def pickle(x: Double): Pickled = JDouble(x)
+ def unpickle(it: PickleIterator): Result[Double] = jsonValue(it, "double") { case JDouble(x) => x }
+ }
+
+ implicit def boolean: Pickler[Boolean] = new Pickler[Boolean] {
+ def pickle(x: Boolean): Pickled = if (x) JTrue else JFalse
+ def unpickle(it: PickleIterator): Result[Boolean] = jsonValue(it, "boolean") {
+ case JTrue => true
+ case JFalse => false
+ }
+ }
+
+ implicit def unit: Pickler[Unit] = new Pickler[Unit] {
+ def pickle(x: Unit): Pickled = JArray()
+ def unpickle(it: PickleIterator): Result[Unit] = Success(())
+ }
+
+ implicit def string: Pickler[String] = nullable {
+ new Pickler[String] {
+ def pickle(x: String): Pickled = JString(x)
+ def unpickle(it: PickleIterator): Result[String] = jsonValue(it, "string") { case JString(x) => x }
+ }
+ }
+
+ implicit def byte: Pickler[Byte] = long.wrapped { _.toByte } { _.toLong }
+ implicit def short: Pickler[Short] = long.wrapped { _.toShort } { _.toLong }
+ implicit def char: Pickler[Char] = long.wrapped { _.toChar } { _.toLong }
+ implicit def int: Pickler[Int] = long.wrapped { _.toInt } { _.toLong }
+ implicit def float: Pickler[Float] = double.wrapped { _.toFloat } { _.toLong }
+
+ implicit def tuple2[T1, T2](implicit p1: Pickler[T1], p2: Pickler[T2]): Pickler[(T1, T2)] =
+ (p1 ~ p2)
+ .wrapped { case x1 ~ x2 => (x1, x2) } { case (x1, x2) => x1 ~ x2 }
+ .labelled ("tuple2")
+
+ implicit def tuple3[T1, T2, T3](implicit p1: Pickler[T1], p2: Pickler[T2], p3: Pickler[T3]): Pickler[(T1, T2, T3)] =
+ (p1 ~ p2 ~ p3)
+ .wrapped { case x1 ~ x2 ~ x3 => (x1, x2, x3) } { case (x1, x2, x3) => x1 ~ x2 ~ x3 }
+ .labelled ("tuple3")
+
+ implicit def tuple4[T1, T2, T3, T4](implicit p1: Pickler[T1], p2: Pickler[T2], p3: Pickler[T3], p4: Pickler[T4]): Pickler[(T1, T2, T3, T4)] =
+ (p1 ~ p2 ~ p3 ~ p4)
+ .wrapped { case x1 ~ x2 ~ x3 ~ x4 => (x1, x2, x3, x4) } { case (x1, x2, x3, x4) => x1 ~ x2 ~ x3 ~ x4 }
+ .labelled ("tuple3")
+
+ implicit def none = obj(None)
+
+ implicit def some[T](implicit pt: Pickler[T]): CondPickler[Some[T]] =
+ pt.wrapped { Some(_) } { _.get }
+ .asClass (classOf[Some[T]])
+
+ implicit def option[T](implicit pt: Pickler[T]): Pickler[Option[T]] = none | some[T]
+
+ implicit def list[T](implicit pt: Pickler[T]): Pickler[List[T]] =
+ rep[T](pt).wrapped { _.toList } { x => x } .labelled ("scala.List")
+
+ implicit def vector[T](implicit pt: Pickler[T]): Pickler[Vector[T]] =
+ rep[T](pt).wrapped { Vector() ++ _ } { x => x } .labelled ("scala.Vector")
+
+ implicit def array[T](implicit ev: ClassManifest[T], pt: Pickler[T]): Pickler[Array[T]] =
+ rep[T](pt).wrapped { _.toArray} { _.toSeq } .labelled ("scala.Array")
+}
+
+abstract class CondPickler[T](val canPickle: Any => Boolean) extends Pickler[T] {
+ import Pickler._
+ def tryPickle(x: Any): Option[Pickled] =
+ if (canPickle(x)) Some(pickle(x.asInstanceOf[T])) else None
+ def | [V >: T, U <: V] (that: CondPickler[U]): CondPickler[V] =
+ either[V, T, U](this, that)
+}
+
+object Test extends Application {
+ import Pickler._
+ import scala.tools.nsc.io.JSON._
+ import java.io.{StringReader, StringWriter}
+
+ case class Foo(x: Int, y: String)
+
+ implicit lazy val foo: Pickler[Foo] =
+ nullable((int ~ string).wrapped { Foo.apply } { toTilde(Foo.unapply) } asClass classOf[Foo])
+
+ case class Rec(x: Int, r: Rec)
+
+ implicit lazy val rec: Pickler[Rec] =
+ nullable((int ~ rec).wrapped { Rec.apply } { toTilde(Rec.unapply) } asClass classOf[Rec])
+
+ abstract class L[+T]
+
+ case class Cons[T](head: T, tail: L[T]) extends L[T]
+ case object NIL extends L[Nothing]
+
+ implicit def cons[T: Pickler] =
+ (pkl[T] ~ pkl[L[T]])
+ .wrapped { case x ~ y => Cons(x, y) } { toTilde(Cons.unapply) } asClass classOf[Cons[T]]
+
+ implicit lazy val nil = obj(NIL)
+
+ implicit def l[T: Pickler]: Pickler[L[T]] = cons[T] | nil
+
+ implicit lazy val test = obj(Test)
+
+ implicit def anyThrowableInstance[T <: Throwable]: CondPickler[T] = anyJavaInstance[T] cond { _ => true }
+
+ def testRelaxed[T: Pickler](x: T): T = {
+ val sw = new PrettyWriter(new StringWriter())
+ val pickler = pkl[T]
+ val pickled = pickler pickle x
+ pickled.write(sw)
+ sw.close()
+ val s = sw.toString
+ println("pickled: "+s)
+ val sr = new JReader(new StringReader(s))
+ val r = pickler unpickle sr.iterator
+ println("unpickled: "+r)
+ val Success(y) = r
+ y
+ }
+
+ def test[T: Pickler](x: T) {
+ assert(testRelaxed(x) == x)
+ }
+
+ test(Foo(123, "abc"))
+ test(List(1, 2, 3))
+ test(Test)
+ test(Foo(1, null))
+ test(Rec(1, Rec(2, Rec(3, null))))
+ test(Cons(1, Cons(2, Cons(3, NIL))))
+ testRelaxed(new java.io.IOException)
+
+}
+
diff --git a/src/compiler/scala/tools/nsc/util/Replay.scala b/src/compiler/scala/tools/nsc/util/Replay.scala
new file mode 100644
index 0000000000..57e8ac0e78
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/util/Replay.scala
@@ -0,0 +1,59 @@
+package scala.tools.nsc.util
+
+import Pickler.{PickleIterator, valueIterator, Result, Success}
+import scala.tools.nsc.io.JSON._
+
+abstract class LogReplay {
+ def logreplay(event: String, x: => Boolean): Boolean
+ def logreplay[T](event: String, x: => Option[T])(implicit pt: Pickler[T]): Option[T]
+}
+
+class Logger(wr: java.io.Writer) extends LogReplay {
+ wr.write('{')
+ def logreplay(event: String, x: => Boolean) = {
+ if (x) (event J_: JNull) write wr
+ x
+ }
+ def logreplay[T](event: String, x: => Option[T])(implicit pt: Pickler[T]) = {
+ x match {
+ case Some(y) => (event J_: (pt pickle y)) write wr
+ case None =>
+ }
+ x
+ }
+ def close() {
+ wr.write('}')
+ wr.close()
+ }
+}
+
+object NullLogger extends LogReplay {
+ def logreplay(event: String, x: => Boolean) = x
+ def logreplay[T](event: String, x: => Option[T])(implicit pt: Pickler[T]) = x
+ def close() {}
+}
+
+class Replayer(log: java.io.Reader) extends LogReplay {
+ var rdr = new JReader(log)
+ val it: BufferedIterator[J_:] = rdr.nextValue() match {
+ case jo: JObject =>
+ jo.inputIterator
+ case _ =>
+ throw new MalformedInput(rdr, "no top-level object found")
+ }
+ def logreplay(event: String, x: => Boolean) = it.head match {
+ case `event` J_: _ => it.next(); true
+ case _ => false
+ }
+ def logreplay[T](event: String, x: => Option[T])(implicit pt: Pickler[T]) = it.head match {
+ case `event` J_: rhs =>
+ it.next()
+ val Success(result) = pt.unpickle(valueIterator(rhs))
+ Some(result)
+ case _ => None
+ }
+ def close() {
+ log.close()
+ }
+}
+
diff --git a/src/compiler/scala/tools/nsc/util/WorkScheduler.scala b/src/compiler/scala/tools/nsc/util/WorkScheduler.scala
index 17aa91b2a3..3822cc8e96 100644
--- a/src/compiler/scala/tools/nsc/util/WorkScheduler.scala
+++ b/src/compiler/scala/tools/nsc/util/WorkScheduler.scala
@@ -17,7 +17,7 @@ class WorkScheduler {
}
/** called from Server: test whether one of todo list, throwables, or InterruptReqs is nonempty */
- def moreWork(): Boolean = synchronized {
+ def moreWork: Boolean = synchronized {
todo.nonEmpty || throwables.nonEmpty || interruptReqs.nonEmpty
}
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index b741834cf1..5238a66f70 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -743,11 +743,11 @@ trait Iterator[+A] extends TraversableOnce[A] {
def hasNext =
hdDefined || self.hasNext
- def next =
+ def next() =
if (hdDefined) {
hdDefined = false
hd
- } else self.next
+ } else self.next()
}
/** A flexible iterator for transforming an `Iterator[A]` into an