Open14
自作言語 eb
数年ぶりに自作言語を作りたい。
今の所、
- スクリプト言語
- 見やすい
- JITできる
- 漸進的型付け
- Rust製
- 他のアプリに組み込める
- JITバックエンドにCraneliftを使いたい
- GCどうしようかなぁ
- 関数ごとに並列でコンパイル(遅延させる)すれば、プログラムが大きくなってもモッサリしない?
- そもそもそんなに大きなプログラム向けじゃないかもね
という感じの構想。
文法の構想
func fact(x i32) i32:
if x == 1:
return 1;;
return x * fact(x - 1);;
// main関数は必要なのか?
func main():
x := fact(10);
print(x);;
;;
がブロックの閉じカッコ(}
)のような役割を果たす。
PythonやHaskellの、インデントでブロックを表現する文法は、見た目は好きだけど、インデントが崩れると上手く機能しないから個人的にはあまり好きではない。だけど、curly bracket {} を使うとなんとなくスクリプト言語っぽくない。
func fact(x):
if x <= 2: return 1;;
return fact(x - 1) + fact(x - 2);;
関数引数の型を省略したいけど、これじゃあ動的型になっちゃうなあ。
と思ったけど、これはreturn 1
のおかげでfact
の返り値の型がi32(int?)とわかるのか。
x
の型はわからないか。
型推論をすれば、 x - 1
から x
がi32だと分かったりしそうです(言語設計によりますが)
-
がOCamlみたいに、整数に対する演算子だとわかっていればできそうですね。(floatでも同じ演算子を使いたい)
演算子のオーバーロードと数値型の型推論を組み合わせるのはやや面倒ですね……綺麗にやろうとするとRustのTraitみたいな仕組みが必要になるかも。四則演算に限るとかなら、それだけ特別扱いすることもできますが、どちらにせよオーバーロードっぽいことは必要になりそう……(めんどくさそう)
いい感じの妥協点を見つけたいですね。(-.
とか+.
みたいな演算子を使いたくないんですよね...)
type Pair:
x i32,
y i32 ;;
type Option<T>:
| Some(T)
| None ;;
type Node:
val i32,
left Node,
right Node ;;
こういうことできるのかなぁ。(型を調べるのがめんどくさいときに使えそう)
言語じゃなくてLintのやることか。
type A:
a: `f(123)` ;; // f(123)の値の型
参照型のことを考えないといけない。GCが必要なのか、線形型とかで頑張るのか。
スクリプト言語だからライフタイム・パズルをしたくない。