Engram 提案 |
|
已經發現至少 [1] 處地方,注意到 string.dump
用於序列化虛擬機器代號層級中的 Lua Code 的格式,具有作為執行期間 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
請在下方新增任何評論或詢問,並以你的名稱標記於上