2013-05-08 21 views
6

Şu anda makrolarıyla biraz etrafına oynuyorum ve belki bu burada kötü bir fikir zaten, ama bir param atamak benim sorunum:Scala makro yapıbozuma fonksiyonu

Aşağıdaki makro:

def using[A <: { def close(): Unit }, B](resource: A)(f: A => B) = macro usingImpl[A, B] 

def usingImpl[A <: { def close(): Unit }, B](c: Context)(resource: c.Expr[A])(f: c.Expr[A => B]): c.Expr[B] = { 

    import c.universe._ 


    f.tree match { 
    case Function(params, body) => 
     //val ValDef(modifiers, name, tpt, _) = params.head 
     c.Expr[B](
     Block(
      List(
      //ValDef(modifiers, name, tpt, resource.tree) 
      ValDef(params.head.symbol, resource.tree) 
     ), 
      body 
     ) 
    ) 

    case _: Select => 
     reify { 
     val res = resource.splice 
     try { 
      f.splice(res) 
     } finally { 
      res.close() 
     } 
     } 
    } 
} 

Select durumunda, sadece işlevi çağırıp kaynağı kapatırım, iyi çalışıyor. Ancak, Function durumunda, param değerini kaynağa atamak ve bedeni aramak istiyorum. ValDef'un kullanımdan kaldırılan oluşturucusunu kullandığımda, bu, Symbol ve Tree alır, her şey yolunda çalışır. Out-commented 4-args yaratıcısı kullanıyorum, x$1 değerinin kapsamda olmadığını belirten bir derleyici hatası alıyorum. Her iki sürüm ürettiğini kod baktığımızda, tam olarak aynı görünüyor:

Expr[Int]({ 
    <synthetic> val x$1: Test.Foo = new Test.this.Foo(); 
    x$1.bar.+(23) 
}) 

belki bir yolu var mı, basitçe params.head kullanmak ve bir değer atamak için? Herhangi bir yardım için teşekkürler!

düzenlemek:, dışarı-yorumladı sürümünü kullanıyorsam Dediğim gibi

object Test extends App { 
    import Macros._ 

    class Foo { 
    def close() {} 

    def bar = 3 
    } 

    println(using(new Foo)(_.bar + 3)) 
} 

, bana bir derleyici hata veriyor baskılar olun:

böyle makro arama AST ve sonunda şu ileti: [error] symbol value x$1 does not exist in Test$delayedInit$body.apply

Ve 2.10.1 kullanıyorum.

+1

'params.head' işlevinin bozulmaması gayet iyi çalışmalıdır — Hatanızı (2.10.0 veya 2.10.1 ile) yeniden oluşturamıyorum ve aslında uncommented sürümüyle bir derleyici hatası elde edemiyorum. Makroyu aramak için kullandığınız kodu gönderir misiniz? –

+0

benim sorum – drexin

+0

Scala içine yıkıcılar yapmaya çalışıyorsunuz? İyi fikir! –

cevap

7

Şimdi hatalarınızı yeniden oluşturabilirim. "Bu giriş derleyiciyi öldürmüş gibi görünüyor." Yığın izleme böyle mesajı ve bakın hatları:

at scala.reflect.internal.SymbolTable.abort(SymbolTable.scala:49) 

sonraki hamle c.resetAllAttrs bir şeyler sarma başlamak olmalıdır. Dürüst olmak gerekirse, ilk kez etrafınızda hata yapamadığım için, body kodunu c.resetAllAttrs(body) koduna kopyalayıp kodunuzu yapıştırdıktan sonra değiştirdim. Bu noktada sadece bir refleks var. Bu numaranın gerekli olduğu bir yere benzeyen örnek için this little single abstract method class demo örneğine bakın.

Senin durumunda

, bu varsa:

Expr[B]({ 
    <synthetic> val x$1: $line3.$read.$iw.$iw.Test.Foo = new Test.this.Foo(); 
    x$1.bar.$plus(3) 
}) 

Tam istediğiniz gibi: Biz test kodu derleme yaparken

import scala.language.experimental.macros 
import scala.reflect.macros.Context 

object Macros { 
    def using[A <: { def close(): Unit }, B](resource: A)(f: A => B) = 
    macro usingImpl[A, B] 

    def usingImpl[A <: { def close(): Unit }, B](c: Context) 
    (resource: c.Expr[A])(f: c.Expr[A => B]): c.Expr[B] = { 
    import c.universe._ 

    val expr = f.tree match { 
     case Function(ValDef(modifiers, name, tpt, _) :: Nil, body) => 
     c.Expr[B](
      Block(
      ValDef(modifiers, name, tpt, resource.tree) :: Nil, 
      c.resetAllAttrs(body) 
     ) 
     ) 

     case _: Select => reify { 
     val res = resource.splice 
     try { f.splice(res) } finally { res.close() } 
     } 
    } 

    println(expr) 
    expr 
    } 
} 

Biz şu göreceksiniz.

+0

Bir çekicilik gibi çalışır, çok teşekkür ederim! – drexin