Please give a code example of how to create an embedded Scala REPL interpreter programmatically, that works in Scala 2.10. (I added this Q&A after spending hours combing various code scraps to get a working interpreter)
Asked
Active
Viewed 4,136 times
2 Answers
23
Example 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)
}
Some notes
- I choose to show the JLineReader (default) rather than
SimpleReader
because it works much better, correctly handling arrow keys, delete etc. JLine does add an jar dependency. - The example shows how to bind values into the repl (variable
e
above). - When I omit
settings.Yreplsync.value = true
, the REPL hangs and is useless. - From my testing, if both
usejavacp
andembeddedDefaults
settings are combined together, an error results
I find this easiest to test via SBT; a sample 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"
)
Sample SBT session:
> 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>

Ben Hutchison
- 2,433
- 2
- 21
- 25
-
I answered this one http://stackoverflow.com/a/18418634/1296806 but I don't think I tried 2.10, and I always forget that -Yrepl-sync option. Also haven't been using sbt console. Thanks! – som-snytt Sep 05 '13 at 05:48
-
1There was also this question about binding values and class loaders http://stackoverflow.com/a/18503457/1296806 I can't tell if it's good info because it was ignored. Where is crowd think when you need it? – som-snytt Sep 05 '13 at 05:49
-
@som-snytt Yes, your answer was the single most useful source for this example – Ben Hutchison Sep 05 '13 at 05:51
-
5doesnt work with scala 2.11 as "method loop cannot override final method" – simbo1905 Mar 14 '15 at 21:41
-
2@simbo1905 For 2.11, instead override createInterpreter and just call super().createInterpreter() before calling the intp.bind. – Clark Updike Feb 26 '16 at 20:24
-
How can bind all local scope to the REPL? (In latest version) – HappyFace Apr 30 '19 at 15:12
4
Based on Ben's excellent answer, below is a helper class to ease starting the interpreter. Usage:
Repl.run(("e", "Double", 2.71828), ("pi", "Double", 3.1415))
It automatically detects when you're running from SBT and accommodates.
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.")
}
}

Sampo
- 4,308
- 6
- 35
- 51