Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Presentation Compiler - Minimal Example

Can somebody supply a minimal example of using the current scala presentation compiler (i.e. scala.tools.nsc.interactive.Global), which accomplishes the following tasks?

  • compile a single virtual source file (i.e. not in the file system but e.g. a String)
  • retrieve the resulting information for all phases from the compiler
  • propagate a change in the source file to the compiler
  • receive further information possibly asynchronously

There seems to be a lot of fluctuation in nsc and i couldn't find up to date small examples. So I would highly appreciate your help here.

like image 415
Martin Ring Avatar asked May 14 '13 08:05

Martin Ring


2 Answers

Ok, one week of 100 bounty and still no answers so I will try it myself... Edits are very very welcome!

The key class to the presentation compiler is scala.tools.nsc.interactive.Global. So to start, we need to create an instance of the compiler.

import scala.tools.nsc.interactive.Global
class PresentationCompiler { // we want the compiler output to be virtual val target = new VirtualDirectory("", None)
// need to be adjusted in order to work with // sbt. See this question. val settings = new Settings() // output to virtual target settings.outputDirs.setSingleOutput(target)
// can be replaced by a custom instance // of AbstractReporter to gain control. val reporter = new ConsoleReporter(settings)
val compiler = new Global(settings, reporter)
... }

For the settings the link provided by Abhishek is very valuable.

But now for the interesting part:

1. compile a single virtual source file

To compile a String there is the possibility to create a BatchSourceFile with an underlying VirtualFile. The api is marked experimental here and seems patchy.

def compile(code: String) {
  val source = new BatchSourceFile("<virtual>", code)
  val response = new Response[Unit]
  compiler.askReload(List(source), response)    
  response.get.left.foreach { _ =>
    // success
  }
}

2. retrieve the resulting information for all phases from the compiler

This is the tricky part. Due to the multi-threaded nature of the compiler and the fact that flags are reused with different meanings across diferent phases, it is impossible to just get everything at once. Basically you will have to resort to the askSomething kind of methods which are documented in the API. For example:

val tcompletion = new Response[List[global.Member]]      
val pos = compiler.ask(() => new OffsetPosition(source, p))
global.askTypeCompletion(pos, tcompletion)
tcompletion.get(5000).get match {
  case Left(members) => // do something with members
  case Right(e) =>
    e.printStackTrace
}

3. propagate a change in the source file to the compiler

This is the interesting part, I wanted to find out about with this question. I really dont get this, because BatchSourceFile is described as a file which's Content does not change over time. So a custom implementation of SourceFile would need to be supplied?? Why would that not be in the interactive package. I am sure I just didn't catch something.

So my solution right now is to call the compile method again.

like image 54
Martin Ring Avatar answered Nov 03 '22 22:11

Martin Ring


Below link might help

https://github.com/twitter/util/blob/master/util-eval/src/main/scala/com/twitter/util/Eval.scala

I reckon it cater all the requirements you are looking for. :)

like image 33
Abhishek kapoor Avatar answered Nov 03 '22 20:11

Abhishek kapoor