Lua lint “luli” のソースコードを公開しました

SUZUKI Tetsuya
shiguredo
Published in
8 min readMay 29, 2017

Lua 言語用のソースコード静的解析ツール luli の販売終了に伴い、ソースコードをオープンソースで公開しました。製品版をベースにしていますが、ソースコードも機能も同一ではありません。実はこれが今後 WebRTC 製品を主力に据える会社の最初の製品です。

開発・販売を終了した理由は二つあります。一つは「売れなかった」、もう一つは「リソースが足りない」です。ただ、会社として「製品がある」ことを重視していたので、売上は最優先ではありませんでした (売れるに越したことはありません) 。問題は「リソースが足りない」です。 luli は私一人で開発していたために専従は難しい。かと言って他の人を巻き込めるリソースもないし、何よりコストとリターンが釣り合いません。

それはともかく、せっかく OSS にしたのでよければ使ってみてください。 OCaml のビルド環境を一から整えるのは大変でしょうから、ビルド済みのバイナリを用意しました。 “luli” コマンドを任意のディレクトリにコピーすれば使えます。インストールは不要です。

なお、 Issues への反応は遅れやすいと思います。ご了承ください。

コーディング規約について

Lua に標準のコーディング規約は現時点では存在しないため、公式のドキュメントと Python の PEP8 を参考にしました。プロジェクトにとって余計なチェック項目があれば設定ファイル (Lulifile) で無効にしてください。

また、 luli はプロジェクト単位での使用を想定しています。設定ファイルは個人個人でバラバラに用意せず、プロジェクトのソースコードのトップディレクトリに置いて管理してください。

開発の動機

きっかけは当時のお手伝い先での開発現場です。諸事情により既存のソースコードのコーディングスタイルがバラバラで、しばらく関わる予定もありまして、弊社だけでも統一しようかと、試しに業務時間外で作ってみました。わりと早く動くようになり、これは使えそうだとの感触を得たので、その後はプロジェクトメンバーにバイナリを渡してフィードバックをもらいながら開発を進めました。 Vim の達人もいたおかげでエディタとの連携もできました。

というわけで、 luli は元々計画されていた製品ではありません。とは言え製品にしようとすれば数々のコストの高い作業が発生するわけで (最初のリリースまでの開発期間はだいたい 4 ヶ月) 、製品に漕ぎ着けられて非常に恵まれていたと思います。製品にしないなら初っ端から OSS にしてた…とは言わないでおきます。

OCaml を選んだ理由

luli は OCaml で実装されています。 OCaml と言えば、最近では Facebook 発のいくつかのツールの実装に使われている関数型言語としてご存知の方も多いでしょう。 PHP と互換性のあるプログラミング言語 Hack を始めとして、 JavaScript 用の静的型チェッカー Flow 、 OCaml に JavaScript 風の文法を被せた Reason 、 JavaScript のコードを OCaml に変換する JSCaml 。 Facebook 以外では OCaml のコードを JaveScript に変換する js_of_caml や BuckleScript があります。いずれも言語処理系に関するツールのためか、「 OCaml は言語処理系の開発に強い」はたまた「言語処理系の実装にしか使えない言語」と思われていなくもないようです。全然そんなことはなくて、世界で一番 OCaml に社運と資金を賭けている Jane Street Capital という金融系企業もあります。ですが Jane Street は外資系かつ金融系という一般的と言いにくい業態・業種でもあり、わりと引き合いに出されるものの、特殊な業務以外に使いようがないというイメージをお持ちの方もいらっしゃるのではないでしょうか。

luli を実装する際、次の理由で OCaml を選びました。

  • 実装者は一人のみなので、比較的選択肢を増やせる。
  • オープンソース。ぶっちゃけ無料で使いたい。
  • ネイティブコードにコンパイルでき、一つの実行ファイルにできる。簡単に使えるのは大きい。
  • 実行ファイルが非常に高速に動作する。
  • 言語処理系の開発に必要なライブラリは揃っている。
  • 趣味程度ではあるが個人的に学習した経験がある。 OCaml とよく比較される Haskell も学習しましたが、状態を持たせようとすると面倒になるのと、遅延評価でのデバッグが大変という個人的な想い出で避けました。もちろん、この時点で私が Haskell のスペシャリストであれば結果は違ったかもしれません。

