This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Non-monolithic compiler plugins

3 replies
paulbutcher
Joined: 2010-03-08,
User offline. Last seen 10 weeks 5 days ago.

My plugin is getting too big to fit comfortably in a single class and a single source file. I'd like to split it up, but I'm struggling.

Here's a simple example to illustrate the problem I'm hitting. The following monolithic (but small :-) plugin compiles just fine:

> class TestComponent(plugin: TestPlugin, val global: Global) extends PluginComponent {
> import global._
>
> val runsAfter = List[String]("typer")
> val phaseName = "testphase"
>
> def newPhase(prev: Phase) = new StdPhase(prev) {
> def apply(unit: CompilationUnit) {
> new ForeachTreeTraverser(findAnnotations).traverse(unit.body)
> }
> }
>
> def findAnnotations(tree: Tree) {
> tree match {
> case ClassDef(_, _, _, _) if tree.hasSymbol => handleAnnotations(tree.symbol)
> case _ =>
> }
> }
>
> def handleAnnotations(sym: Symbol) {
> for (AnnotationInfo(atp, _, _) <- sym.annotations)
> doSomethingWithAnnotation(sym, atp)
> }
>
> def doSomethingWithAnnotation(sym: Symbol, atp: Type) {
> log("found "+ atp.typeSymbol +" annotation on "+ sym.name)
> }
> }

But imagine that I want to split the annotation-handling code out into a separate class. Here's my attempt to do so:

> class AnnotationHandler(global: Global) {
> import global._
>
> def apply(tree: Tree) {
> tree match {
> case ClassDef(_, _, _, _) if tree.hasSymbol => handleAnnotations(tree.symbol)
> case _ =>
> }
> }
>
> def handleAnnotations(sym: Symbol) {
> for (AnnotationInfo(atp, _, _) <- sym.annotations)
> doSomethingWithAnnotation(sym, atp)
> }
>
> def doSomethingWithAnnotation(sym: Symbol, atp: Type) {
> log("found "+ atp.typeSymbol +" annotation on "+ sym.name)
> }
> }

And I modify findAnnotations to look like:

> def findAnnotations(tree: Tree) {
> new AnnotationHandler(global)(tree)
> }

When I compile, I get:

> [error] /Users/paul/scala/foo/src/main/scala/TestPlugin.scala:31: type mismatch;
> [error] found : TestComponent.this.global.Tree
> [error] required: _1.global.Tree where val _1: com.example.AnnotationHandler
> [error] new AnnotationHandler(global)(tree)
> [error] ^
> [error] one error found

I assume because the "global" in AnnotationHandler is distinct from the one in TestComponent?

What is the correct way for me to structure things?

--
paul.butcher->msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: paul@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

rytz
Joined: 2008-07-01,
User offline. Last seen 45 weeks 5 days ago.
Re: Non-monolithic compiler plugins
aah, the dependent types.. take a look at these two files
 https://github.com/soundrabbit/effects/blob/master/src/main/scala/scala/tools/nsc/effects/EffectChecker.scala  https://github.com/soundrabbit/effects/blob/master/src/main/scala/scala/tools/nsc/effects/ExternalEffects.scala
Lukas


On Wed, Oct 26, 2011 at 15:47, Paul Butcher <paul@paulbutcher.com> wrote:
My plugin is getting too big to fit comfortably in a single class and a single source file. I'd like to split it up, but I'm struggling.

Here's a simple example to illustrate the problem I'm hitting. The following monolithic (but small :-) plugin compiles just fine:

> class TestComponent(plugin: TestPlugin, val global: Global) extends PluginComponent {
>   import global._
>
>   val runsAfter = List[String]("typer")
>   val phaseName = "testphase"
>
>   def newPhase(prev: Phase) = new StdPhase(prev) {
>     def apply(unit: CompilationUnit) {
>       new ForeachTreeTraverser(findAnnotations).traverse(unit.body)
>     }
>   }
>
>   def findAnnotations(tree: Tree) {
>     tree match {
>       case ClassDef(_, _, _, _) if tree.hasSymbol => handleAnnotations(tree.symbol)
>       case _ =>
>     }
>   }
>
>   def handleAnnotations(sym: Symbol) {
>     for (AnnotationInfo(atp, _, _) <- sym.annotations)
>       doSomethingWithAnnotation(sym, atp)
>   }
>
>   def doSomethingWithAnnotation(sym: Symbol, atp: Type) {
>     log("found "+ atp.typeSymbol +" annotation on "+ sym.name)
>   }
> }

But imagine that I want to split the annotation-handling code out into a separate class. Here's my attempt to do so:

> class AnnotationHandler(global: Global) {
>   import global._
>
>   def apply(tree: Tree) {
>     tree match {
>       case ClassDef(_, _, _, _) if tree.hasSymbol => handleAnnotations(tree.symbol)
>       case _ =>
>     }
>   }
>
>   def handleAnnotations(sym: Symbol) {
>     for (AnnotationInfo(atp, _, _) <- sym.annotations)
>       doSomethingWithAnnotation(sym, atp)
>   }
>
>   def doSomethingWithAnnotation(sym: Symbol, atp: Type) {
>     log("found "+ atp.typeSymbol +" annotation on "+ sym.name)
>   }
> }

And I modify findAnnotations to look like:

>   def findAnnotations(tree: Tree) {
>     new AnnotationHandler(global)(tree)
>   }

When I compile, I get:

> [error] /Users/paul/scala/foo/src/main/scala/TestPlugin.scala:31: type mismatch;
> [error]  found   : TestComponent.this.global.Tree
> [error]  required: _1.global.Tree where val _1: com.example.AnnotationHandler
> [error]     new AnnotationHandler(global)(tree)
> [error]                                   ^
> [error] one error found

I assume because the "global" in AnnotationHandler is distinct from the one in TestComponent?

What is the correct way for me to structure things?

--
paul.butcher->msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: paul@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher


Mirko Stocker
Joined: 2009-09-10,
User offline. Last seen 45 weeks 6 days ago.
Re: Non-monolithic compiler plugins

On Wednesday 26 October 2011 14:47:18 Paul Butcher wrote:
> What is the correct way for me to structure things?

See this SO question:

http://stackoverflow.com/questions/5629127/splitting-scalac-plugin-into-
multiple-files/5632536

Hope this helps,

Mirko

paulbutcher
Joined: 2010-03-08,
User offline. Last seen 10 weeks 5 days ago.
Re: Non-monolithic compiler plugins

Mirko, Lukas,

Many thanks - I think that that's given me what I need to find an appropriate solution for my case :-)

On 26 Oct 2011, at 15:18, Mirko Stocker wrote:
> On Wednesday 26 October 2011 14:47:18 Paul Butcher wrote:
>> What is the correct way for me to structure things?
>
> See this SO question:
>
> http://stackoverflow.com/questions/5629127/splitting-scalac-plugin-into-
> multiple-files/5632536
>
> Hope this helps,
>
> Mirko
>

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland