- バックエンド / リーダー候補
- PdM
- Webエンジニア(シニア)
- 他19件の職種
- 開発
- ビジネス
RubyKaigi 2023 参加記 #9 - Yet Another Ruby Parser(Day 2)
Photo by Markus Winkler on Unsplash
こんにちは! Wantedlyでエンジニアをしているnasaです。
本記事では2日目のセッション「Yet Another Ruby Parser」について紹介していきます。
本セッションは、Shopifyが開発している新しいRubyパーサーYARPに関するものでした。新しいパーサーを開発するモチベーションや技術的に困難だったことが話されていました。
YARPの状況
YARPは現時点のRubyの構文は100%カバーしているようです。
開発が始まったのが6ヶ月前なのでものすごい開発スピードだと思いました。
ShopifyやGitHubなど複数の大規模アプリケーションで動作確認を行い、問題なく動作することを確認したようです。またCRubyだけでなくJRuby, TruffleRubyでも動作するようです。
どこまで難しいことなのか分かりませんが、半年でここまで出来ることに驚きです。相当開発力が高い組織だと感じました。
参考までにYARPのコード量を貼っておきます(もしかしたらRuby parserのコードを拝借しているのかも?)
:) % tokei
===============================================================================
Language Files Lines Code Comments Blanks
===============================================================================
C 43 19043 16709 940 1394
C Header 19 1591 1029 264 298
Java 1 11 7 0 4
JSON 2 129 129 0 0
Makefile 1 44 32 2 10
Rakefile 7 701 528 48 125
Ruby 1830 77595 75034 403 2158
Ruby HTML 11 1016 879 0 137
Plain Text 1 25 0 20 5
TypeScript 1 199 120 53 26
YAML 3 1897 1830 0 67
-------------------------------------------------------------------------------
Markdown 14 633 0 459 174
|- C 2 68 33 26 9
|- Ruby 2 25 19 1 5
(Total) 726 52 486 188
===============================================================================
Total 1933 102884 96297 2189 4398
===============================================================================
Yet Another Ruby Parser
なぜ新しいRubyパーサーが必要なのでしょうか?
YARPは下記の3つのモチベーションから開発が始まりました。
- エラートレラント
- ポータビリティ
- 保守性
それぞれ説明します。
エラートレラント
エラートレラントはその名の通り、パーサーで何か問題が発生した場合でも可能な限り意味のある結果を返却することです。
本来パーサーはASTを作ることが責務でしたがLSPのことを考えると不十分です。
LSPは常にソースコードをパースして開発者にとってよりより情報を返却するかと思います。このときソースコードは開発者によって絶え間なく変更されています。
そのため下記のようなシンタックスエラーとなるコードが存在するタイミングがあり、パーサーはこれを扱う必要が出てきます。
def main
puts "hello"
上記のコードだとendが無いので補完やユーザーへのレポートがあると開発者フレンドリーですね。
このようにシンタックスエラー時でも開発者にとって有益な情報を返却することがパーサーには求められています。
LSPを例として説明しましたが、その他の開発ツールやRubyインタプリタのエラーメッセージでも活用できそうですね。(Rustだとエラーメッセージがかなり充実しているのでRubyもそうなるととっても嬉しいです!)
ポータビリティ
現状のRubyのパーサーはCRuby, JRuby, TruffleRubyで分散しています。またRuby処理系だけでなくsorbet, steep, ruby-lspなどの開発ツールにもパーサーが実装されています。(5~10個は紹介されていましたが忘れてしまった、、)
この状況を解決するために、YARPはRuby以外の実装やツールでも利用可能なパーサーを目指しているようです。
ポータビリティ実現のためにこれらの設計方針を取っているようです。
- CRubyの内部構造に依存しない: YARPはCRubyには依存せず、独立した構造として開発されています。
- 外部のパーサージェネレーターやツールに依存しない: 外部のパーサージェネレーターやツールに依存しない。これにより、他の実装やツールでもYARP組み込むことが出来る。
保守性
現状のRubyパーサーの保守性には言及してなかったので、なにか課題感があって〜という話では無さそうです。(聞き逃してないならば)
僕の想像ですが、ポータビリティを上げ様々なプロジェクトから使われる様になった場合更に保守性に気を使う必要が出てきたんですかねー。
YARPではドキュメントとテストカバレッジにフォーカスして保守性が高い状態を維持しているようです。
ドキュメンテーションは、コントリビューター向けの開発プロセス、アーキテクチャ、提供しているAPIなど様々なものがあります。
off topic
YARPのセッションについては以上です。
RubyKaigi2023ではYARP以外にもパーサーのセッションがありLramaというRubyパーサーが紹介されていました。
https://rubykaigi.org/2023/presentations/spikeolaf.html#day1
ここからはYARPとLramaについて共通点や差異を書いてみようとも思います。
ただし、あまり踏み込んだ話は出来ないので浅い話です。
共通点
保守性の話はYARPのみでしたが、error tolerantやポータビリティの話は共通していました。
最近のRubyの情勢(?)は追えていませんでしたがかなりホット分野なのでしょうか?
実装方針はかなり違うようですが目指す世界は共通しているようですね。
差異
個人的には、実装方針がかなり違うなと思っていてLramaはCRubyと同じくパーサージェネレーターを使う方針ですがYARPはジェネレーターを使わず手で実装されています。
僕はパーサーに詳しくないので現時点ではよく分かっていませんが、この実装方針の差異が今後どのように影響していくのか興味があります。
余談ですが、Lramaのセッションでパーサージェネレーター(というかLRパーサー)はDSLの表現力が足りていないだけでまだまだやれるんだぞ!と話されていました。
感想
RubyKaigi2023ではパーサーに関するセッションが多くある印象です。(僕は3つ聞いた)
馴染みのない分野だったので難しく面白いと感じました。僕のようにパーサー面白そう!と感じた人は多く居たのではないでしょうか?
本記事の読者の中にも興味を持ってくれた人がいれば嬉しいです。
Lrama、YARPの今後が楽しみです!
最後に参考になりそうなリンクを張っておきます!今後より深く理解して発信できたらと思います。