特に重要だった理由が実行速度です。できれば Vim で :w した瞬間にチェックしたい。スクリプト言語では処理が遅く、Java だと起動が遅く、 C や Rust だと開発がしんどいと判断しました。メジャーな言語では Go も上記の条件をすべて満たしているのですが、言語処理系の開発の面から見ると代数的データ型とパターンマッチがないのが辛いです。

結局作ったのは言語処理系でしょ?と言われると確かにそうです。ただ、私は Swift や Kotlin が書けるなら OCaml も書けると思っています。 OCaml は文法が見慣れないでしょうけど、機能的には Swift/Kotlin と似通っており、かつ仕様が小さく、副作用バリバリのコードを書こうと思えばいくらでも書けます。関数型言語は難しそうというイメージと文法の特異さから、自分の中でハードルを上げてしまっている方は多いのではないでしょうか ( OCaml を使い込んだ結果実用的ではないと判断したケースを見聞きしたことがないので…) 。ただ、開発環境を用意するのは慣れるまでは大変なので、ぜひとも Wandbox をオススメします。

OCaml の弱点

  • Windows での使用が極めて難しい。現行の luli はWindows に対応する予定はありません。一度なんとか Windows でビルドしましたが疲れました。
  • 標準ライブラリが貧弱。今回は商用製品なので、巨大でも構わないので信頼性の高い Jane Street Core を使いました。
  • ライブラリが少ない。これは多くのプロジェクトでかなり厳しい点だと思います (大抵のケースではライブラリの有無で言語が選定されるでしょうから) 。自分たちで必要なライブラリを開発する気合いと根性を覚悟しなければいけませんが、なかなかそこまでのリソースがないのが実情だと思います。 luli では INI ファイルの解析ライブラリを自作しました。
  • ユーザーが少ないので情報が少ない。 Qiita を見てもメジャーな関数型言語の中では最も投稿数が少ないです (一応私はたびたび投稿しています) 。 Advent Calendar もありません。なきゃいけないものでもないと思いますが…
  • マルチコアに対応していないためスケールしない。 Apple の GCD を OCaml から使ってみたらマルチコアを使い切れましたが、そもそも処理系がマルチコアを想定してないので実行中に何が起こるかわかりません。実用はなかなか厳しい気がします。

OCaml が言語処理系の開発によく使われる理由

ついでに OCaml が言語処理系の開発によく使われる理由に触れておきます。個人的にもオレオレ言語の開発に使っています。

  • コードが短く済む。
  • 代数的データ型とパターンマッチがある。 Go を選ばなかった理由はこれです。言語処理系だと代数的データ型で表しやすいデータが多数あるため、パターンマッチがあるのとないのとでは実装しやすさに差が出ます。
  • 強い静的型付けがある。言語処理系で扱うデータは静的型付けに向いています。動的型付けだと実行時の型エラーに苦しみます。
  • 言語処理系に必要なライブラリが揃っている。言語処理系に必要な最低限の処理は字句解析と構文解析です。いわゆる lex と yacc に相当する優秀なツールがあります。 Go も揃っていますが、前述の代数的データ型とパターンマッチがないので辛いです。
  • 副作用のあるコードを書ける。
  • 実行速度が高速。これ大事。

OCaml には言語処理系向けの特殊な仕様も、 OCaml にしか存在しないライブラリも (今のところは) ないことを断っておきます。

最後に

今は luli の開発経験を活かして、 Erlang 向けのフォーマッター eryngii を手の空いた時間に実装しています (OSS です) 。これもやっぱり言語処理系で OCaml で、半分以上 OCaml の話になってしまいました。実際 OCaml に拠るところは大きかったので、これでいいやと思います。

--

--