<commit_before>package org.refptr.iscala

import java.io.File
import java.util.concurrent.locks.ReentrantLock

import scala.collection.mutable

import scala.tools.nsc.interpreter.{IMain,CommandLine,IR}
import scala.tools.nsc.util.Exceptional.unwrap
import scala.tools.nsc.util.ClassPath

import Util.{newThread,timer}

object Results {
    sealed trait Result
    sealed trait Success extends Result
    sealed trait Failure extends Result

    final case class Value(value: AnyRef, tpe: String) extends Success
    final case object NoValue extends Success

    final case class Exception(exception: Throwable) extends Failure
    final case object Error extends Failure
    final case object Incomplete extends Failure
    final case object Cancelled extends Failure
}

class Interpreter(classpath: String, args: Seq[String]) extends InterpreterCompatibility {
    protected val commandLine = new CommandLine(args.toList, println)

    private val _classpath: String = {
        val cp = commandLine.settings.classpath
        cp.value = ClassPath.join(cp.value, classpath)
        logger.debug(s"classpath: ${cp.value}")
        cp.value
    }

    val output = new java.io.StringWriter
    val printer = new java.io.PrintWriter(output)

    val intp: IMain = new IMain(settings, printer)

    private var _runner: Runner = _
    private var _session: Session = _

    private var _n: Int = _

    private var In: mutable.Map[Int, String] = _
    private var Out: mutable.Map[Int, Any] = _

    initVars()

    def runner = _runner
    def session = _session

    def n = _n

    private def initVars() {
        _runner = new Runner(intp.classLoader)
        _session = new Session
        _n = 0
        In = mutable.Map()
        Out = mutable.Map()
    }

    def reset() {
        finish()
        intp.reset()
        initVars()
    }

    def finish() {
        if (_session != null)
            _session.endSession(_n)
    }

    def resetOutput() { // TODO: this shouldn't be maintained externally
        output.getBuffer.setLength(0)
    }

    def nextInput(): Int = { _n += 1; _n }

    def storeInput(input: String) {
        In(n) = input
        session.addHistory(n, input)
    }

    def storeOutput(result: Results.Value, output: String) {
        Out(n) = result.value
        session.addOutputHistory(n, output)
        bind("_" + n, result.tpe, result.value)
    }

    def settings = commandLine.settings

    def classpath(paths: Seq[File]) {
        val cp = ClassPath.join(_classpath, Util.classpath(paths))
        settings.classpath.value = cp
    }

    def completion = new IScalaCompletion(intp)

    def interpret(line: String): Results.Result = interpret(line, false)

    def interpret(line: String, synthetic: Boolean): Results.Result = {
        import intp.Request

        def requestFromLine(line: String, synthetic: Boolean): Either[IR.Result, Request] = {
            // Dirty hack to call a private method IMain.requestFromLine
            val method = classOf[IMain].getDeclaredMethod("requestFromLine", classOf[String], classOf[Boolean])
            val args = Array(line, synthetic).map(_.asInstanceOf[AnyRef])
            method.setAccessible(true)
            method.invoke(intp, args: _*).asInstanceOf[Either[IR.Result, Request]]
        }

        import intp.memberHandlers.{MemberHandler,MemberDefHandler,ValHandler,DefHandler}

        def definesValue(handler: MemberHandler): Boolean = {
            // MemberHandler.definesValue has slightly different meaning from what is
            // needed in loadAndRunReq. We don't want to eagerly evaluate lazy vals
            // or 0-arity defs, so we handle those cases here.
            if (!handler.definesValue) {
                false
            } else {
                handler match {
                    case handler: ValHandler if handler.mods.isLazy => false
                    case handler: DefHandler                        => false
                    case _ => true
                }
            }
        }

        def loadAndRunReq(req: Request): Results.Result = {
            import intp.naming.sessionNames.{result,print}

            val hasValue = definesValue(req.handlers.last)
            val name = if (hasValue) result else print

            val outcome = try {
                runner.execute {
                    try {
                        val value = req.lineRep.call(name)
                        intp.recordRequest(req)

                        if (hasValue && value != null) {
                            val name = req.handlers.last match {
                                case handler: MemberDefHandler => handler.name
                                case _                         => intp.global.nme.NO_NAME
                            }
                            val tpe = req.lookupTypeOf(name)
                            Results.Value(value, tpe)
                        } else
                            Results.NoValue
                    } catch {
                        case exception: Throwable =>
                            req.lineRep.bindError(exception)
                            Results.Exception(unwrap(exception))
                    }
                } result()
            } finally {
                runner.clear()
            }

            outcome
        }

        if (intp.global == null) Results.Error
        else requestFromLine(line, synthetic) match {
            case Left(IR.Incomplete) => Results.Incomplete
            case Left(_) => Results.Error
            case Right(req)   =>
                // null indicates a disallowed statement type; otherwise compile
                // and fail if false (implying e.g. a type error)
                if (req == null || !req.compile) Results.Error
                else loadAndRunReq(req)
        }
    }

