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
请在下方添加任何评论或问题,并用您的姓名标记它们