-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathFILEFORMAT
239 lines (204 loc) · 9.01 KB
/
FILEFORMAT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/*
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. */
};