ソースコード読んだり、実際に処理系を動かしてみたメモを残しておきます。内容は当然ながら無保証です。 基本的に難しいことはやっていないので、ソースを読めばだいたいわかります。
C++で書かれている。
字句解析(flex) → 構文解析(bison)→ コード生成(LLVM IRを生成)
って感じで特に変なことはしていない。LLVM IR使っているというのが今どきぽいけど。
インデントは意味を持たない。ただ単に、 return
がメソッド定義/関数定義の終端子になっているだけ。
function add1(x)
x = x + 1 // 字下げしなくても同じ意味
return x // returnが来たら定義の終わり
class Person(name)
@name = name
@function speak()
print("Hello, ")
print(self.name)
return // returnが来たら定義の終わり
最初に現れた代入が宣言を兼ねる。
x = 1 // これが宣言を兼ねる
x = x + 1 // インクリメント
x = "Foo" // コンパイルエラー
この仕様のため、
if 1 < 2
(
i = 1
)
else
(
i = 2
)
print(int_to_str(i))
というコードは、コンパイルを通らない。
i = 0
if 1 < 2
(
i = 1
)
else
(
i = 2
)
print(int_to_str(i))
のように、if
の外のスコープで宣言してあげる必要がある。この辺、明示的な宣言もないと不便。この、最初の代入が宣言を兼ねて、型もそれになるという方式は、大昔作ったOnionもそうだったけど、それだと困るケースがあったので、明示的な宣言も可能にしてあった。
if 条件式 <改行>
(<改行>
...
)<改行>
else<改行>
(<改行>
...
)<改行>
のような形。ここで、<改行>
と書いてある全ての箇所に必ず改行を入れなければいけない(else
の場合も同様)点に注意。
トークンはあるけど、そもそも実装されてない。試しに実装してみると、こんな感じ。
i = 0
while i < 10
(
i = i + 1
)
print(int_to_str(i)) // 10
Cの for
と見た目が違うだけで同じ。if
と同様に、区切りに全部改行を入れるのを忘れずに。
for 初期化式 "," 条件式 "," インクリメント <改行>
( <改行>
...
) <改行>
function
キーワードで始まる(メソッドは @function
)。最初に書いたように、return
文で、構文的に終端するようになっている。
function id(x)
return x
class
キーワードに続けて、クラス名、コンストラクタ引数、インスタンス変数の定義、メソッド定義の順番で書く。
class クラス名 "(" 引数 ... ")" <改行>
@インスタンス変数名 "=" 式
...
@function メソッド名 "(" 引数 .. ")" <改行>
...
return (式)?
コンストラクタ引数が空だったり、インスタンス変数の定義が空だったりすると構文エラー。無理やり、空を許すように構文をいじくってみたら プログラムが落ちたので、LLVM IRの生成方法に問題があるのかも。
class Person(name, age)
@name = name
@age = age
@function print_age()
print(int_to_str(self.age))
return
@function print_name()
print(self.name)
return
インスタンス生成は、クラス名に ()
をつけるだけ。この部分と、selfが使われているところだけはPythonぽいけど、それ以外は
ほとんど似ていない(似せる意図があったとしても)。
p = Person("Hoge", 15) // インスタンス生成
p.print_age()
p.print_name()
LLVMのAPIから型を取ってきている(より正確には、LLVMのノードから型を取得している。自前で型推論とかはしていない。 動的型ではなくて、ちゃんと静的な型がある。間違うと、LLVMレベルの型エラーが出る(型チェック自体はほとんど自前でやっていないため)。
落とし穴とか。
そもそも定義できない。たとえば、以下の階乗を計算する関数は、 n
が見つからないというコンパイルエラー。
function fact(n)
return if n < 1
(
1
)
else
(
n * fact(n - 1)
)
ちなみに、return
でif
式の値を返そうとすると、実行時にSEGVで落ちる。
以下のようなコードを実行すると、SEGVになる。たぶん、if
が returnの位置に来たときに正しいコードが吐かれていない。
function lt(m, n)
return if m < n
(
1
)
else
(
0
)
というか、以下の例もエラーになるので、if
を式として使うと、つまり、値を返すような使い方をするときは一般に正しい動作をしない
可能性が高い。文法上は式として(値を返すものとして)扱えるのだけど、たぶん、それ以降の部分がそう扱うと不具合が出る状態な気がする。
k = if 2 < 3
(
1
)
else
(
2
)
print(int_to_str(k))
forの中にifをネストすると変な挙動をする(パーザのバグではない)。
for i = 0, i < 10, i = i + 1
(
if i < 5
(
print("i < 5")
)
else
(
print("i >= 5")
)
)
は、"i < 5"
を一回だけ出力して終了してしまう。forの中のifが外側にジャンプするようなコードが吐かれてしまってる気がする。
builtins.cpp で登録している。
print()
int_to_str()
float_to_str()
to_char_ptr()
append_string()
などがある。実態はこの辺: https://github.com/Naotonosato/Blawn/blob/master/src/compiler/builtins/builtins.c
- 四則演算:
+
,-
,*
,/
- 論理和、論理積:
and
,or
- 比較:
<
,<=
,>
,>=
- 等しい:
==
,!=