2013-02-09 31 views
38

Tôi có thể tìm hiểu cách xây dựng AST của Scala mà macro tạo ra?Tôi có thể tìm hiểu về việc xây dựng AST cho các macro Scala ở đâu?

Scaladoc không hữu ích như tôi muốn. Ví dụ:

abstract def Apply(sym: Universe.Symbol, args: Universe.Tree*): Universe.Tree 
A factory method for Apply nodes. 

Nhưng làm cách nào để tìm ra nút Áp dụng là gì? Tôi có thể tìm danh sách các loại nút trong AST và cách chúng khớp với nhau ở đâu?

Trả lời

39

Không có nhiều tài liệu cho nội bộ của trình biên dịch có sẵn, nhưng những thứ sẵn có sẽ đủ để bắt đầu.

Mirko Stocker, đã viết Master Thesis about Scala Refactoring của mình. Trong Phụ lục D (p. 95) ông mô tả kiến ​​trúc của AST. Nó cũng bao gồm một cái nhìn tổng quan đồ họa:

Scala AST

Một cách khác để tìm thông tin về AST là nhìn trực tiếp vào nguồn reflect.internal.Trees, chứa các AST.

Nếu người ta cần để tìm hiểu làm thế nào một đoạn mã nguồn cụ thể được thể hiện trong nội bộ có reify:

scala> import reflect.runtime.universe._ 
import reflect.runtime.universe._ 

scala> showRaw(reify{val i = 0}.tree) 
res8: String = Block(List(ValDef(Modifiers(), newTermName("i"), TypeTree(), 
    Literal(Constant(0)))), Literal(Constant(()))) 
+0

Cảm ơn! Luận án đó là một nguồn tài nguyên tuyệt vời. – Bill

+5

Cảm ơn bạn :-) Tôi hy vọng nó không quá nhiều lỗi thời .. –

+0

Làm thế nào chúng ta có thể vẽ một đồ thị như vậy? – Freewind

22

Bạn có thể có một cái nhìn tại scaladoc (http://docs.scala-lang.org/overviews/reflection/symbols-trees-types.html#trees) hoặc tại các slide (http://scalamacros.org/talks/2012-04-28-MetaprogrammingInScala210.pdf, các " Học cách học "phần".

Đây là những gì tôi thường làm. Tôi đã viết một kịch bản đơn giản có tên là parse, mã Scala làm đối số và sau đó biên dịch nó với -Xprint:parser -Ystop-after:parser -Yshow-trees-stringified -Yshow-trees-compact (parse sử dụng một tập lệnh trợ giúp khác: adhoc-scalac. click here để xem các nguồn của nó).

Lợi thế cách tiếp cận này có trên showRaw là không yêu cầu mã để đánh máy. Bạn có thể viết một đoạn mã nhỏ, đề cập đến các biến hoặc lớp không tồn tại và nó vẫn chạy thành công và hiển thị cho bạn AST. Dưới đây là một ví dụ về đầu ra:

09:26 ~$ parse 'class C { def x = 2 }' 
[[syntax trees at end of parser]]// Scala source: tmp36sVGp 
package <empty> { 
    class C extends scala.AnyRef { 
    def <init>() = { 
     super.<init>(); 
    () 
    }; 
    def x = 2 
    } 
} 
PackageDef(Ident(TermName("<empty>")), List(ClassDef(Modifiers(), TypeName("C"), List(), Template(List(Select(Ident(scala), TypeName("AnyRef"))), emptyValDef, List(DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(())))), DefDef(Modifiers(), TermName("x"), List(), List(), TypeTree(), Literal(Constant(2)))))))) 

Ngoài ra còn có một kịch bản gọi là typecheck, mà không giống nhau, nhưng dừng lại sau khi typer. Điều đó đôi khi rất hữu ích để hiểu chính xác typechecker biến đổi cây phân tích cú pháp như thế nào. Tuy nhiên, cả hai hộp công cụ và macro đều hoạt động với các cây phân tích cú pháp, vì vậy tôi sử dụng typecheck cho mục đích xây dựng cây rất hiếm khi.

+0

Cảm ơn, Eugene! Cuộc gọi scalac rất hữu ích. – Bill

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