新言語『TypoScript』を作った

この記事は、[クソアプリAdvent Calendar2021](https://qiita.com/advent-calendar/2021/kuso-app)の20日目(ホノルル時間)の記事であると同時に、[GMOペパボエンジニア Advent Calendar 2021](https://adventar.org/calendars/6375)の21日目(日本時間)の記事でもあります。

みなさん、TypeScript使ってますか？TypeScriptはJavaScriptの世界に秩序をもたらす素晴らしい言語ですね。

しかし世界には光の秩序だけでなく闇の混沌も必要です。

という訳で、JavaScriptに闇の混沌をもたらす新言語を作ってみました。

その名も『TypoScript』です。

## TypoScript is 何

TypoScriptとは何か。まずはこちらのコードをご覧ください。

```javascript
    function fizz_buzz(count) {
        for (var i = 1; i <= caunt; i++) {
            if (i % 3 === 0 && i % 5 === 0) {
                print("FizzBuzz")
            } else if (i % 3 === 0) {
                print("Fizz")
            } else if (i % 5 === 0) {
                print("Buzz")
            } else {
                qrint(i)
            }
        }
    }
    // ここ注目❗
    fizz_dazz(15)
```

型のない、普通のJavaScriptで書かれたFizzBuzz問題ですね。

もう一度よく見てください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33890/81aa6c4c-d1c2-2c93-e830-2347dbaab915.png)






```as

　　　　　　　　　おわかりいただけただろうか　　　　　　　　　

```

サンプルコードが間違っているのではありません。
このコードが実際に動くのが今回作った『TypoScript』なのです。

上のコードはこちらで**実際に動作させることができます**。

https://kurehajime.github.io/typoscript/
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33890/4529ab3a-d06e-5cf8-7360-dc6b5a382a47.png)
](https://kurehajime.github.io/typoscript/
)

### なんで動くの？

TypoScriptはなぜこんなメチャクチャなコードが動くのでしょうか。

その秘密は『[レーベンシュタイン距離](https://ja.wikipedia.org/wiki/%E3%83%AC%E3%83%BC%E3%83%99%E3%83%B3%E3%82%B7%E3%83%A5%E3%82%BF%E3%82%A4%E3%83%B3%E8%B7%9D%E9%9B%A2)』です。

レーベンシュタイン距離とは、ざっくりいうと二つの文字列がどの程度異なっているかを示す距離のことです。
ある文字からある文字へと、追加・削除・置換を用いて何回の操作で変換できるかを数えた数です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33890/f01abd9d-f9bd-b0bf-08e1-e48b716c1d3f.png)


TypoScriptでは、変数およびファンクション名でタイプミスした際のレーベンシュタイン距離が文字数の25%以内であれば「だいたいあってる」としてOKにしています。

４文字の単語なら１文字までミスってOKです。internationalizationなら５文字間違ってもOKなので、internasyonaraizasionと雑に書いても動きます。

## TypoScriptの作り方

TypoScriptは以下の手順で作りました。

### ①ふつうのJavaScriptの構文解析器を作る

これは[PEG(Parsing Expression Grammar)](https://ja.wikipedia.org/wiki/Parsing_Expression_Grammar)のライブラリ[Peggy.js](https://github.com/peggyjs/peggy)を利用しています。
PEGはパーサーをバッカス・ナウア記法のような定義をするだけで構文解析器を作れるとても便利な仕組みなのですが、TypoScriptではそれすらも面倒なのでPeggyjsに同梱されているJavaScriptパーサーをほぼそのまま利用しています。


JavaScriptでは『[ESTree](https://github.com/estree/estree)』という抽象構文木の形式がデファクトスタンダードになっているので、@babel/parserやAcornなど、解析するライブラリを選び放題です。

### ②ふつうのJavaScriptのインタープリターを作る

これは自作しました。

ESTreeをもとにJavaScrptのコードを生成するライブラリは沢山あるのですが、TypoScriptで実現したい機能はどちらかと言えばインタープリターに細工をする方が近道のような気がしたので、実装してみました。

TypoScriptは開発途上のため、if,for,varなどの基本的な構文には対応していますが、配列やオブジェクト、ES2015以降に導入された構文にはまだ対応していません。

インタープリターを作るというととてもハードルが高そうですが、基本的な構文だけなら実は数百行で書けてしまいます。

この辺については『WEB+DB PRESS Vol.125』や『RubyでつくるRuby』という本がとても分かりやすくてオススメです。

https://gihyo.jp/magazine/wdpress/archive/2021/vol125

https://www.lambdanote.com/products/ruby-ruby

### ③変数参照にレーベンシュタイン距離による補正を組み込む

あとはもう簡単です。
インタープリターの変数を参照する実装の部分にレーベンシュタイン距離による補正を組み込むだけです。

最初は再帰を用いて素直にレーベンシュタイン距離実装していたのですが、『internationalization』のように無駄に長い単語を流し込むと処理に数分かかってしました。
そこで『[メモ化](https://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%A2%E5%8C%96)』 を用いて高速化しています。

## まとめ

いかがでしたでしょうか。

「1文字間違えるだけで動かないなんて…プログラミングって難しい！」と嘆いていたプログラミング初心者の頃の自分に「これが君の望んでいた世界だよ」と教えてあげたいですね。

筆者が所属している[GMOペパボ](https://pepabo.com/)には、プログラミング言語を自作する人たちのためのslackチャンネルがあり、今回はそれに触発されてネタ言語を作ってみました。

まだまだ未成熟な言語なので、コントリビュートお待ちしております。

https://github.com/kurehajime/typoscript