Lua 与C/C++ 交互系列:动态注册枚举enum到Lua Code中,在运行时在Lua Code中获取内省信息
2015-06-28 13:20
796 查看
在Lua 5.1 Reference Manual 对于Lua 值和类型的介绍。Lua是一个动态语言,在Lua中变量仅仅有值而没有类型。所以在Lua中的变量不需要声明。所以的值本身包含类型。
其实Lua 包含一种运行时类型识别,通过type()函数,可以在运行时获取值的类型。
信息来自: Lua 5.1 Reference Manual Values and Types
Lua is a dynamically typed language. This means that variables do not have types; only values do. There are no type definitions in the language. All values carry their own type.
type (variables)
Returns the type of its only argument, coded as a string. The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread", and "userdata".
在C语言特征本身,不提供运行时信息。C语言的拓展集,C++语言特征本身对运行时提供支持。在C++语言中通过typeid(),dynamic_case()等函数可以获取类型的内省信息。
在Java语言中,对内省信息支持强大,spring 等库就是通过内省信息来实现的强大库。在actionscript3.0中也提供了对类的内省信息。在游戏开发中,可以利用内省信息反射出类对象,包括游戏UI编辑器都是通过内省类信息来实现的。C# 是在C++,Java语言发展而来,同时也对运行时内省提供强大支持。对于这些语言的内省信息不详细赘述。
在Python脚本语言中,PyObject 类 实现机制与Lua lua_TValue 实现机制类型,都是通过类型值int 与值相绑定. 虽然,在python 和lua语言中,只存在值,不存在类型,但是通过语言提供的函数,可以在运行时获取到值的类型。
在Lua源代码中,节选出部分与运行时信息相关的代码:
在Lua源代码中提供了8中基本内置类型,随着Lua演化,Lua的基本内置类型变化不大。以后的文章中,就详细介绍Lua类型的演化历史。
内置类型的实现,是通过值与类型相绑定来实现的。值是如何表示的,在Lua 作者的5.0实现介绍中有详细解释。
type (v)
Returns the type of its only argument, coded as a string.
The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread", and "userdata".
注意:lightuserdata 和 full userdata的类型都是 userdata.
type(v)在lua中关键源代码如下:
本文参考了LuaAutoC 开源项目,并节选部分代码,修改而来。本文主要展示把C 语言 struct ,enum等结构注册到Lua Code中,并可以在Lua Code中获取注册类型的运行时信息。
通过lua_pushinteger(L, 0); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_index"); 来管理生成唯一的类型ID,并存储在全局变量中,默认值为0 .
把所有类型都在全局变量表中注册,在Lua Code中就可以获取相关信息,在Lua Code中就可以内省C语言的自定义类型。
本文的核心通过一个全局唯一ID 和Lua Table本身的Hash系统来实现。代码很简单。上菜。
luademo.cpp :
运行结果如下:
本文这样就结束了。抛装引玉,如果不对的地方,请支持来,大家共享知识。
其实Lua 包含一种运行时类型识别,通过type()函数,可以在运行时获取值的类型。
信息来自: Lua 5.1 Reference Manual Values and Types
Lua is a dynamically typed language. This means that variables do not have types; only values do. There are no type definitions in the language. All values carry their own type.
type (variables)
Returns the type of its only argument, coded as a string. The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread", and "userdata".
在C语言特征本身,不提供运行时信息。C语言的拓展集,C++语言特征本身对运行时提供支持。在C++语言中通过typeid(),dynamic_case()等函数可以获取类型的内省信息。
在Java语言中,对内省信息支持强大,spring 等库就是通过内省信息来实现的强大库。在actionscript3.0中也提供了对类的内省信息。在游戏开发中,可以利用内省信息反射出类对象,包括游戏UI编辑器都是通过内省类信息来实现的。C# 是在C++,Java语言发展而来,同时也对运行时内省提供强大支持。对于这些语言的内省信息不详细赘述。
在Python脚本语言中,PyObject 类 实现机制与Lua lua_TValue 实现机制类型,都是通过类型值int 与值相绑定. 虽然,在python 和lua语言中,只存在值,不存在类型,但是通过语言提供的函数,可以在运行时获取到值的类型。
在Lua源代码中,节选出部分与运行时信息相关的代码:
在Lua源代码中提供了8中基本内置类型,随着Lua演化,Lua的基本内置类型变化不大。以后的文章中,就详细介绍Lua类型的演化历史。
/* ** basic types */ #define LUA_TNONE (-1) #define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 #define LUA_TNUMBER 3 #define LUA_TSTRING 4 #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8
内置类型的实现,是通过值与类型相绑定来实现的。值是如何表示的,在Lua 作者的5.0实现介绍中有详细解释。
typedef struct lua_TValue { Value value_; //用来标示Lua的值类型,在lua作者5.0实现中有详细的介绍 int tt_; //用来标示类型,-1 -8 由上面宏定义 } TValue; union Value { GCObject *gc; /* collectable objects */ void *p; /* light userdata */ int b; /* booleans */ lua_CFunction f; /* light C functions */ numfield /* numbers */ };在Lua Code 运行时中,可以通过type()来获取值的类型:
type (v)
Returns the type of its only argument, coded as a string.
The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread", and "userdata".
注意:lightuserdata 和 full userdata的类型都是 userdata.
type(v)在lua中关键源代码如下:
static int luaB_type (lua_State *L) { luaL_checkany(L, 1); lua_pushstring(L, luaL_typename(L, 1)); return 1; } /* Macros to access values */ //获取与值绑定的类型 #define ttype(o) ((o)->tt) //通过数组来返回对应的字符串类型 #define ttypename(x) luaT_typenames_[(x) + 1] LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { "no value", "nil", "boolean", udatatypename, "number", "string", "table", "function", udatatypename, "thread", "proto", "upval" /* these last two cases are used for tests only */ };
本文参考了LuaAutoC 开源项目,并节选部分代码,修改而来。本文主要展示把C 语言 struct ,enum等结构注册到Lua Code中,并可以在Lua Code中获取注册类型的运行时信息。
通过lua_pushinteger(L, 0); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_index"); 来管理生成唯一的类型ID,并存储在全局变量中,默认值为0 .
把所有类型都在全局变量表中注册,在Lua Code中就可以获取相关信息,在Lua Code中就可以内省C语言的自定义类型。
本文的核心通过一个全局唯一ID 和Lua Table本身的Hash系统来实现。代码很简单。上菜。
luademo.cpp :
extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" } #define prefix "prefix_" //作者orangeduck 在他的博客中认为在动态语言中内省机制是核心。同时Lua 也是通过Type_ID来标示类型的。这与作者不谋而合。 //Type_ID是通过运行时动态生成,默认从零开始。可以在运行时获取对象的类型ID. //LuaAutoC 已经在orangeduck 作者的项目中成功的应用。 void luaA_open(lua_State* L) { //用来在运行时动态生成类型的唯一ID,默认开始值为零. 在全局变量表设置 prefix "type_index"的值默认为1,用来标记所有类型. lua_pushinteger(L, 0); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_index"); //在全局变量表,prefix "type_ids" 对应Table结构.称作idTable .名称-Id lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_ids"); //在全局变量表,prefix "type_names"对应Table结构.称作nameTable.名称-名称 lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_names"); //在全局变量表, prefix "type_sizes"对应Table结构.称作sizeTable.名称-大小 lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_sizes"); //与上面类型,在注册表中注册enumsTable,enum_sizesTable,enums_valuesTable用来存储c语言中的枚举值 //这些作为本例中的核心系统。可以在运行时识别C语言用户自定义struct结构的内省信息。 lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"enums"); lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"enums_sizes"); lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"enums_values"); } //用来演示本例子的枚举 enum Week { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday, }; typedef lua_Integer luaA_Type; // 在全局变量表中管理所有注册的类型,可以在运行时通过名字获取内省信息 //在全局环境中type_idsTable 和type_namesTable 以及type_values注册类型。 //如果全局环境表中已经存在该类型则直接返回类型ID,否则注册新类型 /////////////////////////////////////////////////////////////////// // 以Week枚举举例: // _G[prefix_type_ids]["Week"]=WeekId // _G[prefix_type_names][WeekId]=WeekName // _G[prefix_type_sizes][WeekId]=WeekSize ////////////////////////////////////////////////////////////////// luaA_Type luaA_type_add(lua_State* L, const char* type, size_t size) { //获取在全局环境表中idTable,类型名称=ID lua_getfield(L, LUA_GLOBALSINDEX, prefix"type_ids"); //在idTable中获取type_name是否存在 lua_getfield(L, -1, type); //判断是否存在 if (lua_isnumber(L, -1)) { //如果已经存在,则返回类型ID luaA_Type id = lua_tointeger(L, -1); lua_pop(L, 2); return id; } else { //弹出idTable 和类型关联的ID lua_pop(L, 2); //获取自动生成的唯一索引,在运行时自动生成. lua_getfield(L, LUA_GLOBALSINDEX, prefix"type_index"); //转换成整型 luaA_Type id = lua_tointeger(L, -1); //清空栈顶 lua_pop(L, 1); //自动生成下一个唯一索引 id++; //压入到虚拟栈 lua_pushinteger(L, id); //把生成的唯一索引设置成ID,并出栈 lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_index"); //获取idTable lua_getfield(L, LUA_GLOBALSINDEX, prefix"type_ids"); //把自动生成的唯一ID压入栈中 lua_pushinteger(L, id); // 索引[键]=栈顶 设置idTable[type]=id lua_setfield(L, -2, type); lua_pop(L, 1); //获取类型nameTable lua_getfield(L, LUA_GLOBALSINDEX, prefix"type_names"); //把唯一ID入栈 lua_pushinteger(L, id); //把类型name压入栈 lua_pushstring(L, type); //设置 索引[below 栈顶]=栈顶 nameTable[id]=type lua_settable(L, -3); lua_pop(L, 1); lua_getfield(L, LUA_GLOBALSINDEX, prefix"type_sizes"); lua_pushinteger(L, id); lua_pushinteger(L, size); lua_settable(L, -3); lua_pop(L, 1); return id; } } //注册enum类型,用来存储enum每一个枚举值 // 以Week枚举举例: // _G[prefix_enums]["WeekId"]=WeekEnumTable // _G[prefix_enums_values]["WeekId"]=WeekEnumValueTable // _G[prefix_enums_sizes]["WeekId"]=WeekEnumSizeTable void luaA_enum_type(lua_State *L, luaA_Type type, size_t size) { lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums"); lua_pushinteger(L, type); lua_newtable(L); lua_settable(L, -3); lua_pop(L, 1); lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_values"); lua_pushinteger(L, type); lua_newtable(L); lua_settable(L, -3); lua_pop(L, 1); //enum_sizesTable[name] lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_sizes"); lua_pushinteger(L, type); lua_pushinteger(L, size); lua_settable(L, -3); lua_pop(L, 1); } //实际注册enum枚举中每一个值到注册表中 //注册enum类型,用来存储enum每一个枚举值 // 以Week枚举举例: // _G[prefix_enums]["WeekId"]=WeekEnumTable // _G[prefix_enums_values]["WeekId"]=WeekEnumValueTable // _G[prefix_enums_sizes]["WeekId"]=WeekEnumSizeTable // // // _G[prefix_enums_sizes]["WeekId"]["Monday"]=Monday // void luaA_enum_value_type(lua_State *L, luaA_Type type, int lvalue, const char* name) { //获取 _G[prefix_enums]["WeekId"]=WeekEnumTable lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums"); lua_pushinteger(L, type); lua_gettable(L, -2); if (!lua_isnil(L, -1)) { //存储enum大小 lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_sizes"); lua_pushinteger(L, type); lua_gettable(L, -2); size_t size = lua_tointeger(L, -1); lua_pop(L, 2); lua_pushstring(L, name); lua_pushinteger(L, lvalue); lua_settable(L,-3); lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_values"); lua_pushinteger(L, type); lua_gettable(L, -2); size_t v =0; if (!lua_isnil(L, -1)) { v =lua_tonumber(L,-1); } lua_pushinteger(L, v); lua_getfield(L, -4, name); lua_settable(L, -3); lua_pop(L, 4); return; } lua_pop(L, 2); lua_pushfstring(L, "luaA_enum_value: Enum '%s' not registered!", luaA_typename(L, type)); lua_error(L); } //实际注册enum枚举中每一个值到注册表中 //注册enum类型,用来存储enum每一个枚举值 // 以Week枚举举例: // _G[prefix_enums]["WeekId"]=WeekEnumTable // _G[prefix_enums_values]["WeekId"]=WeekEnumValueTable // _G[prefix_enums_sizes]["WeekId"]=WeekEnumSizeTable // // // _G[prefix_enums_sizes]["WeekId"]["Monday"]=Monday // void luaA_enum_value_type(lua_State *L, luaA_Type type, int lvalue, const char* name) { //获取 _G[prefix_enums]["WeekId"]=WeekEnumTable lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums"); lua_pushinteger(L, type); lua_gettable(L, -2); if (!lua_isnil(L, -1)) { //存储enum大小 lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_sizes"); lua_pushinteger(L, type); lua_gettable(L, -2); size_t size = lua_tointeger(L, -1); lua_pop(L, 2); lua_pushstring(L, name); lua_pushinteger(L, lvalue); lua_settable(L,-3); lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_values"); lua_pushinteger(L, type); lua_gettable(L, -2); size_t v =0; if (!lua_isnil(L, -1)) { v =lua_tonumber(L,-1); } lua_pushinteger(L, v); lua_getfield(L, -4, name); lua_settable(L, -3); lua_pop(L, 4); return; } lua_pop(L, 2); lua_pushfstring(L, "luaA_enum_value: Enum '%s' not registered!", luaA_typename(L, type)); lua_error(L); } //利用C语言宏,把c语言中的enum struct 等类型作为字符串 #define luaA_type(L, type) luaA_type_add(L, #type, sizeof(type)) //定义enum类型 #define luaA_enum(L, type) luaA_enum_type(L, luaA_type(L, type), sizeof(type)) //注册枚举值 #define luaA_enum_value(L,enumType,enumValue) luaA_enum_value_type(L, luaA_type(L,enumType),enumValue,#enumValue) int main(int argc, char **argv) { lua_State *L = lua_open(); /* create state */ luaL_openlibs (L); luaA_open(L); //注册枚举类型 luaA_enum(L,Week); //实际注册enum类型中的每一枚举值 luaA_enum_value(L,Week,Monday); luaA_enum_value(L,Week,Tuesday); luaA_enum_value(L,Week,Wednesday); luaA_enum_value(L,Week,Thursday); luaA_enum_value(L,Week,Friday); luaA_enum_value(L,Week,Saturday); luaA_enum_value(L,Week,Sunday); luaL_dofile (L, "demo.lua"); lua_close(L); return 1; }luademo.lua文件代码:
print("=========") --根据注册的enum名称来获取类型Id local WeekId =_G["prefix_type_ids"]["Week"] --获取运行时信息 local nameTable =_G["prefix_type_names"][WeekId] local sizeTable =_G["prefix_type_sizes"][WeekId] print(WeekId) print(nameTable) print(sizeTable) local Week= _G["prefix_enums"][WeekId] local WeekValue= _G["prefix_enums_values"][WeekId] local WeekSize = _G["prefix_enums_sizes"][WeekId] print(Week) print(WeekValue) print(WeekSize) --获取注册的枚举值 print(Week.Monday) print(Week.Tuesday) print(Week.Wednesday) print(Week.Thursday) print(Week.Friday) print(Week.Saturday) print(Week.Sunday)
运行结果如下:
本文这样就结束了。抛装引玉,如果不对的地方,请支持来,大家共享知识。
相关文章推荐
- LUA常见库和工具
- Lua 与C/C++ 交互系列:注册枚举enum到Lua Code中
- [文学阅读] METEOR: An Automatic Metric for MT Evaluation with Improved Correlation with Human Judgments
- lua string.dump
- 触摸精灵lua脚本实现微信群加好友功能
- lua中table如何安全移除元素
- Lua FFI 简单封装 libpcap
- lua5.3 和 vs2010 环境搭建
- lua学习--记录
- Lua Rings库介绍
- Lua面向对象编程系列-通过Table和Closure来实现类机制
- Lua面向对象编程系列-通过Table和Metatable来实现类机制
- Love中conf.lua更改屏幕大小未生效问题
- 让Xcode Lua 语法高亮
- 利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)
- LuaTinker
- lua学习--特殊字符
- [G+smo]gsGeometryEvaluator
- lua学习--冒泡排序和保存奇数
- Lua 与C/C++ 交互系列:利用模板技术在Lua Code中注册C++类