寄付窓口はこちら

AST メタプログラミング | try! Swift Tokyo 2018 Day1-15

Swift にはランタイムにおける動的な振る舞いがほとんどありません。コード注入の実現方法や、AST を用いたアスペクト指向プログラミングについてお話します。

AST メタプログラミング

f:id:niwatako:20180301173005j:plain

こんにちは、フリーランスデベロッパーです。メタプログラミングの手法の話をしたいと思います。 メタプログラミングは興味深いと思います。

f:id:niwatako:20180301173051j:plain

ASTとは、通常見られません。ですが開発ツールを通してみなさん利用していると思います。幾つか種類があります。違いを説明していきます。

ASTは抽象型シンタックスツリーのことです。プログラムの構造を表します。

f:id:niwatako:20180301173125j:plain

Xcodeもリファクタリングのために使っています。 開発ツールの中でプロウグラマティックに扱うことを可能にしています

メトリクス分析は典型例です。

f:id:niwatako:20180301173314j:plain

これらはSourceKitがつくるASTを利用して実現しています

ASTを入手する方法です

f:id:niwatako:20180301173342j:plain

それぞれ違うものが入手できます

SourceKitで生成されたもの

f:id:niwatako:20180301173403j:plain

外部ツールで使いやすいJSONフォーマット。

f:id:niwatako:20180301173438j:plain

f:id:niwatako:20180301173457j:plain

文字列表現をASTで、Swiftコンパイラに使われているASTを見ることができます。

こちらにはより多くの情報が含まれています。 このASTの一番大きな優位性はすべての型情報が解決された状態であるということです。メタプログラミングにはとても使われやすい。

しかしながらこのようなASTのパーサーはありません。

みなさん自身がパースする必要があります。

f:id:niwatako:20180301173620j:plain

こちらは4.1から追加されました。libSyntaxで生成されています。元のソースコードのすべての情報が入っています。ホワイトスペースやブランク業まで入っています。 ASTからリストアできます。ソース変換、コードフォーマッターのようなものに有効です。

f:id:niwatako:20180301173713j:plain

libSyntaxのラッパーでSwiftSyntaxが公開されています。

新しいノードを生成するAPIを提供しています。

比較表です

f:id:niwatako:20180301173742j:plain

SourceKitは始めて使って見るには良いと思います。 SwiftSyntaxは二つ目にやりやすいです。でもまだ積極開発中で変わっていきますのでOSSで使っているところは殆どありません。-dumb-astが非常に強力ですが使うのはこんなんでしょう。

習うより慣れろ言うことで

f:id:niwatako:20180301173858j:plain

使うツールを作ってみましょう

SwiftSourceCodeをHTMLシンタックスハイライトしてみましょう。

すべてのノードをVisitorPatternというのを使って辿っていくことができます。

どこを書き換えるかで変わってきます。今回はすべてのトークンを辿っていきたいと思います。

トークシンタックスを使っていきます。Tokenというのはそれ以上分割できない、if, else, (), :などです。

トークンにspanクラスを割り当ててマークアップします。

f:id:niwatako:20180301174015j:plain

f:id:niwatako:20180301174033j:plain

f:id:niwatako:20180301174040j:plain

ASTプログラミングの最初のステップとしては良さそうです。

ハイライトの目的は達成されました。しかしツリー構造はなくなってしまいました。

この問題を解決するためにより複雑なコードを書く必要があります。

f:id:niwatako:20180301174119j:plain

visitpre, postで事前に処理をしたりできます。

f:id:niwatako:20180301174151j:plain

作ってみたもののデモです

github.com

コードを書くと、サーバーに送られて、ハイライトされて帰ってきます。

f:id:niwatako:20180301174239j:plain

次により実践的な例を紹介したいと思いますアスペクト指向プログラミングです。

ロギングとか。

ViweControllerにログのメソッドを付け加えるなど。

f:id:niwatako:20180301174337j:plain

f:id:niwatako:20180301174427j:plain

CodeblockSyntaxは{}で囲まれたところで呼ばれる

f:id:niwatako:20180301174455j:plain

重複したコードが何度も挿入されないように、

f:id:niwatako:20180301174516j:plain

変換されたASTを後続処理に直接渡せたら良いけど、それは今は無理なので

コード生成して、再ビルドする仕組みを作りました

f:id:niwatako:20180301174540j:plain

アプリケーションを通常通り起動します。 PDFリーダーのようなアプリケーションを起動します。

f:id:niwatako:20180301174636j:plain

outputがありません。printメソッドが入ったコードがないからですね。

ではアスペクト主導型のプログラミングで、お見せします。

f:id:niwatako:20180301174709j:plain

f:id:niwatako:20180301174751j:plain

f:id:niwatako:20180301174823j:plain

f:id:niwatako:20180301174835j:plain

viewXxxx系のfunctionからログが出力されるようになりました。

挿入されたコードはコンパイルが終わるとなくなります。

御覧頂いたようにアスペクト指向型プログラミングで元のコードを汚すことなく変更を加えることができます。

こちらはより高度な例になるでしょう

f:id:niwatako:20180301174938j:plain

f:id:niwatako:20180301174954j:plain

XCTAssertのコンディションを判定している箇所

f:id:niwatako:20180301175023j:plain

デモです

f:id:niwatako:20180301175119j:plain

幾つかのテストが失敗しています

f:id:niwatako:20180301175135j:plain

なぜテストが失敗したのかわかりません。 SwiftPowerAssertを使います。

テストコマンドをラップしていきます。コード挿入して、コンパイルして、、、

f:id:niwatako:20180301175216j:plain

なぜテストがFailしたのか分かるようになりました。値が理解できる形で表示されているからです。 オンラインでも展開されています。

どのようなコードでもエディタの中に書いていくことができます。

コードとサーバーサイドのSwiftのコード挿入、結果表示ができます

f:id:niwatako:20180301175309j:plain

終わったらやってみて下さい。

つぎにSwiftFmt

f:id:niwatako:20180301175351j:plain

Swiftfmt Playground

空白の場所などルールをカスタマイズできる

f:id:niwatako:20180301175512j:plain

ASTを使うとボイラープレートコードをなくすことができます。Swiftをダイナミックに利用できます。

興味を持っていただけたでしょうか。マニアックな趣味のような世界ではありますけれども、Swiftコミュニティにも役に立つものだと思います。

f:id:niwatako:20180301175615j:plain

これらが有益なリソースですのでチェックしてみて下さい。

紹介したものはすべてGithubにあります

f:id:niwatako:20180301175639j:plain

f:id:niwatako:20180301175655j:plain

以上です、ご清聴ありがとうございました。

[広告]面白かったら、ためになったら

  • はてなブックマークSwift タグをつけてブックマーク!
  • 「インターネットで生活を楽しく豊かにしたい」仲間を募集しています
  • Bitcoin: 3KGqXtR1ZaGVdkvcw8CCNrkDxDhdbZBYHL