summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2011-01-06 16:20:51 +0000
committerMartin Odersky <odersky@gmail.com>2011-01-06 16:20:51 +0000
commit715262fcfcefbb75788f287444c4791180e7eb67 (patch)
treeb9cca75f3a75423f843ada9e38656d88bfda6068
parent0b5c9ca6535b38dbfc958d92cfce691aa6de205f (diff)
downloadscala-715262fcfcefbb75788f287444c4791180e7eb67.tar.gz
scala-715262fcfcefbb75788f287444c4791180e7eb67.tar.bz2
scala-715262fcfcefbb75788f287444c4791180e7eb67.zip
Replay now enabled for presentation compiler.
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala30
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Picklers.scala17
-rw-r--r--src/compiler/scala/tools/nsc/interactive/REPL.scala1
-rw-r--r--src/compiler/scala/tools/nsc/io/JSON.scala512
-rw-r--r--src/compiler/scala/tools/nsc/io/Lexer.scala203
-rw-r--r--src/compiler/scala/tools/nsc/io/Pickler.scala320
-rw-r--r--src/compiler/scala/tools/nsc/io/PrettyWriter.scala41
-rw-r--r--src/compiler/scala/tools/nsc/io/Replay.scala74
-rw-r--r--src/compiler/scala/tools/nsc/util/Pickler.scala316
-rw-r--r--src/compiler/scala/tools/nsc/util/Replayer.scala59
10 files changed, 666 insertions, 907 deletions
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 48ddf7d5f6..b3a56278c4 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -7,13 +7,12 @@ 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, LogReplay, Logger, Replayer, NullLogger}
+import scala.tools.nsc.io.{AbstractFile, LogReplay, Logger, NullLogger, Replayer}
+import scala.tools.nsc.util.{SourceFile, Position, RangePosition, NoPosition, WorkScheduler}
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._
+import scala.tools.nsc.io.Pickler._
/** The main class of the presentation compiler in an interactive environment such as an IDE
*/
@@ -34,14 +33,13 @@ self =>
private def replayName = settings.YpresentationReplay.value
private def logName = settings.YpresentationLog.value
- lazy val log =
+ val log =
if (replayName != "") new Replayer(new FileReader(replayName))
else if (logName != "") new Logger(new FileWriter(logName))
else NullLogger
-// import log.logreplay
+ 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) =
@@ -120,6 +118,7 @@ self =>
} catch {
case ex : Throwable =>
if (context.unit != null) integrateNew()
+ log.flush()
throw ex
}
if (typerRun == currentTyperRun)
@@ -201,12 +200,13 @@ self =>
}
def nodeWithWork(): Option[Int] = {
- nodesSeen += 1
if (scheduler.moreWork || pendingResponse.isCancelled) Some(nodesSeen) else None
}
+ nodesSeen += 1
logreplay("atnode", nodeWithWork()) match {
case Some(id) =>
+ debugLog("some work at node "+id+" current = "+nodesSeen)
assert(id >= nodesSeen)
moreWorkAtNode = id
case None =>
@@ -224,7 +224,7 @@ self =>
minRunId = currentRunId
if (outOfDate) throw ex
else outOfDate = true
- case Some(ex: Throwable) => throw ex
+ case Some(ex: Throwable) => log.flush(); throw ex
case _ =>
}
logreplay("workitem", scheduler.nextWorkItem()) match {
@@ -237,6 +237,7 @@ self =>
debugLog("quitting work item: "+action)
}
case None =>
+ debugLog("no work found")
}
}
}
@@ -288,10 +289,12 @@ self =>
*/
def newRunnerThread: Thread = new Thread("Scala Presentation Compiler V"+threadId) {
override def run() {
+ debugLog("starting new runner thread")
try {
while (true) {
- scheduler.waitForMoreWork()
+ logreplay("wait for more work", { scheduler.waitForMoreWork(); true })
pollForWork()
+ debugLog("got more work")
while (outOfDate) {
try {
backgroundCompile()
@@ -299,12 +302,15 @@ self =>
} catch {
case FreshRunReq =>
}
+ log.flush()
}
}
} catch {
- case ShutdownReq =>
- ;
+ case ex @ ShutdownReq =>
+ debugLog("exiting presentation compiler")
+ log.close()
case ex =>
+ log.flush()
outOfDate = false
compileRunner = newRunnerThread
compileRunner.start()
diff --git a/src/compiler/scala/tools/nsc/interactive/Picklers.scala b/src/compiler/scala/tools/nsc/interactive/Picklers.scala
index 79b1921642..45134fca6d 100644
--- a/src/compiler/scala/tools/nsc/interactive/Picklers.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Picklers.scala
@@ -4,16 +4,17 @@ package interactive
import util.{SourceFile, BatchSourceFile}
import io.{AbstractFile, PlainFile}
-import util.{Pickler, CondPickler, Position, RangePosition, NoPosition, OffsetPosition, TransparentPosition}
-import util.Pickler._
+import util.{Position, RangePosition, NoPosition, OffsetPosition, TransparentPosition}
+import io.{Pickler, CondPickler}
+import io.Pickler._
import collection.mutable
trait Picklers { self: Global =>
- lazy val freshRunReq = obj(FreshRunReq)
- lazy val shutdownReq = obj(ShutdownReq)
+ lazy val freshRunReq = singletonPickler(FreshRunReq)
+ lazy val shutdownReq = singletonPickler(ShutdownReq)
- def defaultThrowable[T <: Throwable]: CondPickler[T] = anyJavaInstance[T] cond { _ => true }
+ def defaultThrowable[T <: Throwable]: CondPickler[T] = javaInstancePickler[T] cond { _ => true }
implicit lazy val throwable: Pickler[Throwable] =
freshRunReq | shutdownReq | defaultThrowable
@@ -27,7 +28,7 @@ trait Picklers { self: Global =>
override def default(key: AbstractFile) = Array()
}
- type Diff = (Int /*start*/, Int /*end*/, Array[Char] /*replacement*/)
+ type Diff = (Int /*start*/, Int /*end*/, String /*replacement*/)
def delta(f: AbstractFile, cs: Array[Char]): Diff = {
val bs = sourceFilesSeen(f)
@@ -37,7 +38,7 @@ trait Picklers { self: Global =>
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))
+ (start, end, cs.slice(start, end2).mkString(""))
}
def patch(f: AbstractFile, d: Diff): Array[Char] = {
@@ -69,7 +70,7 @@ trait Picklers { self: Global =>
.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)
+ lazy val noPosition = singletonPickler(NoPosition)
implicit lazy val position: Pickler[Position] = transparentPosition | rangePosition | offsetPosition | noPosition
diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala
index 834747c547..47807ccdac 100644
--- a/src/compiler/scala/tools/nsc/interactive/REPL.scala
+++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala
@@ -124,6 +124,7 @@ object REPL {
case List("complete", file, off1) =>
doComplete(makePos(file, off1, off1))
case List("quit") =>
+ comp.askShutdown()
system.exit(1)
case _ =>
println("unrecongized command")
diff --git a/src/compiler/scala/tools/nsc/io/JSON.scala b/src/compiler/scala/tools/nsc/io/JSON.scala
deleted file mode 100644
index c4584f762a..0000000000
--- a/src/compiler/scala/tools/nsc/io/JSON.scala
+++ /dev/null
@@ -1,512 +0,0 @@
-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/io/Lexer.scala b/src/compiler/scala/tools/nsc/io/Lexer.scala
new file mode 100644
index 0000000000..dd0e826351
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/Lexer.scala
@@ -0,0 +1,203 @@
+package scala.tools.nsc.io
+
+import java.io.{Reader, Writer, StringReader, StringWriter}
+import scala.collection.mutable.{Buffer, ArrayBuffer}
+import scala.math.BigInt
+
+object Lexer {
+
+ class MalformedInput(val rdr: Lexer, val msg: String) extends Exception("Malformed JSON input at "+rdr.tokenPos+": "+msg)
+
+ class Token(val str: String) {
+ override def toString = str
+ }
+
+ case class Delim(char: Char) extends Token("'"+char.toString+"'")
+ case class IntLit(override val str: String) extends Token(str)
+ case class FloatLit(override val str: String) extends Token(str)
+ case class StringLit(override val str: String) extends Token(str) {
+ override def toString = quoted(str)
+ }
+
+ val TrueLit = new Token("true")
+ val FalseLit = new Token("false")
+ val NullLit = new Token("null")
+ val LParen = new Delim('(')
+ val RParen = new Delim(')')
+ val LBrace = new Delim('{')
+ val RBrace = new Delim('}')
+ val LBracket = new Delim('[')
+ val RBracket = new Delim(']')
+ val Comma = new Delim(',')
+ val Colon = new Delim(':')
+ val EOF = new Token("<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 Lexer._
+
+class Lexer(rd: Reader) {
+
+ var ch: Char = 0
+ var pos: Long = 0
+ var token: Token = _
+ 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() {
+ assert(!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 = LParen
+ case ')' => putChar(); token = RParen
+ 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 = TrueLit
+ case 'f' => putAcceptString("false"); token = FalseLit
+ case 'n' => putAcceptString("null"); token = NullLit
+ case '"' => getString()
+ case '-' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => getNumber()
+ case _ => error("illegal string literal character: '"+ch+"'")
+ }
+ println("["+token+"]")
+ }
+
+ 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 = StringLit(sb.toString)
+ }
+
+ def getNumber() {
+ def digit() =
+ if ('0' <= ch && ch <= '9') putChar()
+ else error("<digit> expected")
+ def digits() =
+ do { digit() } while ('0' <= ch && ch <= '9')
+ var isFloating = false
+ if (ch == '-') putChar()
+ if (ch == '0') digit()
+ else digits()
+ if (ch == '.') {
+ isFloating = true
+ putChar()
+ digits()
+ }
+ if (ch == 'e' || ch == 'E') {
+ isFloating = true
+ putChar()
+ if (ch == '+' || ch == '-') putChar()
+ digits()
+ }
+ token = if (isFloating) FloatLit(sb.toString) else IntLit(sb.toString)
+ }
+
+ def accept(t: Token) {
+ if (token == t) nextToken()
+ else error(t+" expected, but "+token+" found")
+ }
+
+ def accept(ch: Char) {
+ token match {
+ case Delim(`ch`) => nextToken()
+ case _ => accept(Delim(ch))
+ }
+ }
+
+ def error(msg: String) = throw new MalformedInput(this, msg)
+
+ nextChar()
+ nextToken()
+}
diff --git a/src/compiler/scala/tools/nsc/io/Pickler.scala b/src/compiler/scala/tools/nsc/io/Pickler.scala
new file mode 100644
index 0000000000..e57e513132
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/Pickler.scala
@@ -0,0 +1,320 @@
+package scala.tools.nsc.io
+
+import annotation.unchecked
+import Lexer._
+import java.io.Writer
+
+abstract class Pickler[T] {
+
+ import Pickler._
+
+ def pickle(wr: Writer, x: T)
+ def unpickle(rd: Lexer): Unpickled[T]
+
+ def ~ [U] (that: => Pickler[U]): Pickler[T ~ U] = seqPickler(this, that)
+
+ def labelled(label: String): Pickler[T] = labelledPickler(label, this)
+ def wrapped [U] (in: T => U)(out: U => T): Pickler[U] = wrappedPickler(this)(in)(out)
+ def orNull(implicit fromNull: Null <:< T): Pickler[T] = nullablePickler(this)
+ def cond(p: Any => Boolean): CondPickler[T] = conditionalPickler(this, p)
+ def asClass[U <: T](c: Class[U]): CondPickler[T] = this.labelled(c.getName).cond(c isInstance _)
+}
+
+object Pickler {
+
+ var picklerDebugMode = false
+
+ abstract class Unpickled[+T] {
+ def map[U](f: T => U): Unpickled[U] = this match {
+ case UnpickleSuccess(x) => UnpickleSuccess(f(x))
+ case f: UnpickleFailure => f
+ }
+ def flatMap[U](f: T => Unpickled[U]): Unpickled[U] = this match {
+ case UnpickleSuccess(x) => f(x)
+ case f: UnpickleFailure => f
+ }
+ def orElse[U >: T](alt: => Unpickled[U]): Unpickled[U] = this match {
+ case UnpickleSuccess(x) => this
+ case f: UnpickleFailure => alt
+ }
+ def requireSuccess: UnpickleSuccess[T] = this match {
+ case s @ UnpickleSuccess(x) => s
+ case f: UnpickleFailure => throw new Error("Unrecoverable unpickle failure:\n"+f)
+ }
+ }
+
+ case class UnpickleSuccess[+T](result: T) extends Unpickled[T]
+
+ class UnpickleFailure(msg: => String, rd: Lexer) extends Unpickled[Nothing] {
+ override def toString = "Failure at "+rd.tokenPos+":\n"+msg
+ }
+
+ private def errorExpected(rd: Lexer, msg: => String) =
+ new UnpickleFailure("expected: "+msg+"\n" +
+ "found : "+rd.token,
+ rd)
+
+ private def nextSuccess[T](rd: Lexer, result: T) = {
+ rd.nextToken()
+ UnpickleSuccess(result)
+ }
+
+ def pkl[T: Pickler] = implicitly[Pickler[T]]
+
+ 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 } }
+
+ def labelledPickler[T](label: String, p: Pickler[T]): Pickler[T] = new Pickler[T] {
+ def pickle(wr: Writer, x: T) = {
+ wr.write(quoted(label));
+ wr.write("(")
+ p.pickle(wr, x)
+ wr.write(")")
+ }
+ def unpickle(rd: Lexer): Unpickled[T] =
+ rd.token match {
+ case StringLit(`label`) =>
+ rd.nextToken()
+ rd.accept('(')
+ val result = p.unpickle(rd).requireSuccess
+ rd.accept(')')
+ result
+ case _ =>
+ errorExpected(rd, quoted(label)+"(...)")
+ }
+ }
+
+ def wrappedPickler[S, T](p: Pickler[S])(in: S => T)(out: T => S) = new Pickler[T] {
+ def pickle(wr: Writer, x: T) = p.pickle(wr, out(x))
+ def unpickle(rd: Lexer) = p.unpickle(rd) map in
+ }
+
+ def conditionalPickler[T](p: Pickler[T], cond: Any => Boolean) = new CondPickler[T](cond) {
+ def pickle(wr: Writer, x: T) = p.pickle(wr, x)
+ def unpickle(rd: Lexer) = p.unpickle(rd)
+ }
+
+ def seqPickler[T, U](p: Pickler[T], q: => Pickler[U]) = new Pickler[T ~ U] {
+ lazy val qq = q
+ def pickle(wr: Writer, x: T ~ U) = {
+ p.pickle(wr, x.fst)
+ wr.write(',')
+ q.pickle(wr, x.snd)
+ }
+ def unpickle(rd: Lexer) =
+ for (x <- p.unpickle(rd); y <- { rd.accept(','); qq.unpickle(rd).requireSuccess })
+ yield x ~ y
+ }
+
+ def eitherPickler[T, U <: T, V <: T](p: CondPickler[U], q: => CondPickler[V]) =
+ new CondPickler[T](x => p.canPickle(x) || q.canPickle(x)) {
+ lazy val qq = q
+ override def tryPickle(wr: Writer, x: Any): Boolean =
+ p.tryPickle(wr, x) || qq.tryPickle(wr, x)
+ def pickle(wr: Writer, x: T) =
+ require(tryPickle(wr, x),
+ "no pickler found for "+x+" of class "+x.asInstanceOf[AnyRef].getClass.getName)
+ def unpickle(rd: Lexer) = p.unpickle(rd) orElse qq.unpickle(rd)
+ }
+
+ def singletonPickler[T <: AnyRef](x: T): CondPickler[T] =
+ unitPickler
+ .wrapped { _ => x } { x => () }
+ .labelled (x.getClass.getName)
+ .cond (x eq _.asInstanceOf[AnyRef])
+
+ def nullablePickler[T](p: Pickler[T])(implicit fromNull: Null <:< T): Pickler[T] = new Pickler[T] {
+ def pickle(wr: Writer, x: T) =
+ if (x == null) wr.write("null") else p.pickle(wr, x)
+ def unpickle(rd: Lexer): Unpickled[T] =
+ if (rd.token == NullLit) nextSuccess(rd, fromNull(null))
+ else p.unpickle(rd)
+ }
+
+ def javaInstancePickler[T <: AnyRef]: Pickler[T] =
+ (stringPickler labelled "$new")
+ .wrapped { name => Class.forName(name).newInstance().asInstanceOf[T] } { _.getClass.getName }
+
+ implicit def iterPickler[T: Pickler]: Pickler[Iterator[T]] = new Pickler[Iterator[T]] {
+ lazy val p = pkl[T]
+ def pickle(wr: Writer, xs: Iterator[T]) {
+ var first = true
+ for (x <- xs) {
+ if (first) first = false else wr.write(',')
+ p.pickle(wr, x)
+ }
+ }
+ def unpickle(rd: Lexer): Unpickled[Iterator[T]] = UnpickleSuccess(new Iterator[T] {
+ var first = true
+ def hasNext = {
+ val t = rd.token
+ t != EOF && t != RParen && t != RBrace && t != RBracket
+ }
+ def next(): T = {
+ if (first) first = false else rd.accept(',')
+ p.unpickle(rd).requireSuccess.result
+ }
+ })
+ }
+
+ private def tokenPickler[T](kind: String)(matcher: PartialFunction[Token, T]) = new Pickler[T] {
+ def pickle(wr: Writer, x: T) = wr.write(x.toString)
+ def unpickle(rd: Lexer) =
+ if (matcher isDefinedAt rd.token) nextSuccess(rd, matcher(rd.token))
+ else errorExpected(rd, kind)
+ }
+
+ implicit val longPickler: Pickler[Long] =
+ tokenPickler("integer literal") { case IntLit(s) => s.toLong }
+ implicit val doublePickler: Pickler[Double] =
+ tokenPickler("floating point literal") { case FloatLit(s) => s.toDouble }
+
+ implicit val bytePickler: Pickler[Byte] = longPickler.wrapped { _.toByte } { _.toLong }
+ implicit val shortPickler: Pickler[Short] = longPickler.wrapped { _.toShort } { _.toLong }
+ implicit val intPickler: Pickler[Int] = longPickler.wrapped { _.toInt } { _.toLong }
+ implicit val floatPickler: Pickler[Float] = doublePickler.wrapped { _.toFloat } { _.toLong }
+
+ private val truePickler =
+ tokenPickler("boolean literal") { case TrueLit => true } cond { _ == true }
+ private val falsePickler =
+ tokenPickler("boolean literal") { case FalseLit => false } cond { _ == false }
+
+ implicit def booleanPickler: Pickler[Boolean] = truePickler | falsePickler
+
+ implicit val unitPickler: Pickler[Unit] = new Pickler[Unit] {
+ def pickle(wr: Writer, x: Unit) {}
+ def unpickle(rd: Lexer): Unpickled[Unit] = UnpickleSuccess(())
+ }
+
+ implicit val stringPickler: Pickler[String] = new Pickler[String] {
+ def pickle(wr: Writer, x: String) = wr.write(if (x == null) "null" else quoted(x))
+ def unpickle(rd: Lexer) = rd.token match {
+ case StringLit(s) => nextSuccess(rd, s)
+ case NullLit => nextSuccess(rd, null)
+ case _ => errorExpected(rd, "string literal")
+ }
+ }
+
+ implicit val charPickler: Pickler[Char] =
+ stringPickler
+ .wrapped { s => require(s.length == 1, "single character string literal expected, but "+quoted(s)+" found"); s(0) } { _.toString }
+
+ implicit def tuple2Pickler[T1: Pickler, T2: Pickler]: Pickler[(T1, T2)] =
+ (pkl[T1] ~ pkl[T2])
+ .wrapped { case x1 ~ x2 => (x1, x2) } { case (x1, x2) => x1 ~ x2 }
+ .labelled ("tuple2")
+
+ implicit def tuple3Pickler[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 tuple4Pickler[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 ("tuple4")
+
+ implicit val nonePickler = singletonPickler(None)
+
+ implicit def somePickler[T: Pickler]: CondPickler[Some[T]] =
+ pkl[T]
+ .wrapped { Some(_) } { _.get }
+ .asClass (classOf[Some[T]])
+
+ implicit def optionPickler[T: Pickler]: Pickler[Option[T]] = nonePickler | somePickler[T]
+
+ implicit def listPickler[T: Pickler]: Pickler[List[T]] =
+ iterPickler[T] .wrapped { _.toList } { _.iterator } .labelled ("scala.List")
+
+ implicit def vectorPickler[T: Pickler]: Pickler[Vector[T]] =
+ iterPickler[T] .wrapped { Vector() ++ _ } { _.iterator } .labelled ("scala.Vector")
+
+ implicit def array[T : ClassManifest : Pickler]: Pickler[Array[T]] =
+ iterPickler[T] .wrapped { _.toArray} { _.iterator } .labelled ("scala.Array")
+}
+
+abstract class CondPickler[T](val canPickle: Any => Boolean) extends Pickler[T] {
+ import Pickler._
+ def tryPickle(wr: Writer, x: Any): Boolean = {
+ val result = canPickle(x)
+ if (result) pickle(wr, x.asInstanceOf[T])
+ result
+ }
+ def | [V >: T, U <: V] (that: => CondPickler[U]): CondPickler[V] =
+ eitherPickler[V, T, U](this, that)
+}
+
+object Test extends Application {
+ import Pickler._
+ import java.io.{StringReader, StringWriter}
+
+ case class Foo(x: Int, y: String)
+
+ implicit val fooPickler: Pickler[Foo] =
+ (pkl[Int] ~ pkl[String])
+ .wrapped { Foo.apply } { toTilde(Foo.unapply) }
+ .asClass (classOf[Foo])
+
+ case class Rec(x: Int, r: Rec)
+
+ implicit val recPickler: Pickler[Rec] =
+ (pkl[Int] ~ pkl[Rec])
+ .wrapped { Rec.apply } { toTilde(Rec.unapply) }
+ .asClass (classOf[Rec])
+ .orNull
+
+ abstract class L[+T]
+
+ case class Cons[T](head: T, tail: L[T]) extends L[T]
+ case object NIL extends L[Nothing]
+
+ implicit def consPickler[T: Pickler] =
+ (pkl[T] ~ pkl[L[T]])
+ .wrapped { case x ~ y => Cons(x, y) } { toTilde(Cons.unapply) }
+ .asClass (classOf[Cons[T]])
+
+ implicit lazy val nilPickler = singletonPickler(NIL)
+
+ implicit def lPickler[T: Pickler]: Pickler[L[T]] = consPickler[T] | nilPickler
+
+ implicit lazy val testPickler = singletonPickler(Test)
+
+ implicit def anyThrowableInstance[T <: Throwable]: CondPickler[T] = javaInstancePickler[T] cond { _ => true }
+
+ def testRelaxed[T: Pickler](x: T): T = {
+ val sw = new PrettyWriter(new StringWriter())
+ val pickler = pkl[T]
+ val pickled = pickler.pickle(sw, x)
+ sw.close()
+ val s = sw.toString
+ println("pickled: "+s)
+ val sr = new Lexer(new StringReader(s))
+ val r = pickler.unpickle(sr)
+ println("unpickled: "+r)
+ val UnpickleSuccess(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/io/PrettyWriter.scala b/src/compiler/scala/tools/nsc/io/PrettyWriter.scala
new file mode 100644
index 0000000000..acd4847469
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/PrettyWriter.scala
@@ -0,0 +1,41 @@
+package scala.tools.nsc.io
+
+import java.io.Writer
+
+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
+}
diff --git a/src/compiler/scala/tools/nsc/io/Replay.scala b/src/compiler/scala/tools/nsc/io/Replay.scala
new file mode 100644
index 0000000000..5cb61b6cb1
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/Replay.scala
@@ -0,0 +1,74 @@
+package scala.tools.nsc.io
+
+import java.io.{Reader, Writer}
+
+import Pickler._
+import Lexer.{Token, EOF}
+
+abstract class LogReplay {
+ def logreplay(event: String, x: => Boolean): Boolean
+ def logreplay[T: Pickler](event: String, x: => Option[T]): Option[T]
+ def close()
+ def flush()
+}
+
+class Logger(wr0: Writer) extends LogReplay {
+ val wr = new PrettyWriter(wr0)
+ private var first = true
+ private def insertComma() = if (first) first = false else wr.write(",")
+
+ def logreplay(event: String, x: => Boolean) = {
+ val xx = x
+ if (xx) { insertComma(); pkl[Unit].labelled(event).pickle(wr, ()) }
+ xx
+ }
+ def logreplay[T: Pickler](event: String, x: => Option[T]) = {
+ val xx = x
+ xx match {
+ case Some(y) => insertComma(); pkl[T].labelled(event).pickle(wr, y)
+ case None =>
+ }
+ xx
+ }
+ def close() { wr.close() }
+ def flush() { wr.flush() }
+}
+
+object NullLogger extends LogReplay {
+ def logreplay(event: String, x: => Boolean) = x
+ def logreplay[T: Pickler](event: String, x: => Option[T]) = x
+ def close() {}
+ def flush() {}
+}
+
+class Replayer(raw: Reader) extends LogReplay {
+ private val rd = new Lexer(raw)
+ private var nextComma = false
+
+ private def eatComma() =
+ if (nextComma) { rd.accept(','); nextComma = false }
+
+ def logreplay(event: String, x: => Boolean) =
+ if (rd.token == EOF) NullLogger.logreplay(event, x)
+ else {
+ eatComma()
+ pkl[Unit].labelled(event).unpickle(rd) match {
+ case UnpickleSuccess(_) => nextComma = true; true
+ case _ => false
+ }
+ }
+
+ def logreplay[T: Pickler](event: String, x: => Option[T]) =
+ if (rd.token == EOF) NullLogger.logreplay(event, x)
+ else {
+ eatComma()
+ pkl[T].labelled(event).unpickle(rd) match {
+ case UnpickleSuccess(y) => nextComma = true; Some(y)
+ case _ => None
+ }
+ }
+
+ def close() { raw.close() }
+ def flush() {}
+}
+
diff --git a/src/compiler/scala/tools/nsc/util/Pickler.scala b/src/compiler/scala/tools/nsc/util/Pickler.scala
deleted file mode 100644
index ef9fcb4c92..0000000000
--- a/src/compiler/scala/tools/nsc/util/Pickler.scala
+++ /dev/null
@@ -1,316 +0,0 @@
-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/Replayer.scala b/src/compiler/scala/tools/nsc/util/Replayer.scala
deleted file mode 100644
index 57e8ac0e78..0000000000
--- a/src/compiler/scala/tools/nsc/util/Replayer.scala
+++ /dev/null
@@ -1,59 +0,0 @@
-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()
- }
-}
-