Engram 提案

lua-users home
wiki

使用 dump 格式进行消息传递和持久化的运行时序列化

至少有一次注意到 [1]string.dump 用于在虚拟机令牌级别序列化 Lua 代码的格式具有所有必要的功能,可以作为运行时 Lua 对象的序列化格式。但是,由于 string.dump 序列化的是函数而不是闭包,因此无法将运行时值放入 dump 中。本提案建议对 Lua 核心进行扩展以实现此目的。

术语engram 现已创造(或借用自神经科学)来指代一个函数,该函数在执行时返回封装在其中的数据对象。engram 生成器是一个库函数,它接收一个数据对象并返回其 engram。engram 生成器直接在虚拟机令牌格式中创建 Lua 函数。此函数等效于在生成时编译对象在运行时状态下的构造函数。

Lua 代码

data = "testit"
en = engram(data)
en = loadstring(string.dump(en))
data = nil
print(en())
此示例打印“testit”。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()
此示例也打印“testit”。该概念扩展到将内部 Lua 函数与 engram 函数中的数据一起封装。当执行 engram 时,它会尾调用内部函数,并将重建的数据对象传递给它。内部函数和数据都封装在 engram 函数中,并通过 string.dump 序列化。

C 代码

不幸的是,无法使用已发布的 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
代码文件 (lengram.c)
/*
** $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

请在下方添加任何评论或问题,并用您的姓名标记它们


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2009 年 2 月 5 日下午 12:56 GMT (差异)