More Related Content Similar to Goにおける静的解析と製品開発への応用 (20) More from Takuya Ueda (8) Goにおける静的解析と製品開発への応用1. Goにおける静的解析と
製品開発への応用
The Go gopher was designed by Renee French.
The gopher stickers was made by Takuya Ueda.
Licensed under the Creative Commons 3.0
Attributions license.
2017/06/24(土)
ハッカーズチャンプルー
2017
1
10. goパッケージ
■ 標準パッケージとして静的解析の機能を提供
go/ast 抽象構文木(AST)を提供
go/build パッケージに関する情報を集める
go/constant 定数に関する型を提供
go/doc ドキュメントをASTから取り出す
go/format コードフォーマッタの機能を提供
go/importer コンパイラに適したImporterを提供
go/parser 構文解析の機能を提供
go/printer ASTの表示機能を提供
go/scanner 字句解析の機能を提供
go/token トークンに関する型を提供
go/types 型チェックに関する機能を提供
10
14. v + 1
構文解析 - go/parser,go/ast
■ トークンを抽象構文木(AST)にしていく
● プログラムの構造を持たせる
14
IDENT ADD INT
ソースコード
+
v 1
BinaryExpr
Ident BasicLit
トークン
抽象構文木(AST)
15. n := 100 + 200
m := n + 300
型チェック - go/types,go/constant
■ 抽象構文木から型に関する情報を取得する
● 識別子の解決
● 型の推論
● 定数の評価
15
定数の評価
=300
型の推論
-> int
識別子の解決
17. package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
}
Hello, Worldの抽象構文木の構成
17
Goの抽象構文木(AST)を手入力してHello, Worldを作る
http://qiita.com/tenntenn/items/0cbc6f1f00dc579fcd8c
Playgroundで動かす
*ast.File
[]ast.Decl
*ast.GenDecl *ast.FuncDecl
18. 式の抽象構文木を取得する
■ 式単位を構文解析する
■ ParseExprFromでも書ける
18
expr, err := parser.ParseExpr(`v + 1`)
if err != nil {
/* エラー処理 */
}
/* exprを解析する処理 */
fset := token.NewFileSet() // ファイル情報
src := []byte(`v + 1`)
f := "" // ファイル名(式なので不要)
m := 0 // モード(式なので不要)
expr, err := parser.ParseExprFrom(fset, f, s, m)
19. const src = `
package main
var v = 100
func main() {
fmt.Println(v+1)
}`
fs := token.NewFileSet()
f, err := parser.ParseFile(fs, "my.go", src, 0)
if err != nil {
/* エラー処理 */
}
/* f を解析する処理 */
ソースから抽象構文木を取得する
■ Goのソースコードを構文解析する
19
引数はparse.ExprFromと
同じ構成
srcがnilだとファイル名
でファイルを開く
解析するファイルの中身
21. *ast.BinaryExpr
*ast.Ident
*ast.BasicLit
v + 1
n, _ := parser.ParseExpr(`v + 1`)
ast.Inspect(n, func(n ast.Node) bool {
if n != nil { fmt.Printf("%Tn", n) }
return true
})
printer.Fprint(os.Stdout, token.NewFileSet(), n)
抽象構文木をトラバースする
■ ast.Inspectを使う
21
+
v 1
構文解析
抽象構文木(AST)を探索
抽象構文木(AST)を出力
BinaryExpr
Ident BasicLit
Playgroundで動かす
ast.Walkというのもある
22. func traverse(n ast.Node) {
switch n := n.(type) {
case *ast.Indent:
fmt.Println(n.Name)
case *ast.BinaryExpr:
traverse(n.X)
traverse(n.Y)
case *ast.UnaryExpr:
traverse(n.X)
}
}
抽象構文木をトラバースする
■ 再帰を使ってトラバースする
22
識別子の場合は名前を出力
二項演算式の場合は
各項を探索
単項演算式の場合は
項を探索
型でswitchする
Playgroundで動かす
ast.Nodeはインタフェース
23. 参考資料
■ goパッケージで簡単に静的解析して世界を広げよう
● コードジェネレータ
○ ASTを取得する方法を調べる
○ 抽象構文木(AST)をトラバースする
○ 抽象構文木(AST)をいじってフォーマットをかける
○ Goの抽象構文木(AST)を手入力してHello, Worldを作る
○ go-app-builderのソースコードを読む
● リファクタリングツール
○ gorenameをライブラリとして使う
○ Goのスコープについて考えてみよう
○ go/typesパッケージを使い変数名をリネームしてみる
● 処理系
○ 簡単な式の評価機を作ってみる
○ 【実践goパッケージ】文字列から複素数型の値をパースする
○ もっと楽して式の評価器を作る
23
26. リクエスト/レスポンスのテスト
■ リクエストのテストからドキュメントを生成
● Request Bodyをリフレクションでテストしている
● 構造体の任意のフィールドを指定できる
26
validator.RequestBody(t, []httpdoc.TestCase{
{"Name", "tenntenn", "User Name"},
{"Attribute.Birthday", "1986-01-12", "User
birthday YYYY-MM-DD format"},
}, &createUserRequest{})
参考:go-httpdocのexample
37. まとめ
■ Goは静的解析に向いている
● 静的型付け言語
● 標準パッケージで対応
■ 静的解析を開発ツールに使う
● よくあるレビュー指摘事項を自動化する
● 自作go vetやlintを作る
■ 開発ツール以外にも使える
● うまく使えば本番で稼働するコードも書ける
● 式としてパースできるのは強い
37