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

compiler question - prepending to a typename

9 replies
Sciss
Joined: 2008-12-17,
User offline. Last seen 28 weeks 5 days ago.

hi,

i have a AST tree transformer, and i would like to duplicate a class like this:

// in a TypingTransfomer
override def transform( tree: Tree ) : Tree = super.transform( tree match {
case cd: ClassDef if( cd.symbol.hasAnnotation( annotationClass )) =>
val txnName = cd.name.prepend( "Txn" )
val cpy = cd.copy( name = txnName )
Seq( cd, cpy )
case _ => tree
})

i have two questions:

- how do i prepend the name? `TypeName` only has an `append` method.
- how do i wrap the two resulting `ClassDef`s into one `Tree` that i can return?

thanks, -sciss-

Sciss
Joined: 2008-12-17,
User offline. Last seen 28 weeks 5 days ago.
Re: compiler question - prepending to a typename

for example, here is my naive approach:

override def transform( tree: Tree ) : Tree = super.transform( tree match {
case cd: ClassDef if( cd.symbol.hasAnnotation( annotationClass )) =>
log( "Has txn annotation : " + cd.name )
cd.symbol.removeAnnotation( annotationClass )
val txnName = ("Txn" + cd.name.decode).encode.toTypeName
val cpy = cd.copy( name = txnName )
Block( cd, cpy )
case _ => tree
})

[info] [log txn.annotations] Has txn annotation : SkipList
??? base not found in basetypes of
[error] {file:/Users/hhrutz/Documents/devel/Transactional/}simpleExamples/compile:compile: java.lang.Error: no-symbol does not have owner
[error] Total time: 2 s, completed Nov 1, 2011 12:55:40 PM

hmmm.....

On 1 Nov 2011, at 12:40, Sciss wrote:

> hi,
>
> i have a AST tree transformer, and i would like to duplicate a class like this:
>
> // in a TypingTransfomer
> override def transform( tree: Tree ) : Tree = super.transform( tree match {
> case cd: ClassDef if( cd.symbol.hasAnnotation( annotationClass )) =>
> val txnName = cd.name.prepend( "Txn" )
> val cpy = cd.copy( name = txnName )
> Seq( cd, cpy )
> case _ => tree
> })
>
> i have two questions:
>
> - how do i prepend the name? `TypeName` only has an `append` method.
> - how do i wrap the two resulting `ClassDef`s into one `Tree` that i can return?
>
> thanks, -sciss-
>

adriaanm
Joined: 2010-02-08,
User offline. Last seen 31 weeks 4 days ago.
Re: compiler question - prepending to a typename


On Tue, Nov 1, 2011 at 1:56 PM, Sciss <contact [at] sciss [dot] de> wrote:
for example, here is my naive approach:

     override def transform( tree: Tree ) : Tree = super.transform( tree match {
        case cd: ClassDef if( cd.symbol.hasAnnotation( annotationClass )) =>
           log( "Has txn annotation : " + cd.name )
           cd.symbol.removeAnnotation( annotationClass )
           val txnName = ("Txn" + cd.name.decode).encode.toTypeName
you can probably just use toString here instead of decoding and encoding, but that's a detail
           val cpy = cd.copy( name = txnName )
           Block( cd, cpy )
I guess a Block could work in some cases, but be sure to check whether this works when your classes are nested in a package, another class, an object,....  
        case _ => tree
     })


[info] [log txn.annotations] Has txn annotation : SkipList
??? base <none> not found in basetypes of <none>
[error] {file:/Users/hhrutz/Documents/devel/Transactional/}simpleExamples/compile:compile: java.lang.Error: no-symbol does not have owner
[error] Total time: 2 s, completed Nov 1, 2011 12:55:40 PM

hmmm.....
it depends on which phase you're in, but it's unlikely you can just generate trees without creating the appropriate symbols and entering them into scope
have a look at Toolboxes.scala (in the compiler source tree) for inspiration on how to set up the symbol and tree structures 
Sciss
Joined: 2008-12-17,
User offline. Last seen 28 weeks 5 days ago.
Re: compiler question - prepending to a typename

thanks adrian -- Toolboxes seems not to be part of 2.9.1, but i found the source online.

so far i managed to get the copy working with this:

private def mkTxnClass( cd: ClassDef ) : ClassDef = {
val txnName = (("Txn" + cd.name) : Name).toTypeName
val cpy = treeCopy.ClassDef( cd, cd.mods, txnName, cd.tparams, cd.impl )
cpy.symbol.removeAnnotation( annotationClass )
cpy.symbol.name = txnName
cpy
}

what i don't understand is why, when i explicitly pass the new name to treeCopy.ClassDef, i still end up with a ClassDef that has the old name, so that i need an additional re-naming of the copy?

best, -sciss-

On 1 Nov 2011, at 13:03, Adriaan Moors wrote:

>
>
> On Tue, Nov 1, 2011 at 1:56 PM, Sciss wrote:
> for example, here is my naive approach:
>
> override def transform( tree: Tree ) : Tree = super.transform( tree match {
> case cd: ClassDef if( cd.symbol.hasAnnotation( annotationClass )) =>
> log( "Has txn annotation : " + cd.name )
> cd.symbol.removeAnnotation( annotationClass )
> val txnName = ("Txn" + cd.name.decode).encode.toTypeName
> you can probably just use toString here instead of decoding and encoding, but that's a detail
>
> val cpy = cd.copy( name = txnName )
> Block( cd, cpy )
> I guess a Block could work in some cases, but be sure to check whether this works when your classes are nested in a package, another class, an object,....
>
> case _ => tree
> })
>
>
> [info] [log txn.annotations] Has txn annotation : SkipList
> ??? base not found in basetypes of
> [error] {file:/Users/hhrutz/Documents/devel/Transactional/}simpleExamples/compile:compile: java.lang.Error: no-symbol does not have owner
> [error] Total time: 2 s, completed Nov 1, 2011 12:55:40 PM
>
> hmmm.....
> it depends on which phase you're in, but it's unlikely you can just generate trees without creating the appropriate symbols and entering them into scope
>
> have a look at Toolboxes.scala (in the compiler source tree) for inspiration on how to set up the symbol and tree structures

adriaanm
Joined: 2010-02-08,
User offline. Last seen 31 weeks 4 days ago.
Re: compiler question - prepending to a typename
you probably need to generate a new symbol -- there should be a one-to-one relation between symbols and definitionsthe symbol's name is more irrelevant than you might think, it's just a way of presenting the symbol to users and the jvm, but it isn't used for lookup (well, modulo a few details wrt nesting and special synthetic symbols)

On Tue, Nov 1, 2011 at 3:30 PM, Sciss <contact [at] sciss [dot] de> wrote:
thanks adrian -- Toolboxes seems not to be part of 2.9.1, but i found the source online.

so far i managed to get the copy working with this:

     private def mkTxnClass( cd: ClassDef ) : ClassDef = {
        val txnName = (("Txn" + cd.name) : Name).toTypeName
        val cpy = treeCopy.ClassDef( cd, cd.mods, txnName, cd.tparams, cd.impl )
        cpy.symbol.removeAnnotation( annotationClass )
        cpy.symbol.name = txnName
        cpy
     }

what i don't understand is why, when i explicitly pass the new name to treeCopy.ClassDef, i still end up with a ClassDef that has the old name, so that i need an additional re-naming of the copy?


best, -sciss-



On 1 Nov 2011, at 13:03, Adriaan Moors wrote:

