Engram 提案

lua-users home
wiki

使用 dump 格式的訊息執行期間序列化和儲存

已經發現至少 [1] 處地方,注意到 string.dump 用於序列化虛擬機器代號層級中的 Lua Code 的格式,具有作為執行期間 Lua 物件序列化格式所需的所有功能。不過,因為 string.dump 序列化函式而非封閉式,所以無法將執行期間的值放入 dump 中。本提案提供一個 Lua 核心延伸來達成此目的。

此處提出 (或借用自神經科學) 的術語 Engram,用於指稱執行後傳回其內部封裝資料物件的函式。Engram 產生器 是接收資料物件並傳回其 engram 的函式庫函式。Engram 產生器直接建立虛擬機器代號格式的 Lua 函式。這個函式等於在產生時編譯物件在執行期間狀態的建構函式。

Lua Code

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 Code

很遺憾,無法使用已發佈的 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 (差異)