Files
integration/luprex/ext/eris-master/FILEFORMAT
2023-02-14 14:05:45 -05:00

240 lines
9.0 KiB
Plaintext

/*
The format is largely equal to that of Pluto, with some changes to reduce
file size, and where necessary due to changes in Lua's architecture.
Pseudo-C is used to express the file format. Padding is assumed to be
nonexistent. The keyword "one_of" is used to express a concept similar to
"union", except that its size is the size of the actual datatype chosen. Thus,
objects which contain, directly or indirectly, a one_of, may vary in size. The
keyword "if" is used to express the fact that the following block may or may
not be present, usually indicated by the type of a previous "one_of".
*/
struct PersistedData {
Header header; /* The header used for basic validation. */
Object rootobj; /* The root object that was persisted. */
};
struct Header {
char header[4] = "ERIS"; /* Header signature for rudimentary validation */
uint8_t sizeof_number; /* sizeof(lua_Number) to check type compatibility */
lua_Number test; /* -1.234567890 to check representation compatibility */
uint8_t sizeof_int; /* sizeof(int) in persisted data */
uint8_t sizeof_size_t; /* sizeof(size_t) in persisted data */
/* Note that the last two fields determine the size of the int and size_t
* fields in the following definitions. We write each value in the native
* "size" and check for truncation when reading, if necessary. */
};
struct Object {
one_of {
int type; /* if the value is one of LUA_TXXX or ERIS_PERMANENT */
Reference r; /* otherwise */
/* Note that the types LUA_TNIL, LUA_TBOOLEAN, LUA_TNUMBER and
* LUA_TLIGHTUSERDATA will never be "referenced", but always be written
* directly. */
}
if (type) {
RealObject o; /* if we have a type, not a reference */
/* If the object is not primitive (see list above) we remember it and
* increment the reference counter, and point any future occurrences of
* it to this one via a reference (see above, Reference r). */
}
};
struct Reference {
int ref; /* The index the object was registered with */
};
struct RealObject {
one_of {
uint8_t b; /* If type == LUA_TBOOLEAN */
size_t l; /* If type == LUA_TLIGHTUSERDATA */
Number n; /* If type == LUA_TNUMBER */
String s; /* If type == LUA_TSTRING */
Table t; /* If type == LUA_TTABLE */
Closure f; /* If type == LUA_TFUNCTION */
Userdata u; /* If type == LUA_TUSERDATA */
Thread th; /* If type == LUA_TTHREAD */
Proto p; /* If type == LUA_TPROTO (from lobject.h) */
UpVal uv; /* If type == LUA_TUPVAL (from lobject.h) */
PermKey pk; /* if type == ERIS_PERMANENT */
};
};
struct Number {
if(sizeof(lua_Number) == sizeof(uint32_t)) {
uint32_t rep; /* binary representation of the number, stored as
* integer to re-use endian-agnosticism */
}
else if (sizeof(lua_Number) == sizeof(uint64_t)) {
uint64_t rep; /* binary representation of the number, stored as
* integer to re-use endian-agnosticism */
}
else {
/* unsupported float type -- error if asserts are enabled */
}
};
struct String {
size_t length; /* The length of the string */
char str[length]; /* The actual string (not always null terminated) */
};
struct Table {
uint8_t isSpecial; /* 1 if SP is used; 0 otherwise */
one_of {
Object c; /* if isspecial == 1; closure to refill the table */
LiteralTable t; /* if isspecial == 0; literal table info */
};
};
struct LiteralTable {
Pair p[]; /* key/value pairs */
Object nil = nil; /* Nil reference to terminate */
Object metatable; /* The metatable (nil for none, otherwise LUA_TTABLE) */
};
struct Pair {
Object key; /* never nil, since that indicates the end */
Object value; /* never nil, since the entry wouldn't exist then */
};
struct Userdata {
uint8_t isSpecial; /* 1 for special persistence, 0 for literal */
one_of {
Object c; /* if isspecial == 1; closure to recreate the udata */
LiteralUserdata lu; /* if is_special is 0 */
};
};
struct LiteralUserdata {
size_t length; /* Size of the data */
char data[length]; /* The actual data */
Object metatable; /* The metatable (nil for none, otherwise LUA_TTABLE) */
};
struct Closure {
uint8_t isCClosure; /* 1 if the closure is a C closure; 0 otherwise */
uint8_t nups; /* Number of upvalues the function uses */
one_of {
CClosure ccl; /* if isCClosure == 1 */
LClosure lcl; /* if isCClosure == 0; it's a Lua closure */
};
};
struct CClosure {
Object f; /* The actual C function. Must be available via the
* permanents table on persist and unpersist. */
Object upvals[Closure.nups]; /* All upvalues */
/* Note that here the upvalues are the actual objects, i.e. these are not
* of type LUA_TUPVAL, since C closures' upalues are always closed. */
};
struct LClosure {
Object proto; /* The proto this function uses */
Object upvals[Closure.nups]; /* All upvalues */
};
struct UpVal {
Object obj; /* The object this upval refers to; we proxy it with
* the LUA_TUPVAL type to keep shared upvalues intact */
}
struct Proto {
int linedefined; /* Start of line range */
int lastlinedefined; /* End of line range */
uint8_t numparams; /* Number of parameters taken */
uint8_t is_vararg; /* 1 if function accepts varargs, 0 otherwise */
uint8_t maxstacksize; /* Size of stack reserved for the function */
int sizecode; /* Number of instructions in code */
Instruction code[sizecode]; /* The proto's code */
int sizek; /* Number of constants referenced */
Object k[sizek]; /* Constants referenced */
int sizep; /* Number of inner Protos referenced */
Object p[sizep]; /* Inner Protos referenced */
int sizeupvalues; /* Number of upvalues used */
Upvaldesc upvalues[sizeupvalues]; /* The locations of the upvalues */
uint8_t debug; /* 1 if debug data is present; 0 otherwise */
if (debug) {
Object source; /* The source code string */
int sizelineinfo; /* Number of opcode-line mappings */
int lineinfo[sizelineinfo]; /* opcode-line mappings */
int sizelocvars; /* Number of local variable names */
LocVar[sizelocvars]; /* Local variable names */
Object upvalnames[sizeupvalues]; /* Upvalue names */
}
};
struct Upvaldesc {
uint8_t instack; /* whether it is in stack */
uint8_t idx; /* index of upvalue (in stack or in outer function's list) */
};
struct LocVar {
int startpc; /* Point where variable is active */
int endpc; /* Point where variable is dead */
Object name; /* Name of the local variable */
};
struct Thread {
int stacksize; /* The overall size of the stack filled with objects,
* including all stack frames. */
size_t top; /* top = L->top - L->stack; */
Object stack[stacksize]; /* All stack values, bottom up */
uint8_t status; /* current thread status (ok, yield) */
size_t errfunc; /* current error handling function (stack index) */
CallInfo ci[]; /* The CallInfo stack, starting with base_ci */
if (status == LUA_YIELD) {
size_t extra; /* value of thread->ci->extra, which is the original
* value of thread->ci->func */
}
OpenUpval openupvals[]; /* Upvalues to open */
};
struct CallInfo {
size_t func; /* func = ci->func - thread->stack */
size_t top; /* top = ci->top - thread->stack */
int16_t nresults; /* expected number of results from this function */
uint8_t callstatus;
if (callstatus & CIST_YPCALL) {
size_t extra; /* the stack level of the function being pcalled */
}
if (callstatus & CIST_LUA) {
size_t base; /* base = ci->u.l.base - thread-stack */
size_t savedpc; /* savedpc = ci->u.l.savedpc - ci_func(ci)->p->code */
}
else {
uint8_t status;
if (callstatus & (CIST_YPCALL | CIST_YIELDED)) {
int ctx; /* context info. in case of yields */
Object k; /* C function, callback for resuming */
}
}
uint8_t hasNext; /* 1 if there's another CI to read; 0 otherwise */
};
struct OpenUpval {
size_t idx; /* stack index of the value + 1; 0 if end of list */
Object upval; /* The upvalue */
};
struct PermKey {
uint8_t type; /* The actual LUA_TXXX of the original value. */
Object key; /* The value to use as a key when unpersisting. */
/* Note that we store the type of the original value (replaced by the
* permanent table value used as a key when unpersisting) to ensure the
* value in the permanents table when unpersisting has the correct type. */
};