>
>
> On Tue, Nov 1, 2011 at 1:56 PM, Sciss <contact [at] sciss [dot] de> wrote:
> for example, here is my naive approach:
>
>      override def transform( tree: Tree ) : Tree = super.transform( tree match {
>         case cd: ClassDef if( cd.symbol.hasAnnotation( annotationClass )) =>
>            log( "Has txn annotation : " + cd.name )
>            cd.symbol.removeAnnotation( annotationClass )
>            val txnName = ("Txn" + cd.name.decode).encode.toTypeName
> you can probably just use toString here instead of decoding and encoding, but that's a detail
>
>            val cpy = cd.copy( name = txnName )
>            Block( cd, cpy )
> I guess a Block could work in some cases, but be sure to check whether this works when your classes are nested in a package, another class, an object,....
>
>         case _ => tree
>      })
>
>
> [info] [log txn.annotations] Has txn annotation : SkipList
> ??? base <none> not found in basetypes of <none>
> [error] {file:/Users/hhrutz/Documents/devel/Transactional/}simpleExamples/compile:compile: java.lang.Error: no-symbol does not have owner
> [error] Total time: 2 s, completed Nov 1, 2011 12:55:40 PM
>
> hmmm.....
> it depends on which phase you're in, but it's unlikely you can just generate trees without creating the appropriate symbols and entering them into scope
>
> have a look at Toolboxes.scala (in the compiler source tree) for inspiration on how to set up the symbol and tree structures


Sciss
Joined: 2008-12-17,
User offline. Last seen 28 weeks 5 days ago.
Re: compiler question - prepending to a typename

but the symbol's name seems to determine the generated class -- if i don't rename the symbol, i end of with a tree that has two classes with the same name, and they overwrite each other's class files.

is this approach (.toTypeName) ok, or should i use another mechanism to generate a new symbol?

best, -sciss-

On 1 Nov 2011, at 14:36, Adriaan Moors wrote:

> you probably need to generate a new symbol -- there should be a one-to-one relation between symbols and definitions
> the symbol's name is more irrelevant than you might think, it's just a way of presenting the symbol to users and the jvm, but it isn't used for lookup (well, modulo a few details wrt nesting and special synthetic symbols)
>
> On Tue, Nov 1, 2011 at 3:30 PM, Sciss wrote:
> thanks adrian -- Toolboxes seems not to be part of 2.9.1, but i found the source online.
>
> so far i managed to get the copy working with this:
>
> private def mkTxnClass( cd: ClassDef ) : ClassDef = {
> val txnName = (("Txn" + cd.name) : Name).toTypeName
> val cpy = treeCopy.ClassDef( cd, cd.mods, txnName, cd.tparams, cd.impl )
> cpy.symbol.removeAnnotation( annotationClass )
> cpy.symbol.name = txnName
> cpy
> }
>
> what i don't understand is why, when i explicitly pass the new name to treeCopy.ClassDef, i still end up with a ClassDef that has the old name, so that i need an additional re-naming of the copy?
>
>
> best, -sciss-
>
>
>
> On 1 Nov 2011, at 13:03, Adriaan Moors wrote:
>
> >
> >
> > On Tue, Nov 1, 2011 at 1:56 PM, Sciss wrote:
> > for example, here is my naive approach:
> >
> > override def transform( tree: Tree ) : Tree = super.transform( tree match {
> > case cd: ClassDef if( cd.symbol.hasAnnotation( annotationClass )) =>
> > log( "Has txn annotation : " + cd.name )
> > cd.symbol.removeAnnotation( annotationClass )
> > val txnName = ("Txn" + cd.name.decode).encode.toTypeName
> > you can probably just use toString here instead of decoding and encoding, but that's a detail
> >
> > val cpy = cd.copy( name = txnName )
> > Block( cd, cpy )
> > I guess a Block could work in some cases, but be sure to check whether this works when your classes are nested in a package, another class, an object,....
> >
> > case _ => tree
> > })
> >
> >
> > [info] [log txn.annotations] Has txn annotation : SkipList
> > ??? base not found in basetypes of
> > [error] {file:/Users/hhrutz/Documents/devel/Transactional/}simpleExamples/compile:compile: java.lang.Error: no-symbol does not have owner
> > [error] Total time: 2 s, completed Nov 1, 2011 12:55:40 PM
> >
> > hmmm.....
> > it depends on which phase you're in, but it's unlikely you can just generate trees without creating the appropriate symbols and entering them into scope
> >
> > have a look at Toolboxes.scala (in the compiler source tree) for inspiration on how to set up the symbol and tree structures
>
>

