Kmkm 進捗
Kmkm プログラミング言語の開発の過程をしるす。
前史
- 2021.04.08
- 左のようなコードから右のようなコードが生成されるコンパイラーを作っている
https://twitter.com/kakkun61/status/1379837244735807488
- 左のようなコードから右のようなコードが生成されるコンパイラーを作っている
- 2021.04.13
- 代数的データ型のある言語から C に変換するコンパイラーの代数的データ型の部分ができたぞい
https://twitter.com/kakkun61/status/1381658350153199616 - VS Code でシンタックスハイライトするようになったぞ
https://twitter.com/kakkun61/status/1381744178242015233
- 代数的データ型のある言語から C に変換するコンパイラーの代数的データ型の部分ができたぞい
- 2021.04.20
- 関数適用ができるようになった(まだ関数適用式の第1部分式は識別子のみ・アリティが合っているかのチェックはしていない
https://twitter.com/kakkun61/status/1384209111852589062 - 型検査して型が付くようになった
https://twitter.com/kakkun61/status/1387105962545192963
- 関数適用ができるようになった(まだ関数適用式の第1部分式は識別子のみ・アリティが合っているかのチェックはしていない
- 2021.04.28
- 部分適用を処理できるようになった(項のルートにある場合のみ
https://twitter.com/kakkun61/status/1387107014770184193
- 部分適用を処理できるようになった(項のルートにある場合のみ
- 2021.05.07
- 外側の変数への参照のあるラムダ式や高階関数が変換できるようになった(副作用として GCC 依存になった
https://twitter.com/kakkun61/status/1390380607209836544
- 外側の変数への参照のあるラムダ式や高階関数が変換できるようになった(副作用として GCC 依存になった
- 2021.05.11
- thunk パスというパスを追加した
https://twitter.com/kakkun61/status/1391778038791106564
- thunk パスというパスを追加した
今のパスの説明をする。
ソースコード(S 式)
↓ 構文解析
↓ Language.Kmkm.Parser.Sexp
構文木(カリー化・未ラムダ持ち上げ・未型付け)
Language.Kmkm.Syntax.Phase1
↓ 型検査
↓ Language.Kmkm.Builder.Pass1
構文木(カリー化・未ラムダ持ち上げ・既型付け)
Language.Kmkm.Syntax.Phase2
↓ 逆カリー化
↓ Language.Kmkm.Builder.Pass2
構文木(非カリー化・未ラムダ持ち上げ・既型付け)
Language.Kmkm.Syntax.Phase3
↓ 部分適用除去
↓ Language.Kmkm.Builder.Pass3
構文木(非カリー化・未ラムダ持ち上げ・既型付け)
Language.Kmkm.Syntax.Phase4
↓ ラムダ持ち上げ
↓ Language.Kmkm.Builder.Pass4
構文木(非カリー化・既ラムダ持ち上げ・既型付け)
Language.Kmkm.Syntax.Phase5
↓ トップレベルの非コンパイル時式の関数化
↓ Language.Kmkm.Builder.C.Pass1
構文木(非カリー化・既ラムダ持ち上げ・既型付け)
Language.Kmkm.Syntax.Phase5
↓ C 構文木へ変換
↓ Language.Kmkm.Builder.C.Pass2
構文木(C 抽象)
Language.Kmkm.Builder.C.Syntax
↓ より具象な C 構文木へ変換
↓ Language.Kmkm.Builder.C.Pass3
構文木(C 具象)
Language.C.Syntax.AST (language-c)
↓ C ソースコード生成
↓ Language.C.Pretty (language-c)
C ソースコード
副作用のある関数(procedure と呼ぶ)を書くための下ごしらえができた
束縛時の型を不要にして型注釈を書けるようにした
型が必須なのは、関数引数と、再起変数を束縛する式への型注釈になった
実装としては
- 変数を束縛する式を見て別の変数への依存を見つける
- 依存関係グラフを強連結成分分解
- トポロジカルソート
- 被依存側から順に型検査
FFI を実装した
C を埋め込めるようにした
モジュールシステム(ソースファイル分割)ができた
パスが更新された
ソースコード(S 式)
↓ 構文解析
↓ Language.Kmkm.Parser.Sexp
構文木(カリー化・未ラムダ持ち上げ・未型付け)
Language.Kmkm.Syntax.Phase1
↓ 型検査
↓ Language.Kmkm.Builder.Pass1
構文木(カリー化・未ラムダ持ち上げ・既型付け)
Language.Kmkm.Syntax.Phase2
↓ 逆カリー化
↓ Language.Kmkm.Builder.Pass2
構文木(非カリー化・未ラムダ持ち上げ・既型付け)
Language.Kmkm.Syntax.Phase3
↓ 部分適用除去
↓ Language.Kmkm.Builder.Pass3
構文木(非カリー化・未ラムダ持ち上げ・既型付け)
Language.Kmkm.Syntax.Phase4
↓ ラムダ持ち上げ
↓ Language.Kmkm.Builder.Pass4
構文木(非カリー化・既ラムダ持ち上げ・既型付け)
Language.Kmkm.Syntax.Phase5
↓ トップレベルの非コンパイル時式の関数化
↓ Language.Kmkm.Builder.C.Pass1
構文木(非カリー化・既ラムダ持ち上げ・既型付け)
Language.Kmkm.Syntax.Phase5
↓ C 構文木へ変換
↓ Language.Kmkm.Builder.C.Pass2
構文木(C 抽象)
Language.Kmkm.Builder.C.Syntax
↓ ソースファイル C 構文木からヘッダーファイル C 構文木へ変換
↓ Language.Kmkm.Builder.C.Pass3
構文木(C 抽象)
Language.Kmkm.Builder.C.Syntax
↓ より具象な C 構文木へ変換
↓ Language.Kmkm.Builder.C.Pass4
構文木(C 具象)
Language.C.Syntax.AST (language-c)
↓ C ソースコード生成
↓ Language.C.Pretty (language-c)
C ソースコード
モジュールの変換ができた(6月19日)
int main(void) {
return ({0});
}
が出力できた
Haskell の where 節のようにローカル変数を定義できるようにしてたのを、let 式に変えた
これが意外にデグレって難儀だった
名前解決パスを実装した
今まで識別子を処理するたびに行き当たりばったりで名前解決の実装をしてたので、最初にフルパス(モジュール名+識別子)に変換するようにした
コンパイルパス
実行ファイルを実際に実行するテストを整備した(6月30日)
見やすいエラー出力(出現位置表示)を実装したら盛大にデグレードしたのをやっと修正した
パーサーも C 依存の部分を分離した
C 以外のバックエンドもできるように
FFI で定義した関数を同一ファイル内で呼べなかった(型検査で失敗する)のを直した。
あわせて、C のグローバル変数に関連してヘッダー・ソースにはくものを直して GCC でビルドできるようにした
C を吐く系言語メモ
-
https://nelua.io/
- Lua-like
-
https://terralang.org/
- Lua-like
- https://koka-lang.github.io/
Language overview を書いた
文字列をとりあえずサポートしたので hello world ができるようになった
(module
main
(list
kmkm.io
kmkm.prim
kmkm.proc)
(list
(bind-value
main
(procedure
(list
(call (apply kmkm.io.print "Hello world!"))
(call (apply kmkm.proc.pureInt 0)))))))
パラメーター多相の実装をポインター(ジェネリクス)か実体化(テンプレート)かでなやんでいる
とりあえずポインターでやってみようかな
2021.10.31
パラメーター多相の実装を実装した。
関数についてのみ。データ型はまだ。
(module
parametricPolymorphism
(list
kmkm.prim)
(list
(bind-value id (for-all a (function a a a)))
(bind-value hello (apply id "Hello world!"))))
副産物
パーサーのリファクターをした
やーーっとパラメーター多相なデータ型(Java 系でいうジェネリックなクラス)の定義ができた
これが
(module
foo
(list)
(list
(define solo (for-all a (list (solo (list (item a))))))))
こうなる
#ifndef FOO_H
#define FOO_H
struct foo_solo {
void (* foo_item);
};
struct foo_solo foo_solo(void const (* const foo_item));
#endif
#include "foo.h"
struct foo_solo foo_solo(void const (* const foo_item))
{
return (struct foo_solo) { foo_item };
}
使う部分の実装がまだ
もっとカジュアルに書き散らした進捗はこっち
今は GCC 固有のネストされた関数を使ってるができたら GCC 依存をなくしたい