自作言語の制作の流れ
こんにちは。原(@yhara)と申します。普段は会社員としてRubyプログラマーをしていますが、趣味としてプログラミング言語の自作というものをやっています。
私が現在制作しているのがプログラミング言語 Shiikaです。Shiikaは「Rubyのように書ける静的型付け言語があったらいいのにな」という思いから作り始めた言語で、まだできることは少ないですが、取り入れたい機能はたくさんあり、日々こつこつと作業を進めています。
今回は自作言語をなぜ作るのか、キャリアに役立つのか、という視点から自作言語の魅力をお伝えできればと思います。
言語の「自作」とは
プログラミング言語を自作する、とはどういうことでしょうか?
プログラマとして働いている人でも、ほとんどの人はC、Java、PHP、Python、Rubyなど既存のプログラミング言語を使っていると思います。しかし、それらの言語も無から発生したわけではなく、人の手によって作られたものなのですから、自分で新しいものを作るのも不可能ではないのです。
言語と処理系
ここで、「プログラミング言語」と「言語処理系」という言葉について説明しておきましょう。両者は混同されることもありますが、この区別をつけておくことは重要です。プログラミング言語は「こう書くとこうなる」というルールのことで、言語処理系はそのルールを実現するソフトウェアのことです。
プログラミング言語と言語処理系は1対1とは限りません。例えばプログラミング言語Rubyには、Cで実装されたCRuby、Javaで実装されたJRubyなど、複数の処理系が存在します。
制作の流れ
プログラミング言語を作ると言った場合、厳密には前者の「ルール」を設計することを指します。しかし、ルールだけ作ってもそれを動かすソフトウェアがないのでは面白くないですよね。そのため、言語を自作する場合は後者の「処理系」の実装も含むのが一般的です。
「ルール」の設計はプログラミング言語の根幹に当たるものです。完全に新しいものを考案するのは難しいので、既存のものに似ているがちょっと違うもの、から始めるとよいでしょう。
「処理系」作りに関しては、まずはインタプリタ・VM・コンパイラという3方式のいずれにするかを決めます。実装が簡単なのはインタプリタですが、VMやコンパイラ方式は実行速度を速くしやすいなどのメリットがあります。
言語自作を作る理由とこだわり
ところで、世の中にはこんなにたくさんのプログラミング言語があるのに、なぜ新しいものを自作するのでしょうか。私がShiikaを作っている理由はいくつかあります。
完全に自分好みの言語がほしかった
あなたが一番好きなプログラミング言語は何でしょうか。答えがすぐに出る人でも、その言語があなたにとって完璧か? と言われたら、いくつかは気になる点が思い浮かぶことでしょう。
私にとって一番理想に近い言語はRubyですが、それでもときどき「こうだったらいいのに」と思うことはあります。その中で最も大きなものが、「静的型言語だったらいいのに」というアイデアです。これはRubyの根幹と真っ向から対立しますから、これを実現するとしたら自分で1から作るしかなかったのです。
Shiikaが目指すもの
Shiikaの目標は、Rubyの手触りを持った静的型言語を作ることです。Rubyの大きな魅力の一つはその書きやすさですが、その書き味はどこから来るのでしょうか?
それは標準で提供される豊富な便利メソッドにあるのかもしれない。それは組み込みクラスが細かく分かれておらず、ArrayやHashだけで多くのことができる点にあるのかもしれない。それは括弧の省略や後置ifといった多彩な文法にあるのかもしれない…。
そのようにRubyを構成する要素を一つ一つ分解し、静的型言語の上に移植したとしたら、それはどのようなものになるだろう。もしかして、安全で手軽で楽しい最強の言語ができあがるのではないか? 想像することはできますが、それを実際に「体験」するには作ってみるより他に手がないのです。
Shiikaのつくりかた
さて、最強の言語を構想したはいいものの、それはまだ頭の中にしか存在しないので、形にするには何か既存のプログラミング言語の手を借りる必要があります。Shiikaの場合はRustを使うことにしました。
Rustのメリットは実行効率の良さと、GCはないもののライフタイムという仕組みにより安全にメモリ管理が行える点です。Go言語とも迷ったのですが、独自色の強いGoと比べるとRustの型システムはHaskellなどの関数型言語に近く、個人的には書きやすかったです。
日々の作業のモチベーション
プログラミング言語の自作というと何だか凄そうですが、実際には極めて地道な作業の積み重ねです。一つの機能を作るのに一ヶ月かかることも珍しくありません。それでも、一つ機能を足すごとに書けるプログラムが増えていくのは嬉しいものです。
また、処理系は構文解析・コンパイル・コード生成などいくつかのパーツに分かれており、それぞれでやることが全然違います。作業の幅広さも言語自作の面白いところです。
自作言語はスキルアップ・副業にも繋がる
言語処理系の仕組みがわかる
プログラミング言語はプログラマにとって身近な「道具」ですが、その中身について理解している人は少ないのではないでしょうか。プログラミング言語について深く知るには、実際に作ってみるのが一番です。
先述したようにプログラミング言語の処理系はインタプリタ方式・VM方式・コンパイラ方式という3つの方式に分類できますが、同じ方式の処理系なら言語が違っても大まかな構成は共通しています。そのため、簡単な言語を作って処理の流れを理解することは、実際に使われている処理系の中身を解析する際にも大きな助けになります。
処理系制作で得られる知識
処理系を実装することで得られる重要な知識に「AST(抽象構文木)」があります。ASTはプログラミング言語のソースコードをプログラムから扱いやすい木構造に変換したもので、一般的な言語はほぼ全てこれを利用して実装されています。
ASTの扱いをマスターすれば、例えばプログラムの面倒な修正処理を自動で行うこともできるようになります。私の経験では、Railsのバージョンアップで引数の仕様が変更された際、parserというライブラリを使ってRubyプログラムをASTに変換し、そこに操作を加えてソースコードに書き戻すことで、大量のファイルの修正を自動化したことがあります。
副業の案件に繋がることも
言語処理系の知識が実際の仕事で役立つこともあります。私の場合、プログラミング言語開発の経験を買われて、副業の仕事を請けたことがあります。その仕事というのは、とあるソフトウェアの設定言語を実装することでした。あるパラメータを、ユーザが独自の式で設定できる機能があったのです。
言語の規模としては関数呼び出しと四則演算くらいの小さなものでしたが、これだけでも案外複雑な式が書けますし、それを適切に処理するのは言語実装の知識がないと難しいものです。このような形でプログラミング言語を作った経験が役立つこともあります。
まずは小さな言語から始めよう!
いきなり実用に耐えるプログラミング言語を作るのは大変ですから、まずは小さなものから始めてみるのがよいでしょう。手前味噌ですが、私の著書の『Rubyで作る奇妙なプログラミング言語』は、Esoteric Languageと呼ばれる「風変わりな、小さなプログラミング言語」の処理系作成を通じてプログラミング言語の作り方を学ぶという内容になっています。
それ以外にも、近年では『RubyでつくるRuby』や『Go言語でつくるインタプリタ』など、言語制作にフォーカスした書籍はたくさん発行されています。ぜひ一度自分に合いそうな書籍を探してみてください。