adriaanm
Joined: 2010-02-08,
User offline. Last seen 31 weeks 4 days ago.
Re: compiler question - prepending to a typename


On Tue, Nov 1, 2011 at 3:40 PM, Sciss <contact [at] sciss [dot] de> wrote:
but the symbol's name seems to determine the generated class -- if i don't rename the symbol, i end of with a tree that has two classes with the same name, and they overwrite each other's class files.

is this approach (.toTypeName) ok, or should i use another mechanism to generate a new symbol?
I meant that changing a symbol's name does not generate a new symbol, it just changes the way that same symbol is presented to the user and the back-end for classfile generation
the toolbox shows how to generate new symbols (ownerSym.newClass(...))
Sciss
Joined: 2008-12-17,
User offline. Last seen 28 weeks 5 days ago.
Re: compiler question - prepending to a typename

sorry -- which Toolboxes are you referring to. I only found this:

https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src//compiler/sca...

and that doesn't seem to be the one. I unjars my 2.9.1 compiler source and that doesn't contain anything called Toolboxes, either...

thanks again, -sciss-

On 1 Nov 2011, at 14:51, Adriaan Moors wrote:

>
>
> On Tue, Nov 1, 2011 at 3:40 PM, Sciss wrote:
> but the symbol's name seems to determine the generated class -- if i don't rename the symbol, i end of with a tree that has two classes with the same name, and they overwrite each other's class files.
>
> is this approach (.toTypeName) ok, or should i use another mechanism to generate a new symbol?
> I meant that changing a symbol's name does not generate a new symbol, it just changes the way that same symbol is presented to the user and the back-end for classfile generation
>
> the toolbox shows how to generate new symbols (ownerSym.newClass(...))
>

Sciss
Joined: 2008-12-17,
User offline. Last seen 28 weeks 5 days ago.
Re: compiler question - prepending to a typename

i'm still stuck. i can't find the Toolboxes examples you were pointing, to. i tried with owner.newClass:

private def mkTxnClass( cd: ClassDef ) : ClassDef = {
val txnName = (("Txn" + cd.name) : Name).toTypeName
val txnImpl = mkTxnClassImpl( cd.impl )
val txnMods = cd.mods | Flags.SYNTHETIC
val cpy = treeCopy.ClassDef( cd, txnMods, txnName, Nil /* cd.tparams */, txnImpl )
val txnSym = cd.symbol.owner.newClass( txnName )
cpy.symbol = txnSym
cpy
}

private def mkTxnClassImpl( orig: Template ) : Template = {
val txnBody = List.empty[ Tree ] // let's just strip it away for now
val txnSelf = orig.self // treeCopy.ValDef( ... )
treeCopy.Template( orig, orig.parents, txnSelf, txnBody )
}

and this prints the AST fine:

...
abstract trait SkipList[A >: Nothing <: Any] extends java.lang.Object with ScalaObject {
def /*SkipList*/$init$(): Unit = {
()
};
def contains(v: A): Boolean;
....
};
trait TxnSkipList extends java.lang.Object with ScalaObject
...

although the 'abstract' is somewhat gone. but then scalac fails with an unexplained error:

java.lang.AssertionError: assertion failed: TxnSkipList

i have all of the following options: -verbose, -Ydebug, -Yshow-syms, -Ycheck:txn.annotations, -Xshow-phases, -Xprint:txn.annotations, -Ylog:txn.annotations, -Xplugin-require:transactional

