go の parser.ParseFile
で AST を取得して、この情報からコメントの情報を消して format.Node
を使って再度コードに戻すことでコメントだけが消えたソースを生成することが出来ます。
package main
import (
"go/ast"
"go/format"
"go/parser"
"go/token"
"os"
)
var src = `
package p; // p package
/*
* sample
*/
func main() {
a := 1
a++ // increment
}
`
func main() {
fset := token.NewFileSet()
f, _ := parser.ParseFile(fset, "example.go", src, 0)
f.Comments = make([]*ast.CommentGroup, 0)
format.Node(os.Stdout, fset, f)
}
実行結果
package p
func main() {
a := 1
a++
}
コメントが消えたソースが出力されていることを確認出来ました。
仕組み
parser.ParseFile
を利用して AST を取得するのですが、このデータの実態は ast.File
でその中の情報にソースコードのコメント一覧が格納されているフィールドがあります。( Comments
)
type File struct {
Doc *CommentGroup // associated documentation; or nil
Package token.Pos // position of "package" keyword
Name *Ident // package name
Decls []Decl // top-level declarations; or nil
Scope *Scope // package scope (this file only)
Imports []*ImportSpec // imports in this file
Unresolved []*Ident // unresolved identifiers in this file
Comments []*CommentGroup // list of all comments in the source file
}
format.Node
を使って ast.File
をソースコードに変換する際に、コメント情報が Comments
から取られるので Comments
を何かしらの方法で値が空の状態にしてあげればコメント情報が戻せなくなるという訳です。
今回は parser.ParseFile
実行時のモード指定を 0
にしていたので各ノードにコメント情報が存在していませんでしたが、モードに parser.ParseComments
を含めて Comments
を nil
で初期化するとソースコードを戻す際にノードのコメント情報も見るようになるので、今回の例だと一部のコメントは消されず戻ってきます。
} else if n, ok := node.(*ast.File); ok {
// use ast.File comments, if any
p.comments = n.Comments
}
// if there are no comments, use node comments
p.useNodeComments = p.comments == nil
パース時に parser.ParseComments
を指定して Comments
を nil
で初期化した ver
func main() {
fset := token.NewFileSet()
f, _ := parser.ParseFile(fset, "example.go", src, parser.ParseComments)
ast.Print(fset, f)
f.Comments = nil
format.Node(os.Stdout, fset, f)
}
実行結果
package p
/*
* sample
*/
func main() {
a := 1
a++
}
なんで一部だけ戻ってきたのかはまだ詳しく見てないのでわかっていないです。。。(わかったら追記します)