Juliaでかんたんな自作言語のコンパイラを書いた

<!--
[移植一覧に戻る](https://memo88.hatenablog.com/entry/2020/08/30/132314)

---
-->

とりあえず触って慣れようということで、何も分からないところからいきなり作り初めてその都度調べるという感じで雑に書いてみました。

<!--
とりあえず触って慣れようということで、いきなり書き初める、その都度調べる、という感じで雑に書いてみました。
やっつけなので汚いです。ライフゲームのコンパイルが通ったのでヨシ、というレベルの雑なものです。

https://github.com/sonota88/vm2gol-v2-julia
-->

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






# 移植元

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

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

ライフゲームのプログラムだけコンパイルできればOKという簡単なコンパイラです。
ベースになっているバージョン: [tag:57](https://github.com/sonota88/vm2gol-v2/tree/57) のあたり

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



# メモ

主な部分のサイズ（行数）:

```
$ wc -l *.jl lib/utils.jl
  359 codegen.jl
  113 lexer.jl
  360 parser.jl
   56 lib/utils.jl
  888 合計
```

----

<!--
行列とかも使っていないし、Julia 独自な部分にはほとんど触れずに書き終わってしまいましたね。
-->

Ruby のような動的言語で書くのと似たフィーリングで書けました。


ただし、こういうのはダメで、

```julia
xs = ["a"]
push!(xs, 1) # xs に整数を追加
#=> ERROR: LoadError: MethodError: Cannot `convert` an object of type Int64 to an object of type String
```

次のように型について教えてあげないといけない、なんて場面はあったり。

```julia
xs = Any["a"]
push!(xs, 1)
```



<!--

---

マルチバイト文字列を文字単位で扱うのがちょっとめんどくさい。たぶん慣れてないせい。

```julia
s = "\"漢字\"fdsa"
```

たとえばこの文字列から `漢字` の部分だけを取り出す場合、バイト単位でのインデックスはこうなっていて、

```
"  1
漢 2~4
字 5~7
"  8
f  9
...
```

- 閉じる方の `"` の位置を探して、8 が得られたとする
- `漢字` を取り出すには `s[2:8]` ではなく `s[2:5]` としなければいけない
    - `"` ではなく、 `字` の最初のバイト単位インデックスを指定する必要がある
- ではどうするかというと、たとえば `s[2:prevind(s, 8)]` とする方法がある

……みたいな感じです。添字が 1 から始まることもあり、慣れるまでちょっと混乱しますね。
-->

<!--
閉じる方の `"` の位置は 8 だから `s[2:8]` でいいんだっけと思って取り出そうとすると `漢字"` が取れてしまう。
この場合の正解は `s[2:5]` （取り出す文字の最後の文字の先頭のバイト単位インデックスを終端のインデックスとして指定する）で、閉じる方の `"` のインデックス 8 からこれを割り出すには、閉じる方の `"` の直前の文字（`字`）のサイズが分からないといけなくて、ではどうするかというと `s[2:prevind(s, 8)]` とする……といった感じ。

`s[x:y]` 記法や操作用の関数の引数や戻り値がバイトのインデックスなのか文字のインデックスなのか、ちゃんと把握してないと混乱しますね（それはそう）。
-->

----

今回のおためし。
ブランチ: [trial](https://github.com/sonota88/vm2gol-v2-julia/tree/trial)

今回は case 文のネストを減らしてみました。
おためしというか [v3](https://github.com/sonota88/pric) ですでに適用済みになっていて、 v2 にも取り込もうかなと考えているもの。

```javascript
// before

case {
  (current_val == 0) {
    case {
      (count == 3) {
        set next_val = 1;
      }
    }
  (0 == 0) {
    case {
      (count == 2) {
        set next_val = 1;
      }
      (count == 3) {
        set next_val = 1;
      }
    }
  }
}
```

```javascript
// after

case
when (current_val == 0) {
  case
  when (count == 3) {
    set next_val = 1;
  }
when (0 == 0) {
  case
  when (count == 2) {
    set next_val = 1;
  }
  when (count == 3) {
    set next_val = 1;
  }
}
```

 `{` 〜 `}` が1段なくなるため、ネストが減り、行数も減ってちょっとコンパクトになります。

ついでに、when 句の先頭にキーワード `when` を置くようにしてみました。パーサの都合としてはあってもなくてもほとんど違いはなく、 `when` を置いた方がなんとなく見た目的に落ち着きがよいかな、という程度の理由です。




# 他の言語への移植

| 記事 | リポジトリ | 日付 |
| --- | --- | --- |
| [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 |
| [Rust](https://memo88.hatenablog.com/entry/20210407_vm2gol_v2_rust) | [github](https://github.com/sonota88/vm2gol-v2-rust) | 2021-04-07 |
| [Crystal](https://qiita.com/sonota88/items/275c2b5407986b100cc8) | [github](https://github.com/sonota88/vm2gol-v2-crystal) | 2021-03-27 |
| [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 |