素朴な自作言語のコンパイラをCrystalに移植した

Crystal が 1.0 になりましたね :confetti_ball:

- [Crystal 1.0 - What to expect - The Crystal Programming Language](https://crystal-lang.org/2021/03/22/crystal-1.0-what-to-expect.html)
- [プログラミング言語Crystal、初のメジャーリリースとなるバージョン1.0を公開：CodeZine（コードジン）](https://codezine.jp/article/detail/13820)

めでたい。

というわけで（といいつつ少し前から作っていたのですが）移植しました。例によってライフゲームのコンパイルが通ったのでヨシ、という程度の雑なものです。

https://github.com/sonota88/vm2gol-v2-crystal



# 移植元

https://memo88.hatenablog.com/entry/2020/05/04/155425

ベースになっているバージョン: [tag:56](https://github.com/sonota88/vm2gol-v2/tree/56) のあたり

（2022-01-09 追記） [step62](https://memo88.hatenablog.com/entry/20210930_vm2gol_v2_62_case_when) の変更まで反映しました。

作り方はここに全部書いています（Ruby 版のものですが）: [vm2gol v2 製作メモ](https://memo88.hatenablog.com/entry/2019/05/04/234516)



# 動かし方の例

```sh
# Docker イメージをビルド
./docker_build.sh

# コンテナに入る
./docker_run.sh

# 以下はコンテナ内で実行

# コンパイラをビルド ... bin/* が生成される
./build_container.sh

# コンパイル
echo '
  func add(a, b) {
    return a + b;
  }

  func main() {
    var one = 1;
    var result;
    call_set result = add(one, 2);
  }
' | bin/lexer | bin/parser | bin/codegen

# ↓ アセンブリが出力される
  call main
  exit

label add
  push bp
  cp sp bp

  # 関数の処理本体
  cp [bp:2] reg_a
  push reg_a
  cp [bp:3] reg_a
  push reg_a
  pop reg_b
  pop reg_a
  add_ab

  cp bp sp
  pop bp
  ret

label main
  push bp
  cp sp bp

  # 関数の処理本体
  sub_sp 1
  cp 1 reg_a
  cp reg_a [bp:-1]
  sub_sp 1
  cp 2 reg_a
  push reg_a
  cp [bp:-1] reg_a
  push reg_a
  _cmt call~~add
  call add
  add_sp 2
  cp reg_a [bp:-2]

  cp bp sp
  pop bp
  ret

# ... snip ...
```


# メモ

- `is_a?` で型を調べて分岐させると型が制限される。自分が知ってる中では TypeScript が近い。
  - https://ja.crystal-lang.org/reference/syntax_and_semantics/if_varis_a.html
- ユニオン型からのキャスト: `as`
  - https://ja.crystal-lang.org/reference/syntax_and_semantics/as.html
- `of` による型の指定
  - > これは推論された型を置き換えるので、生成時には同じ型しか入っていないけれど、あとで別の型が入ってくるような場合に対応できます。  
    https://ja.crystal-lang.org/reference/syntax_and_semantics/literals/array.html
- String からシンボルへの変換
  - できなさそうだった
  - https://ja.crystal-lang.org/reference/syntax_and_semantics/literals/symbol.html
  - https://crystal-lang.org/api/1.0.0/String.html
- グローバル変数は使えない
  - > しかし Crystal にグローバル変数はありません。代わりにクラス変数や定数を使ってください。  
    https://crystal-jp.github.io/introducing-crystal/chapters/03-syntax.html
- レキサの出力も `["kw", "func", 1]` のような JSON にしてみた。
  少し冗長になるけど、扱いが楽になるので良さそう。
  これは Ruby 版にフィードバックしようかな。




# 参考

- [【Crystalと○○】Crystalとグローバル変数？](https://zenn.dev/arcage/articles/crystal_and_global_variables)




# 他の言語への移植

| 記事 | リポジトリ | 日付 |
| --- | --- | --- |
| [Haskell](https://memo88.hatenablog.com/entry/20210628_vm2gol_v2_haskell) | [github](https://github.com/sonota88/vm2gol-v2-haskell) | 2021-06-28 |
| [OCaml](https://memo88.hatenablog.com/entry/2021/06/26/054540) | [github](https://github.com/sonota88/vm2gol-v2-ocaml) | 2021-06-26 |
| [Pascal](https://qiita.com/sonota88/items/4d446b778ffbbaab267c) | [github](https://github.com/sonota88/vm2gol-v2-pascal) | 2021-05-22 |
| [Julia](https://qiita.com/sonota88/items/b80696f23a08c3c2fc5d) | [github](https://github.com/sonota88/vm2gol-v2-julia) | 2021-05-03 |
| [Rust](https://memo88.hatenablog.com/entry/20210407_vm2gol_v2_rust) | [github](https://github.com/sonota88/vm2gol-v2-rust) | 2021-04-07 |
| [セルフホスト](https://qiita.com/sonota88/items/1e683276541cf1b87b76) | [github](https://github.com/sonota88/pric) | 2021-02-21 |
| [Kotlin](https://memo88.hatenablog.com/entry/2021/01/14/032813) | [github](https://github.com/sonota88/vm2gol-v2-kotlin) | 2021-01-14 |
| [Zig](https://memo88.hatenablog.com/entry/2021/01/07/235019) | [github](https://github.com/sonota88/vm2gol-v2-zig) | 2021-01-07 |
| [LibreOffice Basic](https://qiita.com/sonota88/items/31c127c42a9722892aa8) | [github](https://github.com/sonota88/vm2gol-v2-libreoffice-basic) | 2020-12-14 |
| [Go](https://memo88.hatenablog.com/entry/2020/09/25/073200) | [github](https://github.com/sonota88/vm2gol-v2-go) | 2020-09-25 |
| [PHP](https://memo88.hatenablog.com/entry/2020/09/18/193844) | [github](https://github.com/sonota88/vm2gol-v2-php) | 2020-09-18 |
| [C♭](https://memo88.hatenablog.com/entry/2020/09/13/133735) | [github](https://github.com/sonota88/vm2gol-v2-cflat) | 2020-09-13 |
| [Perl](https://memo88.hatenablog.com/entry/2020/09/08/053329) | [github](https://github.com/sonota88/vm2gol-v2-perl) | 2020-09-08 |
| [C](https://memo88.hatenablog.com/entry/2020/09/06/043607) | [github](https://github.com/sonota88/vm2gol-v2-c) | 2020-09-06 |
| [Java](https://memo88.hatenablog.com/entry/2020/08/30/121437) | [github](https://github.com/sonota88/vm2gol-v2-java) | 2020-08-30 |
| [Dart](https://memo88.hatenablog.com/entry/2020/08/22/162201) | [github](https://github.com/sonota88/vm2gol-v2-dart) | 2020-08-22 |
| [Python](https://qiita.com/sonota88/items/5267dcd4750235680c8f) | [github](https://github.com/sonota88/vm2gol-v2-python) | 2020-08-19 |
| [TypeScript (Deno)](https://memo88.hatenablog.com/entry/2020/08/15/114754) | [github](https://github.com/sonota88/vm2gol-v2-typescript/tree/20200815) | 2020-08-15 |