Встроенный Scala REPL Пример интерпретатора для 2.10

Пожалуйста, дайте пример кода о том, как программно создавать встроенный интерпретатор Scala REPL, который работает в Scala 2.10. (Я добавил этот Q & A, проведя часы, расчесывая различные фрагменты кода, чтобы получить рабочий интерпретатор)

Ответы

Ответ 1

Пример Repl.scala:

import scala.tools.nsc.interpreter._
import scala.tools.nsc.Settings


object Repl extends App {
  def repl = new ILoop {
    override def loop(): Unit = {
      intp.bind("e", "Double", 2.71828)
      super.loop()
    }
  }

  val settings = new Settings
  settings.Yreplsync.value = true


  //use when launching normally outside SBT
  settings.usejavacp.value = true      

  //an alternative to 'usejavacp' setting, when launching from within SBT
  //settings.embeddedDefaults[Repl.type]

  repl.process(settings)
}

Некоторые примечания

  • Я хочу показать JLineReader (по умолчанию), а не SimpleReader, потому что он работает намного лучше, правильно обрабатывает клавиши со стрелками, удаляет и т.д. JLine добавляет зависимость jar.
  • В этом примере показано, как связывать значения в repl (переменная e выше).
  • Когда я опускаю settings.Yreplsync.value = true, REPL зависает и бесполезен.
  • Из моего тестирования, если оба параметра usejavacp и embeddedDefaults объединены вместе, ошибка показывает

Я считаю, что это проще всего протестировать через SBT; образец build.sbt:

name := "Repl"

organization := "ExamplesRUs"

scalaVersion := "2.10.2"

libraryDependencies ++= Seq(
 "org.scala-lang" % "scala-compiler" % "2.10.2",
 "org.scala-lang" % "jline" % "2.10.2"
)

Пример сеанса SBT:

> run-main Repl
[info] Running Repl
Welcome to Scala version 2.10.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).
Type in expressions to have them evaluated.
Type :help for more information.
e: Double = 2.71828

scala> 2 * e
res1: Double = 5.43656

scala>

Ответ 2

Основываясь на замечательном ответе Бен, ниже приведен вспомогательный класс, чтобы облегчить запуск интерпретатора. Использование:

Repl.run(("e", "Double", 2.71828), ("pi", "Double", 3.1415))

Он автоматически определяет, когда вы работаете из SBT и вмещает.

Repl.scala:

import scala.tools.nsc.interpreter.ILoop
import scala.tools.nsc.Settings
import java.io.CharArrayWriter
import java.io.PrintWriter

object Repl {

  def run(params: (String, String, Any)*) {

    def repl = new ILoop {
      override def loop(): Unit = {
        params.foreach(p => intp.bind(p._1, p._2, p._3))
        super.loop()
      }
    }

    val settings = new Settings
    settings.Yreplsync.value = true

    // Different settings needed when running from SBT or normally
    if (isRunFromSBT) {
      settings.embeddedDefaults[Repl.type]
    } else {
      settings.usejavacp.value = true
    }

    repl.process(settings)
  }

  def isRunFromSBT = {
    val c = new CharArrayWriter()
    new Exception().printStackTrace(new PrintWriter(c))
    c.toString().contains("at sbt.")
  }

}