1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
|
#ifndef __LUA_BIND_STATE_H__
#define __LUA_BIND_STATE_H__
#include <string>
#include "LuaBindConfig.h"
#include "LuaBindRefTable.h"
#include "LuaBindGlobalState.h"
#include "LuaBindTable.h"
#include "LuaBindLClass.h"
namespace LuaBind
{
class VM;
class Enum;
class StrongRef;
class WeakRef;
typedef void (*ErrorHandler) (cc8 * msg);
typedef void(*OnRegisterClassHandler)(State&, int clsIdx, std::string clsName, std::string pkgName);
extern ErrorHandler onErrorOccured;
extern OnRegisterClassHandler onRegisterNativeClass;
extern std::string g_NameSpace;
// 对lua_State的代理,除了保存一个lua_State的引用不保存其他内容。一个实例的metatable如下:
// class table
// member table
// ref table
// userdata
// 从userdata通过getmetatable获取上级metatable。除此之外还有一个class table注册在对应
// 的名称空间里。
// 把LuaState理解成执行栈
LUA_BIND_API class State
{
public:
State(lua_State* state);
State(const State& state);
virtual ~State();
inline lua_State* operator ->() { return mState; };
inline lua_State& operator *() { return *mState; };
inline operator lua_State*() { return mState; }
inline operator bool() { return mState != nullptr; };
// 获取绑定的lua_State
inline lua_State* GetHandle() { return mState; };
global_State* GetGlobalState();
VM* GetVM();
//------------------------------------------------------------------------------//
void OpenLibs();
//------------------------------------------------------------------------------//
// 名称空间管理,名称空间就是一个表,_G是最上面的表
void PushGlobalNamespace();
void PushNamespace(cc8* name);
void PopNamespace();
bool IsNamespace(int idx);
//------------------------------------------------------------------------------//
void SetTop(int top);
int GetTop();
bool CheckParams(int idx, cc8* format, int len);
bool CheckParams(int idx, cc8* format);
int AbsIndex(int idx);
void Call(int nArgs, int nResults, ErrorHandler handler = NULL);
//------------------------------------------------------------------------------//
void GetField(int idx, cc8* name);
void GetField(int idx, int key);
std::string GetField(int idx, cc8* key, cc8* value);
std::string GetField(int idx, int key, cc8* value);
std::string GetField(int idx, cc8* key, const std::string& value);
std::string GetField(int idx, int key, const std::string& value);
bool GetFieldWithType(int idx, cc8* name, int type);
bool GetFieldWithType(int idx, int key, int type);
bool GetSubfieldWithType(int idx, cc8* format, int type, ...);
static cc8* GetLuaTypeName(int type);
void SetField(int idx, cc8* key);
bool IsNil(int idx);
bool IsNilOrNone(int idx);
bool IsTable(int idx);
bool IsTableOrUserdata(int idx);
bool IsTrueOrNotNil(int idx);
bool IsType(int idx, int type);
bool IsType(int idx, cc8* name, int type);
bool IsValid();
bool HasField(int idx, cc8* name);
bool HasField(int idx, int key);
bool HasField(int idx, cc8* name, int type);
bool HasField(int idx, int name, int type);
bool HasKeys(int idx);
void PushLuaObject(const ILuaClass& lc);
void PushTable(const INativeTable& tb);
void PushNil();
void Push(bool value);
void Push(cc8* value);
void Push(double value);
void Push(float value);
void Push(int value);
void Push(u16 value);
void Push(u32 value);
void Push(u64 value);
void Push(s64 value);
void Push(uintptr value);
void Push(lua_CFunction value);
void Push(void* data, size_t size);
void Push(const void* value);
void Push(std::string value);
// 将idx开始的n个push到栈顶,idx会被取正,n向上生长。
void PushValues(int idx, int n);
// 以void** 的形式创建userdata,并将值设置为ptr
void PushPtrUserdata(void* ptr);
void Pop(int n = 1);
void Settop(int idx);
template<typename T> T* GetUserdata(int idx = 1);
//------------------------------------------------------------------------------//
int ErrorType(int idx, cc8* hint);
//------------------------------------------------------------------------------//
template<typename T> T GetValue(int idx, T default_value);
template<typename T> T GetField(int idx, int key, T value);
template<typename T> T GetField(int idx, cc8* key, T value);
template<typename T> void SetField(int idx, cc8* key, T value);
template<typename T> void SetFieldByIndex(int idx, int key, T value);
template<typename T> T* CheckUserdata(int idx);
template<typename T> T CheckValue(int idx);
//------------------------------------------------------------------------------//
void DoString(const std::string& code);
void DoFile(const std::string& file, ErrorHandler handler = NULL);
void LoadFile(const std::string& file);
//------------------------------------------------------------------------------//
// 注册方法
// 注册工厂,适用于普通类,有New方法
template<class TYPE> void RegisterNativeClass();
// 注册枚举
void RegisterEnum(cc8* name, Enum* enums);
// 注册C函数,注意后面加一行{0, 0}
void RegisterMethods(const luaL_Reg *l);
// 注册单个C函数
void RegisterMethod(cc8* fname, lua_CFunction func);
// 把preloader加到package.preload里,当require"libname"时lua的loader_preload根据
// libname找到preloader直接加载。用来实现需要require的时候才加载,并且加载过一次后
// package.loaded记录下来,下次不会再加载。通过require会调用这个preloader。
void RegisterPreloader(cc8* libname, lua_CFunction preloader);
// 根据luaL_Reg建立lib table,并在_G和package.loaded建立对libname的索引,指向lib table。
void RegisterLib(cc8* libname, const luaL_Reg* l);
protected:
friend class VM;
// 屏蔽对State的地址相关操作
void* operator &();
void* operator new(size_t size);
lua_State* const mState;
};
//--------------------------------------------------------------------------------//
// GetValue()模板特化
template <> bool State::GetValue < bool >(int idx, const bool value);
template <> cc8* State::GetValue < cc8* >(int idx, const cc8* value);
template <> double State::GetValue < double >(int idx, const double value);
template <> float State::GetValue < float >(int idx, const float value);
template <> s8 State::GetValue < s8 >(int idx, const s8 value);
template <> s16 State::GetValue < s16 >(int idx, const s16 value);
template <> s32 State::GetValue < s32 >(int idx, const s32 value);
template <> s64 State::GetValue < s64 >(int idx, const s64 value);
template <> u8 State::GetValue < u8 >(int idx, const u8 value);
template <> u16 State::GetValue < u16 >(int idx, const u16 value);
template <> u32 State::GetValue < u32 >(int idx, const u32 value);
template <> u64 State::GetValue < u64 >(int idx, const u64 value);
template <> std::string State::GetValue < std::string >(int idx, const std::string value);
template <> const void* State::GetValue < const void* >(int idx, const void* value);
//--------------------------------------------------------------------------------//
// CheckValue模板特化
template <> bool State::CheckValue < bool >(int idx);
template <> cc8* State::CheckValue < cc8* >(int idx);
template <> double State::CheckValue < double >(int idx);
template <> float State::CheckValue < float >(int idx);
template <> s8 State::CheckValue < s8 >(int idx);
template <> s16 State::CheckValue < s16 >(int idx);
template <> s32 State::CheckValue < s32 >(int idx);
template <> s64 State::CheckValue < s64 >(int idx);
template <> u8 State::CheckValue < u8 >(int idx);
template <> u16 State::CheckValue < u16 >(int idx);
template <> u32 State::CheckValue < u32 >(int idx);
template <> u64 State::CheckValue < u64 >(int idx);
template <> std::string State::CheckValue < std::string >(int idx);
template <> const void* State::CheckValue < const void* >(int idx);
// 在成员方法里创建State并对参数进行检查。
#define LUA_BIND_SETUP(L, params) \
LuaBind::State state(L); \
if(!state.CheckParams(1, params)) return 0
#define LUA_BIND_STATE(L) \
LuaBind::State state(L);\
state.GetVM()->SetCurThread(L)
//--------------------------------------------------------------------------------//
// RAII, 确保不安全的lua调用能够在调用之后返回到最初stack状态。
class ScopedState : public State
{
public:
ScopedState(lua_State* state)
: State(state)
{
mRestoreTop = lua_gettop(mState);
}
ScopedState(const State& state)
: State(state)
{
mRestoreTop = lua_gettop(mState);
}
~ScopedState()
{
if (mState) {
if (lua_gettop(mState) != mRestoreTop) {
lua_settop(mState, mRestoreTop);
}
}
}
private:
void* operator new(size_t);
int mRestoreTop;
};
// 注册工厂,注册class table,以type name为键设置在名称空间上。在注册阶段不会设置元表,等到New方法调用的时候才会。
template<class TYPE>
void State::RegisterNativeClass()
{
cc8* type = TYPE::GetNativeClassName();
lua_State* L = mState;
State& state = *this;
int top = lua_gettop(L); // namespace table
assert(lua_istable(L, top));
// class table
lua_newtable(L);
int clsIdx = lua_gettop(L);
TYPE::RegisterClassShared(state);
TYPE::RegisterNativeClass(state);
// 自定义注册内容
if (onRegisterNativeClass)
onRegisterNativeClass(state, clsIdx, type, g_NameSpace);
// 清理栈
lua_settop(state, clsIdx);
// 检测TYPE里面是否没有注册必须的方法
#define _assertmethod(I, NAME) \
GetField(I, NAME); \
assert(IsType(-1, LUA_TFUNCTION)); \
Pop();
//_assertmethod(-1, "New");
#undef _assertmethod
// class["__index"] = class
lua_pushvalue(state, -1); // class table
lua_setfield(state, -2, "__index");
TYPE::SetClassTableRef(state, -1);
// namespace[type] = class
SetField(top, type);
// reset top
lua_settop(L, top);
// 后处理
TYPE::RegisterPostprocess(state);
}
template<typename TYPE>
void State::SetField(int idx, cc8* key, TYPE value)
{
if (IsTableOrUserdata(idx))
{
idx = AbsIndex(idx);
this->Push(value);
lua_setfield(mState, idx, key);
}
}
template<typename TYPE>
void State::SetFieldByIndex(int idx, int key, TYPE value)
{
if (IsTableOrUserdata(idx))
{
idx = AbsIndex(idx);
this->Push(value);
lua_rawseti(mState, idx, key);
}
}
template<typename TYPE>
TYPE State::GetField(int idx, cc8* key, TYPE value)
{
GetField(idx, key);
TYPE result = GetValue < TYPE >(-1, value);
this->Pop();
return result;
}
template<typename TYPE>
TYPE State::GetField(int idx, int key, TYPE value)
{
GetField(idx, key);
TYPE result = GetValue < TYPE >(-1, value);
Pop();
return result;
}
template<typename TYPE>
TYPE* State::GetUserdata(int idx)
{
void* p = nullptr;
if (IsType(idx, LUA_TUSERDATA))
{
p = *(void**)lua_touserdata(mState, idx);
}
return static_cast<TYPE*>(p);
}
template<typename TYPE>
TYPE* State::CheckUserdata(int idx)
{
if (IsType(idx, LUA_TUSERDATA))
{
if (lua_getmetatable(mState, idx)) // ref table
{
if (lua_getmetatable(mState, -1)) // member table
{
if (lua_getmetatable(mState, -1)) // class table
{
TYPE::PushClassTable(*this); // target class table
if (lua_rawequal(mState, -1, -2))
{
Pop(4); // ref\member\class\target class
TYPE* udata = GetUserdata<TYPE>(idx);
return udata; // userdata
}
Pop(2); // target class table\class table
}
Pop(1); // member table
}
Pop(1); // ref table
}
}
luaL_typerror(mState, idx, TYPE::GetNativeClassName());
return nullptr;
}
}
#endif
|