    def bind(name: String, boundType: String, value: Any, modifiers: List[String] = Nil): IR.Result = {
        val imports = (intp.definedTypes ++ intp.definedTerms) match {
            case Nil   => "/* imports */"
            case names => names.map(intp.originalPath(_)).map("import " + _).mkString("\n  ")
        }

        val bindRep = new intp.ReadEvalPrint()
        val source = s"""
            |object ${bindRep.evalName} {
            |  $imports
            |  var value: ${boundType} = _
            |  def set(x: Any) = value = x.asInstanceOf[${boundType}]
            |}
            """.stripMargin

        bindRep.compile(source)
        bindRep.callEither("set", value) match {
            case Right(_) =><commit_msg>Minor cleanup in Interpreter.interpret()<commit_after>package org.refptr.iscala

import java.io.File
import java.util.concurrent.locks.ReentrantLock

import scala.collection.mutable

import scala.tools.nsc.interpreter.{IMain,CommandLine,IR}
import scala.tools.nsc.util.Exceptional.unwrap
import scala.tools.nsc.util.ClassPath

import Util.{newThread,timer}

object Results {
    sealed trait Result
    sealed trait Success extends Result
    sealed trait Failure extends Result

    final case class Value(value: AnyRef, tpe: String) extends Success
    final case object NoValue extends Success

    final case class Exception(exception: Throwable) extends Failure
    final case object Error extends Failure
    final case object Incomplete extends Failure
    final case object Cancelled extends Failure
}

class Interpreter(classpath: String, args: Seq[String]) extends InterpreterCompatibility {
    protected val commandLine = new CommandLine(args.toList, println)

    private val _classpath: String = {
        val cp = commandLine.settings.classpath
        cp.value = ClassPath.join(cp.value, classpath)
        logger.debug(s"classpath: ${cp.value}")
        cp.value
    }

    val output = new java.io.StringWriter
    val printer = new java.io.PrintWriter(output)

    val intp: IMain = new IMain(settings, printer)

    private var _runner: Runner = _
    private var _session: Session = _

    private var _n: Int = _

    private var In: mutable.Map[Int, String] = _
    private var Out: mutable.Map[Int, Any] = _

    initVars()

    def runner = _runner
    def session = _session

    def n = _n

    private def initVars() {
        _runner = new Runner(intp.classLoader)
        _session = new Session
        _n = 0
        In = mutable.Map()
        Out = mutable.Map()
    }

    def reset() {
        finish()
        intp.reset()
        initVars()
    }

    def finish() {
        if (_session != null)
            _session.endSession(_n)
    }

    def resetOutput() { // TODO: this shouldn't be maintained externally
        output.getBuffer.setLength(0)
    }

    def nextInput(): Int = { _n += 1; _n }

    def storeInput(input: String) {
        In(n) = input
        session.addHistory(n, input)
    }

    def storeOutput(result: Results.Value, output: String) {
        Out(n) = result.value
        session.addOutputHistory(n, output)
        bind("_" + n, result.tpe, result.value)
    }

    def settings = commandLine.settings

    def classpath(paths: Seq[File]) {
        val cp = ClassPath.join(_classpath, Util.classpath(paths))
        settings.classpath.value = cp
    }

    def completion = new IScalaCompletion(intp)

    def interpret(line: String): Results.Result = interpret(line, false)

    def interpret(line: String, synthetic: Boolean): Results.Result = {
        import intp.Request

        def requestFromLine(line: String, synthetic: Boolean): Either[IR.Result, Request] = {
            // Dirty hack to call a private method IMain.requestFromLine
            val method = classOf[IMain].getDeclaredMethod("requestFromLine", classOf[String], classOf[Boolean])
            val args = Array(line, synthetic).map(_.asInstanceOf[AnyRef])
            method.setAccessible(true)
            method.invoke(intp, args: _*).asInstanceOf[Either[IR.Result, Request]]
        }

        import intp.memberHandlers.{MemberHandler,MemberDefHandler,ValHandler,DefHandler}

        def definesValue(handler: MemberHandler): Boolean = {
            // MemberHandler.definesValue has slightly different meaning from what is
            // needed in loadAndRunReq. We don't want to eagerly evaluate lazy vals
            // or 0-arity defs, so we handle those cases here.
            if (!handler.definesValue) {
                false
            } else {
                handler match {
                    case handler: ValHandler if handler.mods.isLazy => false
                    case handler: DefHandler                        => false
                    case _ => true
                }
            }
        }

        def loadAndRunReq(req: Request): Results.Result = {
            try {
                val hasValue = definesValue(req.handlers.last)
                runner.execute {
                    try {
                        val value = req.lineRep.call {
                            import intp.naming.{sessionNames=>names}
                            if (hasValue) names.result else names.print
                        }

                        intp.recordRequest(req)

                        if (hasValue && value != null) {
                            val name = req.handlers.last match {
                                case handler: MemberDefHandler => handler.name
                                case _                         => intp.global.nme.NO_NAME
                            }
                            val tpe = req.lookupTypeOf(name)
                            Results.Value(value, tpe)
                        } else
                            Results.NoValue
                    } catch {
                        case exception: Throwable =>
                            req.lineRep.bindError(exception)
                            Results.Exception(unwrap(exception))
                    }
                } result()
            } finally {
                runner.clear()
            }
        }

        requestFromLine(line, synthetic) match {
            case Left(IR.Incomplete) => Results.Incomplete
            case Left(_)             => Results.Error      // parse error
            case Right(req)          =>
                // null indicates a disallowed statement type; otherwise compile
                // and fail if false (implying e.g. a type error)
                if (req == null || !req.compile) Results.Error
                else loadAndRunReq(req)
        }
    }

    def bind(name: String, boundType: String, value: Any, modifiers: List[String] = Nil): IR.Result = {
        val imports = (intp.definedTypes ++ intp.definedTerms) match {
            case Nil   => "/* imports */"
            case names => names.map(intp.originalPath(_)).map("import " + _).mkString("\n  ")
        }

        val bindRep = new intp.ReadEvalPrint()
        val source = s"""
            |object ${bindRep.evalName} {
            |  $imports
            |  var value: ${boundType} = _
            |  def set(x: Any) = value = x.asInstanceOf[${boundType}]
            |}
            """.stripMargin

        bindRep.compile(source)
        bindRep.callEither("set", value) match {
            case Right(_) =>
{'fraction_non_alphanumeric': 0.09162681241934259, 'fraction_numerical': 0.000607302816366811, 'mean_word_length': 1.7572205943909585, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6119418', 'n_tokens_mistral': 3569, 'n_tokens_neox': 3440, 'n_words': 913}