Tôi đang làm việc trong một DSL nhúng Scala và macro đang trở thành một công cụ chính để đạt được mục đích của tôi. Tôi gặp lỗi khi cố gắng sử dụng lại một cây con từ biểu thức macro đến vào biểu thức kết quả. Tình hình khá phức tạp, nhưng (tôi hy vọng) tôi đã đơn giản hóa nó vì sự hiểu biết của nó.Làm cách nào để tôi có thể sử dụng lại các subtrees định nghĩa (AST) trong macro?
Giả sử chúng ta có mã này:
val y = transform {
val x = 3
x
}
println(y) // prints 3
nơi 'cải tạo' là macro tham gia. Mặc dù nó có thể dường như nó hoàn toàn không có gì, nó thực sự là chuyển khối hiển thị vào biểu thức này:
3 match { case x => x }
Nó được thực hiện với thực hiện macro này:
def transform(c: Context)(block: c.Expr[Int]): c.Expr[Int] = {
import c.universe._
import definitions._
block.tree match {
/* {
* val xNam = xVal
* xExp
* }
*/
case Block(List(ValDef(_, xNam, _, xVal)), xExp) =>
println("# " + showRaw(xExp)) // prints Ident(newTermName("x"))
c.Expr(
Match(
xVal,
List(CaseDef(
Bind(xNam, Ident(newTermName("_"))),
EmptyTree,
/* xExp */ Ident(newTermName("x"))))))
case _ =>
c.error(c.enclosingPosition, "Can't transform block to function")
block // keep original expression
}
}
ý rằng xNam tương ứng với tên biến, xVal tương ứng với giá trị được liên kết và cuối cùng là xExp tương ứng với biểu thức có chứa biến. Vâng, nếu tôi in cây thô xExp tôi nhận được Ident (newTermName ("x")), và đó là chính xác những gì được thiết lập trong trường hợp RHS. Vì biểu thức có thể được sửa đổi (ví dụ x + 2 thay vì x), đây không phải là giải pháp hợp lệ cho tôi. Những gì tôi muốn làm là tái sử dụng cây xExp (xem bình luận xExp) trong khi thay đổi ý nghĩa 'x' (nó là một định nghĩa trong biểu thức đầu vào nhưng sẽ là biến LHS trong trường hợp đầu ra), nhưng nó khởi chạy lỗi dài tóm tắt trong:
symbol value x does not exist in org.habla.main.Main$delayedInit$body.apply); see the error output for details.
giải pháp hiện tại của tôi bao gồm trên phân tích của xExp để sustitute tất cả các Idents với những cái mới, nhưng nó là hoàn toàn phụ thuộc vào internals trình biên dịch, và như vậy, một cách giải quyết tạm thời. Rõ ràng là xExp xuất hiện cùng với nhiều thông tin hơn được cung cấp bởi showRaw. Làm thế nào tôi có thể làm sạch xExp đó để cho phép 'x' đóng vai trò biến trường hợp? Bất cứ ai có thể giải thích toàn bộ hình ảnh của lỗi này?
PS: Tôi đã cố gắng không thành công để sử dụng gia đình phương pháp thay thế * từ TreeApi nhưng tôi thiếu những điều cơ bản để hiểu ý nghĩa của nó.
Tác vụ 'resetAllAttrs' có hoạt động không? –
Có, nó đã làm. Nó làm việc trong đoạn mã đã cho thấy, cũng như trong một cái cây khá phức tạp với một vài "thay đổi" thay đổi. – jeslg
Bạn gọi là 'resetAllAttrs' trên kết quả' c.Expr', trên 'block', hoặc trên một số cây đã chọn? –