2012-12-01 21 views
9

varsayalım Bu makro varScala makrolarında varargs tip tanımıyla denetleniyor

scala> FooExample.foo(List(1, 2, 3): _*) 
res1: Int = 1 

Ve balık şey wi devam ettiğini göstermek için: varargs tip bana (Scala 2.10.0-RC3 olarak) kafa karıştırıcı ertelenmiş türden:

scala> FooExample.foo[Int](List(1, 2, 3): _*) 
res2: Int = 1 

Burada bir derleme zamanı hatası olmasını beklerdim, ve istediğim bu.

object BarExample { 
    def bar(xs: Int*): Int = macro bar_impl 
    def bar_impl(c: Context)(xs: c.Expr[Int]*) = { 
    import c.universe._ 
    c.literal(
     xs.map(_.tree).headOption map { 
     case Literal(Constant(x: Int)) => x 
     case _ => c.abort(c.enclosingPosition, "bar wants literal arguments!") 
     } getOrElse c.abort(c.enclosingPosition, "bar wants arguments!") 
    ) 
    } 
} 

Ve bu derleme zamanında sorunu yakalar:

scala> BarExample.bar(3, 2, 1) 
res3: Int = 3 

scala> BarExample.bar(List(3, 2, 1): _*) 
<console>:8: error: bar wants literal arguments! 
       BarExample.bar(List(3, 2, 1): _*) 

Bu, olsa-bana kesmek gibi hissediyor Ben yazdım makrolar çoğunda aşağıdaki yaklaşımı kullandım bir bit geçerliliğini (argümanların değişmez olduğunu kontrol ederek) bir diğeriyle karıştırıyor (gerçekten varargs olduğumuzu onaylıyor). Aynı zamanda argümanlara gerek duymadığım durumlarda (ya da türlerinin jenerik olmasını istediğim durumlarda) hayal edebiliyorum.

Ben şu yapabileceğini biliyorum:

object BazExample { 
    def baz[A](xs: A*): Int = macro baz_impl[A] 
    def baz_impl[A](c: Context)(xs: c.Expr[A]*) = { 
    import c.universe._ 

    xs.toList.map(_.tree) match { 
     case Typed(_, Ident(tpnme.WILDCARD_STAR)) :: Nil => 
     c.abort(c.enclosingPosition, "baz wants real varargs!") 
     case _ => c.literal(xs.size) 
    } 
    } 
} 

Ama bu argüman doğrulama çok basit (ve yaygın gerekli varsayalım ediyorum) biraz kontrol altına almaya yönelik çirkin bir yoldur. Burada özlediğim bir numara var mı? İlk örneğimde foo(1 :: Nil: _*)'un bir derleme zamanı hatası verdiğinden emin olmanın en basit yolu nedir?

+0

"Burada bir derleme zamanı hatası beklerdim" yazdığınızda, lütfen açıklayabilir misiniz? Bunun bir hata olmasını beklersiniz, çünkü bu alan adınızın gereği midir? Ya da bu her çeşit vararg makro için bir hata olmalı? –

+0

@EugeneBurmako: Benim endişem şu ki, 'xs.head' aslında bir “c.Expr [A]' değil, daha çok bir “c.Expr [Seq [A]]' gibi bir yazıyla yazılmış durumda. İşte [birkaç örnek] (https://gist.github.com/4191360). –

cevap

1

Bu, beklendiği gibi çalışıyor mu?

object BarExample { 
    def bar(xs: Int*): Int = macro bar_impl 
    def bar_impl(c: Context)(xs: c.Expr[Int]*) = { 
    import c.universe._ 
    import scala.collection.immutable.Stack 
    Stack[Tree](xs map (_.tree): _*) match { 
     case Stack(Literal(Constant(x: Int)), _*) => c.literal(x) 
     case _ => c.abort(c.enclosingPosition, "bar wants integer constant arguments!") 
    } 
    } 
} 
+0

Teşekkürler, ama aslında benim 'BarExample' ile aynı, ve genel durumda çalışmayacak. –