2012-07-26 38 views
5

Tôi đang thử nghiệm với các tính năng macro scala 2.10. Tuy nhiên, tôi gặp sự cố khi sử dụng LabelDef trong một số trường hợp. Ở một mức độ nào đó, tôi đã nhìn vào mã của trình biên dịch, đọc các đoạn trích của Miguel Garcia's papers nhưng tôi vẫn bị kẹt.
Sử dụng LabelDef trong các macro scala (2.10)

Nếu hiểu biết của tôi là đúng, một giả định nghĩa sẽ là:
LabelDef(labelName, listOfParameters, stmsAndApply) nơi 3 đối số là Trees và:
- labelName là định danh của nhãn $ L được xác định
- listOfParameters tương ứng với các đối số được truyền khi label- áp dụng xảy ra, như trong $ L (a1, ..., an), và có thể để trống
- stmsAndApply tương ứng với khối của báo cáo (có thể không có) và chính thức áp dụng -expression
nhãn áp dụng ý nghĩa hơn hoặc ít hơn một GOTO để một nhãn

Ví dụ, trong trường hợp của một vòng lặp đơn giản, một LabelDef thể cuối cùng áp dụng bản thân:
LabelDef($L,(), {...; $L()})

Bây giờ, nếu tôi muốn xác định 2 LabelDef rằng nhảy với nhau:

... 
LabelDef($L1,(), $L2()) 
... 
LabelDef($L2,(), $L1()) 
... 

Nhãn thứ haiDef là tốt, nhưng trình biên dịch xuất ra lỗi trên giá trị thứ nhất "không tìm thấy: $ L2". Tôi đoán đó là bởi vì $ L2 chưa được xác định trong khi có một nỗ lực để áp dụng nó. Đây là một cây đang được xây dựng nên sẽ hợp lý với tôi. Sự hiểu biết của tôi có đúng không? Bởi vì nếu không có lỗi được mong đợi, điều đó có nghĩa là việc triển khai macro của tôi có thể là lỗi.

Dù sao, tôi tin rằng có phải là một cách để áp dụng $ L2 (ví dụ: Nhảy đến $ L2) từ $ L1, bằng cách nào đó, nhưng tôi chỉ không có đầu mối làm thế nào để làm điều đó. Có ai có một ví dụ về làm điều đó, hoặc bất kỳ con trỏ?


Các điểm không rõ ràng khác (nhưng ít quan tâm hơn) về cách sử dụng LabelDef trong macro là:
- đối số thứ 2 là gì, cụ thể như thế nào khi được sử dụng khi không trống? Nói cách khác, cơ chế của một nhãn-áp dụng với các tham số là gì?
- nó có hợp lệ để đưa vào biểu thức cuối cùng của đối số thứ 3 khác với nhãn không? (không phải là tôi không thể thử, nhưng macro vẫn còn thử nghiệm)
-có thể thực hiện chuyển tiếp nhãn áp dụng bên ngoài một LabelDef không? (có thể đây là câu hỏi dư thừa)

Bất kỳ ví dụ triển khai macro nào trong câu trả lời là, tất nhiên, rất được hoan nghênh!
Chúc mừng,

+0

Nó có thể là một ý tưởng tốt để yêu cầu này tại http://groups.google.com/group/scala-internals –

+0

@Eugene tôi cuối cùng đã phải đọc * scala liên quan -internal * chủ đề. Tuy nhiên nó xuất hiện mà thả 'LabelDef' từ Scala 2.11 đã được quyết định (và thực hiện). Mặc dù tôi hiểu được động lực từ quan điểm nội bộ, DSL có các tính năng 'GOTO'-ish dựa trên' LabelDef' sẽ bị ảnh hưởng, tôi tin (ví dụ: thay vì hướng dẫn JVM 'goto', một loạt các hướng dẫn cách giải quyết). Bạn có bất kỳ đầu vào về điều đó? – eruve

+0

