おはようございます!
このマニュアルでは、今回の夏合宿のために急遽用意した企画、「言語実装ハッカソン&コードゴルフ」の解説をしていきます。
開発環境として、以下を用意しておくと当日すんなり開発に着手できる。
- Docker
- 開発したい言語のベースとなるesolang-boxイメージ
- dobi
- 最新のRuby
- 当日実装する言語のアイデア
Dockerインストールメモ - Qiita なども参照。
以下のリンクから Docker for Windows をダウンロードしてインストールする。
https://docs.docker.com/docker-for-windows/install/#install-docker-for-windows-desktop-app
cmdもしくはPowershellを開き、docker run hello-world
を実行する。Hello from Docker!
と表示されれば成功。
以下のリンクから Docker Toolbox for Windows をダウンロードしてインストールする。
https://docs.docker.com/toolbox/toolbox_install_windows/
スタートメニューなどに Docker Quickstart Terminal なるものが追加されるので、ここからターミナルを起動する。
その中で docker run hello-world
を実行する。Hello from Docker!
と表示されれば成功。
以下のリンクから Docker for Mac をダウンロードしてインストールする。
https://docs.docker.com/docker-for-mac/install/
ターミナルを開き、docker run hello-world
を実行する。Hello from Docker!
と表示されれば成功。
適当に頑張れ。
実際にプログラミング言語を開発する際には、なにか別のプログラミング言語、例えばRubyやPythonなどを使ってインタプリタを実装することになる。esolang-box上でプログラミング言語を動かす際にもベースとなる言語のDockerイメージが必要になる。
esolang-boxのライブラリにはプログラミング言語を実装する上で必要になる環境は一通り揃っているので、実装のベースにしたい言語をあらかじめ自分の得意なプログラミング言語の中から選んでおく。これを List of Boxes から選び、以下のコマンドでローカル環境に事前にダウンロードしておく。
docker pull esolang/<言語の名前>
例えば、ベースの言語として
- CやC++を利用する場合は
esolang/build-base
- Python3を利用する場合は
esolang/python3
- Node.jsを利用する場合は
esolang/node
- Rubyを利用する場合は
esolang/ruby
をダウンロードする。
esolang-boxの開発に必要となるソフトウェア。
Releases · dnephin/dobi から最新のバイナリをダウンロードしてきて、どこかパスの通るところに配置しておく。
esolang-boxの開発に必要。2.5系であれば問題ない。
Rubyのインストール - ruby-lang.org などを参考に。
ここから先のマニュアルを読んで、当日実装する言語のアイデアを考えておくとよい。
1日目、みなさんには即席でオリジナルの言語を実装してもらいます。
オリジナルの言語と言っても、作ってもらうのはCとかPythonとかの本格的なものではなく、他のプログラミング言語で実装されるお遊び程度のプログラミング言語です。厳密なレキサーや複雑な文法を導入する必要はありませんし、簡単な文字列処理で実装できる範疇のもので構いません。
下のようなesolangの実装を見てみると雰囲気がつかめるかもしれません。
必ずしもゼロから言語を実装する必要はありません。既存の言語になんらかの (面白い) 制約を加えたものや、文法が異なるものもOKです。
どうしてもアイデアが思いつかない/実装が困難な場合はorenonoのようなツールを使ってBrainfuck方言を一瞬で作成することができます。が、面白みがないのでできればもう少しひねった言語を考えてほしいです。
複数言語の提出もOKです。
提出締切は原則9/22が終わるまで (JST) です。これ以降に提出すると博多市の睡眠時間が犠牲になります。
2日目のコードゴルフ大会の前に実装した言語についての簡単なプレゼンを行ってもらいます。提出方法はのちほど案内します (たぶんGoogleスライド)。
コードゴルフに使用するという要件から、実装してもらう言語は以下の制約を満たす必要があります。
- 任意長の文字列の入力と出力を持つ
- ほぼ任意のタスクを実装できる (おおむねチューリング完全である)
- よくあるダメなパターンが、数値入力しか受け付けないなど。
ソースコードがテキストファイルである必要はありません。
面白いプログラミング言語のアイデアはいくらでも転がっています。特に以下のページが非常に充実しています。とても参考になるのでまずはここを眺めてみましょう。
博多市がざっと眺めて面白そうだと思ったアイデアはこんな感じ。
- 野球やサッカーのルールをベースにした言語
- 結び目理論に基づく言語
- ソースコードがアニメGIFの言語
- Cと文法が同じだが挙動が全く異なる言語
参考図書として、
- Rubyで作る奇妙なプログラミング言語
- RubyでつくるRuby
- きつねさんでもわかるLLVM
- あなたの知らない超絶技巧プログラミングの世界
の4冊を用意したので、参考にしてください。
これらの参考図書のうち最初の2冊はP社の備品なので、特に丁寧に扱ってください。
esolang-box内に実装を持つこともできますが、更新がめんどくさいので各々のGitHubアカウントにリポジトリを作って開発することを推奨します。
言語が開発できたら、esolang-boxをフォークしてプルリクエストを送信してください。
esolang-boxの開発には以下のソフトウェアが必要です。インストールしてください。
開発した言語をesolang-boxリポジトリに追加するために、以下のファイルを編集する必要があります。
- 言語一覧ファイル (boxes.yml)
- Dockerfile (boxes/<言語名>/Dockerfile)
- 起動スクリプト (boxes/<言語名>/script)
- テスト (spec/boxes_spec.rb)
- テストアセット (spec/assets/hello.<言語名>, spec/assets/cat.<言語名>)
- テストアセットのコピーライト (spec/assets/README.md)
リポジトリに含まれるプログラミング言語の一覧と依存関係を記述したファイルです。
ベースにした言語の下に、プログラミング言語の名前とURLを記述します。例えば、Rubyで実装した**「すごい言語」**を追加したい場合は以下のように編集します。
--- a/boxes.yml
+++ b/boxes.yml
@@ -30,6 +30,9 @@ base:
ruby:
_name: Ruby 2.5.0
_link: https://www.ruby-lang.org/
+ sugoi-lang:
+ _name: すごい言語
+ _link: https://github.com/hakatashi/sugoi-lang
golfscript:
_name: GolfScript
_link: http://www.golfscript.com/golfscript/tutorial.html
boxes.ymlを編集したあとは、必ず ruby build.rb
を実行してください。dobi.yamlが更新されます。
実装した言語を動かすためのDockerイメージをビルドするための手順を書いたファイルです。
すでにある実装例を参考にしてほしいですが、だいたい以下の手順が含まれます。
- FROM句でベースとなるDockerイメージを指定する
- プログラミング言語のソースコードをホームディレクトリにcloneする
- (必要なら) ビルドを実行する
/bin/<言語名>
から/bin/script
へのシンボリックリンクを貼るscript
ファイルを/root/script
にコピーする
Pythonの例
FROM esolang/python3
RUN git clone --depth 1 https://github.com/stestoltz/Width.git ~/Width && \
ln -s /bin/script /bin/width
COPY script /root/script
Rubyの例
FROM esolang/ruby
RUN git clone --depth 1 https://github.com/m-ender/alice.git ~/alice && \
ln -s /bin/script /bin/alice
COPY script /root/script
Node.jsの例
FROM esolang/node
RUN git clone --depth 1 https://github.com/TehFlaminTaco/MaybeLater.git ~/MaybeLater && \
ln -s /bin/script /bin/maybelater
COPY script /root/script
C/C++の例
FROM esolang/build-base
RUN cd /tmp && \
git clone --depth 1 https://github.com/aaronryank/Cubically.git && \
cd Cubically && \
make && \
mv cubically /usr/bin/cubically && \
rm -rf /tmp/* && \
ln -s /bin/script /bin/cubically
COPY script /root/script
Dockerコンテナ内でプログラミング言語を起動するためのbashスクリプトです。
ソースコードのパスが第一引数で、入力が標準入力で与えられるので、標準出力に実行結果を出力してください。
標準エラー出力にビルドなどの情報を出力することができます。
Pythonの例
#!/bin/sh
cat - | /usr/bin/python3 ~/Width/width.py "$1"
Rubyの例
#!/bin/sh
cat - | /usr/local/ruby-2.5.0/bin/ruby ~/alice/interpreter.rb "$1"
Node.jsの例
#!/bin/sh
cat - | /usr/bin/node ~/MaybeLater/interpreter.js "$1"
C/C++の例
#!/bin/sh
cat - | /usr/bin/cubically f "$1"
追加した言語が正常に動くことを確かめるためのテストファイルです。
テストでは原則として Hello, World! プログラムとcatプログラムを用います。
こんな感じでテストを追加してください。
--- a/spec/boxes_spec.rb
+++ b/spec/boxes_spec.rb
@@ -679,4 +679,9 @@ describe 'esolang-box', v2: true do
describe 'whenever' do
it { expect(result_of(subject, 'hello.whenever')).to eql("Hello, World!\n") }
end
+
+ describe 'sugoi-lang' do
+ it { expect(result_of(subject, 'hello.sugoi-lang')).to eql("Hello, World!") }
+ it { expect(result_of(subject, 'cat.sugoi-lang', 'meow')).to eql("meow") }
+ end
end
テストで実行される Hello, World! プログラムとcatプログラムの内容です。
spec/assets/hello.<言語名>
に Hello, World! プログラムを追加spec/assets/cat.<言語名>
にcatプログラムを追加
assetsディレクトリに含まれるファイルのコピーライト表記です。
hello.<言語名>
と cat.<言語名>
の出典となるURLと作者名 (たぶん自分) を記述してください。
--- a/spec/assets/README.md
+++ b/spec/assets/README.md
@@ -75,6 +75,7 @@ Contents under this directory retains their original licenses.
* `cat.stackcats`: [m-ender](https://github.com/m-ender/stackcats/blob/master/examples/cat.sks)
* `cat.stk`: Original
* `cat.strm`: [matz](https://github.com/matz/streem/blob/master/examples/01cat.strm)
+* `cat.sugoi-lang`: [hakatashi](https://github.com/hakatashi/sugoi-lang/blob/master/cat.sugoi-lang)
* `cat.suzy`: Original
* `cat.sqlite3.sql`: Original
* `cat.swift`: Original
@@ -186,6 +187,7 @@ Contents under this directory retains their original licenses.
* `hello.starry`: [esolangs.org](https://esolangs.org/wiki/Starry#Hello.2C_world.21)
* `hello.strm`: [matz](https://github.com/matz/streem/blob/master/examples/02hello.strm)
* `hello.spl`: [Karl Hasselström and Jon Åslund](http://shakespearelang.sourceforge.net/report/shakespeare/#sec:hello)
+* `hello.sugoi-lang`: [hakatashi](https://github.com/hakatashi/sugoi-lang/blob/master/hello.sugoi-lang)
* `hello.suzy`: Original
* `hello.sqlite3.sql`: Original
* `hello.swift`: [developer.apple.com](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html)
以下のコマンドを実行すると、esolang/<言語名>
というDockerイメージが生成されます。
$ docker pull esolang/<ベースとなる言語> # やってなければ
$ ruby build.rb # やってなければ
$ dobi <言語名>
何らかの理由でdobiを使わない場合、以下の手順でdobiを使わずビルドすることができる。
$ docker pull esolang/<ベースとなる言語> # やってなければ
$ cd boxes/<言語名>
$ docker build -t esolang/<言語名> .
以下のコマンドを実行すると、カレントディレクトリにあるファイル hoge
を実行できます。
$ docker run --rm -v `pwd`:/code:ro esolang/<言語名> <言語名> /code/hoge
Ruby 2.5 をインストールし、以下のコマンドを実行するとテストを実行できます。
$ gem install bundler # なければ
$ bundle install
$ bundle exec rspec -e <言語名>