but no idea what assertion fails and why :(

best, -sciss-

On 1 Nov 2011, at 14:51, Adriaan Moors wrote:

>
>
> On Tue, Nov 1, 2011 at 3:40 PM, Sciss wrote:
> but the symbol's name seems to determine the generated class -- if i don't rename the symbol, i end of with a tree that has two classes with the same name, and they overwrite each other's class files.
>
> is this approach (.toTypeName) ok, or should i use another mechanism to generate a new symbol?
> I meant that changing a symbol's name does not generate a new symbol, it just changes the way that same symbol is presented to the user and the back-end for classfile generation
>
> the toolbox shows how to generate new symbols (ownerSym.newClass(...))
>

Sciss
Joined: 2008-12-17,
User offline. Last seen 28 weeks 5 days ago.
Re: compiler question - prepending to a typename

sorry, didn't 'reload', here is the info from show-syms:

...
[info] [[symbol layout at end of txn.annotations]]
[info] package (final)
[info] package (final)
[info] class Any (abstract)
[info] class Boolean (final)
[info] class Int (final)
[info] method <<
[info] method +
[info] class Object
[info] constructor Object
[info] * class TxnSkipList
[info] class Unit (final)
...
[info] trait SkipList (abstract)
...
[consistency check at the beginning of phase pickler]
[info] [checking SkipList.scala]
[check: txn.annotations] 62 new symbols.
[error] {file:/Users/hhrutz/Documents/devel/Transactional/}simpleExamples/compile:compile: java.lang.AssertionError: assertion failed: TxnSkipList
[error] Total time: 2 s, completed Nov 1, 2011 4:09:43 PM

obviously i ended up with a non abstract `class TxnSkipList` (marked with an asterisk) instead of a `trait TxnSkipList (abstract)`

maybe i just need to copy the attributes from the old symbol to the new symbol, somehow?

best, -sciss-

On 1 Nov 2011, at 16:08, Sciss wrote:

> i'm still stuck. i can't find the Toolboxes examples you were pointing, to. i tried with owner.newClass:
>
> private def mkTxnClass( cd: ClassDef ) : ClassDef = {
> val txnName = (("Txn" + cd.name) : Name).toTypeName
> val txnImpl = mkTxnClassImpl( cd.impl )
> val txnMods = cd.mods | Flags.SYNTHETIC
> val cpy = treeCopy.ClassDef( cd, txnMods, txnName, Nil /* cd.tparams */, txnImpl )
> val txnSym = cd.symbol.owner.newClass( txnName )
> cpy.symbol = txnSym
> cpy
> }
>
> private def mkTxnClassImpl( orig: Template ) : Template = {
> val txnBody = List.empty[ Tree ] // let's just strip it away for now
> val txnSelf = orig.self // treeCopy.ValDef( ... )
> treeCopy.Template( orig, orig.parents, txnSelf, txnBody )
> }
>
> and this prints the AST fine:
>
> ...
> abstract trait SkipList[A >: Nothing <: Any] extends java.lang.Object with ScalaObject {
> def /*SkipList*/$init$(): Unit = {
> ()
> };
> def contains(v: A): Boolean;
> ....
> };
> trait TxnSkipList extends java.lang.Object with ScalaObject
> ...
>
> although the 'abstract' is somewhat gone. but then scalac fails with an unexplained error:
>
> java.lang.AssertionError: assertion failed: TxnSkipList
>
> i have all of the following options: -verbose, -Ydebug, -Yshow-syms, -Ycheck:txn.annotations, -Xshow-phases, -Xprint:txn.annotations, -Ylog:txn.annotations, -Xplugin-require:transactional
>
> but no idea what assertion fails and why :(
>
>
> best, -sciss-
>
>
>
>
> On 1 Nov 2011, at 14:51, Adriaan Moors wrote:
>
>>
>>
>> On Tue, Nov 1, 2011 at 3:40 PM, Sciss wrote:
>> but the symbol's name seems to determine the generated class -- if i don't rename the symbol, i end of with a tree that has two classes with the same name, and they overwrite each other's class files.
>>
>> is this approach (.toTypeName) ok, or should i use another mechanism to generate a new symbol?
>> I meant that changing a symbol's name does not generate a new symbol, it just changes the way that same symbol is presented to the user and the back-end for classfile generation
>>
>> the toolbox shows how to generate new symbols (ownerSym.newClass(...))
>>
>

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