All checks were successful
Build / build (push) Successful in 11m36s
148 lines
4.1 KiB
Markdown
148 lines
4.1 KiB
Markdown
#mimium
|
||
|
||
モジュールシステムの意味論と実装について考える
|
||
|
||
### 必要要件
|
||
|
||
理想としては、以下を全部満たしたい
|
||
|
||
- 分割コンパイルしたうえで、コンパイル済みのモジュールは変更がなければ再利用できる
|
||
- 操作的意味論的にもある程度一貫性がある
|
||
- モジュール内ではシンボルの相互参照が可能(後から定義されるシンボルでも参照可能)
|
||
|
||
で、デザインチョイスのトレードオフとしては意味論を楽にしようと思うと分割コンパイルがめんどくさくなる
|
||
|
||
複数のコードを合体させるときに、流用されるコードの複製が増える問題
|
||
|
||
ただ、どっちみちDSPにおけるコードの量なんてたかが知れているのでは?という問題も
|
||
|
||
実際、そこまでモジュール内での相互参照って必要か?というのもある、Letrecで十分じゃね?
|
||
|
||
モジュールの循環参照が起きたらどうなるのかという問題もある
|
||
|
||
|
||
#### モジュール内での宣言一覧
|
||
```rust
|
||
//関数のvisibilityセッティングはRustとおなじ感じ
|
||
pub fn (){
|
||
|
||
}
|
||
pub const Foo = 100
|
||
pub type Bar = Constructor(()->float) //新しい型宣言
|
||
pub type alias Hoge = ()->float //エイリアス宣言
|
||
|
||
```
|
||
|
||
#### モジュールの宣言
|
||
|
||
```rust
|
||
mod(macro) modname{
|
||
//toplevel_decls
|
||
}
|
||
```
|
||
- モジュール単位でMIRとバイトコードを生成して、あとからリンクできるようにする
|
||
- ただし、ステージ0マクロの展開もしないといけないので、ASTも出力して保持していないといけない
|
||
|
||
モジュールを値としてレコード型に型付けできると話が早いんだけど、それ一級モジュールの機能だよな
|
||
|
||
#### 意味論
|
||
|
||
```rust
|
||
stage(1)
|
||
mod(0) modname{
|
||
//toplevel_decls
|
||
fn foo(){
|
||
...
|
||
}
|
||
}
|
||
modname::foo!()
|
||
```
|
||
これがあったとすると、
|
||
|
||
```rust
|
||
extern modname = ${
|
||
foo = | | { },
|
||
...
|
||
}
|
||
|
||
modname.foo!()
|
||
|
||
```
|
||
|
||
こういう感じかなー、あ、でもこうするとモジュール内での相互参照が解決できないか
|
||
|
||
トップレベルでのモジュールの名前解決は後から定義されたシンボルも参照できるので、型推論のやり方はなんか考える必要がありそう
|
||
|
||
一旦トップレベルの宣言の名前だけを回収して、あとから実際の定義の型推論を行っていく形になる
|
||
|
||
しかし、そうするとラムダ計算として定義する旨味はあんまりないのでは、という気がしてくる
|
||
|
||
`extern name : Type `という宣言に変換さえできれば意味論を保ってコンパイルはできそう
|
||
|
||
型がつけられさえすればいいから、そこで循環する定義にならなければOK
|
||
|
||
```rust
|
||
//modA.mmm
|
||
use modB
|
||
pub fn hoge(){
|
||
modB::hoge()
|
||
}
|
||
|
||
//modB.mmm
|
||
use modA
|
||
pub fn hoge(){
|
||
modA::hoge()
|
||
}
|
||
```
|
||
|
||
(ランタイムで無限ループするけどそれはいいとして)変換するとこう
|
||
|
||
```rust
|
||
// modA.mmm
|
||
extern modB:{
|
||
hoge: ?
|
||
}
|
||
fn hoge(){
|
||
modB.hoge()
|
||
}
|
||
|
||
//modB.mmm
|
||
extern modA:{//実際は型コンストラクタとかで覆って区別できるようにすべき
|
||
hoge: ?
|
||
}
|
||
fn hoge(){
|
||
modA.hoge()
|
||
}
|
||
```
|
||
|
||
`modA::hoge : 'a ()->'a, modB::hoge : 'a ()->'a `
|
||
|
||
ここまでしか型は決定できないということに
|
||
|
||
---
|
||
|
||
|
||
|
||
|
||
```
|
||
Program = FunctionDefinition
|
||
|GlobalDeclaration
|
||
|ModuleDeclaration
|
||
|use ModuleName
|
||
ModuleDeclaration = Visibility(stage) { Program }
|
||
|
||
|
||
```
|
||
|
||
|
||
Pythonのモジュールシステム [Python's Import System - Module object|Regular/Namespace Packages|Finders & Loaders|Relative imports - YouTube](https://www.youtube.com/watch?v=QCSz0j8tGmI)
|
||
|
||
モジュールはオブジェクトであり、`__file__`などはモジュールオブジェクトに付属するメンバ変数
|
||
|
||
|
||
[[Gluon]]のモジュール [Modules - Gluon Documentation](https://gluon-lang.org/doc/crates_io/book/modules.html)
|
||
|
||
これマクロとして実装してあって、それこそレコードとして出力されるだけなので、分割コンパイルとかモジュール内相互参照とかは全然考慮されてないけど意味論はすっきり
|
||
|
||
|