見出し画像

【日記を書く32日目】mini-typescriptのコードを眺めてみる

れみです。

今日は定時後に、明日の朝6時ねって言われました。仕事で必要なのはわかるけど、朝早いのはしんどいです。というか、急に決まるんですね。別にいいですけどー。

明日は頑張って早起きです。

昨日の記事

昨日の日記は書きながら調べ物してたんですけど、その時、mini-typescriptというレポジトリがあることを知りました。

彼は、どうやらTypeScriptのコンパイラのコードを書いている人のようです。開発者本人が、本当にTypeScriptでコンパイラを書き始めるなら、という感じでこのレポジトリを作ったようです。TypeScriptのコンパイラをTypeScriptを使って書こう、ってことですね。

そして、mainブランチの内容は本当にテンプレートのようで、READMEに書いてあるExercisesを解きながら、最低限のコンパイラが出来上がる、ということです。

では、そのテンプレートを眺めてみます。

index.ts

ここに書かれてることは簡単ですね。指定されたファイルの中身を文字列として取り出し、compileというメソッドに渡すと、コンパイル結果が返ってくるようです。

ここでcompileという処理は、字句解析、構文解析、トランスパイル、コード生成、の一連の流れのことだと想像しています。もしかしたら違ってるかもしれません。

では、そのcompileメソッドが定義されているcompile.tsを見に行きます。

compile.ts

と思ったら、ここに処理の流れがわかりやすく書いてありますね。

export function compile(s: string): [Module, Error[], string] {
    errors.clear()
    const tree = parse(lex(s))
    bind(tree)
    check(tree)
    const js = emit(transform(tree.statements))
    return [tree, Array.from(errors.values()), js]
}

sというのは、コンパイルするTypeScript(のような言語)のソースコードになります。

AST(コード中ではtree変数に格納される値)を作るために、lexで字句解析してトークンを作り、そのトークンをparseで構文解析する、ということでしょうか。

bindは、名前から察するに、値と変数の対応を作る?のでしょうか。bindの定義を見てないので、まだわかりません。

checkは静的型解析ですかね?

そして、transformでTypeScriptをJavaScriptに変換して、emitでコードに直す、みたいな感じでしょうか。

まだ推測ですが、おそらくこんな感じでしょう。読みやすいですね。最小限しか書かれてないからだと思いますが。

ではlexメソッドがあるlex.tsに移ります。

lex.ts

字句解析のコードがありました。あとは、字句解析の結果を表現するトークンの定義がtypes.tsにあることもわかりました。特別なことは特にやってないですが、登場するコードの少なさから、これはトークンすら全然足りてない気がします。

あと、lexは字句解析の結果を返すのではなく、字句解析をする字句解析器を作って返すようです。

ではトークンの定義を見に行きます。

types.ts

export enum Token {
    Function,
    Var,
    Type,
    Return,
    Equals,
    Literal,
    Identifier,
    Newline,
    Semicolon,
    Colon,
    Whitespace,
    Unknown,
    BOF,
    EOF,
}

まだこれだけ・・・!

えーと、まだ丸かっこと中かっこがないから、ブロックも関数の引数も定義できないんですね。なるほど。

では、これどんな構文をacceptするのか気になります。parseメソッドが定義されているparse.tsを見に行きます。

parse.ts

parseはLexer、つまり字句解析器を受け取って、AST(のようなもの)を返しているようです。そのASTはtypes.tsで定義されています。

ちなみにASTの定義を見ると、トップレベルはModuleのようです。Moduleは、statementsを持っています。これは、StatementのArrayです。つまり、この言語で書かれたファイルはModuleであり、ModuleはStatementのリストと言い換えることができそうです。

ということは、parseの結果は、必ずModuleが1つ返ってくることになります。

parseに戻ると、処理としては、字句解析して、構文解析です。ただし、字句解析を全て終えてから構文解析、というわけではなく、決められた構文に従って字句解析しその結果のトークンが期待通りであれば、その構文に対応するASTのノードを作る、という流れになっています。てっきり字句解析をやり切った後に構文解析をするのかと思っていたので、予想が外れました。

中身をざっくり読んだ感じ、どうやらvarによる変数宣言と、typeによる型宣言しかないみたいです。トークン的にはfunctionとかもありますが、上で書いた通り、まだかっこがないので構文を定義できない、ということですかね。

変数の宣言時の初期化もサポートされていますが、定義されている値は数値だけですね。しかもその数値は単純な数字列です。しかも先頭がどれだけ0が続いても許されてますね。(lex参照)

なるほど、つまり本当に最小限しか定義されてないんですね。



とりあえずASTを作るところまで来ました。次はbindとトランスパイルとコード生成ですね。これは明日にします。

では今日はここまで。

この記事が気に入ったらサポートをしてみませんか?