Inside of Swift
Yuka Ezura, Dev-3 Center
Swift5new!
Swift5
Proposal
Swift-evolution に PR 出す
Core チームからフィードバック
“実装と共に”公式レビュー
大航海時代の幕開け
地図が欲しい!
Swift を使う
Swift の内部への入り口
• Swift プロジェクトの構成のイメージを掴む
• どの部分を変更するのか推測できる
Goal
- 環境構築
- 構成のイメージ
- イメージを固める
Agenda
環境構築
Swift と関連プロジェクトのソースコード
準備
Build tools (CMake, Ninja)
Disk space (>20GB)
Xcode (指定されているバージョン; 最新)
git clone git@github.com:apple/swift.git
./swift/utils/update-checkout --clone-with-ssh
コマンド
brew install cmake ninja
xcode-select -s [Xcode へのパス]
公式ドキュメント: https://github.com/apple/swift#getting-started
mkdir swift-source
cd swift-source
結果
swift/utils/build-script -x --skip-build
+α
Xcode プロジェクト作成
• build/Xcode-DebugAssert/swift-macosx-
x86_64/Swift.xcodeproj が作成される
• 利点
• 補完・宣言部の表示
• マクロで作成されたコードを即時に評価
swift/utils/build-script -R
ビルド
• Options
• -R: Release build
• -d: Debug build
• -t: Run test
• -h: ヘルプ
• …
swift-source
/build
/Ninja-ReleaseAssert
/swift-macosx-x86_64
/bin
/swift
結果
動作確認
./build/Ninja-ReleaseAssert/swift-macosx-
x86_64/bin/swift
構成のイメージ
コード解析の流れ
コード
字句
解析
構文
解析
意味
解析
Text Token
抽象構文木
(型情報 未解決)
抽象構文木
(型情報 解決済)
コード解析の流れ
SIL
Optimizer
LLVM
IR 生成
SIL
生成
LLVM
Swift 中間言語
= Swift の情報存在
制約検査
最適化
…
LLVM IR
途中経過出力コマンド例
swift -frontend -dump-parse [file name]
構文
解析
意味
解析
SIL
Gen
SIL
Opt
swift -frontend -dump-ast [file name]
swift -frontend -emit-silgen [file name]
swift -frontend -emit-sil [file name]
プロジェクト
構成
swift-source
/stdlib —- 標準ライブラリ (.swift, .gyb)
/lib —- コンパイラのソース群
/Parse —- 構文解析
/Sema —- 意味解析
/…
標準ライブラリ
.swift.gyb
.swift .swift
gyb (コード生成ツール)
% for Self in [
% 'Range',
% 'ClosedRange',
% ]:
extension ${Self} /* 中略 */ {
/* 中略 */
}
% end
gyb (コード生成ツール)
% for Self in [
% 'Range',
% 'ClosedRange',
% ]:
extension ${Self} /* 中略 */ {
/* 中略 */
}
% end
gyb (コード生成ツール)
extension Range /* 中略 */ {
/* 中略 */
}
extension ClosedRange /* 中略 */ {
/* 中略 */
}
構成
swift-source
/stdlib —- 標準ライブラリ (.swift, .gyb)
/lib —- コンパイラのソース群
/Parse —- 構文解析
/Sema —- 意味解析
/…
コード解析の流れ
コード
字句
解析
構文
解析
意味
解析
lib/Parse lib/Parse lib/Sema
lib/AST
コード解析の流れ
SIL
Optimizer
LLVM
IR 生成
SIL
生成
LLVM
lib/SILGen lib/
SILOptimizer
lib/IRGen
Raw SIL
加工済み SIL
LLVM IR
おまけ
Replace typealias keyword with associatedtype
for associated type declarations
(proposal: SE0011)
https://github.com/apple/swift-evolution/blob/master/proposals/0011-replace-typealias-associated.md
https://github.com/apple/swift-evolution/blob/master/proposals/0011-replace-typealias-associated.md
protocol P {
associatedtype T
}
Before
After
protocol P {
typealias T
}
コード解析の流れ
コード
字句
解析
構文
解析
意味
解析
lib/Parse lib/Parse lib/Sema
答え合わせ
https://github.com/apple/swift/pull/964/files
単純な変更
答え合わせ: https://github.com/ezura/swift-sample/commit/8e639f9e285f04c63ed9b307054d2246df459b2a
struct 🐻 {
var moon: Any
}
brown 🐻 {
conny moon: Wow
}
Before
After
コード解析の流れ
コード
字句
解析
構文
解析
意味
解析
Text Token lib/Parse
• 環境構築やビルド等、必要なスクリプトは準備済み
• 流れが整理されていて、眺めやすい
Conclusion
Thank you
References
- apple/swift
https://github.com/apple/swift
- apple/swift README
https://github.com/apple/swift/blob/master/README.
md
- Swift Programming Language Evolution
https://github.com/apple/swift-evolution#development-
major-version--swift-50
- Swift Contributing
https://swift.org/contributing/
- Compiler and Standard Library
https://swift.org/compiler-stdlib/#compiler-architecture
- gyb.py
https://github.com/apple/swift/blob/master/utils/gyb.py
- Swiftコンパイラ開発環境構築
http://qiita.com/rintaro/items/2047a9b88d9249459d9a
- Swift コンパイラのアーキテクチャ
http://qiita.com/rintaro/items/3ad640e3938207218c20
- Swiftコンパイラの構造と基盤テクニック
http://qiita.com/demmy/items/f08a65298d2f2caf1360
- Swiftのコンパイラを改造して独自構文を追加する
http://qiita.com/koher/items/aea1b44d0aef43b0059c
- How to Read the Swift Standard Library Source
https://oleb.net/blog/2016/10/swift-stdlib-source/
- Swift Intermediate Language (SIL)
https://github.com/apple/swift/blob/master/docs/SIL.rs
t
- StandardLibraryProgrammersManual.md (書き途中)
https://github.com/apple/swift/blob/27b044ec19d9cb9
2e3d49d678f5249b9031ff99d/docs/StandardLibraryPr
ogrammersManual.md

