Documentation: Interface between C++ and plang

このチュートリアルはC++プログラマーを対象としています。C++でplangを実行する場合、boostがインストールしてある事が前提となっています。またユーザーはある程度boost::shared_ptr、boost::functionに対する知識を持っていることが望まれます。

plangではC++で実装した関数をnative function (using::*)を使用し呼び出すことが可能ですが、使用される関数はC++側で実行までに登録しなければなりません。
例としてusing::writeはC++内部では以下のように定義されています。

plang::factor::shared_ptr write(plang::factor::vector& argv){
    try{
        if(argv.size()!=1)
            throw plang_exception("invalid argument count");
        argv.at(0)->write_ostream(std::wcout);
        return plang::factor::shared_ptr(new plang::nil());
    }
    catch(const std::exception& e){
        throw plang_exception("catch exception").append(e);
    }
}


native functionとして登録される関数は必ず、

plang::factor::shared_ptr function_name (plang::factor::vector& )

の形式をとります。

plangはname space名です。
factorは全てのオブジェクトのbase classです。plangにおけるオブジェクトは全てfactor::shared_ptrで表現されています。
factor::vectorは、std::vector<factor::shared_str>を継承したvectorクラスです。
plang_exceptionは<plang/exception.hpp>でdefineされたplang::exceptionを作成するものです。plangにおけるexceptionはplang::exceptionをthrowすることが望まれます。

plang::prog<wchar_t> prog;
prog.global.define_native(L"write",write);


定義されたwriteはplang::prog<>().global.define_nativeで登録することによって、plangから使用することが可能となります。
define_nativeの第一引数はstd::basic_string<>で、plangで登録される関数名となります。例ではL"write"を指定しているので、using::writeとして使用されることになります。
第二引数はplang::native_typeで、

typedef boost::function<factor::shared_ptr (factor::vector&)> native_type;


と定義されています。ここで渡される関数はboost::functionが受け取れる形式のものでなければなりません。boost::functionでは関数はそのまま渡すことができますが、classのメンバー関数はそのままでは渡すことは出来ません。

class test{
public:
    void define_print(plang::prog<wchar_t>& prog){
        prog.global.define_native(L"print1",boost::bind1st(boost::mem_fun(&test::print),this));
    }

    plang::factor::shared_ptr print(plang::factor::vector& argv){
        std::wcout<<"print test"<<std::endl;
        return plang::factor::shared_ptr(new plang::nil());
    }
};

test a;
a.define_print(prog);
prog.global.define_native(L"print2",boost::bind1st(boost::mem_fun(&test::print),&a));


classのメンバー関数を登録したい場合、boost::bind1stとboost::mem_funをしようして関数オブジェクトを作成することが可能です。
例はオブジェクトaのprintをオブジェクト内で登録する場合と、外部から登録する場合の二通りのサンプルです。

このC++プログラムで上のplangを実行した場合、

using::write("this is write\n");


ではthis is writeと出力され、

using::print1();
using::print2();


ではそれぞれprint test1、print test2と出力されることになります。