Skip to content

Instantly share code, notes, and snippets.

@AonekoSS
Last active December 17, 2015 23:39
Show Gist options
  • Save AonekoSS/5691206 to your computer and use it in GitHub Desktop.
Save AonekoSS/5691206 to your computer and use it in GitHub Desktop.
v8エンジンを変態チックにバインドしてみるテスト。Variadic Templateやら関数SFINAEやら使える環境なら、もうちとスマートに書ける筈なのだけど……orz
#include <iostream>
#include <type_traits>
using namespace v8;
//---------------------------------------------------------------------------
// メタプロ用マクロとか
//---------------------------------------------------------------------------
// 引数バリエーション
#define __A0__
#define __A1__ A1
#define __A2__ A1,A2
#define __A3__ A1,A2,A3
#define __A4__ A1,A2,A3,A4
#define __A5__ A1,A2,A3,A4,A5
#define __A6__ A1,A2,A3,A4,A5,A6
#define __A7__ A1,A2,A3,A4,A5,A6,A7
#define __A8__ A1,A2,A3,A4,A5,A6,A7,A8
#define __V0__
#define __V1__ CVal<A1>(a[0])
#define __V2__ CVal<A1>(a[0]),CVal<A2>(a[1])
#define __V3__ CVal<A1>(a[0]),CVal<A2>(a[1]),CVal<A3>(a[2])
#define __V4__ CVal<A1>(a[0]),CVal<A2>(a[1]),CVal<A3>(a[2]),CVal<A4>(a[3])
#define __V5__ CVal<A1>(a[0]),CVal<A2>(a[1]),CVal<A3>(a[2]),CVal<A4>(a[3]),CVal<A5>(a[4])
#define __V6__ CVal<A1>(a[0]),CVal<A2>(a[1]),CVal<A3>(a[2]),CVal<A4>(a[3]),CVal<A5>(a[4]),CVal<A6>(a[5])
#define __V7__ CVal<A1>(a[0]),CVal<A2>(a[1]),CVal<A3>(a[2]),CVal<A4>(a[3]),CVal<A5>(a[4]),CVal<A6>(a[5]),CVal<A7>(a[6])
#define __V8__ CVal<A1>(a[0]),CVal<A2>(a[1]),CVal<A3>(a[2]),CVal<A4>(a[3]),CVal<A5>(a[4]),CVal<A6>(a[5]),CVal<A7>(a[6]),CVal<A8>(a[7])
#define __C0__
#define __C1__ class A1
#define __C2__ class A1,class A2
#define __C3__ class A1,class A2,class A3
#define __C4__ class A1,class A2,class A3,class A4
#define __C5__ class A1,class A2,class A3,class A4,class A5
#define __C6__ class A1,class A2,class A3,class A4,class A5,class A6
#define __C7__ class A1,class A2,class A3,class A4,class A5,class A6,class A7
#define __C8__ class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8
// 共通要素
#define __SCOPE__ HandleScope scope;
#define __CATCH__ catch(std::exception& e){ return ThrowException(Exception::Error(String::New(e.what()))); }
typedef Handle<Value> RES;
typedef Arguments const & ARG;
//---------------------------------------------------------------------------
// C++オブジェクトへの変換
//---------------------------------------------------------------------------
template <class T>
inline T CVal(const Handle<Value>& v, typename std::enable_if<std::is_fundamental<T>::value>::type* = nullptr){
if(std::is_same<T, bool>::value)return static_cast<T>(v->BooleanValue());
if(std::is_unsigned<T>::value)return static_cast<T>(v->Uint32Value());
if(std::is_integral<T>::value)return static_cast<T>(v->Int32Value());
return static_cast<T>(v->NumberValue());
};
template <class T>
inline T CVal(const Handle<Value>& v, typename std::enable_if<std::is_same<T, std::string>::value>::type* = nullptr){
return *String::AsciiValue(v);
}
template <class T>
inline T CVal(const Handle<Value>& v, typename std::enable_if<std::is_pointer<T>::value>::type* = nullptr){
return static_cast<T>(Handle<External>::Cast(v)->Value());
}
template <class T>
inline T CVal(const Handle<Value>& v, typename std::enable_if<std::is_member_pointer<T>::value>::type* = nullptr){
return *static_cast<T*>(Handle<External>::Cast(v)->Value());
}
//---------------------------------------------------------------------------
// JavaScriptオブジェクトへの変換
//---------------------------------------------------------------------------
template <class T>
inline Handle<Value> JVal(T v){
if(std::is_same<T, bool>::value)return Boolean::New(v!=false);
if(std::is_unsigned<T>::value)return Integer::NewFromUnsigned(v);
if(std::is_integral<T>::value)return Integer::New(v);
return Number::New(v);
}
template <class T>
inline Handle<Value> JVal(T* v){
return External::New(v);
}
template <>
inline Handle<Value> JVal<const std::string&>(const std::string& v){
return String::New(v.c_str());
}
//---------------------------------------------------------------------------
// C++オブジェクトのラッピング(クラスメンバへのポインタとか、void*より大きいの向け)
//---------------------------------------------------------------------------
template <class T>
Persistent<External> Wrap(T *obj){
Isolate *isolate = Isolate::GetCurrent();
auto ext = Persistent<External>::New(isolate, External::New(obj));
ext.MakeWeak(isolate, obj, Deleter<T>);
return ext;
}
template <class T>
void Deleter(Isolate *isolate, Persistent<Value> h, void* obj){
delete static_cast<T*>(obj);
h.Dispose(isolate);
}
//---------------------------------------------------------------------------
// 関数プロキシ郡(Variadic Templateが使えれば、もうちとスッキリする筈……)
//---------------------------------------------------------------------------
// 通常関数
template <class F> F GetF(ARG a){ return CVal<F>(a.Data()); }
template <class R>
struct FuncProxyT{
template <class F __C0__> static RES F0(ARG a){ __SCOPE__ try{ return JVal(GetF<F>(a)(__V0__)); }__CATCH__ return Undefined(); }
template <class F,__C1__> static RES F1(ARG a){ __SCOPE__ try{ return JVal(GetF<F>(a)(__V1__)); }__CATCH__ return Undefined(); }
template <class F,__C2__> static RES F2(ARG a){ __SCOPE__ try{ return JVal(GetF<F>(a)(__V2__)); }__CATCH__ return Undefined(); }
template <class F,__C3__> static RES F3(ARG a){ __SCOPE__ try{ return JVal(GetF<F>(a)(__V3__)); }__CATCH__ return Undefined(); }
template <class F,__C4__> static RES F4(ARG a){ __SCOPE__ try{ return JVal(GetF<F>(a)(__V4__)); }__CATCH__ return Undefined(); }
template <class F,__C5__> static RES F5(ARG a){ __SCOPE__ try{ return JVal(GetF<F>(a)(__V5__)); }__CATCH__ return Undefined(); }
template <class F,__C6__> static RES F6(ARG a){ __SCOPE__ try{ return JVal(GetF<F>(a)(__V6__)); }__CATCH__ return Undefined(); }
template <class F,__C7__> static RES F7(ARG a){ __SCOPE__ try{ return JVal(GetF<F>(a)(__V7__)); }__CATCH__ return Undefined(); }
template <class F,__C8__> static RES F8(ARG a){ __SCOPE__ try{ return JVal(GetF<F>(a)(__V8__)); }__CATCH__ return Undefined(); }
};
template <>
struct FuncProxyT<void>{
template <class F __C0__> static RES F0(ARG a){ __SCOPE__ try{ GetF<F>(a)(__V0__); }__CATCH__ return Undefined(); }
template <class F,__C1__> static RES F1(ARG a){ __SCOPE__ try{ GetF<F>(a)(__V1__); }__CATCH__ return Undefined(); }
template <class F,__C2__> static RES F2(ARG a){ __SCOPE__ try{ GetF<F>(a)(__V2__); }__CATCH__ return Undefined(); }
template <class F,__C3__> static RES F3(ARG a){ __SCOPE__ try{ GetF<F>(a)(__V3__); }__CATCH__ return Undefined(); }
template <class F,__C4__> static RES F4(ARG a){ __SCOPE__ try{ GetF<F>(a)(__V4__); }__CATCH__ return Undefined(); }
template <class F,__C5__> static RES F5(ARG a){ __SCOPE__ try{ GetF<F>(a)(__V5__); }__CATCH__ return Undefined(); }
template <class F,__C6__> static RES F6(ARG a){ __SCOPE__ try{ GetF<F>(a)(__V6__); }__CATCH__ return Undefined(); }
template <class F,__C7__> static RES F7(ARG a){ __SCOPE__ try{ GetF<F>(a)(__V7__); }__CATCH__ return Undefined(); }
template <class F,__C8__> static RES F8(ARG a){ __SCOPE__ try{ GetF<F>(a)(__V8__); }__CATCH__ return Undefined(); }
};
template <class R __C0__> InvocationCallback FunctionProxy(R f(__A0__)){ return FuncProxyT<R>::F0<R(*)(__A0__) __A0__>; }
template <class R,__C1__> InvocationCallback FunctionProxy(R f(__A1__)){ return FuncProxyT<R>::F1<R(*)(__A1__),__A1__>; }
template <class R,__C2__> InvocationCallback FunctionProxy(R f(__A2__)){ return FuncProxyT<R>::F2<R(*)(__A2__),__A2__>; }
template <class R,__C3__> InvocationCallback FunctionProxy(R f(__A3__)){ return FuncProxyT<R>::F3<R(*)(__A3__),__A3__>; }
template <class R,__C4__> InvocationCallback FunctionProxy(R f(__A4__)){ return FuncProxyT<R>::F4<R(*)(__A4__),__A4__>; }
template <class R,__C5__> InvocationCallback FunctionProxy(R f(__A5__)){ return FuncProxyT<R>::F5<R(*)(__A5__),__A5__>; }
template <class R,__C6__> InvocationCallback FunctionProxy(R f(__A6__)){ return FuncProxyT<R>::F6<R(*)(__A6__),__A6__>; }
template <class R,__C7__> InvocationCallback FunctionProxy(R f(__A7__)){ return FuncProxyT<R>::F7<R(*)(__A7__),__A7__>; }
template <class R,__C8__> InvocationCallback FunctionProxy(R f(__A8__)){ return FuncProxyT<R>::F8<R(*)(__A8__),__A8__>; }
// メンバー関数
template <class C> C* GetI(ARG a){ return CVal<C*>(a.This()->GetInternalField(0)); }
template <class M> M GetM(ARG a){ return *CVal<M*>(a.Data()); }
template <class C, class R>
struct MethodProxyT{
template <class M __C0__> static RES F0(ARG a){ __SCOPE__ try{ return JVal((GetI<C>(a)->*GetM<M>(a))(__V0__)); }__CATCH__ return Undefined(); }
template <class M,__C1__> static RES F1(ARG a){ __SCOPE__ try{ return JVal((GetI<C>(a)->*GetM<M>(a))(__V1__)); }__CATCH__ return Undefined(); }
template <class M,__C2__> static RES F2(ARG a){ __SCOPE__ try{ return JVal((GetI<C>(a)->*GetM<M>(a))(__V2__)); }__CATCH__ return Undefined(); }
template <class M,__C3__> static RES F3(ARG a){ __SCOPE__ try{ return JVal((GetI<C>(a)->*GetM<M>(a))(__V3__)); }__CATCH__ return Undefined(); }
template <class M,__C4__> static RES F4(ARG a){ __SCOPE__ try{ return JVal((GetI<C>(a)->*GetM<M>(a))(__V4__)); }__CATCH__ return Undefined(); }
template <class M,__C5__> static RES F5(ARG a){ __SCOPE__ try{ return JVal((GetI<C>(a)->*GetM<M>(a))(__V5__)); }__CATCH__ return Undefined(); }
template <class M,__C6__> static RES F6(ARG a){ __SCOPE__ try{ return JVal((GetI<C>(a)->*GetM<M>(a))(__V6__)); }__CATCH__ return Undefined(); }
template <class M,__C7__> static RES F7(ARG a){ __SCOPE__ try{ return JVal((GetI<C>(a)->*GetM<M>(a))(__V7__)); }__CATCH__ return Undefined(); }
template <class M,__C8__> static RES F8(ARG a){ __SCOPE__ try{ return JVal((GetI<C>(a)->*GetM<M>(a))(__V8__)); }__CATCH__ return Undefined(); }
};
template <class C>
struct MethodProxyT<C,void>{
template <class M __C0__> static RES F0(ARG a){ __SCOPE__ try{ (GetI<C>(a)->*GetM<M>(a))(__V0__); }__CATCH__ return Undefined(); }
template <class M,__C1__> static RES F1(ARG a){ __SCOPE__ try{ (GetI<C>(a)->*GetM<M>(a))(__V1__); }__CATCH__ return Undefined(); }
template <class M,__C2__> static RES F2(ARG a){ __SCOPE__ try{ (GetI<C>(a)->*GetM<M>(a))(__V2__); }__CATCH__ return Undefined(); }
template <class M,__C3__> static RES F3(ARG a){ __SCOPE__ try{ (GetI<C>(a)->*GetM<M>(a))(__V3__); }__CATCH__ return Undefined(); }
template <class M,__C4__> static RES F4(ARG a){ __SCOPE__ try{ (GetI<C>(a)->*GetM<M>(a))(__V4__); }__CATCH__ return Undefined(); }
template <class M,__C5__> static RES F5(ARG a){ __SCOPE__ try{ (GetI<C>(a)->*GetM<M>(a))(__V5__); }__CATCH__ return Undefined(); }
template <class M,__C6__> static RES F6(ARG a){ __SCOPE__ try{ (GetI<C>(a)->*GetM<M>(a))(__V6__); }__CATCH__ return Undefined(); }
template <class M,__C7__> static RES F7(ARG a){ __SCOPE__ try{ (GetI<C>(a)->*GetM<M>(a))(__V7__); }__CATCH__ return Undefined(); }
template <class M,__C8__> static RES F8(ARG a){ __SCOPE__ try{ (GetI<C>(a)->*GetM<M>(a))(__V8__); }__CATCH__ return Undefined(); }
};
template <class C,class R __C0__> InvocationCallback MethodProxy(R(C::*m)(__A0__)){ return MethodProxyT<C,R>::F0<R(C::*)(__A0__) __A0__>; }
template <class C,class R,__C1__> InvocationCallback MethodProxy(R(C::*m)(__A1__)){ return MethodProxyT<C,R>::F1<R(C::*)(__A1__),__A1__>; }
template <class C,class R,__C2__> InvocationCallback MethodProxy(R(C::*m)(__A2__)){ return MethodProxyT<C,R>::F2<R(C::*)(__A2__),__A2__>; }
template <class C,class R,__C3__> InvocationCallback MethodProxy(R(C::*m)(__A3__)){ return MethodProxyT<C,R>::F3<R(C::*)(__A3__),__A3__>; }
template <class C,class R,__C4__> InvocationCallback MethodProxy(R(C::*m)(__A4__)){ return MethodProxyT<C,R>::F4<R(C::*)(__A4__),__A4__>; }
template <class C,class R,__C5__> InvocationCallback MethodProxy(R(C::*m)(__A5__)){ return MethodProxyT<C,R>::F5<R(C::*)(__A5__),__A5__>; }
template <class C,class R,__C6__> InvocationCallback MethodProxy(R(C::*m)(__A6__)){ return MethodProxyT<C,R>::F6<R(C::*)(__A6__),__A6__>; }
template <class C,class R,__C7__> InvocationCallback MethodProxy(R(C::*m)(__A7__)){ return MethodProxyT<C,R>::F7<R(C::*)(__A7__),__A7__>; }
template <class C,class R,__C8__> InvocationCallback MethodProxy(R(C::*m)(__A8__)){ return MethodProxyT<C,R>::F8<R(C::*)(__A8__),__A8__>; }
// コンストラクター
template <class C __C0__> RES CtorProxy(ARG a){ __SCOPE__ a.This()->SetInternalField(0, Wrap(new C(__V0__))); return a.This(); }
template <class C,__C1__> RES CtorProxy(ARG a){ __SCOPE__ a.This()->SetInternalField(0, Wrap(new C(__V1__))); return a.This(); }
template <class C,__C2__> RES CtorProxy(ARG a){ __SCOPE__ a.This()->SetInternalField(0, Wrap(new C(__V2__))); return a.This(); }
template <class C,__C3__> RES CtorProxy(ARG a){ __SCOPE__ a.This()->SetInternalField(0, Wrap(new C(__V3__))); return a.This(); }
template <class C,__C4__> RES CtorProxy(ARG a){ __SCOPE__ a.This()->SetInternalField(0, Wrap(new C(__V4__))); return a.This(); }
template <class C,__C5__> RES CtorProxy(ARG a){ __SCOPE__ a.This()->SetInternalField(0, Wrap(new C(__V5__))); return a.This(); }
template <class C,__C6__> RES CtorProxy(ARG a){ __SCOPE__ a.This()->SetInternalField(0, Wrap(new C(__V6__))); return a.This(); }
template <class C,__C7__> RES CtorProxy(ARG a){ __SCOPE__ a.This()->SetInternalField(0, Wrap(new C(__V7__))); return a.This(); }
template <class C,__C8__> RES CtorProxy(ARG a){ __SCOPE__ a.This()->SetInternalField(0, Wrap(new C(__V8__))); return a.This(); }
//---------------------------------------------------------------------------
// クラス
//---------------------------------------------------------------------------
template <class C>
class Class{
friend class JavaScript;
public:
Class(){
handle = FunctionTemplate::New(CtorProxy<C>);
handle->SetClassName(String::New(typeid(C).name()));
handle->InstanceTemplate()->SetInternalFieldCount(1);
}
~Class(){}
// コンストラクタ定義(Variadic Templateが……略)
template <__C1__> void Constructor(){ handle->SetCallHandler(CtorProxy<C, __A1__>); }
template <__C2__> void Constructor(){ handle->SetCallHandler(CtorProxy<C, __A2__>); }
template <__C3__> void Constructor(){ handle->SetCallHandler(CtorProxy<C, __A3__>); }
template <__C4__> void Constructor(){ handle->SetCallHandler(CtorProxy<C, __A4__>); }
template <__C5__> void Constructor(){ handle->SetCallHandler(CtorProxy<C, __A5__>); }
template <__C6__> void Constructor(){ handle->SetCallHandler(CtorProxy<C, __A6__>); }
template <__C7__> void Constructor(){ handle->SetCallHandler(CtorProxy<C, __A7__>); }
template <__C8__> void Constructor(){ handle->SetCallHandler(CtorProxy<C, __A8__>); }
// アクセサ
class Accessor{
public:
Accessor(Local<ObjectTemplate> methods, Local<ObjectTemplate> objects, const std::string& name):
methods_(methods), objects_(objects), name_(name){}
// メンバ関数バインド
template <class T>
Accessor& operator <= (T C::*method){
typedef decltype(method) P;
static_assert(std::is_member_function_pointer<P>::value,"must be member function");
HandleScope scope;
methods_->Set(name_.c_str(), FunctionTemplate::New(MethodProxy(method), Wrap(new P(method))));
return *this;
}
// メンバ変数バインド
template <class T>
Accessor& operator = (T C::*object){
typedef decltype(object) P;
static_assert(std::is_member_object_pointer<P>::value,"must be member object");
HandleScope scope;
objects_->SetAccessor(String::New(name_.c_str()), Getter<T>, Setter<T>, Wrap(new P(object)));
return *this;
}
private:
Local<ObjectTemplate> methods_;
Local<ObjectTemplate> objects_;
const std::string& name_;
};
Accessor operator[](const std::string& name){
return Accessor(handle->PrototypeTemplate(), handle->InstanceTemplate(), name);
}
private:
Local<FunctionTemplate> handle;
template <class T>
static Handle<Value> Getter(Local<String> name, const AccessorInfo& info){
C* instance = CVal<C*>(info.Holder()->GetInternalField(0));
T C::*pointer = CVal<T C::*>(info.Data());
return JVal(instance->*pointer);
}
template <class T>
static void Setter(Local<String> name, Local<Value> value, const AccessorInfo& info){
C* instance = CVal<C*>(info.Holder()->GetInternalField(0));
T C::*pointer = CVal<T C::*>(info.Data());
instance->*pointer = CVal<T>(value);
}
};
//---------------------------------------------------------------------------
// 実行環境
//---------------------------------------------------------------------------
class JavaScript{
public:
JavaScript() : global(ObjectTemplate::New()){}
~JavaScript(){}
// 実行
bool Execute(const std::string& code, const std::string& name=""){
HandleScope scope;
Local<Context> context = Context::New(Isolate::GetCurrent(), 0, global);
Context::Scope cscope(context);
TryCatch trycatch;
Local<Script> script = Script::Compile(String::New(code.c_str()), String::New(name.c_str()));
if( script.IsEmpty() ){ Catch(trycatch); return false; }
Local<Value> result = script->Run();
if( result.IsEmpty() ){ Catch(trycatch); return false; }
return true;
}
// アクセサ
class Accessor{
public:
Accessor(Local<ObjectTemplate> table, const std::string& name):
table_(table), name_(name){}
// 関数バインド
template <class F>
Accessor& operator <= (F func){
static_assert(std::is_function<std::remove_pointer<F>::type>::value,"must be function");
HandleScope scope;
table_->Set(name_.c_str(), FunctionTemplate::New(FunctionProxy(func), External::New(func)));
return *this;
}
// クラスバインド
template <class C>
Accessor& operator = (const Class<C>& cls){
HandleScope scope;
cls.handle->SetClassName(String::New(name_.c_str()));
table_->Set(name_.c_str(), cls.handle);
return *this;
}
private:
Local<ObjectTemplate> table_;
const std::string& name_;
};
Accessor operator[](const std::string& name){
return Accessor(global, name);
}
private:
HandleScope handle_scope;
Local<ObjectTemplate> global;
// 例外キャッチ
static void Catch(TryCatch& trycatch) {
HandleScope scope;
std::string message = CVal<std::string>(trycatch.Exception());
Local<Message> info = trycatch.Message();
if(info.IsEmpty()){
std::cerr << message << std::endl;
}else{
std::string name = CVal<std::string>(info->GetScriptResourceName());
std::string code = CVal<std::string>(info->GetSourceLine());
int line = info->GetLineNumber();
int start = info->GetStartColumn();
int end = info->GetEndColumn();
std::cerr << name << "[" << line << "] " << message << std::endl;
std::cerr << code << std::endl << std::string(start,' ') << std::string(end-start,'^') << std::endl;
}
}
};
//---------------------------------------------------------------------------
// マクロの後始末
//---------------------------------------------------------------------------
#undef __A0__
#undef __A1__
#undef __A2__
#undef __A3__
#undef __A4__
#undef __A5__
#undef __A6__
#undef __A7__
#undef __A8__
#undef __V0__
#undef __V1__
#undef __V2__
#undef __V3__
#undef __V4__
#undef __V5__
#undef __V6__
#undef __V7__
#undef __V8__
#undef __C0__
#undef __C1__
#undef __C2__
#undef __C3__
#undef __C4__
#undef __C5__
#undef __C6__
#undef __C7__
#undef __C8__
#undef __SCOPE__
#undef __CATCH__
//---------------------------------------------------------------------------
// 以下、テスト用コード
//---------------------------------------------------------------------------
// テスト用関数
void Test(){ std::cout << "Test()" << std::endl; }
void Test2(int a){ std::cout << "Test2(" << a << ")" << std::endl; }
void Test3(std::string s){ std::cout << "Test3(" << s << ")" << std::endl; }
// テスト用クラス
class Hoge{
public:
~Hoge(){ std::cout << "Hoge デストラクタ" << std::endl; }
Hoge(){ std::cout << "Hoge コンストラクタ(デフォルト)" << std::endl; }
Hoge(int a){ std::cout << "Hoge コンストラクタ(" << a << ")" << std::endl; }
void Test(int a){ std::cout << "Hoge::Test(" << a << ")" << std::endl; }
int value;
};
void run(){
// テストコード
const char* name = "test_script.txt";
const char* code =
"test()\n"
"test2(999)\n"
"test3(\"abcdefg\"))\n"
"var hoge=new Hoge(123)\n"
"hoge.Test(234)\n"
"hoge.value=12\n";
// グローバル関数のバインド
JavaScript js;
js["test"] <= Test;
js["test2"]<= Test2;
js["test3"]<= Test3;
// クラスのバインド
Class<Hoge> cls;
cls.Constructor<int>(); // コンストラクタ定義
cls["Test"] <= &Hoge::Test; // メンバ関数
cls["value"] = &Hoge::value; // メンバ変数
// クラス登録
js["Hoge"] = cls;
// 実行
js.Execute(code,name);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment