このチュートリアルは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と出力されることになります。