Engram 提案 |
|
至少有一次注意到 [1],string.dump
用于在虚拟机令牌级别序列化 Lua 代码的格式具有所有必要的功能,可以作为运行时 Lua 对象的序列化格式。但是,由于 string.dump
序列化的是函数而不是闭包,因此无法将运行时值放入 dump 中。本提案建议对 Lua 核心进行扩展以实现此目的。
术语engram 现已创造(或借用自神经科学)来指代一个函数,该函数在执行时返回封装在其中的数据对象。engram 生成器是一个库函数,它接收一个数据对象并返回其 engram。engram 生成器直接在虚拟机令牌格式中创建 Lua 函数。此函数等效于在生成时编译对象在运行时状态下的构造函数。
data = "testit" en = engram(data) en = loadstring(string.dump(en)) data = nil print(en())
engram
是 engram 生成器库函数,这是完成序列化往返所需的唯一额外代码。由 string.dump
生成的字符串可以保存到文件或数据库中,也可以通过管道或网络连接传输到另一台 Lua 机器或实例。不需要任何代码来读取序列化格式 - 现有的 loadstring
库函数就可以了。data
可以是数字、布尔值、字符串或表,其键是这些类型之一,其值是这些类型之一或满足这些条件的嵌套表。
func = function(x) print(x) end data = "testit" en = engram(data, func) en = loadstring(string.dump(en)) data = nil; func = nil en()
string.dump
序列化。
不幸的是,无法使用已发布的 Lua C API 编写 engram 生成器函数。有必要将函数编译到 Lua 核心。以下代码是高度实验性的,在此作为概念证明和专家代码审查提供。这是我对修改 Lua 核心的第一次尝试,我可能误解了一些细节或遗漏了一些必要的步骤。特别是,我担心我可能没有“与 Lua 垃圾收集器配合良好”。非常感谢 Lua 专家进行评论!
另请注意,此版本不支持表。我预计在接下来的几天内解决这个问题。
头文件 (lengram.h)
/* ** $Id: lengram.h,v 1.0.0.0 2009/02/02 John Hind $ ** Engram add-on for Lua **EXPERIMENTAL** ** See Copyright Notice in lua.h */ #ifndef lengram_h #define lengram_h LUA_API int luaX_engram (lua_State *L, int usesfunc); LUALIB_API int luaopen_engram (lua_State *L); #endif
/* ** $Id: lengram.h,v 1.0.0.0 2009/02/02 John Hind $ ** Engram add-on for Lua **EXPERIMENTAL** ** See Copyright Notice in lua.h */ #include <assert.h> #include <math.h> #include <stdarg.h> #include <string.h> #define lengram_c #define LUA_CORE #include "lua.h" #include "lauxlib.h" #include "lengram.h" #include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lstring.h" //On entry: // top - 1 : Lua Data object (number, boolean, string or table) // top - 2 : Inner Lua Function (if (usesfunc)) //On exit: // top - 1 : Engram Lua Function LUA_API int luaX_engram (lua_State *L, int usesfunc) { int pc; int kc; int ms; int tab; Proto* f; Closure* cl; if (lua_istable(L, -1)) { // TODO: Check table and evaluate resources needed tab = 1; luaL_error(L, "Engram: Unsupported type (for now)"); } else { tab = 0; pc = (usesfunc)? 4 : 2; //Number of opcodes kc = 1; //Number of constants ms = 2; //Number of registers } f = luaF_newproto(L); cl = luaF_newLclosure(L, 0, clvalue(L->top)->l.env); cl->l.p = f; setclvalue(L, L->top, cl); incr_top(L); f->source = luaS_newliteral(L,"=(ENGRAM)"); f->maxstacksize = ms; if (usesfunc) { f->p = luaM_newvector(L, 1, Proto*); //Space for one inner function f->p[0] = clvalue(L->top - 3)->l.p; //Insert the inner function f->sizep = 1; //Number of functions } f->k = luaM_newvector(L, kc, TValue); //Space for constants kc = 0; if (tab) { //TODO: Define the table constants } else { f->k[kc++] = *(L->top - 2); } f->sizek = kc; f->code = luaM_newvector(L, pc, Instruction); //Space for opcodes pc=0; if (tab) { // TODO: Table code generator } else { f->code[pc++] = CREATE_ABx(OP_LOADK, 1, 0); } if (usesfunc) { f->code[pc++] = CREATE_ABx(OP_CLOSURE, 0, 0); f->code[pc++] = CREATE_ABC(OP_TAILCALL, 0, 2, 0); f->code[pc++] = CREATE_ABC(OP_RETURN, 0, 0, 0); } else { f->code[pc++] = CREATE_ABC(OP_RETURN, 1, 2, 0); } f->sizecode = pc; return 0; } // The C function published to Lua static int LuaEngram (lua_State *L) { if (!lua_isfunction(L, -1)) lua_pushnil(L); lua_settop(L, 2); lua_insert(L, 1); switch (lua_type(L, 2)) {case LUA_TBOOLEAN: case LUA_TNUMBER: case LUA_TSTRING: case LUA_TTABLE: break; default: luaL_error(L, "Engram: Unsupported data type"); break;} switch (lua_type(L, 1)) {case LUA_TFUNCTION: case LUA_TNIL: break; default: luaL_error(L, "Engram: Second parameter must be a function"); break;} luaX_engram(L, lua_isfunction(L, 1)); return 1; } // Open the engram library LUALIB_API int luaopen_engram (lua_State *L) { lua_pushcfunction(L, LuaEngram); lua_setglobal(L, "engram"); return 0; }
-- JohnHind
请在下方添加任何评论或问题,并用您的姓名标记它们