1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Golangの構文木操作ライブラリdstの紹介

Posted at

dstとはDecorated Syntax Treeの略で、GOの構文木(go/astパッケージ)にファイルの情報を付加したものである。
go/astパッケージではスペースやコメントの情報を持たないので、コードを生成するという目的には適さない。

例えば以下の例の場合、コメントの位置情報を持たないので順序が保存されずに出力の際に壊れてしまう。

code := `package a

func main(){
	var a int    // foo
	var b string // bar
}
`
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "", code, parser.ParseComments)
if err != nil {
	panic(err)
}

list := f.Decls[0].(*ast.FuncDecl).Body.List
list[0], list[1] = list[1], list[0]

if err := format.Node(os.Stdout, fset, f); err != nil {
	panic(err)
}

//Output:
//package a
//
//func main() {
//	// foo
//	var b string
//	var a int
//	// bar
//}

この例をdstなら以下のように出力できてコメントとソースの順序も保存されいてる。

code := `package a

func main(){
	var a int    // foo
	var b string // bar
}
`
f, err := decorator.Parse(code)
if err != nil {
	panic(err)
}

list := f.Decls[0].(*dst.FuncDecl).Body.List
list[0], list[1] = list[1], list[0]

if err := decorator.Print(f); err != nil {
	panic(err)
}

//Output:
//package a
//
//func main() {
//	var b string // bar
//	var a int    // foo
//}

astからdstへ

dstはastのほぼ互換なので構文木に関するものはastをdstに置き換えれば大体いける

decorator.ParseFileを使ってdst.Fileを取得します

https://www.notion.so

func (d *[Decorator](https://pkg.go.dev/github.com/dave/dst/decorator#Decorator)) ParseFile(filename [string](https://pkg.go.dev/builtin#string), src interface{}, mode [parser](https://pkg.go.dev/go/parser).[Mode](https://pkg.go.dev/go/parser#Mode)) (*[dst](https://pkg.go.dev/github.com/dave/dst@v0.27.2).[File](https://pkg.go.dev/github.com/dave/dst@v0.27.2#File), [error](https://pkg.go.dev/builtin#error))

ParseFile uses parser.ParseFile to parse and decorate a Go source file. The ParseComments flag is added to mode if it doesn't exist.


	f, err := decorator.ParseFile(fset, "postback_strategy.go", nil, parser.DeclarationErrors|parser.AllErrors|parser.ParseComments)
	if err != nil {
		switch err := err.(type) {
		case scanner.ErrorList:
			for _, e := range err {
				fmt.Printf("%s:%d:%d %s\n", e.Pos.Filename, e.Pos.Line, e.Pos.Column, e.Msg)
			}
		default:
			fmt.Println(err)
		}
		return
	}

このfを使って、ast.とされてる箇所をdst.に置き換えれば大体いける。

なのでgolangでコード生成する必要があれば、こちらを使った方がいいかもしれない。

https://github.com/dave/dst

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?