はじめに
昨年からCrystalのコンパイラが簡単にライブラリとして利用できるようになっていたことに気がついたので、その手順を共有したいと思います。
プロジェクトの作成
まず、Crystalの新しいプロジェクトを作成します。
crystal init app duck_egg
cd duck_egg
shard.yml
の編集
作成した shard.yml
に以下のように設定を追加します。
ここでは dependencies
に markd
と reply
を追加します。
name: duck_egg
version: 0.1.0
targets:
🥚:
main: src/duck_egg.cr
dependencies:
markd:
github: icyleaf/markd
reply:
github: I3oris/reply
duck_egg.cr
の作成
次に、src/duck_egg.cr
を作成し、以下のコードを記述します。
require "compiler/requires"
BIRDS = [
{ "🐔", "cluck!" },
{ "🐓", "cock-a-doodle-doo" },
{ "🦃", "gobble" },
{ "🦆", "quack" },
{ "🦉", "hoot" },
{ "🦜", "squawk" },
{ "🕊", "coo" },
{ "🦢", "honk" },
{ "🦩", "brrrrt" },
{ "🐧", "honk honk" },
{ "🦤", "boop" },
{ "🦕", "Bwooooon!!" },
{ "🦖", "Raaaaawr!!" }
]
bird, sound = BIRDS.sample
compiler = Crystal::Compiler.new
source = Crystal::Compiler::Source.new(bird, %Q(puts "#{bird} < #{sound}"))
compiler.compile source, bird
Crystalコンパイラを 🥚 に組み込みます。
🥚 を実行すると、ランダムに鳥が選ばれ、鳥と鳴き声を表示するバイナリファイルが(組み込まれたコンパイラによって)生成されます。
ビルドと実行
まず shards build
でビルドします。
shards build
次に環境変数 CRYSTAL_PATH
を確認して、Crystalの標準ライブラリがどこにインストールされているかチェックします。
crystal env # 環境変数の確認
今回生成する実行ファイル 🥚 にはCrystalのコンパイラが組み込まれています。
Crystalコンパイラは、puts 0
のような単純なコードであっても、それだけでコンパイルすることはできません。標準ライブラリを読み込む必要があるため、標準ライブラリのパスを指定する必要があります。これが CRYSTAL_PATH
環境変数の設定が必要な理由です。
export CRYSTAL_PATH=lib:/usr/local/bin/../share/crystal/src
実行してみましょう。
bin/🥚
例えば、次のような出力が得られます。
🦖
実行してみましょう
./🦖
🦖 < Raaaaawr!!
まとめ
Crystalのコンパイラをライブラリとして使用することで、動的にコードを生成しコンパイルすることが可能になりました。おもしろい応用があるといいですね。
すぐに試したくなるのは、共有ファイルを作成し、それを動的に呼び出すようなツールですが、ここには重大な制約があるため、実現するためにはもう一歩工夫が必要でしょう。
この記事は以上です。