All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.reactors.debugger.repl.ScalaRepl.scala Maven / Gradle / Ivy

package io.reactors
package debugger
package repl



import io.reactors.common.TransferQueue
import java.io.BufferedReader
import java.io.PrintStream
import java.io.PrintWriter
import java.io.StringReader
import java.io.StringWriter
import java.util.concurrent.locks.ReentrantLock
import scala.collection._
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.tools.nsc.Settings
import scala.tools.nsc.interpreter._



class ScalaRepl(val system: ReactorSystem) extends Repl {
  private val monitor = system.monitor
  private val lock = new ReentrantLock
  private val startedPromise = Promise[Boolean]()
  private val pendingOutputQueue = new TransferQueue[String](monitor)
  private val commandQueue = new TransferQueue[String](monitor)
  private val outputQueue = new TransferQueue[Repl.Result](monitor)
  class ExtractableWriter {
    val localStringWriter = new StringWriter
    val localPrintWriter = new PrintWriter(localStringWriter)
    def extractPending(): String = {
      val sb = new StringBuilder
      var first = true
      while (!pendingOutputQueue.isEmpty) {
        if (first) first = false else sb.append("\n")
        sb.append(pendingOutputQueue.waitUntilDequeue())
      }
      sb.toString
    }
    def extract(): String = {
      var output = localStringWriter.getBuffer.toString
      localStringWriter.getBuffer.setLength(0)
      output = output.split("\n")
        .map(_.replaceFirst("scala> ", ""))
        .filter(_ != "     | ")
        .filter(_.trim() != "")
        .mkString("\n")
      val pendingOutput = extractPending()
      pendingOutput + output
    }
  }
  private val extractableWriter = new ExtractableWriter
  class QueueReader extends BufferedReader(new StringReader("")) {
    var continueMode = false
    override def readLine() = {
      if (continueMode) outputQueue.enqueue(
        Repl.Result(0, extractableWriter.extract(), "     | ", true))
      val line = commandQueue.waitUntilDequeue()
      if (line == null) {
        line
      } else if (line == "\u0004") {
        if (continueMode) null
        else {
          pendingOutputQueue.enqueue("scala> ")
          ""
        }
      } else if (line.contains('\u0004')) {
        line.takeWhile(_ != '\u0004')
      } else {
        line
      }
    }
  }
  private val queueReader = new QueueReader
  private val repl = new ILoop(Some(queueReader), extractableWriter.localPrintWriter) {
    private def pendingPrintln(x: Any) {
      System.out.println(x)
      pendingOutputQueue.enqueue(x.toString)
    }
    override def createInterpreter() {
      super.createInterpreter()
      intp.beQuietDuring {
        intp.bind("system", "io.reactors.ReactorSystem", system)
        intp.bind("println", "Any => Unit", (x: Any) => pendingPrintln(x))
      }
    }
    override def processLine(line: String): Boolean = {
      val res = try {
        queueReader.continueMode = true
        super.processLine(line)
      } finally {
        queueReader.continueMode = false
      }
      val output = extractableWriter.extract()
      if (!startedPromise.isCompleted) {
        pendingOutputQueue.enqueue(output)
        startedPromise.trySuccess(true)
      } else {
        outputQueue.enqueue(Repl.Result(0, output, "scala> ", false))
      }
      res
    }
  }
  private val replThread = new Thread(s"reactors-io.${system.name}.repl-thread") {
    setDaemon(true)
    override def run() {
      try {
        val settings = new Settings
        settings.Yreplsync.value = true
        settings.usejavacp.value = true
        repl.process(settings)
      } catch {
        case t: Throwable =>
          t.printStackTrace()
          throw t
      }
    }
  }

  {
    // Add import command, which also triggers output of splash message.
    commandQueue.enqueue("import io.reactors._")
    // Start REPL thread.
    replThread.start()
  }

  def tpe = "Scala"

  def started = startedPromise.future

  def eval(cmd: String) = Future {
    lock.lock()
    try {
      monitor.synchronized {
        commandQueue.enqueue(cmd)
        val result = outputQueue.waitUntilDequeue()
        result
      }
    } finally {
      lock.unlock()
    }
  }

  def log(x: Any) = {
    pendingOutputQueue.enqueue(x.toString)
  }

  def flush(): String = {
    monitor.synchronized {
      val lines = mutable.Buffer[String]()
      while (!pendingOutputQueue.isEmpty)  {
        lines += pendingOutputQueue.waitUntilDequeue()
      }
      lines.mkString("\n")
    }
  }

  def shutdown() {
    lock.lock()
    monitor.synchronized {
      commandQueue.enqueue(null)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy