PyPy で Grass を実装してみた

PyPy について調べてチュートリアルも翻訳してみたので、折角だからなにか実装してみようと思い立って実装してみた。

で、今回のターゲットはお手軽そうな ちょっと草植えときますね型言語 Grass を実装してみようかなと。

結果

まずは結果。

ソースはこちら GitHub - shomah4a/grass-pypy: implementation of grass for pypy

使い方
$ git clone https://github.com/shomah4a/grass-pypy.git
$ cd grass-pypy
$ python ${PYPY_REPOSITORY_ROOT}/pypy/translator/goal/translate.py grass.py
$ ./grass-c samples/hello.grass
Hello, World!

とかやると動かせる。

JIT を有効にする場合は

$ python ${PYPY_REPOSITORY_ROOT}/pypy/translator/goal/translate.py --opt=jit grass.py

として translate.py を実行するだけ。

作り方

  • Python で普通に grass を実装する
  • trasnlate.py で変換してみて、怒られたら直す
  • jit もつけるなら付ける

というステップだけなので非常に簡単。

RPython について

PyPy で言語を実装する際には、 RPython を使うわけだが、これは 標準の Python に多少の制限を加えたもので、 Restricted Python の略らしい。
で、今回直す必要があった箇所はそんなに多くなかったけども、いくつかあったのでメモ。

正規表現

CPython 標準の正規表現ライブラリ re モジュールは使えない。
今回は wWv をカウントするだけだったので、文字列処理で済ませたけど、より複雑な事をする際には正規表現が使えないと厳しい。
で、 PyPy には pypy.rlib.parsing というパッケージがあり、このパッケージの中に正規表現や拡張BNFなどのモジュールがあるので使ってみると良いのかもしれない。
使い方は pypy.rlib.parsing.test に大体書いてあるのでそっち見るといい。

コマンドライン

sys.argv でのコマンドライン引数の参照ができない。
コマンドライン引数は target 関数で返すエントリポイント関数の引数に渡されるので、そのリストを使う必要がある。

標準入出力

標準入力は sys.stdin が使えないため os.read(0, bytes) でファイル記述子直接指定で読み込む必要がある。
標準出力への書き出しは、 print を使った場合はそのまま使えるが、 sys.stdout.write を使う場合は os.write(1, str) で書き込む必要がある。
標準エラーも同様にファイル記述子 2 を使う。

型推論

結構しっかり型推論してくれて、継承構造もチェックしてくれるようなので、クラスは割と普通に使える。
あとは関数の引数・返値の型を合わせないと怒られるので注意(当たり前)。
構造的部分型まで推論してくれるのかはチェックしていないので気になるところ。

感覚としては普通に型推論してくれる言語をそのまま使っている感じ。
でも書いているのは Python という不思議。

まとめ

  • Python ぽく書くだけで grass の解釈器ができた
  • rlib がステキ
  • RPython って型推論する普通の静的型言語なんじゃねーの
  • コンパイル遅いお