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

.11.do.source-code.repl.scala Maven / Gradle / Ivy

There is a newer version: dp
Show newest version
//-- license info
/*
   Copyright 2010 Aaron J. Radke

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package cc.drx

/* repl object to launch a repl from mvn directly from a launcher command (oh an nicely for windows too)
 * The solution is essentially a combination of the scala repl programmatic doc and stack overvlow classpath trick
 *  https://docs.scala-lang.org/overviews/repl/embedding.html
 *  this excelent post is the classpath trick that finally made it work https://stackoverflow.com/a/4937135/622016
 *  http://www.scala-lang.org/api/2.12.3/scala-compiler/scala/tools/nsc/interpreter/ILoop.html
 *  https://docs.scala-lang.org/overviews/repl/embedding.html
 *  roll your own repl https://stackoverflow.com/a/18628517/622016
 */
object Repl{

  import scala.tools.nsc.Settings
  import scala.tools.nsc.interpreter._
  // import scala.tools.nsc.interpreter.shell._ //TODO needed for 2.13 compiling

  def main(args:Array[String]):Unit = {
    //TODO install the jansi features if running in windows mode?? is this needed or already part of the sbt launcher? for now it doesn't seem to need explicit installation and seems to work in Windows since drx.Boot includes jansi itself, but non boot may not work
    
    //--- command line args
    val isVerbose = args contains "-v"

    //---javax.script features
    // val engine = new javax.script.ScriptEngineManager().getEngineByName("scala")
    // println(engine eval code)


    //--fantastic robust detection trick from https://stackoverflow.com/a/22039095/622016
    val traceClasses = new Exception().getStackTrace.map{_.getClassName}
    val isSBT = traceClasses contains "sbt.Run"
    val isLauncher = traceClasses contains "xsbt.boot.Boot"

    //-- find sbt-luancher already loaded classpaths to pass to the repl
    // Uses the drx.Classpath abstrcation for cross platform classpath read and construct 
    val loaderClasspath = Classpath.local
    
    //--just find the missing scala paths
    //this excelent post is the classpath trick that finally made it work https://stackoverflow.com/a/4937135/622016
    val scalaClasspath = {
      def alreadyContains(name:String):Boolean = loaderClasspath.files.exists(_.name == name)
      val bootPathPat = """/(scala-2\.[^/]+)/.*""".r //look for some directory that looks like a scala-2.12.5 like folder
      val scalaPaths = loaderClasspath.files.map{_.unixPath}.find(bootPathPat existsMatch _).toList.flatMap{ path =>
        for(fname <- List("jline.jar","scala-library.jar", "scala-compiler.jar") if !alreadyContains(fname)) yield 
          bootPathPat.replaceAllIn(path, "/$1/lib/"+fname)
      }
      Classpath(scalaPaths map File.apply)
    }

    //-- join classpaths
    val classpath = if(isSBT) scalaClasspath else (scalaClasspath ++ loaderClasspath)

    //--setup compiler & env settings
    System.setProperty("scala.color", "true")
    val settings = new Settings
    settings.Yreplsync.value = true
    settings.processArgumentString(
      "-unchecked -deprecation -feature -Xfatal-warnings -Xfuture -Ywarn-value-discard -Yno-adapted-args -encoding UTF-8"
    )

    settings.classpath.value = classpath.toString
    settings.usejavacp.value = if(isSBT || isLauncher) false else true //(external from sbt)
    // if(isSBT) settings.embeddedDefaults[Repl.type]
    // else      settings.usejavacp.value = true //(external from sbt)

    //---show verbose info
    if(isVerbose){
      println(s"#-- class trace")
      traceClasses foreach println
      println(s"#-- settings")
      println("isSBT:"+isSBT)
      println("isLauncher:"+isLauncher)
      println("settings.usejavacp:"+settings.usejavacp)
      println("settings:"+settings)
      // println("settings.classpath:"+settings.classpath)
      println("#-- injected classpath:")
      println(classpath.nice)
    }

    //--programatic repl
//     val imain = new IMain(settings)
//     Console println imain.interpret("val x = 5")
//     Console println imain.interpret("x+5")

    //--interactive repl
    val iloop = new ILoop(){
      override def createInterpreter():Unit = { //example from keithohara sp5repl.scala
        super.createInterpreter()
        intp.quietRun("import cc.drx._") //prelude
        ()
      }
      override def prompt:String = "scala> " ansi Color.Pink //drx>
      override def printWelcome:Unit = echo("Welcome to drx.cc.Repl, a scala repl with launcher support and default imports for cc.drx._")
    }
    iloop.process(settings)

    println("Done.");
    // iloop.close()   //null pointer if if this is called after a close interpreter

    () //end of main
  }
}
object Eval{

  import scala.reflect.runtime._
  import scala.reflect.runtime.universe._
  import scala.tools.reflect.ToolBox

  // import scala.reflect.runtime.universe //val cm = universe.runtimeMirror(getClass.getClassLoader)

  private val cm = universe.runtimeMirror(getClass.getClassLoader)
  private val toolbox = cm.mkToolBox()
  // private lazy val toolbox = scala.reflect.runtime.currentMirror.mkToolBox()

  type EvalExpr = () => Any
  // def compile(code: String): () => Any = toolbox compile treeOf(code)
  def compile(code: String):EvalExpr = {
    val tree = toolbox parse code
    toolbox compile tree
  }

  def evalAny(code: String): Any = compile(code)()

  def eval[T](code: String): T = evalAny(code).asInstanceOf[T]

  def main(args:Array[String]) = {
    val argsCode = args.mkString(" ").trim
    val code = if(argsCode != "") argsCode else "2+2"
    val res = eval[Int]( code )
    println(res)
  }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy