BackEnd

Goの抽象構文木でコードを解析する

投稿日:2024年5月13日 更新日:

はじめに

Goでアプリケーションを開発していると、 go generate でコードを生成することがよくあると思います。大抵の場合は、コードを解析するのに抽象構文木(Abstract Syntax Tree)が用いられ、そのためにGoでは ast パッケージが提供されています。

最近、コードを自動生成する処理を実装する必要に迫られてきたため、 ast パッケージとそれを使ったコードの解析について調べてみました。

抽象構文木とは

抽象構文木は Abstract Syntax Tree の訳で、プログラムの文法構造を木構造で表したものを指します。

詳細は省きますので、詳しく知りたい方はこちら等をご覧ください

ASTでコードを解析する

サンプルコードを解析する

ASTで解析するためのサンプルコードとして、以下のファイルを用意しました。

まず初めに、このファイルを解析してパッケージ名、インポートしたパッケージ、定義された構造体の名前と変数名をそれぞれ出力してみます。

f, err := parser.ParseFile(fset, "src/book.go", nil, parser.ParseComments) で対象のファイルを ast,File に変換しています。

このコードを実行した際の出力は以下の通りです。

上記の通り、パッケージ名は src 、インポートしているパッケージは fmt 、そして、 Book 構造体が定義されていて、 TitleAuthorPages フィールドがあることがわかります。

このファイルを解析すると第一階層には3つのNodeがあります、それぞれのNodeが表しているものは以下の通りです。

  1. import文
  2. Book構造体
  3. Book構造体のStringメソッド

import文の部分はシンプルなので飛ばして、構造体の部分から見ていきます。

構造体の木構造を確認する

構造体は、 ast.GenDecl の中の ast.StructType で表されています。以下はこの構造体と関連する構造体の一部を抜粋したものです。

BookをFieldListで表すと以下のようになります(最低限のみで簡略化しています)

このように、Namesの中のNameにフィールド名が、Typeの中のNameに型の名前が入っています。

ちなみに、以下のように構造体の定義を type() でまとめると、 ast.GenDecl.Specs の要素が複数になります。

メソッドの木構造を確認する

Bookには (b *Book) String() string メソッドが生えていますが、 ast.StructType には含まれていませんでした。最初に説明した通り、第一階層のBookと別のNodeに含まれており、 ast.FuncDecl の中の ast.FuncType で表されています(ただし、 receiver の情報は ast.FuncDecl に含まれています)

以下はこの構造体と関連する構造体の一部を抜粋したものです。

StringメソッドをFuncTypeで表すと以下のようになります(最低限のみで簡略化しています)

このようにかなり長くなってしまいましたが、 Recv の中の Field[0].Names.Name にreceiver変数名が、 Field[0].Type.X.Name にreceiverの型の名前が入っています。

メソッド名は Name.Name にあり、返り値の型は Type.Results.List[0].Type.Name にあります。

return文は Body.List[1].Results に表されており、その中の各要素がそれぞれ b.Title+ " by " +b.Author を表しています。

任意の対象を捜索する

ASTから特定の対象を見つけるには、 astutil.Apply メソッドを使ってすべてのNodeを再帰的に探索します。

また、 astutil.CursorReplace メソッドを使うことで、対象のNodeを置き換える事もできます。

ASTをファイルに反映する

最後に、ASTをもとにファイルに出力する方法を紹介します。

もともとの book.goString メソッドを一部書き換えて、 book2.go に出力してみます。

出力されたファイルは以下の通りです。

string メソッドの代わりに string2 メソッドになっています。

さいごに

go generate によるファイル生成を行うために、 ast パッケージを使ったファイルの解析と変更について調べてみました。これを応用することで、定型的なコードを自動生成できるようになれば良いなと思います。

おすすめ書籍

Go言語プログラミングエッセンス エンジニア選書 Go言語 100Tips ありがちなミスを把握し、実装を最適化する impress top gearシリーズ 初めてのGo言語 ―他言語プログラマーのためのイディオマティックGo実践ガイド

blog-page_footer_336




blog-page_footer_336




-BackEnd
-

執筆者:

免責事項

このブログは、記事上部に記載のある投稿日時点の一般的な情報を提供するものであり、投資等の勧誘・法的・税務上の助言を提供するものではありません。仮想通貨の投資・損益計算は複雑であり、個々の取引状況や法律の変更によって異なる可能性があります。ブログに記載された情報は参考程度のものであり、特定の状況に基づいた行動の決定には専門家の助言を求めることをお勧めします。当ブログの情報に基づいた行動に関連して生じた損失やリスクについて、筆者は責任を負いかねます。最新の法律や税務情報を確認し、必要に応じて専門家に相談することをお勧めします。


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

PHPerだけどKotlinを勉強したって良いよね その2〜コンストラクタ編〜

1 はじめに2 コンストラクタ2.1 プライマリコンストラクタ2.2 セカンダリコンストラクタ2.3 ニックネームのみを入力した人2.4 ニックネームと email を入力した人2.5 Faceboo ...

Docker上のLaravelのログをFluentdに出力する

1 はじめに2 環境3 Fluentdについて4 目的5 Fluentd本体はdocker-composeで導入5.1 fluentd5.2 db5.3 app5.4 web6 Laravelからログ ...

Rust入門してみた (基本構文編)

1 はじめに2 Rustとは?3 Rustの特徴的な基本構文3.1 変数と定数3.2 所有権3.3 所有権の借用3.4 関数3.5 エラーハンドリング3.5.1 回復不能なエラー(panic!)3.5 ...

rails

Shrineでアップロードする際に画像を加工する

1 はじめに2 アップロードする画像のリサイズ2.1 Gemを追加2.2 Uploaderの修正3 サムネイルを作成する3.1 Uploaderの修正3.2 サムネイルを表示する4 バリデーションの追 ...

laravel logo

Laravelのブラウザテスト「Dusk」で非同期で重たい処理のテストを実装してみよう

1 はじめに2 JavaScriptの式で待機する2.1 テスト対象となるコード2.2 Duskのテストコード3 DOM要素の表示を待つ3.1 テスト対象となるコード3.2 Duskテストコードの実装 ...

フォロー

blog-page_side_responsive

2024年5月
 1234
567891011
12131415161718
19202122232425
262728293031  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。