Boolean

現実逃避の度合=開発の進み具合。

構文は順に対処していくだけですので、今のところは特に問題は無いのですが、吐いた機械語の無駄具合がなんとも。最適化は後回しと決めているにしても…。
このコンパイラでは、ソースコード構文木→三番地文(このレベルで雀の涙最適化)→機械語(nasmのソースコード)、という手順を踏んでいるわけです。で、三番地文だけ弄り回しても、無駄な変数は消せるのですが、使うレジスタは相変わらずeaxだけだったりするのです。最終的には三番地文から機械語への変換過程でレジスタ割付けなんかもしないといけないのですが、そうすると今必要な分だけ書いている三番地文を機械語に直訳するルーチンも無駄になる訳で…。
デバッグ情報の出力なども考えると恐らく既存のバックエンドを持ってきた方が賢いのでしょうけれど、gccをハックする気力は無いので、もっとお手軽なのが欲しいところです。擬似アセンブラと行番号情報を渡せば、勝手に最適化してデバッグ情報付き.objファイルにしてくれるようなやつ。サンデープログラマでもコンパイラが作れるバックエンド。

唐突に、そういや何か記憶が…と思い出しまして。

http://www.kmonos.net/alang/etc/cecil.php
http://www.cs.washington.edu/research/projects/cecil/www/vortex.html

Vortexってどうなんでしょう?

…ひょっとしてSPARC以外はgcc経由か?

マクロの代わり

class TypeAndId2Type(T, uint id)
{
}

template message_handler(_T, uint _id, alias _handler)
{
    enum { id = _id }
    alias _T T;
    bit dispatch_handler(Message m, TypeAndId2Type!(T, _id) dummy)
    {
        if(m.id == _id){
            _handler(m);
            return true;
        }else{
            return false;
        }
    }
}

template message_handler(_T, uint _id, alias _handler, alias _next)
{
    enum { id = _id }
    alias _T T;
    bit dispatch_handler(Message m, TypeAndId2Type!(T, _id) dummy)
    {
        if(m.id == _id){
            _handler(m);
            return true;
        }else{
            TypeAndId2Type!(_next.T, _next.id) dummy;
            return _next.dispatch_handler(m, dummy);
        }
    }
}


template message_dispatcher(alias _list)
{
    void dispatch(Message m)
    {
        TypeAndId2Type!(_list.T, _list.id) dummy;
        if(!_list.dispatch_handler(m, dummy)){
            on_default(m);
        }
    }
}

template message_inheriter(alias _list)
{
    private final void inherit(Message m)
    {
        TypeAndId2Type!(_list.T, _list.id) dummy;
        if(!_list.dispatch_handler(m, dummy)){
            on_default(m);
        }
    }
}

const uint create_id = 10;
const uint destroy_id = 11;

class Message
{
    uint id, w, l, result;
}

class Window
{
    private final void on_create(Message m)
    {
        printf("Window.on_create\n");
    }
    
    private final void on_destroy(Message m)
    {
        printf("Window.on_destroy\n");
    }
    
    void on_default(Message m)
    {
        printf("Window.on_default %d\n", m.id);
    }
    
    mixin message_handler!(Window, create_id, on_create) create_handler;
    mixin message_handler!(Window, destroy_id, on_destroy, create_handler) destroy_handler;
    mixin message_dispatcher!(destroy_handler) dispatcher;
    alias destroy_handler window_handler_list;
}

class Button : Window
{
    private final void on_create(Message m)
    {
        printf("Button.on_create\n");
        inheriter.inherit(m);
    }
    
    mixin message_handler!(Button, create_id, on_create, window_handler_list) create_handler;
    mixin message_dispatcher!(create_handler) dispatcher;
    alias create_handler button_handler_list;
    mixin message_inheriter!(window_handler_list) inheriter;
}

class CheckBox : Button
{
    private final void on_destroy(Message m)
    {
        printf("CheckBox.on_destroy\n");
        inheriter.inherit(m);
    }
    
    mixin message_handler!(CheckBox, destroy_id, on_destroy, button_handler_list) destroy_handler;
    mixin message_dispatcher!(destroy_handler) dispatcher;
    alias destroy_handler checkbox_handler_list;
    mixin message_inheriter!(button_handler_list) inheriter;
}

void main()
{
    CheckBox c = new CheckBox;
    Message m = new Message;
    m.id = create_id;
    c.dispatch(m);
    m.id = destroy_id;
    c.dispatch(m);
}

わかったこと。

  • template中でsuper使うとdmdが落ちる
  • class中のmixinのalias引数にfunctionやdelegateリテラルを渡せない
  • privateにするとoverrideを免れることができる
  • alias引数でメソッドを渡す場合、template側ではレシーバが選べない(暗黙のthisのみ)

マクロの代わりとしてはいまいち力不足な気がします。無いよりまし。templateまわりでdmdがよく落ちるのは相変わらず。

mixinのサンプルがあまり出てきてないのは、dmdがバグバグなせいなのか、それとも私がテンションを盛り下げるような事を書いたせいなのか…。