💈

DSONという型注釈の付けられるObject Notationを作ってみた

2021/12/02に公開

この記事は言語実装カレンダー2021の3日目の記事です。

最近Desk言語という静的型付けの言語を作っています。Deskコンパイラを開発する上でそのテストケースをテストコードではなくデータで作っていきたいという思いがありました。そこで、Desk言語のサブセットとしてDSON(DeSk Object Notation)を作って、それでテストケースを書いていくことにしました。この記事ではDSONの紹介とDSONを作ってテストコードを書くまでにどのような工程が必要だったかを紹介しようと思います。

DSONの嬉しいこと

何ごともモチベーションがないと始まらないので、DSONを使ってみて嬉しいことを考えてみます。

まずは型注釈が付けられることと静的型検査ができるということです。JSON Schemaと違ってデータ自体がSelf-describingに自身の型を示すことができるところが面白いと思いました。

また、構文はDesk言語の完全なサブセットで、型検査もDesk言語のものを完全にそのまま借用しているので、Deskが発展すればそれがそのままDSONの発展にもつながります。例えばDesk言語のLanguage ServerができたらDSONでもエディタ支援を受けながら、型を確認しながらデータを記述するといったことができるようになります。

DSONデータ

DSONには大まかに、数字、文字列、配列、セット、タプルといったデータがあります。そのなかで配列、セット、タプルについてそれぞれの違いを説明します。

配列は同じ型の値が並び順でインデックスされて集まっているというデータ構造です。JSONの配列とほとんど一緒です。「同じ型の値」でないといけないから ["a", 1] のようなデータが許されないというわけではなく、「文字列または数字」という型が作れるので問題ありません。

セットは同じ型の値が重複なく並び順に関係なく集まっているというデータです。JSONのオブジェクトのようにkey-valueにしたい場合はタプルのセットにする必要があります。

タプルは違う型の集まりです。並び順も関係ありません。違う型、並び順なしということなので座標を示す数字と数字のタプルのようなものはそのままでは作れず、型にラベルをつけて@x 'number@y 'numberのタプルというようにする必要があります。

構文

「構文は見たままです」とは言えずいくつかクセがあるので紹介します。

まず()内がコメントです。タプルは* 1, "a"のように前置で*がつきます。空のタプルは単に*です。@x 1のようにすると型にラベルを付けて@x numberのような型にすることができます

DSONの例

これは実際にDesk言語の一つのテストケースとして使われているDSONです。シンタックスハイライトをされたものをお見せしたかったので画像にしました。

Desk言語からDSONを切り出す

Deskコンパイラのステージは大まかに以下のようになっています。

  1. 字句解析
  2. 構文解析
  3. High-level IRの生成
  4. 型推論
  5. Typed High-level IRの生成
  6. Abstract Mid-level IRの生成
  7. つづく……

その中からDSONは1から5までをそのまま使うようにして、Typed High-level IRからDSONのデータ構造に変換するようにしました。そうすることにより、型推論も含めてDesk言語のいろいろな機能が使えるようになっています。

serde_dson

DSONを使ってテストコードを書くためにRustの構造体とDSONを相互変換するライブラリを作りました。DSONからRustの構造体に変換できればいいので相互変換である必要はないのですが、相互変換の方が楽しいです。

Rustのデータ構造を表現するためにDSONのどの表現を使うかをまず決める必要がありました。この対応に正解はありませんが、できるだけ書きやすく読みやすい方がいいと思います。

serde_dsonでは最終的に構造体に、セット、構造体のfield名に型ラベル、タプルはそのままタプル、EnumのVariantに型ラベルを使うというようにしました。型ラベルの構文を構造体のfield名とEnumのVariant名の両方に使っているので若干の複雑さはありますが、Rustの構造体のfield名は小文字を、EnumのVariantにはCamelCaseを使うという習わしになっているのでなんとか区別はつきます。

終わりに

このような感じにしてDSONというObject Notationを作り、実際にテストケースとして使えるようになりました。

こちらのレポジトリryo33/deskc-prototypeで開発しているので、応援していただけると嬉しいです。

Discussion