Inside of swift

Editor's Notes

  • #4 次のバージョン、Swift5 の議論が開始されましたね。 Swift4 で間に合わなかった、ABIの安定化がメインの目標となるようです。 そして、その影響もあり、proposal のフローが変わりましたね
  • #5 公式レビュー前に実装が必要になりました。 敷居が高くなったようにも感じますが、要件にされたからこそ、実装すること、つまり、言語自体をいじることに対しての特別さは少し薄れたようにも思えます。
  • #6 そう、もっと乗り出していっていいのだと
  • #7 新しく始めるときに、見通しがつくと進みやすいですよね。 しかし、公式ドキュメントには部分的に詳しい説明はあるのですが、全体をざっくり掴める資料はなかなかありません。
  • #8 ということで、今回話すのは、Swift を使う上での知識ではなく
  • #9 Swift 自身を触り始める話です
  • #10 この発表のゴールは、 Swift の、特にコンパイラの構成のイメージをざっくり掴み どこで何をしているか予想できるようになることです。
  • #11 流れとしては、まず、環境構築、次に構成の概要、最後にプロジェクトが実際にどうなっているのかイメージを固めていきます
  • #12 最初に環境構築です
  • #13 必要なものは、ソースコードと、ビルドに使うツールです。
  • #14 MacOS 上で構築する場合の具体的なコマンドはスライドの通りです。 Swift プロジェクトだけでなく、関連プロジェクトも取得するため、最初にディレクトリを作り、その中で Swift プロジェクトを clone しています。 基本的にこれで十分ですが、Linux 上の場合など、詳細な説明は下に記載している公式ドキュメントにあります。 2:09
  • #15 これらの作業が終わると、swift と、関連プロジェクトができています
  • #16 これはなくても開発できますが、Xcode上で Swift を触りたい場合、このスクリプトで xcodeproject を作ることができます。 Xcode でビルドもできますが、コマンドの方がビルド時間が短縮できます。
  • #17 環境構築が終わりましたので、ビルドして、動作確認までしてみます。 ビルドも、スクリプトが用意されています。 オプションがいろいろありますが、ここでは、ビルド時間の短縮のため、テストなし、リリースビルドを指定しています。
  • #18 ビルドが終わると、swift コンパイラのバイナリができています。
  • #19 動作確認をしてみましょう。 swift ファイル名を指定すればそのソースコードをコンパイルしますし、指定しなければ REPL モードになります。 これで準備は完了です。 回線やPCなどの環境にもよりますが、1 時間かからないくらいでできます。
  • #20 次に、コンパイラのフロントエンドの部分を中心に構成を見ていきましょう。 3:50
  • #21 コンパイラへソースコードを渡してから、 Swift の情報が消える、LLVM IR に変換するまでの処理の流れをお話しします。 まずは前半部分です。 ここは教科書的な構成となっています。 @@ ソースコードは文字列の集まり、つまりテキストです。 @@ それを、文字列の意味や文法を考慮しながらトークンにして、木構造でコードを表現します。 @@ このとき、文法にあっていないと木が作れず、構文エラーになります。 作成された抽象構文木、略称は AST なのですが、 この、AST を作るまでが字句解析と構文解析の役割です。 @@ その後、意味解析に移ります。 ここで、型情報を解決します。 型推論もこのフェーズで実行しています。 5:00
  • #22 そして、後半です。 @@ AST を元に SIL を生成します。 SIL とは Swift と LLVM IR の中間の言語で、LLVM IR にすると Swift の型情報はなくなるのですが、この時点ではまだ情報があります。 @@ SIL Optimizer で、変数を初期化しているかとか、switch 文で全網羅しているかなどのフローの制約を検査したり、ARC の最適化などが行われます。 @@ そして最後に、SIL を LLVM IR に変換します。
  • #23 流れを抽象化して説明してきましたが、 これらの処理結果を出力できるコマンドがあります。 この発表では、雰囲気を掴むことが目的なので、紹介までに留めます。
  • #24 次に、もう少し現実に寄って、実際のプロジェクトの構成を見ていきましょう 6:00
  • #25 Swift プロジェクトの中にたくさんディレクトリがあるのですが、 その中の、stdlib の中に、我々が日頃慣れ親しんでいる、標準ライブラリがあり、 lib の中に、コンパイラのソースがあります。
  • #26 標準ライブラリの中には、Swift ファイルとgyb という拡張子のファイルがあります。 これは、Generate your boilerplate の略で、最終的に、Swift コードに変換されるものです。 gym について少し説明しますと
  • #27 例えば、Range と ClosedRange 型で同じ内容の extension を記述したい箇所でこのように書かれています。
  • #28 Swift とそうでない部分があります。 これをツールで展開すると、
  • #29 このような Swift ファイルが生成されます。 標準ライブラリのいくつかの実装はこのように生成されています
  • #30 次にコンパイラのソース群ですが、
  • #31 対応関係は先ほどの図にそれぞれ対応しています。
  • #32 なので、それぞれの役割を知って入れば、プロジェクトのどのあたりを見れば良いのかあたりがつきます
  • #33 最後に、ちょっとした遊びを紹介します 7:30
  • #34 実装済の proposal を見て、コードのどこを変更したのか予想する遊びなのですが、気楽にコードリーディングできますし、議論の跡や歴史を知ることができて、おもしろいなと思っています。 ちなみに、こちらの Proposal は Swift2.2 で実装済です。
  • #35 proposal の概要は、protocol の associatedtype を宣言する際に、以前は typealias キーワードを使っていたのですが、 typealias キーワードが複数の意味を持ってしまい、わかりにくいので、名前を変更しようというものでした。
  • #36 これは今までの話の中で考えると、文字をトークンに変える部分と、文法の部分が変わっていそうだと予想できます。 lib/Parse の部分と…、実装によっては Sema もかもしれません。
  • #37 答えは時間の都合で解説は省きます。 Parse 部分の変更のほかに、token の定義の仕方や使われる場所、IDE へのサポートなども見ることができます。
  • #38 今までの話の知識でこのような悪戯も簡単にできます。 最低限の変更にしたので、3行だけの書き換えで実現しています。 答えは、下に記載してある URL でみることができます。
  • #39 ヒントですが、飛ばします。
  • #40 まとめますと、環境構築やビルドなど、必要なスクリプトは用意されていて、簡単に始められます。 ざっくりとした流れを知っていれば、意外と読みやすいです。