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


関連記事

Go言語

[Go初心者]Interfaceについて学習

1 はじめに2 interfaceとは3 interfaceのメリット3.1 インターフェースを使うとコードの共通化ができる3.2 インターフェースを使うと実装を隠蔽することができる3.3 インターフ ...

laravel logo

Inertia使ってみた①

1 はじめに2 Inertiaとは3 ルーティング4 LaravelからReactに値渡し5 レスポンス5.1 初回5.2 page object5.3 2回目以降5.4 リロード時6 さいごに7 お ...

rails

Railsで複合主キーのテーブルを扱う

1 はじめに1.1 前提条件2 実装例2.1 config2.2 マイグレーション2.3 モデル3 さいごに はじめに RailsでWebサービスを開発する際のDB設計では基本的にidが主キーになると ...

aws

ALB+EC2な環境でhttpをhttpsにリダイレクトする

1 はじめに1.1 前提条件2 ALBの設定3 Nginxの設定3.1 注意点4 さいごに はじめに httpsに対応済みのWebサイトの場合、httpでアクセスされた時にhttpsでリダイレクトする ...

laravel logo

[Laravel]データベースの暗号化について考えてみる

1 はじめに2 環境3 Laravelでの暗号化4 暗号化されたカラムは、そのままではLIKE検索ができない4.1 問題点4.2 解決案1:全件取得してPHP側でがんばって検索する4.3 解決案2:暗 ...

フォロー

blog-page_side_responsive

2024年5月
 1234
567891011
12131415161718
19202122232425
262728293031  

アプリ情報

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