3項演算子

3項演算子に対応した
3項演算子は正規化中にif文へ置き換えている
なんで正規化中かっていうとthen節とelse節をif文に付け替えてから正規化しないといけないし
かといって正規化前に3項演算子を処理しようとするとややこしい
結局3項演算子をちゃんと見つけてthen節とelse節の中身も正規化されるにはここしかないかなって
変だけど
f:id:zenu:20180927014256p:plain


3項演算子に対応している時にパーサがLALR(1)じゃなくてLR(1)?の表を吐いているって気が付いて
ムカついて対応を中断してた
ほんまクソ


classの対応しよ思ってうまくいかないから息抜きに3項演算子見てたせいでやる気がそがれたし

暗黙の引数がなぜか動作

ラムダ式の引数をいちいち書くのがじゃんくさいから$1とかで引数にアクセスできるようにしてみた
ひさびさにレキサをちょっと変更して名前解決の時に$1をArgumentsにぶちこむようなコードだけ書いたところ・・・なぜか完成した
なんでや、ILでは引数1個の関数をなんで呼び出し側が引数3個でうまく動くねん!

f:id:zenu:20180609223217p:plain

この時ILはこうなっていた
なるほど引数が違う関数ポインタをInvokeしてもおちないんだ・・・ええんか、これ?
.NETの呼び出し規約は呼び出し側が引数をpopするのか?よく分かんないや

f(=> print($1))
↓
newobj     instance void 'Bind_#5,0'::.ctor()
stloc.0
ldloc.0
ldftn      void 'implicit_param2.#5,0'(int32)
stfld      native int 'Bind_#5,0'::f
ldloc.0
ldftn      instance void 'Bind_#5,0'::Invoke(int32)
newobj     instance void class [mscorlib]System.Action`1<int32>::.ctor(object, native int)
call       void implicit_param2.f(class [mscorlib]System.Action`3<int32,string,int32>)

ラムダ式の戻り値の型を型推論

ラムダ式の戻り値の型を作った側が毎回書くのはじゃんくさい
関数の引数に使った感じから型推論できるように対応してみた

型推論の途中で戻り値なし、またはIntってゆーのを [Void | Int] みたいに表して
関数からフィードバックを受けて最後にVoidが残ったら戻り値無しよって感じにしてみた

f:id:zenu:20180605002521p:plain

変数にバインドした時はちょっと無理
でも、よくわかんなけりゃ戻り値ありに固定してもいいかもしれない

# f1は戻り値あり
var f1 = => 1
var a = f1()
need_Int(a)

# f2も戻り値あり、いらないかもしれないけどあっても困らない
var f2 = => 2
f2()

タプルに対応 続

タプルの型定義をかけるようにしてみた
構文は[Int, String]にした
使う側はvar x = (1, "str")なのに型定義はカギカッコなのはちょっとどうかなと思ったけど
戻り値がIntとStringの関数で
sub f() (Int, String)が良いか
sub f() [Int, String]が良いか考えたら後者がいい
f:id:zenu:20180506012127p:plain
そろそろ一通りの機能が揃ってきたので自作コンパイラでアプリを作りたい
自作コンパイラで作るものと言ったら、もちろんセルフコンパイルできるコンパイラだろう
何の機能がたんねーかなー?

タプルに対応

タプルが使えるようになった
最初はvar x = [1, "str"]なんて文法がええかと思っていたけど
これやと配列と区別が付かないのでvar x = (1, "str")にした

タプルの要素へは数字のプロパティでアクセスする
なんか知らんけど、深夜のテンションでそう決めた
勢いでプロパティ名の変数名だけ数字が使えるようになっている
f:id:zenu:20180430053136p:plain
ホンマはprint(x[1])とかいう風に配列の添え字風にアクセスできたらええんやけど
これやと型解決ができへん

1要素のタプルは作れへん
いらんし

ローカルスコープに対応

ローカルスコープが扱えるようになりifの中で変数が定義できるようになった
スコープ内で外側の変数と同名の変数を定義した場合、別の変数として扱うことにした
オーソドックスなCと同じ仕様にした
なんかjavascriptあたりがきしょい動きをしていたような気がする

f:id:zenu:20180427005356p:plain

クロージャ変数の取り扱いがちょっと変わった
今までは関数スコープにクロージャ変数とマークされた変数があればframeを作りつつぶちこんでいた

今度からはローカルにクロージャ変数があるやもしれへん
クロージャ変数が見つかったタイミングで関数へframeを作るようにし、ローカルスコープ側から関数のframeを作るようにした

nullに対応

nullに対応した
え、いまさら?
はい

nullはNull型のインスタンスとした
せやから[Foo | Bar]?[Foo | Bar | Null]シンタックスシュガーになる
CILでは値型にnull入れれへんから、Object型にしてBox/UnBoxする事にした

f:id:zenu:20180409034452p:plain

.NET Frameworkの参照型はnullが無制限で入るから、全部Foo?にするんかい、って所は面倒なのであまりやりたくない
ただ、本当にnullを入れたい時に型が合わんくて代入できなくなるから・・・そのうちやらんといかん