QuasiQuotes and Literals

조회수 375회
읽지 않은 첫 메시지로 건너뛰기

Nathan Matthews

읽지 않음,
2014. 2. 7. 오후 12:21:4414. 2. 7.
받는사람 scala-l...@googlegroups.com
Hi All,

I have a scenario where my macro has generated a value. Lets say its a Map. I want the literal map to be transformed into an AST for insertion into the generated code. Is there an easy way to do this with QuasiQuotes? 

E.g.

In macro...

val map : Map[String, Int] = someFunctionThatGeneratesAMap(context)

val tree : c.Tree = toTree(map) // returns something like: q"map("the" -> 0, "answer" -> 42)"

Jason Zaugg

읽지 않음,
2014. 2. 7. 오후 12:27:2514. 2. 7.
받는사람 scala-l...@googlegroups.com
On Fri, Feb 7, 2014 at 6:21 PM, Nathan Matthews <nathan.r...@gmail.com> wrote:
Hi All,

I have a scenario where my macro has generated a value. Lets say its a Map. I want the literal map to be transformed into an AST for insertion into the generated code. Is there an easy way to do this with QuasiQuotes? 

That's the perfect use case for Liftable [1]. One of the standard liftable instances [2] handles maps (assuming we can also find liftable instances for the key and value types):

scala> val m = Map(1 -> "one"); q"$m"
m: scala.collection.immutable.Map[Int,String] = Map(1 -> one)
res1: $r.intp.global.Tree = scala.collection.immutable.Map(scala.Tuple2(1, "one"))

-jason
 

E.g.

In macro...

val map : Map[String, Int] = someFunctionThatGeneratesAMap(context)

val tree : c.Tree = toTree(map) // returns something like: q"map("the" -> 0, "answer" -> 42)"

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Nathan Matthews

읽지 않음,
2014. 2. 7. 오후 6:16:2914. 2. 7.
받는사람 scala-l...@googlegroups.com
Hi Jason,

Thanks for the reply, I'm having some issues using Liftable. I'm on Scala 2.10.3. Standard Liftables doesn't seem to be available for that release so i'm trying to roll my own. The type signature for liftable is:

trait Liftable[T] {
  def apply(universe: Universe, value: T): universe.Tree
}

But in the context of the macro I have a different universe: context.universe. Im not sure how I'd go about creating a Liftable which lifts context.universe.Type for instance. I could call universe.TypeTree(value) but value has to be of type universe.Type. I'm not sure how I'd constrain the type parameter T on the Liftable class to be the path dependent type universe.Type in that instance. I must be missing some magic.

- Nathan

Denys Shabalin

읽지 않음,
2014. 2. 8. 오전 7:05:0514. 2. 8.
받는사람 scala-l...@googlegroups.com
Hi Nathan,

Unfortunately 2.10.x paradise doesn't contain latest liftables and newer simpler api that will be a part of 2.11 release.

In 2.10 you could do something like:

import universe1._

case class Foo(typ: Type)

implicit val liftFoo: Liftable[Foo] = new Liftable[Foo] {
   def apply(universe2, foo): Tree = {
      require(universe1 == universe2)
      import universe2._
      val typ2  = foo.type.asInstanceOf[univese2.Type]     
      // lifting code goes here
   }
}

Eugene Burmako

읽지 않음,
2014. 2. 8. 오전 7:08:1414. 2. 8.
받는사람 scala-l...@googlegroups.com
Just to add to Denys's excellent answer, we're planning to eventually migrate 2.11 stuff to 2.10 paradise right before or shortly after the 2.11.0-final release.

Naftoli Gugenheim

읽지 않음,
2014. 2. 12. 오전 12:17:0214. 2. 12.
받는사람 scala-l...@googlegroups.com, Alexander Nemish

Great to hear about Liftable. I could have used it some time ago...

Nick Stanchenko

읽지 않음,
2014. 3. 16. 오후 2:25:2614. 3. 16.
받는사람 scala-l...@googlegroups.com
Hi,

I’m having trouble implementing even a simple Liftable due to some path-dependent type weirdness. I’m on 2.10.3 with quasiquotes-M3.

object X {
  implicit def `List is liftable`[A: Liftable] = new Liftable[List[A]] {
    def apply(universe: Universe, value: List[A]) = {
      import universe._
      q"scala.collection.immutable.List(..$value)"
    }
  }
}

type mismatch;
[error]  found   : universe.Apply
[error]  required: universe.Tree

The cast does not help:

object X {
  implicit def `List is liftable`[A: Liftable] = new Liftable[List[A]] {
    def apply(universe: Universe, value: List[A]) = {
      import universe._
      q"scala.collection.immutable.List(..$value)".asInstanceOf[universe.Tree]
    }
  }
}

type mismatch;
[error]  found   : universe.Tree
[error]  required: universe.Tree

Nick

Eugene Burmako

읽지 않음,
2014. 3. 17. 오후 6:02:1614. 3. 17.
받는사람 scala-l...@googlegroups.com
Looks like you need to specify the return type of apply explicitly. No idea why this is required :(


--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nick Stanchenko

읽지 않음,
2014. 3. 17. 오후 6:07:0314. 3. 17.
받는사람 scala-l...@googlegroups.com
That works! Interesting...

While we are at it, what’s the closest I can get to `symbolOf` on 2.10?

Eugene Burmako

읽지 않음,
2014. 3. 17. 오후 6:07:3114. 3. 17.
받는사람 scala-l...@googlegroups.com
I guess that would be typeOf[T].typeSymbol

Nick Stanchenko

읽지 않음,
2014. 3. 17. 오후 6:12:5814. 3. 17.
받는사람 scala-l...@googlegroups.com
Thanks! Also, is there a simple way to get the fully qualified method symbol for a singleton method? Or should I use `q"${typeOf[MySingleton.type]`.typeSymbol}.meth` (don’t know if that works)? I’ve just got tired of qualifying everything by hand and want to learn the right way :)

Eugene Burmako

읽지 않음,
2014. 3. 17. 오후 6:20:5814. 3. 17.
받는사람 scala-l...@googlegroups.com
I think that's the best you can get at the moment, while quasiquotes are still unhygienic. It also helps to predefine a bunch of vals that refer to frequently used symbols.

Nick Stanchenko

읽지 않음,
2014. 3. 17. 오후 8:06:5714. 3. 17.
받는사람 scala-l...@googlegroups.com
Hmm...

implicitly[Liftable[List[Tree]]]
// compiles

def test(list: List[Tree]) = q"$list"
Can't splice List[....universe.Tree], consider using ..
[error]     def apply(list: List[Tree]) = q"$list"
[error]                                      ^

So here I am, really trying to use Liftable and stuff...

Eugene Burmako

읽지 않음,
2014. 3. 17. 오후 8:11:3714. 3. 17.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
Quite possibly this is something not yet supported in 2.10's implementation of quasiquotes. Denys might know more.

Nick Stanchenko

읽지 않음,
2014. 3. 17. 오후 8:21:3014. 3. 17.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
> Quite possibly this is something not yet supported in 2.10's implementation of quasiquotes. Denys might know more.

Well, the docs kind of hint that it should be (http://docs.scala-lang.org/overviews/macros/quasiquotes.html#tips_and_tricks), but do not give any information (unlike the awesome 2.11 guide). I read that bit quite a while ago and all this time was under the impression that it was the way to go :)

Also, I haven’t checked whether it’s something implemented in 2.11 yet, but would be nice to have a macro-materialized Liftable instance for case classes. I think paradise/palladium committers have a much higher chance of doing it properly and it would save a lot of effort for those who want to unquote a variety of case classes.

Alex Cruise

읽지 않음,
2014. 3. 17. 오후 9:02:2714. 3. 17.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
I know I still sometimes get tripped up by this... I don't know if it was causing problems for you specifically, but...


implicit def `List is liftable`[A: Liftable] = new Liftable[List[A]] {

There's no explicit return type on this implicit, which limits its accessbility to callsites that are syntactically afterward, in the same file.  At least it used to, someone might have fixed that. :)

-0xe1a
 


--

Nick Stanchenko

읽지 않음,
2014. 3. 17. 오후 9:13:3714. 3. 17.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
Alex, good point! Normally I try to follow the practice of providing explicit return types for implicits, but for some reason did not do it here.

However this brought even more weirdness!

// Without explicit type

implicit object `X is liftable` extends Liftable[X] { ... }
implicit def `List is liftable`[A: Liftable] = new Liftable[List[A]] { ... }
implicitly[Liftable[List[X]]] // OK

// With explicit type

implicit def `List is liftable`[A: Liftable]: Liftable[List[A]] = new Liftable[List[A]] {
    def apply(universe: Universe, value: List[A]): universe.Tree = {
      import universe._
      q"scala.collection.immutable.List(..$value)"
    }
  }

overloaded method value Apply with alternatives:
[error]   (sym: universe.Symbol,args: universe.Tree*)universe.Tree <and>
[error]   => universe.ApplyExtractor
[error]  cannot be applied to (universe.Select, universe.Tree)
[error]       q"scala.collection.immutable.List(..$value)"
[error]       ^

Eugene Burmako

읽지 않음,
2014. 3. 18. 오전 5:40:1114. 3. 18.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
I believe this could be of interest to you: https://github.com/scala/scala/pull/3326


--

Eugene Burmako

읽지 않음,
2014. 3. 18. 오전 5:43:0614. 3. 18.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
It looks like this implicit picks itself inside the quasiquote, because quasiquotes see ..$ and that somehow triggers a lookup for List[A]. Denys could provide the ultimate reference here, but I think we should just wait until 2.11 quasiquotes are backported to 2.10 paradise (because there was a number of changes to lifting recently) and maybe then the problem will fix itself.


--

Nick Stanchenko

읽지 않음,
2014. 3. 18. 오전 11:42:1614. 3. 18.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
I believe this could be of interest to you: https://github.com/scala/scala/pull/3326
Ah, yes. Funny enough, now I even remember reading that pull request :) Sorry then!


It looks like this implicit picks itself inside the quasiquote, because quasiquotes see ..$ and that somehow triggers a lookup for List[A]. Denys could provide the ultimate reference here, but I think we should just wait until 2.11 quasiquotes are backported to 2.10 paradise (because there was a number of changes to lifting recently) and maybe then the problem will fix itself.
I thought that might be a recursion problem, but wasn’t the compiler supposed to complain about the unspecified return type? 
Anyway, I agree that we should wait for backporting. Do you have any estimates for when that could happen?

Nick Stanchenko

읽지 않음,
2014. 3. 23. 오후 12:30:2414. 3. 23.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
That was fast! I tried the new backport (M4) and it compiles. However at runtime I get

exception during macro expansion: 
[error] java.lang.ClassNotFoundException: scala.reflect.api.Universe$Liftable

Is there a way to fix this?

Eugene Burmako

읽지 않음,
2014. 3. 23. 오후 12:34:3914. 3. 23.
받는사람 scala-l...@googlegroups.com
Do you have the quasiquote lib on your classpath?
--

Eugene Burmako

읽지 않음,
2014. 3. 23. 오후 12:36:5014. 3. 23.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
Oh man I know. I had to comment out java files because scaladoc was failing on them, but in doing so I made sbt produce a jar without those files compiled. It looks like I blew a release. Will publish M5 within the hour...

On 23 Mar 2014, at 17:30, Nick Stanchenko <nick....@gmail.com> wrote:

--

Nick Stanchenko

읽지 않음,
2014. 3. 23. 오후 12:39:4014. 3. 23.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
Nice :) I was already suspicious when IDEA rendered `Liftable` in red...

Eugene Burmako

읽지 않음,
2014. 3. 23. 오후 1:07:3214. 3. 23.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
For that matter, I don't think that IDEA is going to support liftables in 2.10.x, since they are introduced by a compiler plugin hack. However, the crash you're facing can and shall be fixed.

Nick Stanchenko

읽지 않음,
2014. 3. 23. 오후 1:23:5014. 3. 23.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
Right. We already submitted one issue like this (http://youtrack.jetbrains.com/issue/SCL-5965) and apparently they want to focus on 2.11 & Palladium instead, so not worth bugging them again.

Eugene Burmako

읽지 않음,
2014. 3. 23. 오후 1:55:1914. 3. 23.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
I've just released 2.0.0-M5 and that should take care of the issue.


--

Nick Stanchenko

읽지 않음,
2014. 3. 23. 오후 1:59:3214. 3. 23.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
I got

exception during macro expansion: 
[error] java.lang.UnsupportedClassVersionError: scala/reflect/api/Universe$Liftable : Unsupported major.minor version 51.0

Something on my side?

Nick Stanchenko

읽지 않음,
2014. 3. 23. 오후 2:03:0014. 3. 23.
받는사람 scala-l...@googlegroups.com, Denys Shabalin

Eugene Burmako

읽지 않음,
2014. 3. 23. 오후 2:02:5114. 3. 23.
받는사람 scala-l...@googlegroups.com, Denys Shabalin
It's fascinating how many facets fail can have! This one is caused by Java-compiled portions of quasiquotes.jar being compiled with Java 7 :)

Would it be possible for you to use Java 7 or 8? I'd prefer to cool down the pace of releases if that's not an absolute blocker for you. Alternatively I could publish a snapshot build with Java 6.
전체답장
작성자에게 답글
전달
새 메시지 0개