2014-04-22 44 views
4

我有一個scala宏,它依賴於通過包含它的位置的靜態字符串指定的任意xml文件。Scala宏的非scala源位置

def myMacro(path: String) = macro myMacroImpl 

def myMacroImpl(c: Context)(path: c.Expr[String]): c.Expr[Any] = { 
    // load file specified by path and generate some code 
    ... 
} 

這意味着,如果xml文件格式錯誤,宏將無法展開。在提供包含xml文件中錯誤位置的文本表示的錯誤消息的那一刻。然而,這顯然不是最好的解決方案。

是否有可能爲我生成的代碼在不同的(可能的非scala)文件中提供源位置,以便錯誤將指向xml文件而不是包含xml文件的scala文件?我不明白我可以自己創建地點而不是改變現有地點。

回答

4

這個用例肯定非常有趣,它看起來像反射API應該支持的東西。不幸的是,目前還沒有公共的API來實現這一目標,即使內部的,儘管是相當低級的機器已經到位。

import scala.language.experimental.macros 
import scala.reflect.macros.blackbox.Context 
import scala.reflect.io.AbstractFile 
import scala.reflect.internal.util.BatchSourceFile 
import scala.reflect.internal.util.OffsetPosition 

class Impl(val c: Context) { 
    def impl: c.Tree = { 
    val filePath = "foo.txt" 
    val af = AbstractFile.getFile(filePath) 
    val content = scala.io.Source.fromFile(filePath).mkString 
    val sf = new BatchSourceFile(af, content) 
    val pos = new OffsetPosition(sf, 3).asInstanceOf[c.universe.Position] 
    c.abort(pos, "it works") 
    } 
} 

object Macros { 
    def foo: Any = macro Impl.impl 
} 

object Test extends App { 
    Macros.foo 
} 

運行一個簡單的文本文件,該代碼產生以下結果:

20:56 ~/Projects/Master/sandbox (master)$ cat foo.txt 
hello 
world 
20:56 ~/Projects/Master/sandbox (master)$ scalac Test.scala 
foo.txt:1: error: it works 
hello 
^
one error found 

請注意,此解決方案涉及scala.reflect.internal和cast(兩者無效所有兼容性保證我們提供scala-reflect.jar ),所以這不是我推薦的生產代碼。

+0

很酷,非常感謝你的回答。 :)這會幫助我玩這個宏,直到在公共API中支持這樣的東西。我將提交一張票。 –

+0

謝謝您的機票! –

+0

供將來參考:機票以[SI-8526](https://issues.scala-lang.org/browse/SI-8526)提交, –