#ifndef JM_SERVER_AUTOBIND_H#define JM_SERVER_AUTOBIND_H#include <angelscript.h>#define REG_NUM __LINE__#define REG_CLASS REG_CAT(REGISTER,REG_NUM)#define REG_INSTANCE REG_CAT(REGISTER_INSTANCE,REG_NUM)//Normally, the preprocessor pastes tokens before expanding them. REG_CAT gets around//that problem by delaying concatanation until after expansion. I don't know how it//works; I took this trick from boost.#define REG_CAT(a,b) REG_CAT_I(a,b)#define REG_CAT_I(a,b) REG_CAT_II(a ## b)#define REG_CAT_II(a) a//Must be in a CPP file. Inserts a call to AutoBind::XXX at program//startup. Hides identifiers in anonymous namespace - safe across compilation units.#define REGISTER_FUNCTION(SIG,FUNC,CALL_CONV) namespace { class REG_CLASS { public: REG_CLASS() { AutoBind::BindFunction(SIG,FUNC,CALL_CONV); } }; REG_CLASS REG_INSTANCE ; };#define REGISTER_TYPE(OBJ,TYPE,FLAGS) namespace { class REG_CLASS { public: REG_CLASS() { AutoBind::BindType(OBJ,sizeof(TYPE),FLAGS); } }; REG_CLASS REG_INSTANCE ; };#define REGISTER_METHOD(OBJ,SIG,FUNC,CALL_CONV) namespace { class REG_CLASS { public: REG_CLASS() { AutoBind::BindMethod(OBJ,SIG,FUNC,CALL_CONV); } }; REG_CLASS REG_INSTANCE ; };#define REGISTER_BEHAVIOR(BEHAVIOR,SIG,FUNC,CALL_CONV) namespace { class REG_CLASS { public: REG_CLASS() { AutoBind::BindBehavior(BEHAVIOR,SIG,FUNC,CALL_CONV); } }; REG_CLASS REG_INSTANCE ; };#define REGISTER_TYPE_BEHAVIOR(OBJ,BEHAVIOR,SIG,FUNC,CALL_CONV) namespace { class REG_CLASS { public: REG_CLASS() { AutoBind::BindTypeBehavior(OBJ,BEHAVIOR,SIG,FUNC,CALL_CONV); } }; REG_CLASS REG_INSTANCE ; };namespace AutoBind{ void Bind(asIScriptEngine*); void BindFunction(const char*,asUPtr,asDWORD); void BindType(const char*,int,asDWORD); void BindBehavior(asDWORD,const char*,asUPtr,asDWORD); void BindTypeBehavior(const char*,asDWORD,const char*,asUPtr,asDWORD); void BindMethod(const char*, const char*,asUPtr,asDWORD);};#endif
#include <angelscript.h>#include "AutoBind.h"#include <list>namespace { class Binder { public: virtual void bind(asIScriptEngine*) = 0; virtual ~Binder() {} }; class FunctionBinder: public Binder { public: const char* sig; asUPtr fptr; asDWORD call_conv; FunctionBinder(const char* str, asUPtr fp, asDWORD cc) : sig(str), fptr(fp), call_conv(cc) {} virtual void bind(asIScriptEngine* engine) { engine->RegisterGlobalFunction(sig,fptr,call_conv); } }; class TypeBinder: public Binder { public: const char* ident; asDWORD flags; int size; TypeBinder(const char* i, int s, asDWORD t) : ident(i), size(s), flags(t) {} virtual void bind(asIScriptEngine* engine) { engine->RegisterObjectType(ident,size,flags); } }; class MethodBinder: public Binder { public: const char* obj; const char* sig; asUPtr fptr; asDWORD call_conv; MethodBinder(const char* o, const char* s, asUPtr f, asDWORD c) : obj(o), sig(s), fptr(f), call_conv(c) {} virtual void bind(asIScriptEngine* engine) { engine->RegisterObjectMethod(obj, sig, fptr, call_conv); } }; class BehaviorBinder: public Binder { public: asDWORD behave; const char* sig; asUPtr fptr; asDWORD call_conv; BehaviorBinder(asDWORD b, const char* s, asUPtr f, asDWORD c) : behave(b), sig(s), fptr(f), call_conv(c) {} virtual void bind(asIScriptEngine* engine) { engine->RegisterGlobalBehaviour(behave, sig, fptr, call_conv); } }; class TypeBehaviorBinder: public Binder { public: const char* obj; asDWORD behave; const char* sig; asUPtr fptr; asDWORD call_conv; TypeBehaviorBinder(const char* o, asDWORD b, const char* s, asUPtr f, asDWORD c) : obj(o), behave(b), sig(s), fptr(f), call_conv(c) {} virtual void bind(asIScriptEngine* engine) { engine->RegisterObjectBehaviour(obj, behave, sig, fptr, call_conv); } }; typedef std::list<Binder*> BinderList; BinderList& GetBinder() //Static creation method { static BinderList binders; return binders; } void PushBackBinder(Binder* b) { GetBinder().push_back(b); } void PushFrontBinder(Binder* b) { GetBinder().push_front(b); }};void AutoBind::Bind(asIScriptEngine* engine){ while (!GetBinder().empty()) { GetBinder().front()->bind(engine); delete GetBinder().front(); GetBinder().pop_front(); }}void AutoBind::BindFunction(const char* s, asUPtr f, asDWORD c){ PushBackBinder(new FunctionBinder(s,f,c));}void BindType(const char* o, int s, asDWORD f){ PushFrontBinder(new TypeBinder(o,s,f));}void BindBehavior(asDWORD b, const char* s, asUPtr f, asDWORD c){ PushBackBinder(new BehaviorBinder(b,s,f,c));}void BindTypeBehavior(const char* o, asDWORD b, const char* s, asUPtr f, asDWORD c){ PushBackBinder(new TypeBehaviorBinder(o,b,s,f,c));}void BindMethod(const char* o, const char* s, asUPtr f, asDWORD c){ PushBackBinder(new MethodBinder(o,s,f,c));}
All I need to add now are properties. Ideally I want to just say 'REGISTER(XXX)' in the application and have it bound properly. Given the actual object, template meta-programming may be able to do this. This would probably preclude me from doing some of the evil things I have done in one project - that is, registering a pointer to an object as a type, then registering free functions as methods on that pointer type, so the script thinks it has an X, and does x.something, but really has a smart pointer to X and is doing something(x).