Nó chắc chắn chưa được triển khai, vì LabelDefs vẫn nằm trong nhánh 2.11: https://github.com/scala/scala/blob/master/src/reflect/scala/reflect/internal/Trees.scala. Tôi đã đặt câu hỏi tại http://groups.google.com/group/scala-internals/browse_thread/thread/50c8643af1fe0973 - vui lòng, tham gia và chia sẻ mối quan tâm của bạn. –

Trả lời

1

Vì nếu không xảy ra lỗi, điều đó có nghĩa là việc triển khai macro của tôi có thể là lỗi.
Vâng, có vẻ như đó là một lỗi (^^; Mặc dù tôi không chắc chắn có hay không giới hạn với sự kết hợp Block/LabelDef tồn tại trên mục đích.

def EVIL_LABELS_MACRO = macro EVIL_LABELS_MACRO_impl 
def EVIL_LABELS_MACRO_impl(c:Context):c.Expr[Unit] = { // fails to expand 
    import c.universe._ 
    val lt1 = newTermName("$L1"); val lt2 = newTermName("$L2") 
    val ld1 = LabelDef(lt1, Nil, Block(c.reify{println("$L1")}.tree, Apply(Ident(lt2), Nil))) 
    val ld2 = LabelDef(lt2, Nil, Block(c.reify{println("$L2")}.tree, Apply(Ident(lt1), Nil))) 
    c.Expr(Block(ld1, c.reify{println("ignored")}.tree, ld2)) 
} 

def FINE_LABELS_MACRO = macro FINE_LABELS_MACRO_impl 
def FINE_LABELS_MACRO_impl(c:Context):c.Expr[Unit] = { // The End isn't near 
    import c.universe._ 
    val lt1 = newTermName("$L1"); val lt2 = newTermName("$L2") 
    val ld1 = LabelDef(lt1, Nil, Block(c.reify{println("$L1")}.tree, Apply(Ident(lt2), Nil))) 
    val ld2 = LabelDef(lt2, Nil, Block(c.reify{println("$L2")}.tree, Apply(Ident(lt1), Nil))) 
    c.Expr(Block(ld1, c.reify{println("ignored")}.tree, ld2, c.reify{println("The End")}.tree)) 
} 

Tôi nghĩ rằng một khối được phân tích cú pháp thành {statements; biểu thức} do đó đối số cuối cùng là biểu thức . Nếu một LabelDef "rơi vào" biểu thức , ví dụ: mẫu EVIL_LABELS_MACRO, mở rộng của nó sẽ không hiển thị trong các câu lệnh ; do đó lỗi "không tìm thấy: giá trị $ L2".

Vì vậy, tốt hơn hết là đảm bảo tất cả các câu hỏi về nhãn hiệu "rơi vào" . FINE_LABELS_MACRO nào đó và mở rộng để:

{ 
    $L1(){ 
    scala.this.Predef.println("$L1"); 
    $L2() 
    }; 
    scala.this.Predef.println("ignored"); 
    $L2(){ 
    scala.this.Predef.println("$L2"); 
    $L1() 
    }; 
    scala.this.Predef.println("The End") 
} 
+0

Nó có thể kết thúc bằng một 'EmptyTree' không? –

+0

Tôi nghĩ rằng 'EmptyTree' không có kiểu đính kèm, _even not_ a' scala.Nothing', do đó không áp dụng cho _expression_. Trong ví dụ của tôi, kết thúc không bao giờ đạt được, nhưng '' '' '' Block' có thể kết thúc bằng 'Literal (Constant (()))', vì macro phải sinh ra một 'Unit'. – eruve

+0

@daniel: nếu bạn có nghĩa là 'LabelDef', tôi _believe_ cây của đối số thứ 3 cũng sẽ tạo ra một _expression_, vì vậy không có' EmptyTree'. Tôi không biết nếu đó sẽ vẫn _valid_ trong tương lai nhưng arg thứ 3 không nhất thiết phải là _label-apply_ rõ ràng. – eruve

Các vấn đề liên quan