├── .gitignore ├── LICENSE ├── README.md ├── bugs ├── lapi.c ├── lapi.h ├── lauxlib.c ├── lauxlib.h ├── lbaselib.c ├── lbitlib.c ├── lcode.c ├── lcode.h ├── lcorolib.c ├── lctype.c ├── lctype.h ├── ldblib.c ├── ldebug.c ├── ldebug.h ├── ldo.c ├── ldo.h ├── ldump.c ├── lfunc.c ├── lfunc.h ├── lgc.c ├── lgc.h ├── linit.c ├── liolib.c ├── ljumptab.h ├── llex.c ├── llex.h ├── llimits.h ├── lmathlib.c ├── lmem.c ├── lmem.h ├── loadlib.c ├── lobject.c ├── lobject.h ├── lopcodes.c ├── lopcodes.h ├── loslib.c ├── lparser.c ├── lparser.h ├── lprefix.h ├── lstate.c ├── lstate.h ├── lstring.c ├── lstring.h ├── lstrlib.c ├── ltable.c ├── ltable.h ├── ltablib.c ├── ltests.c ├── ltests.h ├── ltm.c ├── ltm.h ├── lua.c ├── lua.h ├── luaconf.h ├── lualib.h ├── lundump.c ├── lundump.h ├── lutf8lib.c ├── lvm.c ├── lvm.h ├── lzio.c ├── lzio.h ├── makefile ├── tests ├── benchmark1.lua ├── benchmark_results.txt └── test.lua └── todo.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | lua 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 1994–2021 Lua.org, PUC-Rio. 2 | 3 | lua-array modifications 4 | Copyright © 2018-2021 Petri Häkkinen 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a experimental patch for Lua 5.4-work1 that adds first class support for arrays. The goal of the patch is to not be a production ready solution -- there are surely several bugs with the implementation. For example, the Lua C API and metatables have not been tested at all. It should be merely treated as a proof of concept that could be used to evaluate the general feasibility of arrays in Lua. 2 | 3 | Arrays are implemented as a subtype of tables. In fact, the implementation reuses the table data structures inside Lua VM. Internally an array is a table with only integer keys starting at index 1 and all key-values are stored in the array part of the table data structure. 4 | 5 | An array does not suffer from the problem with holes, a well known issue with Lua tables and the '#' length operator, because an array always has an explicit size. Insertions to an array potentially enlarges the array, so that if a new key is outside the bounds of the array, the array is resized to fit the new element. To shrink an array, the code has to be explicit about it by using the table.resize() or table.remove() functions. An array can be considered to be a dense table (as opposed to sparse regular Lua tables). 6 | 7 | Elements of an array are always stored sequentially in memory, so value retrieval and setting happen in constant time, provided that the array access is within the bounds of the array. The '#' length operator for arrays is O(1). Together these have positive performance implications compared to regular tables. 8 | 9 | The implementation has been carefully designed to not negatively affect the performance of regular Lua tables (see benchmarks and implementation notes at the end). 10 | 11 | ~~~~ 12 | -- arrays are constructed using [...] syntax 13 | local a = [1, 2, 3, [4, 5]] 14 | 15 | -- an array can contain nils without problems 16 | local a = [1, nil, 2, 3, nil] 17 | print(#a) --> 5 18 | 19 | -- caveat: array indices can only be positive (non-zero) integers 20 | local a = [] 21 | a[-1] = 1 --> error: invalid array index 22 | a.foo = 1 --> error: invalid array index 23 | 24 | -- caveat: array are dense by nature and array constructors don't support named or sparse elements 25 | -- use tables if you need them 26 | local a = [1, [3] = true] --> syntax error 27 | local a = [1, b = true] --> syntax error 28 | 29 | -- arrays grow to fit new keys automatically 30 | local a = [] 31 | a[10] = true 32 | print(#a) --> 10 33 | 34 | -- table.insert() works on arrays as well as regular tables 35 | local a = [1, 2] 36 | table.insert(a, 3) --> a = [1, 2, 3] 37 | 38 | -- setting a value to nil never resizes an array 39 | local a = [1,2,3] 40 | print(#a) --> 3 41 | a[3] = nil 42 | print(#a) --> 3 43 | 44 | -- table.resize() can be used to explicitly resize an array 45 | local a = [] 46 | table.resize(a, 10) 47 | print(#a) --> 10 48 | 49 | -- table.remove() also resizes the array 50 | local a = [1, 2, 3] 51 | table.remove(a, 1) --> a = [2, 3] 52 | 53 | -- table.pack() is not needed for a version of Lua with arrays, as nils 54 | -- can be stored naturally in an array 55 | local a = table.pack(1, 2, 3) -- not needed 56 | local a = [1, nil, 3] -- use this instead 57 | 58 | -- table.unpack() works with arrays as you'd expect 59 | table.unpack([1, nil, 3]) --> 1, nil, 3 60 | 61 | -- there is no difference between pairs() and ipairs(); both iterate all integer keys of an array in numeric order 62 | for i,v in ipairs([1,nil,3,nil]) do print(i, v) end 63 | --> (1 1) (2 nil) (3 3) (4 nil) 64 | 65 | -- syntactic sugar for function call syntax f{...} -> f({...}) does not have 66 | -- an equivalent for arrays because the grammar would be ambiguous 67 | local a = fun[1] -- indexing table 'fun' 68 | local a = fun([1]) -- call function 'fun' with array as an argument 69 | ~~~~ 70 | 71 | # Benchmarks 72 | 73 | A number of benchmarks stressing table and array operations were run on unmodified and patched version of Lua 5.4. The benchmarks were repeated 4 times and the best result was chosen in each case out of these 4 runs. See the following table. In the "Unmodified Tables" column are the results for unmodified Lua 5.4-work1. The "Patched Tables" column shows the results of the benchmarks for patched Lua but still using regular tables. The "Patches Arrays" column shows the results for the benchmarks when using arrays. 74 | 75 | The benchmarks show that there is no noticeable performance difference between the unmodified and patched version of Lua when using tables. The small differences in execution times vary from run to run because of varying system load, base address randomization of the Lua executable and other factors. The first two columns show that the addition of an array subtype for tables does not negatively impact the performance of regular tables. When using arrays, "Push" and "Length" benchmarks show significant performance increases, and "Insert", "Scatter-Write" and "Scatter-read" are also clearly faster. The major performance increase of "Push" and "Length" is mainly due to the O(1) implementation of the '#' operator. 76 | 77 | ~~~~ 78 | Benchmark Unmodified Patched Patched 79 | Tables Tables Arrays 80 | 81 | Insert 0.352s 0.359s 0.319s 82 | Write 0.470s 0.478s 0.456s 83 | Read 0.429s 0.423s 0.420s 84 | Push 2.268s 2.323s 0.419s 85 | Scatter-write 0.217s 0.203s 0.180s 86 | Scatter-read 0.200s 0.208s 0.170s 87 | Length 1.999s 1.969s 0.124s 88 | ~~~~ 89 | 90 | ## About the benchmarks 91 | 92 | The benchmarks were run on macOS 10.13.3 with a Intel Core i7 CPU running at 2.3 GHz and with 8 GB 1600 MHz DDR3 RAM. For benchmarking Lua API checks were disabled and the code was compiled with the same version of the C compiler using the same options (-O2). If you want to repeat the benchmarks, the unmodified Lua sources can be found in this repository in the "unmodified" branch. 93 | 94 | Insert: Starting with an empty table, this does a large number of table/array insertions to sequential indices. The point of this benchmark is to test the efficiency of growing the table/array data structure. 95 | 96 | Write/read: These benchmarks stress setting and getting existing indices of a table/array. 97 | 98 | Push: Does a large number of inserts using the "t[#t+1] = value" Lua idiom. 99 | 100 | Scatter-write/scatter-read: Does a large number of random accesses to a table/array. 101 | 102 | Length: Tests the performance of the '#' operator. 103 | 104 | The code for benchmarks can be found in tests/benchmark1.lua. 105 | 106 | # Summary and conclusions 107 | 108 | The main contributions of this work are: 109 | * The addition of a new high performance array subtype for tables, which does not negatively affect the performance of regular tables (within measurement precision). 110 | * The arrays don't suffer from the issue with holes (also see Opinions below how the hole issue can be resolved in the future for regular tables). 111 | * Implementation of '#' operator for arrays in constant time (O(1)). 112 | * "[...]" syntax for arrays. 113 | * Arrays have been implemented in a way that is fully backwards compatible, meaning that old Lua programs can be run without modification with the patched Lua interpreter. 114 | 115 | The work shows that Lua could benefit from an array subtype for tables. 116 | 117 | # Opinions 118 | 119 | From a purely theoretical point of view, the inclusion of a new subtype adds some weight to the language, but from a more pragmatic view, the increased performance and fixing the hole issue overweights the theoretical issue. Moving forward, if arrays would be adopted to mainstream Lua, the '#' operator could be deprecated for tables and eventually made an array only feature. Of course, the '#' could still be implemented using a metatable for tables if needed. This would be the final nail in coffin for the hole issue. 120 | 121 | With the addition of arrays another small wart in the language, the 'n' field of the table returned by table.pack(), could be eliminated by changing table.pack() to return an array. Since the array has a well defined length, the 'n' field would not be required. This would however break backwards compatibility, so this could be an opt-in feature at first. 122 | 123 | In addition to the other benefits, in my opinion the inclusion of an array type would clarify the intent of Lua code, because the code explicitly uses the "[..]" syntax when creating an array. 124 | 125 | # Implementation details 126 | 127 | The implementation adds two new fields to the Table structure: "truearray" and "sizeused". "Truearray" is a 8-bit boolean field that does not increase the memory consumption of Table struct, because of C struct packing and alignment rules. "Sizeused" is used to track the used size of the array as reported by '#', and it adds 4 or 8 bytes (depending whether Lua is compiled as a 32 or 64-bit application) to the size of the struct, but this does not seem to affect the CPU cache hit ratio or slow down the interpreter. 128 | 129 | The implementation has been carefully designed to not increase the size of the main VM loop, which could negatively affect performance. Particularly no new opcodes have been added to the VM. Incrementing "sizeused" when setting array elements is implemented without branching and CPU cache usage has also been taken into account. 130 | -------------------------------------------------------------------------------- /lapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lapi.h,v 2.10 2017/11/01 18:20:48 roberto Exp $ 3 | ** Auxiliary functions from Lua API 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lapi_h 8 | #define lapi_h 9 | 10 | 11 | #include "llimits.h" 12 | #include "lstate.h" 13 | 14 | #define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ 15 | "stack overflow");} 16 | 17 | #define adjustresults(L,nres) \ 18 | { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } 19 | 20 | #define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ 21 | "not enough elements in the stack") 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /lauxlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lauxlib.h,v 1.133 2017/06/27 18:32:49 roberto Exp roberto $ 3 | ** Auxiliary functions for building Lua libraries 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lauxlib_h 9 | #define lauxlib_h 10 | 11 | 12 | #include 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | 18 | /* global table */ 19 | #define LUA_GNAME "_G" 20 | 21 | 22 | 23 | /* extra error code for 'luaL_loadfilex' */ 24 | #define LUA_ERRFILE (LUA_ERRERR+1) 25 | 26 | 27 | /* key, in the registry, for table of loaded modules */ 28 | #define LUA_LOADED_TABLE "_LOADED" 29 | 30 | 31 | /* key, in the registry, for table of preloaded loaders */ 32 | #define LUA_PRELOAD_TABLE "_PRELOAD" 33 | 34 | 35 | typedef struct luaL_Reg { 36 | const char *name; 37 | lua_CFunction func; 38 | } luaL_Reg; 39 | 40 | 41 | #define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) 42 | 43 | LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); 44 | #define luaL_checkversion(L) \ 45 | luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) 46 | 47 | LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); 48 | LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); 49 | LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); 50 | LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); 51 | LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, 52 | size_t *l); 53 | LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, 54 | const char *def, size_t *l); 55 | LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); 56 | LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); 57 | 58 | LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); 59 | LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, 60 | lua_Integer def); 61 | 62 | LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); 63 | LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); 64 | LUALIB_API void (luaL_checkany) (lua_State *L, int arg); 65 | 66 | LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); 67 | LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); 68 | LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); 69 | LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); 70 | 71 | LUALIB_API void (luaL_where) (lua_State *L, int lvl); 72 | LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); 73 | 74 | LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, 75 | const char *const lst[]); 76 | 77 | LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); 78 | LUALIB_API int (luaL_execresult) (lua_State *L, int stat); 79 | 80 | /* predefined references */ 81 | #define LUA_NOREF (-2) 82 | #define LUA_REFNIL (-1) 83 | 84 | LUALIB_API int (luaL_ref) (lua_State *L, int t); 85 | LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); 86 | 87 | LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, 88 | const char *mode); 89 | 90 | #define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) 91 | 92 | LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, 93 | const char *name, const char *mode); 94 | LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); 95 | 96 | LUALIB_API lua_State *(luaL_newstate) (void); 97 | 98 | LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); 99 | 100 | LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, 101 | const char *r); 102 | 103 | LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); 104 | 105 | LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); 106 | 107 | LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, 108 | const char *msg, int level); 109 | 110 | LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, 111 | lua_CFunction openf, int glb); 112 | 113 | /* 114 | ** =============================================================== 115 | ** some useful macros 116 | ** =============================================================== 117 | */ 118 | 119 | 120 | #define luaL_newlibtable(L,l) \ 121 | lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) 122 | 123 | #define luaL_newlib(L,l) \ 124 | (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) 125 | 126 | #define luaL_argcheck(L, cond,arg,extramsg) \ 127 | ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) 128 | #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) 129 | #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) 130 | 131 | #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) 132 | 133 | #define luaL_dofile(L, fn) \ 134 | (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) 135 | 136 | #define luaL_dostring(L, s) \ 137 | (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) 138 | 139 | #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) 140 | 141 | #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) 142 | 143 | #define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) 144 | 145 | 146 | /* 147 | ** {====================================================== 148 | ** Generic Buffer manipulation 149 | ** ======================================================= 150 | */ 151 | 152 | typedef struct luaL_Buffer { 153 | char *b; /* buffer address */ 154 | size_t size; /* buffer size */ 155 | size_t n; /* number of characters in buffer */ 156 | lua_State *L; 157 | union { 158 | LUAI_MAXALIGN; /* ensure maximum alignment for buffer */ 159 | char b[LUAL_BUFFERSIZE]; /* initial buffer */ 160 | } init; 161 | } luaL_Buffer; 162 | 163 | 164 | #define luaL_addchar(B,c) \ 165 | ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ 166 | ((B)->b[(B)->n++] = (c))) 167 | 168 | #define luaL_addsize(B,s) ((B)->n += (s)) 169 | 170 | LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); 171 | LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); 172 | LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); 173 | LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); 174 | LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); 175 | LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); 176 | LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); 177 | LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); 178 | 179 | #define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) 180 | 181 | /* }====================================================== */ 182 | 183 | 184 | 185 | /* 186 | ** {====================================================== 187 | ** File handles for IO library 188 | ** ======================================================= 189 | */ 190 | 191 | /* 192 | ** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and 193 | ** initial structure 'luaL_Stream' (it may contain other fields 194 | ** after that initial structure). 195 | */ 196 | 197 | #define LUA_FILEHANDLE "FILE*" 198 | 199 | 200 | typedef struct luaL_Stream { 201 | FILE *f; /* stream (NULL for incompletely created streams) */ 202 | lua_CFunction closef; /* to close stream (NULL for closed streams) */ 203 | } luaL_Stream; 204 | 205 | /* }====================================================== */ 206 | 207 | /* 208 | ** {================================================================== 209 | ** "Abstraction Layer" for basic report of messages and errors 210 | ** =================================================================== 211 | */ 212 | 213 | /* print a string */ 214 | #if !defined(lua_writestring) 215 | #define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) 216 | #endif 217 | 218 | /* print a newline and flush the output */ 219 | #if !defined(lua_writeline) 220 | #define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) 221 | #endif 222 | 223 | /* print an error message */ 224 | #if !defined(lua_writestringerror) 225 | #define lua_writestringerror(s,p) \ 226 | (fprintf(stderr, (s), (p)), fflush(stderr)) 227 | #endif 228 | 229 | /* }================================================================== */ 230 | 231 | 232 | /* 233 | ** {============================================================ 234 | ** Compatibility with deprecated conversions 235 | ** ============================================================= 236 | */ 237 | #if defined(LUA_COMPAT_APIINTCASTS) 238 | 239 | #define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) 240 | #define luaL_optunsigned(L,a,d) \ 241 | ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) 242 | 243 | #define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) 244 | #define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) 245 | 246 | #define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) 247 | #define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) 248 | 249 | #endif 250 | /* }============================================================ */ 251 | 252 | 253 | 254 | #endif 255 | 256 | 257 | -------------------------------------------------------------------------------- /lbitlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lbitlib.c,v 1.31 2017/11/16 13:19:06 roberto Exp roberto $ 3 | ** Standard library for bitwise operations 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | Deprecated module. 8 | -------------------------------------------------------------------------------- /lcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lcode.h,v 1.70 2017/12/18 15:44:44 roberto Exp roberto $ 3 | ** Code generator for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lcode_h 8 | #define lcode_h 9 | 10 | #include "llex.h" 11 | #include "lobject.h" 12 | #include "lopcodes.h" 13 | #include "lparser.h" 14 | 15 | 16 | /* 17 | ** Marks the end of a patch list. It is an invalid value both as an absolute 18 | ** address, and as a list link (would link an element to itself). 19 | */ 20 | #define NO_JUMP (-1) 21 | 22 | 23 | /* 24 | ** grep "ORDER OPR" if you change these enums (ORDER OP) 25 | */ 26 | typedef enum BinOpr { 27 | OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, 28 | OPR_DIV, 29 | OPR_IDIV, 30 | OPR_BAND, OPR_BOR, OPR_BXOR, 31 | OPR_SHL, OPR_SHR, 32 | OPR_CONCAT, 33 | OPR_EQ, OPR_LT, OPR_LE, 34 | OPR_NE, OPR_GT, OPR_GE, 35 | OPR_AND, OPR_OR, 36 | OPR_NOBINOPR 37 | } BinOpr; 38 | 39 | 40 | #define luaK_codeABC(fs,o,a,b,c) luaK_codeABCk(fs,o,a,b,c,0) 41 | 42 | 43 | typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; 44 | 45 | 46 | /* get (pointer to) instruction of given 'expdesc' */ 47 | #define getinstruction(fs,e) ((fs)->f->code[(e)->u.info]) 48 | 49 | 50 | #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) 51 | 52 | #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) 53 | 54 | LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); 55 | LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); 56 | LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, 57 | int B, int C, int k); 58 | LUAI_FUNC int luaK_isKint (expdesc *e); 59 | LUAI_FUNC void luaK_fixline (FuncState *fs, int line); 60 | LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); 61 | LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); 62 | LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); 63 | LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); 64 | LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n); 65 | LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); 66 | LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); 67 | LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); 68 | LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); 69 | LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); 70 | LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); 71 | LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); 72 | LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); 73 | LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); 74 | LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); 75 | LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); 76 | LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); 77 | LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); 78 | LUAI_FUNC int luaK_jump (FuncState *fs); 79 | LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); 80 | LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); 81 | void luaK_patchgoto (FuncState *fs, int list, int target, int hasclose); 82 | LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); 83 | LUAI_FUNC void luaK_patchclose (FuncState *fs, int list); 84 | LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); 85 | LUAI_FUNC int luaK_getlabel (FuncState *fs); 86 | LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); 87 | LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); 88 | LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, 89 | expdesc *v2, int line); 90 | LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); 91 | LUAI_FUNC void luaK_finish (FuncState *fs); 92 | LUAI_FUNC void luaK_codeundef (FuncState *fs, expdesc *e); 93 | LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg); 94 | 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /lcorolib.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp roberto $ 3 | ** Coroutine Library 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lcorolib_c 8 | #define LUA_LIB 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "lauxlib.h" 18 | #include "lualib.h" 19 | 20 | 21 | static lua_State *getco (lua_State *L) { 22 | lua_State *co = lua_tothread(L, 1); 23 | luaL_argcheck(L, co, 1, "thread expected"); 24 | return co; 25 | } 26 | 27 | 28 | static int auxresume (lua_State *L, lua_State *co, int narg) { 29 | int status, nres; 30 | if (!lua_checkstack(co, narg)) { 31 | lua_pushliteral(L, "too many arguments to resume"); 32 | return -1; /* error flag */ 33 | } 34 | if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { 35 | lua_pushliteral(L, "cannot resume dead coroutine"); 36 | return -1; /* error flag */ 37 | } 38 | lua_xmove(L, co, narg); 39 | status = lua_resume(co, L, narg, &nres); 40 | if (status == LUA_OK || status == LUA_YIELD) { 41 | if (!lua_checkstack(L, nres + 1)) { 42 | lua_pop(co, nres); /* remove results anyway */ 43 | lua_pushliteral(L, "too many results to resume"); 44 | return -1; /* error flag */ 45 | } 46 | lua_xmove(co, L, nres); /* move yielded values */ 47 | return nres; 48 | } 49 | else { 50 | lua_xmove(co, L, 1); /* move error message */ 51 | return -1; /* error flag */ 52 | } 53 | } 54 | 55 | 56 | static int luaB_coresume (lua_State *L) { 57 | lua_State *co = getco(L); 58 | int r; 59 | r = auxresume(L, co, lua_gettop(L) - 1); 60 | if (r < 0) { 61 | lua_pushboolean(L, 0); 62 | lua_insert(L, -2); 63 | return 2; /* return false + error message */ 64 | } 65 | else { 66 | lua_pushboolean(L, 1); 67 | lua_insert(L, -(r + 1)); 68 | return r + 1; /* return true + 'resume' returns */ 69 | } 70 | } 71 | 72 | 73 | static int luaB_auxwrap (lua_State *L) { 74 | lua_State *co = lua_tothread(L, lua_upvalueindex(1)); 75 | int r = auxresume(L, co, lua_gettop(L)); 76 | if (r < 0) { 77 | if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */ 78 | luaL_where(L, 1); /* add extra info */ 79 | lua_insert(L, -2); 80 | lua_concat(L, 2); 81 | } 82 | return lua_error(L); /* propagate error */ 83 | } 84 | return r; 85 | } 86 | 87 | 88 | static int luaB_cocreate (lua_State *L) { 89 | lua_State *NL; 90 | luaL_checktype(L, 1, LUA_TFUNCTION); 91 | NL = lua_newthread(L); 92 | lua_pushvalue(L, 1); /* move function to top */ 93 | lua_xmove(L, NL, 1); /* move function from L to NL */ 94 | return 1; 95 | } 96 | 97 | 98 | static int luaB_cowrap (lua_State *L) { 99 | luaB_cocreate(L); 100 | lua_pushcclosure(L, luaB_auxwrap, 1); 101 | return 1; 102 | } 103 | 104 | 105 | static int luaB_yield (lua_State *L) { 106 | return lua_yield(L, lua_gettop(L)); 107 | } 108 | 109 | 110 | static int luaB_costatus (lua_State *L) { 111 | lua_State *co = getco(L); 112 | if (L == co) lua_pushliteral(L, "running"); 113 | else { 114 | switch (lua_status(co)) { 115 | case LUA_YIELD: 116 | lua_pushliteral(L, "suspended"); 117 | break; 118 | case LUA_OK: { 119 | lua_Debug ar; 120 | if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ 121 | lua_pushliteral(L, "normal"); /* it is running */ 122 | else if (lua_gettop(co) == 0) 123 | lua_pushliteral(L, "dead"); 124 | else 125 | lua_pushliteral(L, "suspended"); /* initial state */ 126 | break; 127 | } 128 | default: /* some error occurred */ 129 | lua_pushliteral(L, "dead"); 130 | break; 131 | } 132 | } 133 | return 1; 134 | } 135 | 136 | 137 | static int luaB_yieldable (lua_State *L) { 138 | lua_pushboolean(L, lua_isyieldable(L)); 139 | return 1; 140 | } 141 | 142 | 143 | static int luaB_corunning (lua_State *L) { 144 | int ismain = lua_pushthread(L); 145 | lua_pushboolean(L, ismain); 146 | return 2; 147 | } 148 | 149 | 150 | static const luaL_Reg co_funcs[] = { 151 | {"create", luaB_cocreate}, 152 | {"resume", luaB_coresume}, 153 | {"running", luaB_corunning}, 154 | {"status", luaB_costatus}, 155 | {"wrap", luaB_cowrap}, 156 | {"yield", luaB_yield}, 157 | {"isyieldable", luaB_yieldable}, 158 | {NULL, NULL} 159 | }; 160 | 161 | 162 | 163 | LUAMOD_API int luaopen_coroutine (lua_State *L) { 164 | luaL_newlib(L, co_funcs); 165 | return 1; 166 | } 167 | 168 | -------------------------------------------------------------------------------- /lctype.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lctype.c,v 1.11 2011/10/03 16:19:23 roberto Exp roberto $ 3 | ** 'ctype' functions for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lctype_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include "lctype.h" 14 | 15 | #if !LUA_USE_CTYPE /* { */ 16 | 17 | #include 18 | 19 | LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { 20 | 0x00, /* EOZ */ 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ 22 | 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 25 | 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ 26 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 27 | 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ 28 | 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 29 | 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ 30 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 31 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ 32 | 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, 33 | 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ 34 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 35 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ 36 | 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | }; 54 | 55 | #endif /* } */ 56 | -------------------------------------------------------------------------------- /lctype.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lctype.h,v 1.11 2011/06/27 18:22:46 roberto Exp roberto $ 3 | ** 'ctype' functions for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lctype_h 8 | #define lctype_h 9 | 10 | #include "lua.h" 11 | 12 | 13 | /* 14 | ** WARNING: the functions defined here do not necessarily correspond 15 | ** to the similar functions in the standard C ctype.h. They are 16 | ** optimized for the specific needs of Lua 17 | */ 18 | 19 | #if !defined(LUA_USE_CTYPE) 20 | 21 | #if 'A' == 65 && '0' == 48 22 | /* ASCII case: can use its own tables; faster and fixed */ 23 | #define LUA_USE_CTYPE 0 24 | #else 25 | /* must use standard C ctype */ 26 | #define LUA_USE_CTYPE 1 27 | #endif 28 | 29 | #endif 30 | 31 | 32 | #if !LUA_USE_CTYPE /* { */ 33 | 34 | #include 35 | 36 | #include "llimits.h" 37 | 38 | 39 | #define ALPHABIT 0 40 | #define DIGITBIT 1 41 | #define PRINTBIT 2 42 | #define SPACEBIT 3 43 | #define XDIGITBIT 4 44 | 45 | 46 | #define MASK(B) (1 << (B)) 47 | 48 | 49 | /* 50 | ** add 1 to char to allow index -1 (EOZ) 51 | */ 52 | #define testprop(c,p) (luai_ctype_[(c)+1] & (p)) 53 | 54 | /* 55 | ** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' 56 | */ 57 | #define lislalpha(c) testprop(c, MASK(ALPHABIT)) 58 | #define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) 59 | #define lisdigit(c) testprop(c, MASK(DIGITBIT)) 60 | #define lisspace(c) testprop(c, MASK(SPACEBIT)) 61 | #define lisprint(c) testprop(c, MASK(PRINTBIT)) 62 | #define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) 63 | 64 | /* 65 | ** this 'ltolower' only works for alphabetic characters 66 | */ 67 | #define ltolower(c) ((c) | ('A' ^ 'a')) 68 | 69 | 70 | /* two more entries for 0 and -1 (EOZ) */ 71 | LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; 72 | 73 | 74 | #else /* }{ */ 75 | 76 | /* 77 | ** use standard C ctypes 78 | */ 79 | 80 | #include 81 | 82 | 83 | #define lislalpha(c) (isalpha(c) || (c) == '_') 84 | #define lislalnum(c) (isalnum(c) || (c) == '_') 85 | #define lisdigit(c) (isdigit(c)) 86 | #define lisspace(c) (isspace(c)) 87 | #define lisprint(c) (isprint(c)) 88 | #define lisxdigit(c) (isxdigit(c)) 89 | 90 | #define ltolower(c) (tolower(c)) 91 | 92 | #endif /* } */ 93 | 94 | #endif 95 | 96 | -------------------------------------------------------------------------------- /ldebug.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldebug.h,v 2.15 2017/06/27 11:35:31 roberto Exp roberto $ 3 | ** Auxiliary functions from Debug Interface module 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ldebug_h 8 | #define ldebug_h 9 | 10 | 11 | #include "lstate.h" 12 | 13 | 14 | #define pcRel(pc, p) (cast_int((pc) - (p)->code) - 1) 15 | 16 | #define resethookcount(L) (L->hookcount = L->basehookcount) 17 | 18 | /* 19 | ** mark for entries in 'lineinfo' array that has absolute information in 20 | ** 'abslineinfo' array 21 | */ 22 | #define ABSLINEINFO (-0x80) 23 | 24 | LUAI_FUNC int luaG_getfuncline (Proto *f, int pc); 25 | LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, 26 | const char *opname); 27 | LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, 28 | const TValue *p2); 29 | LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, 30 | const TValue *p2, 31 | const char *msg); 32 | LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, 33 | const TValue *p2); 34 | LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, 35 | const TValue *p2); 36 | LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); 37 | LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, 38 | TString *src, int line); 39 | LUAI_FUNC l_noret luaG_errormsg (lua_State *L); 40 | LUAI_FUNC void luaG_traceexec (lua_State *L); 41 | 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /ldo.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldo.h,v 2.42 2018/02/15 15:34:29 roberto Exp roberto $ 3 | ** Stack and Call structure of Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ldo_h 8 | #define ldo_h 9 | 10 | 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | #include "lzio.h" 14 | 15 | 16 | /* 17 | ** Macro to check stack size and grow stack if needed. Parameters 18 | ** 'pre'/'pos' allow the macro to preserve a pointer into the 19 | ** stack across reallocations, doing the work only when needed. 20 | ** 'condmovestack' is used in heavy tests to force a stack reallocation 21 | ** at every check. 22 | */ 23 | #define luaD_checkstackaux(L,n,pre,pos) \ 24 | if (L->stack_last - L->top <= (n)) \ 25 | { pre; luaD_growstack(L, n, 1); pos; } \ 26 | else { condmovestack(L,pre,pos); } 27 | 28 | /* In general, 'pre'/'pos' are empty (nothing to save) */ 29 | #define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) 30 | 31 | 32 | 33 | #define savestack(L,p) ((char *)(p) - (char *)L->stack) 34 | #define restorestack(L,n) ((StkId)((char *)L->stack + (n))) 35 | 36 | 37 | /* macro to check stack size, preserving 'p' */ 38 | #define checkstackp(L,n,p) \ 39 | luaD_checkstackaux(L, n, \ 40 | ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ 41 | luaC_checkGC(L), /* stack grow uses memory */ \ 42 | p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ 43 | 44 | 45 | /* macro to check stack size and GC */ 46 | #define checkstackGC(L,fsize) \ 47 | luaD_checkstackaux(L, (fsize), (void)0, luaC_checkGC(L)) 48 | 49 | 50 | /* type of protected functions, to be ran by 'runprotected' */ 51 | typedef void (*Pfunc) (lua_State *L, void *ud); 52 | 53 | LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, 54 | const char *mode); 55 | LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, 56 | int fTransfer, int nTransfer); 57 | LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); 58 | LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); 59 | LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); 60 | LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); 61 | LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); 62 | LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, 63 | ptrdiff_t oldtop, ptrdiff_t ef); 64 | LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, 65 | int nres); 66 | LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror); 67 | LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror); 68 | LUAI_FUNC void luaD_shrinkstack (lua_State *L); 69 | LUAI_FUNC void luaD_inctop (lua_State *L); 70 | 71 | LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); 72 | LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); 73 | 74 | #endif 75 | 76 | -------------------------------------------------------------------------------- /ldump.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldump.c,v 2.40 2017/11/28 11:19:07 roberto Exp roberto $ 3 | ** save precompiled Lua chunks 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define ldump_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "lobject.h" 18 | #include "lstate.h" 19 | #include "lundump.h" 20 | 21 | 22 | typedef struct { 23 | lua_State *L; 24 | lua_Writer writer; 25 | void *data; 26 | int strip; 27 | int status; 28 | } DumpState; 29 | 30 | 31 | /* 32 | ** All high-level dumps go through DumpVector; you can change it to 33 | ** change the endianness of the result 34 | */ 35 | #define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) 36 | 37 | #define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) 38 | 39 | 40 | static void DumpBlock (const void *b, size_t size, DumpState *D) { 41 | if (D->status == 0 && size > 0) { 42 | lua_unlock(D->L); 43 | D->status = (*D->writer)(D->L, b, size, D->data); 44 | lua_lock(D->L); 45 | } 46 | } 47 | 48 | 49 | #define DumpVar(x,D) DumpVector(&x,1,D) 50 | 51 | 52 | static void DumpByte (int y, DumpState *D) { 53 | lu_byte x = (lu_byte)y; 54 | DumpVar(x, D); 55 | } 56 | 57 | 58 | /* DumpInt Buff Size */ 59 | #define DIBS ((sizeof(size_t) * 8 / 7) + 1) 60 | 61 | static void DumpSize (size_t x, DumpState *D) { 62 | lu_byte buff[DIBS]; 63 | int n = 0; 64 | do { 65 | buff[DIBS - (++n)] = x & 0x7f; /* fill buffer in reverse order */ 66 | x >>= 7; 67 | } while (x != 0); 68 | buff[DIBS - 1] |= 0x80; /* mark last byte */ 69 | DumpVector(buff + DIBS - n, n, D); 70 | } 71 | 72 | 73 | static void DumpInt (int x, DumpState *D) { 74 | DumpSize(x, D); 75 | } 76 | 77 | 78 | static void DumpNumber (lua_Number x, DumpState *D) { 79 | DumpVar(x, D); 80 | } 81 | 82 | 83 | static void DumpInteger (lua_Integer x, DumpState *D) { 84 | DumpVar(x, D); 85 | } 86 | 87 | 88 | static void DumpString (const TString *s, DumpState *D) { 89 | if (s == NULL) 90 | DumpSize(0, D); 91 | else { 92 | size_t size = tsslen(s); 93 | const char *str = getstr(s); 94 | DumpSize(size + 1, D); 95 | DumpVector(str, size, D); 96 | } 97 | } 98 | 99 | 100 | static void DumpCode (const Proto *f, DumpState *D) { 101 | DumpInt(f->sizecode, D); 102 | DumpVector(f->code, f->sizecode, D); 103 | } 104 | 105 | 106 | static void DumpFunction(const Proto *f, TString *psource, DumpState *D); 107 | 108 | static void DumpConstants (const Proto *f, DumpState *D) { 109 | int i; 110 | int n = f->sizek; 111 | DumpInt(n, D); 112 | for (i = 0; i < n; i++) { 113 | const TValue *o = &f->k[i]; 114 | DumpByte(ttypetag(o), D); 115 | switch (ttypetag(o)) { 116 | case LUA_TNIL: 117 | break; 118 | case LUA_TBOOLEAN: 119 | DumpByte(bvalue(o), D); 120 | break; 121 | case LUA_TNUMFLT: 122 | DumpNumber(fltvalue(o), D); 123 | break; 124 | case LUA_TNUMINT: 125 | DumpInteger(ivalue(o), D); 126 | break; 127 | case LUA_TSHRSTR: 128 | case LUA_TLNGSTR: 129 | DumpString(tsvalue(o), D); 130 | break; 131 | default: lua_assert(0); 132 | } 133 | } 134 | } 135 | 136 | 137 | static void DumpProtos (const Proto *f, DumpState *D) { 138 | int i; 139 | int n = f->sizep; 140 | DumpInt(n, D); 141 | for (i = 0; i < n; i++) 142 | DumpFunction(f->p[i], f->source, D); 143 | } 144 | 145 | 146 | static void DumpUpvalues (const Proto *f, DumpState *D) { 147 | int i, n = f->sizeupvalues; 148 | DumpInt(n, D); 149 | for (i = 0; i < n; i++) { 150 | DumpByte(f->upvalues[i].instack, D); 151 | DumpByte(f->upvalues[i].idx, D); 152 | } 153 | } 154 | 155 | 156 | static void DumpDebug (const Proto *f, DumpState *D) { 157 | int i, n; 158 | n = (D->strip) ? 0 : f->sizelineinfo; 159 | DumpInt(n, D); 160 | DumpVector(f->lineinfo, n, D); 161 | n = (D->strip) ? 0 : f->sizeabslineinfo; 162 | DumpInt(n, D); 163 | for (i = 0; i < n; i++) { 164 | DumpInt(f->abslineinfo[i].pc, D); 165 | DumpInt(f->abslineinfo[i].line, D); 166 | } 167 | n = (D->strip) ? 0 : f->sizelocvars; 168 | DumpInt(n, D); 169 | for (i = 0; i < n; i++) { 170 | DumpString(f->locvars[i].varname, D); 171 | DumpInt(f->locvars[i].startpc, D); 172 | DumpInt(f->locvars[i].endpc, D); 173 | } 174 | n = (D->strip) ? 0 : f->sizeupvalues; 175 | DumpInt(n, D); 176 | for (i = 0; i < n; i++) 177 | DumpString(f->upvalues[i].name, D); 178 | } 179 | 180 | 181 | static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { 182 | if (D->strip || f->source == psource) 183 | DumpString(NULL, D); /* no debug info or same source as its parent */ 184 | else 185 | DumpString(f->source, D); 186 | DumpInt(f->linedefined, D); 187 | DumpInt(f->lastlinedefined, D); 188 | DumpByte(f->numparams, D); 189 | DumpByte(f->is_vararg, D); 190 | DumpByte(f->maxstacksize, D); 191 | DumpCode(f, D); 192 | DumpConstants(f, D); 193 | DumpUpvalues(f, D); 194 | DumpProtos(f, D); 195 | DumpDebug(f, D); 196 | } 197 | 198 | 199 | static void DumpHeader (DumpState *D) { 200 | DumpLiteral(LUA_SIGNATURE, D); 201 | DumpByte(LUAC_VERSION, D); 202 | DumpByte(LUAC_FORMAT, D); 203 | DumpLiteral(LUAC_DATA, D); 204 | DumpByte(sizeof(int), D); 205 | DumpByte(sizeof(size_t), D); 206 | DumpByte(sizeof(Instruction), D); 207 | DumpByte(sizeof(lua_Integer), D); 208 | DumpByte(sizeof(lua_Number), D); 209 | DumpInteger(LUAC_INT, D); 210 | DumpNumber(LUAC_NUM, D); 211 | } 212 | 213 | 214 | /* 215 | ** dump Lua function as precompiled chunk 216 | */ 217 | int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, 218 | int strip) { 219 | DumpState D; 220 | D.L = L; 221 | D.writer = w; 222 | D.data = data; 223 | D.strip = strip; 224 | D.status = 0; 225 | DumpHeader(&D); 226 | DumpByte(f->sizeupvalues, &D); 227 | DumpFunction(f, NULL, &D); 228 | return D.status; 229 | } 230 | 231 | -------------------------------------------------------------------------------- /lfunc.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lfunc.c,v 2.50 2017/06/27 11:35:31 roberto Exp roberto $ 3 | ** Auxiliary functions to manipulate prototypes and closures 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lfunc_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "lfunc.h" 18 | #include "lgc.h" 19 | #include "lmem.h" 20 | #include "lobject.h" 21 | #include "lstate.h" 22 | 23 | 24 | 25 | CClosure *luaF_newCclosure (lua_State *L, int n) { 26 | GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); 27 | CClosure *c = gco2ccl(o); 28 | c->nupvalues = cast_byte(n); 29 | return c; 30 | } 31 | 32 | 33 | LClosure *luaF_newLclosure (lua_State *L, int n) { 34 | GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); 35 | LClosure *c = gco2lcl(o); 36 | c->p = NULL; 37 | c->nupvalues = cast_byte(n); 38 | while (n--) c->upvals[n] = NULL; 39 | return c; 40 | } 41 | 42 | /* 43 | ** fill a closure with new closed upvalues 44 | */ 45 | void luaF_initupvals (lua_State *L, LClosure *cl) { 46 | int i; 47 | for (i = 0; i < cl->nupvalues; i++) { 48 | GCObject *o = luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal)); 49 | UpVal *uv = gco2upv(o); 50 | uv->v = &uv->u.value; /* make it closed */ 51 | setnilvalue(uv->v); 52 | cl->upvals[i] = uv; 53 | luaC_objbarrier(L, cl, o); 54 | } 55 | } 56 | 57 | 58 | UpVal *luaF_findupval (lua_State *L, StkId level) { 59 | UpVal **pp = &L->openupval; 60 | GCObject *o; 61 | UpVal *p; 62 | UpVal *uv; 63 | lua_assert(isintwups(L) || L->openupval == NULL); 64 | while ((p = *pp) != NULL && uplevel(p) >= level) { 65 | if (uplevel(p) == level && !isdead(G(L), p)) /* corresponding upvalue? */ 66 | return p; /* return it */ 67 | pp = &p->u.open.next; 68 | } 69 | /* not found: create a new upvalue between 'pp' and 'p' */ 70 | o = luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal)); 71 | uv = gco2upv(o); 72 | uv->u.open.next = p; /* link it to list of open upvalues */ 73 | uv->u.open.previous = pp; 74 | if (p) 75 | p->u.open.previous = &uv->u.open.next; 76 | *pp = uv; 77 | uv->v = s2v(level); /* current value lives in the stack */ 78 | if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ 79 | L->twups = G(L)->twups; /* link it to the list */ 80 | G(L)->twups = L; 81 | } 82 | return uv; 83 | } 84 | 85 | 86 | void luaF_unlinkupval (UpVal *uv) { 87 | lua_assert(upisopen(uv)); 88 | *uv->u.open.previous = uv->u.open.next; 89 | if (uv->u.open.next) 90 | uv->u.open.next->u.open.previous = uv->u.open.previous; 91 | } 92 | 93 | 94 | void luaF_close (lua_State *L, StkId level) { 95 | UpVal *uv; 96 | while (L->openupval != NULL && 97 | (uv = L->openupval, uplevel(uv) >= level)) { 98 | TValue *slot = &uv->u.value; /* new position for value */ 99 | luaF_unlinkupval(uv); 100 | setobj(L, slot, uv->v); /* move value to upvalue slot */ 101 | uv->v = slot; /* now current value lives here */ 102 | if (!iswhite(uv)) 103 | gray2black(uv); /* closed upvalues cannot be gray */ 104 | luaC_barrier(L, uv, slot); 105 | } 106 | } 107 | 108 | 109 | Proto *luaF_newproto (lua_State *L) { 110 | GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); 111 | Proto *f = gco2p(o); 112 | f->k = NULL; 113 | f->sizek = 0; 114 | f->p = NULL; 115 | f->sizep = 0; 116 | f->code = NULL; 117 | f->cache = NULL; 118 | f->cachemiss = 0; 119 | f->sizecode = 0; 120 | f->lineinfo = NULL; 121 | f->sizelineinfo = 0; 122 | f->abslineinfo = NULL; 123 | f->sizeabslineinfo = 0; 124 | f->upvalues = NULL; 125 | f->sizeupvalues = 0; 126 | f->numparams = 0; 127 | f->is_vararg = 0; 128 | f->maxstacksize = 0; 129 | f->locvars = NULL; 130 | f->sizelocvars = 0; 131 | f->linedefined = 0; 132 | f->lastlinedefined = 0; 133 | f->source = NULL; 134 | return f; 135 | } 136 | 137 | 138 | void luaF_freeproto (lua_State *L, Proto *f) { 139 | luaM_freearray(L, f->code, f->sizecode); 140 | luaM_freearray(L, f->p, f->sizep); 141 | luaM_freearray(L, f->k, f->sizek); 142 | luaM_freearray(L, f->lineinfo, f->sizelineinfo); 143 | luaM_freearray(L, f->abslineinfo, f->sizeabslineinfo); 144 | luaM_freearray(L, f->locvars, f->sizelocvars); 145 | luaM_freearray(L, f->upvalues, f->sizeupvalues); 146 | luaM_free(L, f); 147 | } 148 | 149 | 150 | /* 151 | ** Look for n-th local variable at line 'line' in function 'func'. 152 | ** Returns NULL if not found. 153 | */ 154 | const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { 155 | int i; 156 | for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { 157 | if (pc < f->locvars[i].endpc) { /* is variable active? */ 158 | local_number--; 159 | if (local_number == 0) 160 | return getstr(f->locvars[i].varname); 161 | } 162 | } 163 | return NULL; /* not found */ 164 | } 165 | 166 | -------------------------------------------------------------------------------- /lfunc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lfunc.h,v 2.19 2018/01/28 15:13:26 roberto Exp roberto $ 3 | ** Auxiliary functions to manipulate prototypes and closures 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lfunc_h 8 | #define lfunc_h 9 | 10 | 11 | #include "lobject.h" 12 | 13 | 14 | #define sizeCclosure(n) (cast_int(offsetof(CClosure, upvalue)) + \ 15 | cast_int(sizeof(TValue)) * (n)) 16 | 17 | #define sizeLclosure(n) (cast_int(offsetof(LClosure, upvals)) + \ 18 | cast_int(sizeof(TValue *)) * (n)) 19 | 20 | 21 | /* test whether thread is in 'twups' list */ 22 | #define isintwups(L) (L->twups != L) 23 | 24 | 25 | /* 26 | ** maximum number of upvalues in a closure (both C and Lua). (Value 27 | ** must fit in a VM register.) 28 | */ 29 | #define MAXUPVAL 255 30 | 31 | 32 | #define upisopen(up) ((up)->v != &(up)->u.value) 33 | 34 | 35 | #define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v)) 36 | 37 | 38 | /* 39 | ** maximum number of misses before giving up the cache of closures 40 | ** in prototypes 41 | */ 42 | #define MAXMISS 10 43 | 44 | 45 | LUAI_FUNC Proto *luaF_newproto (lua_State *L); 46 | LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); 47 | LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); 48 | LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); 49 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); 50 | LUAI_FUNC void luaF_close (lua_State *L, StkId level); 51 | LUAI_FUNC void luaF_unlinkupval (UpVal *uv); 52 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); 53 | LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, 54 | int pc); 55 | 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /lgc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lgc.h,v 2.102 2018/02/19 13:55:34 roberto Exp roberto $ 3 | ** Garbage Collector 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lgc_h 8 | #define lgc_h 9 | 10 | 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | 14 | /* 15 | ** Collectable objects may have one of three colors: white, which 16 | ** means the object is not marked; gray, which means the 17 | ** object is marked, but its references may be not marked; and 18 | ** black, which means that the object and all its references are marked. 19 | ** The main invariant of the garbage collector, while marking objects, 20 | ** is that a black object can never point to a white one. Moreover, 21 | ** any gray object must be in a "gray list" (gray, grayagain, weak, 22 | ** allweak, ephemeron) so that it can be visited again before finishing 23 | ** the collection cycle. These lists have no meaning when the invariant 24 | ** is not being enforced (e.g., sweep phase). 25 | */ 26 | 27 | 28 | /* 29 | ** Possible states of the Garbage Collector 30 | */ 31 | #define GCSpropagate 0 32 | #define GCSenteratomic 1 33 | #define GCSatomic 2 34 | #define GCSswpallgc 3 35 | #define GCSswpfinobj 4 36 | #define GCSswptobefnz 5 37 | #define GCSswpend 6 38 | #define GCScallfin 7 39 | #define GCSpause 8 40 | 41 | 42 | #define issweepphase(g) \ 43 | (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) 44 | 45 | 46 | /* 47 | ** macro to tell when main invariant (white objects cannot point to black 48 | ** ones) must be kept. During a collection, the sweep 49 | ** phase may break the invariant, as objects turned white may point to 50 | ** still-black objects. The invariant is restored when sweep ends and 51 | ** all objects are white again. 52 | */ 53 | 54 | #define keepinvariant(g) ((g)->gcstate <= GCSatomic) 55 | 56 | 57 | /* 58 | ** some useful bit tricks 59 | */ 60 | #define resetbits(x,m) ((x) &= cast_byte(~(m))) 61 | #define setbits(x,m) ((x) |= (m)) 62 | #define testbits(x,m) ((x) & (m)) 63 | #define bitmask(b) (1<<(b)) 64 | #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) 65 | #define l_setbit(x,b) setbits(x, bitmask(b)) 66 | #define resetbit(x,b) resetbits(x, bitmask(b)) 67 | #define testbit(x,b) testbits(x, bitmask(b)) 68 | 69 | 70 | /* 71 | ** Layout for bit use in 'marked' field. First three bits are 72 | ** used for object "age" in generational mode. 73 | */ 74 | #define WHITE0BIT 3 /* object is white (type 0) */ 75 | #define WHITE1BIT 4 /* object is white (type 1) */ 76 | #define BLACKBIT 5 /* object is black */ 77 | #define FINALIZEDBIT 6 /* object has been marked for finalization */ 78 | #define TESTGRAYBIT 7 /* used by tests (luaL_checkmemory) */ 79 | 80 | 81 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) 82 | 83 | 84 | #define iswhite(x) testbits((x)->marked, WHITEBITS) 85 | #define isblack(x) testbit((x)->marked, BLACKBIT) 86 | #define isgray(x) /* neither white nor black */ \ 87 | (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) 88 | 89 | #define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) 90 | 91 | #define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) 92 | #define isdeadm(ow,m) ((m) & (ow)) 93 | #define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) 94 | 95 | #define changewhite(x) ((x)->marked ^= WHITEBITS) 96 | #define gray2black(x) l_setbit((x)->marked, BLACKBIT) 97 | 98 | #define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS) 99 | 100 | 101 | /* object age in generational mode */ 102 | #define G_NEW 0 /* created in current cycle */ 103 | #define G_SURVIVAL 1 /* created in previous cycle */ 104 | #define G_OLD0 2 /* marked old by frw. barrier in this cycle */ 105 | #define G_OLD1 3 /* first full cycle as old */ 106 | #define G_OLD 4 /* really old object (not to be visited) */ 107 | #define G_TOUCHED1 5 /* old object touched this cycle */ 108 | #define G_TOUCHED2 6 /* old object touched in previous cycle */ 109 | 110 | #define AGEBITS 7 /* all age bits (111) */ 111 | 112 | #define getage(o) ((o)->marked & AGEBITS) 113 | #define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a)) 114 | #define isold(o) (getage(o) > G_SURVIVAL) 115 | 116 | #define changeage(o,f,t) \ 117 | check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t))) 118 | 119 | 120 | /* Default Values for GC parameters */ 121 | #define LUAI_GENMAJORMUL 100 122 | #define LUAI_GENMINORMUL 20 123 | 124 | /* wait memory to double before starting new cycle */ 125 | #define LUAI_GCPAUSE 200 /* 200% */ 126 | 127 | /* 128 | ** some gc parameters are stored divided by 4 to allow a maximum value 129 | ** larger than 1000 in a 'lu_byte'. 130 | */ 131 | #define getgcparam(p) ((p) * 4) 132 | #define setgcparam(p,v) ((p) = (v) / 4) 133 | 134 | #define LUAI_GCMUL 100 135 | 136 | /* how much to allocate before next GC step (log2) */ 137 | #define LUAI_GCSTEPSIZE 13 /* 8 KB */ 138 | 139 | 140 | /* 141 | ** Does one step of collection when debt becomes positive. 'pre'/'pos' 142 | ** allows some adjustments to be done only when needed. macro 143 | ** 'condchangemem' is used only for heavy tests (forcing a full 144 | ** GC cycle on every opportunity) 145 | */ 146 | #define luaC_condGC(L,pre,pos) \ 147 | { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ 148 | condchangemem(L,pre,pos); } 149 | 150 | /* more often than not, 'pre'/'pos' are empty */ 151 | #define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) 152 | 153 | 154 | #define luaC_barrier(L,p,v) ( \ 155 | (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ 156 | luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0)) 157 | 158 | #define luaC_barrierback(L,p,v) ( \ 159 | (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ 160 | luaC_barrierback_(L,p) : cast_void(0)) 161 | 162 | #define luaC_objbarrier(L,p,o) ( \ 163 | (isblack(p) && iswhite(o)) ? \ 164 | luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) 165 | 166 | #define luaC_protobarrier(L,p,o) \ 167 | (isblack(p) ? luaC_protobarrier_(L,p) : cast_void(0)) 168 | 169 | LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); 170 | LUAI_FUNC void luaC_freeallobjects (lua_State *L); 171 | LUAI_FUNC void luaC_step (lua_State *L); 172 | LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); 173 | LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); 174 | LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); 175 | LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); 176 | LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); 177 | LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p); 178 | LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); 179 | LUAI_FUNC void luaC_changemode (lua_State *L, int newmode); 180 | 181 | 182 | #endif 183 | -------------------------------------------------------------------------------- /linit.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: linit.c,v 1.40 2017/06/27 18:32:49 roberto Exp roberto $ 3 | ** Initialization of libraries for lua.c and other clients 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #define linit_c 9 | #define LUA_LIB 10 | 11 | /* 12 | ** If you embed Lua in your program and need to open the standard 13 | ** libraries, call luaL_openlibs in your program. If you need a 14 | ** different set of libraries, copy this file to your project and edit 15 | ** it to suit your needs. 16 | ** 17 | ** You can also *preload* libraries, so that a later 'require' can 18 | ** open the library, which is already linked to the application. 19 | ** For that, do the following code: 20 | ** 21 | ** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); 22 | ** lua_pushcfunction(L, luaopen_modname); 23 | ** lua_setfield(L, -2, modname); 24 | ** lua_pop(L, 1); // remove PRELOAD table 25 | */ 26 | 27 | #include "lprefix.h" 28 | 29 | 30 | #include 31 | 32 | #include "lua.h" 33 | 34 | #include "lualib.h" 35 | #include "lauxlib.h" 36 | 37 | 38 | /* 39 | ** these libs are loaded by lua.c and are readily available to any Lua 40 | ** program 41 | */ 42 | static const luaL_Reg loadedlibs[] = { 43 | {LUA_GNAME, luaopen_base}, 44 | {LUA_LOADLIBNAME, luaopen_package}, 45 | {LUA_COLIBNAME, luaopen_coroutine}, 46 | {LUA_TABLIBNAME, luaopen_table}, 47 | {LUA_IOLIBNAME, luaopen_io}, 48 | {LUA_OSLIBNAME, luaopen_os}, 49 | {LUA_STRLIBNAME, luaopen_string}, 50 | {LUA_MATHLIBNAME, luaopen_math}, 51 | {LUA_UTF8LIBNAME, luaopen_utf8}, 52 | {LUA_DBLIBNAME, luaopen_debug}, 53 | {NULL, NULL} 54 | }; 55 | 56 | 57 | LUALIB_API void luaL_openlibs (lua_State *L) { 58 | const luaL_Reg *lib; 59 | /* "require" functions from 'loadedlibs' and set results to global table */ 60 | for (lib = loadedlibs; lib->func; lib++) { 61 | luaL_requiref(L, lib->name, lib->func, 1); 62 | lua_pop(L, 1); /* remove lib */ 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /ljumptab.h: -------------------------------------------------------------------------------- 1 | #undef vmdispatch 2 | #undef vmcase 3 | #undef vmbreak 4 | 5 | #define vmdispatch(x) goto *disptab[x]; 6 | 7 | #define vmcase(l) L_##l: 8 | 9 | #define vmbreak vmfetch(); vmdispatch(GET_OPCODE(i)); 10 | 11 | 12 | static void *disptab[] = { 13 | 14 | #if 0 15 | ** you can update the following list with this command: 16 | ** 17 | ** sed -n '/^OP_/\!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h 18 | ** 19 | #endif 20 | 21 | &&L_OP_MOVE, 22 | &&L_OP_LOADI, 23 | &&L_OP_LOADF, 24 | &&L_OP_LOADK, 25 | &&L_OP_LOADKX, 26 | &&L_OP_LOADBOOL, 27 | &&L_OP_LOADNIL, 28 | &&L_OP_GETUPVAL, 29 | &&L_OP_SETUPVAL, 30 | &&L_OP_GETTABUP, 31 | &&L_OP_GETTABLE, 32 | &&L_OP_GETI, 33 | &&L_OP_GETFIELD, 34 | &&L_OP_SETTABUP, 35 | &&L_OP_SETTABLE, 36 | &&L_OP_SETI, 37 | &&L_OP_SETFIELD, 38 | &&L_OP_NEWTABLE, 39 | &&L_OP_SELF, 40 | &&L_OP_ADDI, 41 | &&L_OP_SUBI, 42 | &&L_OP_MULI, 43 | &&L_OP_MODI, 44 | &&L_OP_POWI, 45 | &&L_OP_DIVI, 46 | &&L_OP_IDIVI, 47 | &&L_OP_BANDK, 48 | &&L_OP_BORK, 49 | &&L_OP_BXORK, 50 | &&L_OP_SHRI, 51 | &&L_OP_SHLI, 52 | &&L_OP_ADD, 53 | &&L_OP_SUB, 54 | &&L_OP_MUL, 55 | &&L_OP_MOD, 56 | &&L_OP_POW, 57 | &&L_OP_DIV, 58 | &&L_OP_IDIV, 59 | &&L_OP_BAND, 60 | &&L_OP_BOR, 61 | &&L_OP_BXOR, 62 | &&L_OP_SHL, 63 | &&L_OP_SHR, 64 | &&L_OP_UNM, 65 | &&L_OP_BNOT, 66 | &&L_OP_NOT, 67 | &&L_OP_LEN, 68 | &&L_OP_CONCAT, 69 | &&L_OP_CLOSE, 70 | &&L_OP_JMP, 71 | &&L_OP_EQ, 72 | &&L_OP_LT, 73 | &&L_OP_LE, 74 | &&L_OP_EQK, 75 | &&L_OP_EQI, 76 | &&L_OP_LTI, 77 | &&L_OP_LEI, 78 | &&L_OP_GTI, 79 | &&L_OP_GEI, 80 | &&L_OP_TEST, 81 | &&L_OP_TESTSET, 82 | &&L_OP_UNDEF, 83 | &&L_OP_ISDEF, 84 | &&L_OP_CALL, 85 | &&L_OP_TAILCALL, 86 | &&L_OP_RETURN, 87 | &&L_OP_RETURN0, 88 | &&L_OP_RETURN1, 89 | &&L_OP_FORLOOP1, 90 | &&L_OP_FORPREP1, 91 | &&L_OP_FORLOOP, 92 | &&L_OP_FORPREP, 93 | &&L_OP_TFORCALL, 94 | &&L_OP_TFORLOOP, 95 | &&L_OP_SETLIST, 96 | &&L_OP_CLOSURE, 97 | &&L_OP_VARARG, 98 | &&L_OP_PREPVARARG, 99 | &&L_OP_EXTRAARG 100 | 101 | }; 102 | -------------------------------------------------------------------------------- /llex.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: llex.h,v 1.80 2018/01/28 15:13:26 roberto Exp roberto $ 3 | ** Lexical Analyzer 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef llex_h 8 | #define llex_h 9 | 10 | #include "lobject.h" 11 | #include "lzio.h" 12 | 13 | 14 | #define FIRST_RESERVED 257 15 | 16 | 17 | #if !defined(LUA_ENV) 18 | #define LUA_ENV "_ENV" 19 | #endif 20 | 21 | 22 | /* 23 | * WARNING: if you change the order of this enumeration, 24 | * grep "ORDER RESERVED" 25 | */ 26 | enum RESERVED { 27 | /* terminal symbols denoted by reserved words */ 28 | TK_AND = FIRST_RESERVED, TK_BREAK, 29 | TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, 30 | TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, 31 | TK_RETURN, TK_THEN, TK_TRUE, TK_UNDEF, TK_UNTIL, TK_WHILE, 32 | /* other terminal symbols */ 33 | TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, 34 | TK_SHL, TK_SHR, 35 | TK_DBCOLON, TK_EOS, 36 | TK_FLT, TK_INT, TK_NAME, TK_STRING 37 | }; 38 | 39 | /* number of reserved words */ 40 | #define NUM_RESERVED (cast_int(TK_WHILE-FIRST_RESERVED + 1)) 41 | 42 | 43 | typedef union { 44 | lua_Number r; 45 | lua_Integer i; 46 | TString *ts; 47 | } SemInfo; /* semantics information */ 48 | 49 | 50 | typedef struct Token { 51 | int token; 52 | SemInfo seminfo; 53 | } Token; 54 | 55 | 56 | /* state of the lexer plus state of the parser when shared by all 57 | functions */ 58 | typedef struct LexState { 59 | int current; /* current character (charint) */ 60 | int linenumber; /* input line counter */ 61 | int lastline; /* line of last token 'consumed' */ 62 | Token t; /* current token */ 63 | Token lookahead; /* look ahead token */ 64 | struct FuncState *fs; /* current function (parser) */ 65 | struct lua_State *L; 66 | ZIO *z; /* input stream */ 67 | Mbuffer *buff; /* buffer for tokens */ 68 | Table *h; /* to avoid collection/reuse strings */ 69 | struct Dyndata *dyd; /* dynamic structures used by the parser */ 70 | TString *source; /* current source name */ 71 | TString *envn; /* environment variable name */ 72 | } LexState; 73 | 74 | 75 | LUAI_FUNC void luaX_init (lua_State *L); 76 | LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, 77 | TString *source, int firstchar); 78 | LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); 79 | LUAI_FUNC void luaX_next (LexState *ls); 80 | LUAI_FUNC int luaX_lookahead (LexState *ls); 81 | LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); 82 | LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); 83 | 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /llimits.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: llimits.h,v 1.148 2017/12/28 11:51:00 roberto Exp roberto $ 3 | ** Limits, basic types, and some other 'installation-dependent' definitions 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef llimits_h 8 | #define llimits_h 9 | 10 | 11 | #include 12 | #include 13 | 14 | 15 | #include "lua.h" 16 | 17 | /* 18 | ** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count 19 | ** the total memory used by Lua (in bytes). Usually, 'size_t' and 20 | ** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. 21 | */ 22 | #if defined(LUAI_MEM) /* { external definitions? */ 23 | typedef LUAI_UMEM lu_mem; 24 | typedef LUAI_MEM l_mem; 25 | #elif LUAI_BITSINT >= 32 /* }{ */ 26 | typedef size_t lu_mem; 27 | typedef ptrdiff_t l_mem; 28 | #else /* 16-bit ints */ /* }{ */ 29 | typedef unsigned long lu_mem; 30 | typedef long l_mem; 31 | #endif /* } */ 32 | 33 | 34 | /* chars used as small naturals (so that 'char' is reserved for characters) */ 35 | typedef unsigned char lu_byte; 36 | typedef signed char ls_byte; 37 | 38 | 39 | /* maximum value for size_t */ 40 | #define MAX_SIZET ((size_t)(~(size_t)0)) 41 | 42 | /* maximum size visible for Lua (must be representable in a lua_Integer */ 43 | #define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ 44 | : (size_t)(LUA_MAXINTEGER)) 45 | 46 | 47 | #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) 48 | 49 | #define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) 50 | 51 | 52 | #define MAX_INT INT_MAX /* maximum value of an int */ 53 | 54 | 55 | /* 56 | ** floor of the log2 of the maximum signed value for integral type 't'. 57 | ** (That is, maximum 'n' such that '2^n' fits in the given signed type.) 58 | */ 59 | #define log2maxs(t) (sizeof(t) * 8 - 2) 60 | 61 | 62 | /* 63 | ** conversion of pointer to unsigned integer: 64 | ** this is for hashing only; there is no problem if the integer 65 | ** cannot hold the whole pointer value 66 | */ 67 | #define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) 68 | 69 | 70 | 71 | /* types of 'usual argument conversions' for lua_Number and lua_Integer */ 72 | typedef LUAI_UACNUMBER l_uacNumber; 73 | typedef LUAI_UACINT l_uacInt; 74 | 75 | 76 | /* internal assertions for in-house debugging */ 77 | #if defined(lua_assert) 78 | #define check_exp(c,e) (lua_assert(c), (e)) 79 | /* to avoid problems with conditions too long */ 80 | #define lua_longassert(c) ((c) ? (void)0 : lua_assert(0)) 81 | #else 82 | #define lua_assert(c) ((void)0) 83 | #define check_exp(c,e) (e) 84 | #define lua_longassert(c) ((void)0) 85 | #endif 86 | 87 | /* 88 | ** assertion for checking API calls 89 | */ 90 | #if !defined(luai_apicheck) 91 | #define luai_apicheck(l,e) lua_assert(e) 92 | #endif 93 | 94 | #define api_check(l,e,msg) luai_apicheck(l,(e) && msg) 95 | 96 | 97 | /* macro to avoid warnings about unused variables */ 98 | #if !defined(UNUSED) 99 | #define UNUSED(x) ((void)(x)) 100 | #endif 101 | 102 | 103 | /* type casts (a macro highlights casts in the code) */ 104 | #define cast(t, exp) ((t)(exp)) 105 | 106 | #define cast_void(i) cast(void, (i)) 107 | #define cast_voidp(i) cast(void *, (i)) 108 | #define cast_num(i) cast(lua_Number, (i)) 109 | #define cast_int(i) cast(int, (i)) 110 | #define cast_uint(i) cast(unsigned int, (i)) 111 | #define cast_byte(i) cast(lu_byte, (i)) 112 | #define cast_uchar(i) cast(unsigned char, (i)) 113 | #define cast_char(i) cast(char, (i)) 114 | #define cast_charp(i) cast(char *, (i)) 115 | #define cast_sizet(i) cast(size_t, (i)) 116 | 117 | 118 | /* cast a signed lua_Integer to lua_Unsigned */ 119 | #if !defined(l_castS2U) 120 | #define l_castS2U(i) ((lua_Unsigned)(i)) 121 | #endif 122 | 123 | /* 124 | ** cast a lua_Unsigned to a signed lua_Integer; this cast is 125 | ** not strict ISO C, but two-complement architectures should 126 | ** work fine. 127 | */ 128 | #if !defined(l_castU2S) 129 | #define l_castU2S(i) ((lua_Integer)(i)) 130 | #endif 131 | 132 | 133 | /* 134 | ** non-return type 135 | */ 136 | #if defined(__GNUC__) 137 | #define l_noret void __attribute__((noreturn)) 138 | #elif defined(_MSC_VER) && _MSC_VER >= 1200 139 | #define l_noret void __declspec(noreturn) 140 | #else 141 | #define l_noret void 142 | #endif 143 | 144 | 145 | 146 | /* 147 | ** maximum depth for nested C calls and syntactical nested non-terminals 148 | ** in a program. (Value must fit in an unsigned short int. It must also 149 | ** be compatible with the size of the C stack.) 150 | */ 151 | #if !defined(LUAI_MAXCCALLS) 152 | #define LUAI_MAXCCALLS 2200 153 | #endif 154 | 155 | 156 | 157 | /* 158 | ** type for virtual-machine instructions; 159 | ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) 160 | */ 161 | #if LUAI_BITSINT >= 32 162 | typedef unsigned int Instruction; 163 | #else 164 | typedef unsigned long Instruction; 165 | #endif 166 | 167 | 168 | 169 | /* 170 | ** Maximum length for short strings, that is, strings that are 171 | ** internalized. (Cannot be smaller than reserved words or tags for 172 | ** metamethods, as these strings must be internalized; 173 | ** #("function") = 8, #("__newindex") = 10.) 174 | */ 175 | #if !defined(LUAI_MAXSHORTLEN) 176 | #define LUAI_MAXSHORTLEN 40 177 | #endif 178 | 179 | 180 | /* 181 | ** Initial size for the string table (must be power of 2). 182 | ** The Lua core alone registers ~50 strings (reserved words + 183 | ** metaevent keys + a few others). Libraries would typically add 184 | ** a few dozens more. 185 | */ 186 | #if !defined(MINSTRTABSIZE) 187 | #define MINSTRTABSIZE 128 188 | #endif 189 | 190 | 191 | /* 192 | ** Size of cache for strings in the API. 'N' is the number of 193 | ** sets (better be a prime) and "M" is the size of each set (M == 1 194 | ** makes a direct cache.) 195 | */ 196 | #if !defined(STRCACHE_N) 197 | #define STRCACHE_N 53 198 | #define STRCACHE_M 2 199 | #endif 200 | 201 | 202 | /* minimum size for string buffer */ 203 | #if !defined(LUA_MINBUFFER) 204 | #define LUA_MINBUFFER 32 205 | #endif 206 | 207 | 208 | /* 209 | ** macros that are executed whenever program enters the Lua core 210 | ** ('lua_lock') and leaves the core ('lua_unlock') 211 | */ 212 | #if !defined(lua_lock) 213 | #define lua_lock(L) ((void) 0) 214 | #define lua_unlock(L) ((void) 0) 215 | #endif 216 | 217 | /* 218 | ** macro executed during Lua functions at points where the 219 | ** function can yield. 220 | */ 221 | #if !defined(luai_threadyield) 222 | #define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} 223 | #endif 224 | 225 | 226 | /* 227 | ** these macros allow user-specific actions when a thread is 228 | ** created/deleted/resumed/yielded. 229 | */ 230 | #if !defined(luai_userstateopen) 231 | #define luai_userstateopen(L) ((void)L) 232 | #endif 233 | 234 | #if !defined(luai_userstateclose) 235 | #define luai_userstateclose(L) ((void)L) 236 | #endif 237 | 238 | #if !defined(luai_userstatethread) 239 | #define luai_userstatethread(L,L1) ((void)L) 240 | #endif 241 | 242 | #if !defined(luai_userstatefree) 243 | #define luai_userstatefree(L,L1) ((void)L) 244 | #endif 245 | 246 | #if !defined(luai_userstateresume) 247 | #define luai_userstateresume(L,n) ((void)L) 248 | #endif 249 | 250 | #if !defined(luai_userstateyield) 251 | #define luai_userstateyield(L,n) ((void)L) 252 | #endif 253 | 254 | 255 | 256 | /* 257 | ** The luai_num* macros define the primitive operations over numbers. 258 | */ 259 | 260 | /* floor division (defined as 'floor(a/b)') */ 261 | #if !defined(luai_numidiv) 262 | #define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b))) 263 | #endif 264 | 265 | /* float division */ 266 | #if !defined(luai_numdiv) 267 | #define luai_numdiv(L,a,b) ((a)/(b)) 268 | #endif 269 | 270 | /* 271 | ** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when 272 | ** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of 273 | ** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b) 274 | ** ~= floor(a/b)'. That happens when the division has a non-integer 275 | ** negative result, which is equivalent to the test below. 276 | */ 277 | #if !defined(luai_nummod) 278 | #define luai_nummod(L,a,b,m) \ 279 | { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); } 280 | #endif 281 | 282 | /* exponentiation */ 283 | #if !defined(luai_numpow) 284 | #define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b)) 285 | #endif 286 | 287 | /* the others are quite standard operations */ 288 | #if !defined(luai_numadd) 289 | #define luai_numadd(L,a,b) ((a)+(b)) 290 | #define luai_numsub(L,a,b) ((a)-(b)) 291 | #define luai_nummul(L,a,b) ((a)*(b)) 292 | #define luai_numunm(L,a) (-(a)) 293 | #define luai_numeq(a,b) ((a)==(b)) 294 | #define luai_numlt(a,b) ((a)<(b)) 295 | #define luai_numle(a,b) ((a)<=(b)) 296 | #define luai_numisnan(a) (!luai_numeq((a), (a))) 297 | #endif 298 | 299 | 300 | 301 | 302 | 303 | /* 304 | ** macro to control inclusion of some hard tests on stack reallocation 305 | */ 306 | #if !defined(HARDSTACKTESTS) 307 | #define condmovestack(L,pre,pos) ((void)0) 308 | #else 309 | /* realloc stack keeping its size */ 310 | #define condmovestack(L,pre,pos) \ 311 | { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_, 0); pos; } 312 | #endif 313 | 314 | #if !defined(HARDMEMTESTS) 315 | #define condchangemem(L,pre,pos) ((void)0) 316 | #else 317 | #define condchangemem(L,pre,pos) \ 318 | { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } 319 | #endif 320 | 321 | #endif 322 | -------------------------------------------------------------------------------- /lmem.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lmem.c,v 1.95 2017/12/11 12:27:48 roberto Exp roberto $ 3 | ** Interface to Memory Manager 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lmem_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "ldebug.h" 18 | #include "ldo.h" 19 | #include "lgc.h" 20 | #include "lmem.h" 21 | #include "lobject.h" 22 | #include "lstate.h" 23 | 24 | 25 | #if defined(HARDMEMTESTS) 26 | #define hardtest(L,os,s) /* force a GC whenever possible */ \ 27 | if ((s) > (os) && (G(L))->gcrunning) luaC_fullgc(L, 1); 28 | #else 29 | #define hardtest(L,os,s) ((void)0) 30 | #endif 31 | 32 | 33 | 34 | /* 35 | ** About the realloc function: 36 | ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); 37 | ** ('osize' is the old size, 'nsize' is the new size) 38 | ** 39 | ** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no 40 | ** matter 'x'). 41 | ** 42 | ** * frealloc(ud, p, x, 0) frees the block 'p' 43 | ** (in this specific case, frealloc must return NULL); 44 | ** particularly, frealloc(ud, NULL, 0, 0) does nothing 45 | ** (which is equivalent to free(NULL) in ISO C) 46 | ** 47 | ** frealloc returns NULL if it cannot create or reallocate the area 48 | ** (any reallocation to an equal or smaller size cannot fail!) 49 | */ 50 | 51 | 52 | 53 | #define MINSIZEARRAY 4 54 | 55 | 56 | void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize, 57 | int size_elems, int limit, const char *what) { 58 | void *newblock; 59 | int size = *psize; 60 | if (nelems + 1 <= size) /* does one extra element still fit? */ 61 | return block; /* nothing to be done */ 62 | if (size >= limit / 2) { /* cannot double it? */ 63 | if (size >= limit) /* cannot grow even a little? */ 64 | luaG_runerror(L, "too many %s (limit is %d)", what, limit); 65 | size = limit; /* still have at least one free place */ 66 | } 67 | else { 68 | size *= 2; 69 | if (size < MINSIZEARRAY) 70 | size = MINSIZEARRAY; /* minimum size */ 71 | } 72 | lua_assert(nelems + 1 <= size && size <= limit); 73 | /* 'limit' ensures that multiplication will not overflow */ 74 | newblock = luaM_realloc_(L, block, cast_sizet(*psize) * size_elems, 75 | cast_sizet(size) * size_elems); 76 | if (newblock == NULL) 77 | luaM_error(L); 78 | *psize = size; /* update only when everything else is OK */ 79 | return newblock; 80 | } 81 | 82 | 83 | void *luaM_shrinkvector_ (lua_State *L, void *block, int *size, 84 | int final_n, int size_elem) { 85 | global_State *g = G(L); 86 | void *newblock; 87 | size_t oldsize = cast_sizet((*size) * size_elem); 88 | size_t newsize = cast_sizet(final_n * size_elem); 89 | lua_assert(newsize <= oldsize); 90 | newblock = (*g->frealloc)(g->ud, block, oldsize, newsize); 91 | if (newblock == NULL && final_n > 0) /* allocation failed? */ 92 | luaM_error(L); 93 | else { 94 | g->GCdebt += newsize - oldsize; 95 | *size = final_n; 96 | return newblock; 97 | } 98 | } 99 | 100 | 101 | l_noret luaM_toobig (lua_State *L) { 102 | luaG_runerror(L, "memory allocation error: block too big"); 103 | } 104 | 105 | 106 | /* 107 | ** Free memory 108 | */ 109 | void luaM_free_ (lua_State *L, void *block, size_t osize) { 110 | global_State *g = G(L); 111 | lua_assert((block == 0) == (block == NULL)); 112 | (*g->frealloc)(g->ud, block, osize, 0); 113 | g->GCdebt -= osize; 114 | } 115 | 116 | 117 | 118 | /* 119 | ** generic allocation routine. 120 | */ 121 | void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { 122 | void *newblock; 123 | global_State *g = G(L); 124 | lua_assert((osize == 0) == (block == NULL)); 125 | hardtest(L, osize, nsize); 126 | newblock = (*g->frealloc)(g->ud, block, osize, nsize); 127 | if (newblock == NULL && nsize > 0) { 128 | /* Is state fully built? Not shrinking a block? */ 129 | if (g->version && nsize > osize) { 130 | luaC_fullgc(L, 1); /* try to free some memory... */ 131 | newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ 132 | } 133 | if (newblock == NULL) 134 | return NULL; 135 | } 136 | lua_assert((nsize == 0) == (newblock == NULL)); 137 | g->GCdebt = (g->GCdebt + nsize) - osize; 138 | return newblock; 139 | } 140 | 141 | 142 | void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, 143 | size_t nsize) { 144 | void *newblock = luaM_realloc_(L, block, osize, nsize); 145 | if (newblock == NULL && nsize > 0) /* allocation failed? */ 146 | luaM_error(L); 147 | return newblock; 148 | } 149 | 150 | 151 | void *luaM_malloc_ (lua_State *L, size_t size, int tag) { 152 | hardtest(L, 0, size); 153 | if (size == 0) 154 | return NULL; /* that's all */ 155 | else { 156 | global_State *g = G(L); 157 | void *newblock = (*g->frealloc)(g->ud, NULL, tag, size); 158 | if (newblock == NULL) { 159 | if (g->version) { /* is state fully built? */ 160 | luaC_fullgc(L, 1); /* try to free some memory... */ 161 | newblock = (*g->frealloc)(g->ud, NULL, tag, size); /* try again */ 162 | } 163 | if (newblock == NULL) 164 | luaM_error(L); 165 | } 166 | g->GCdebt += size; 167 | return newblock; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /lmem.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lmem.h,v 1.46 2017/12/08 17:28:25 roberto Exp roberto $ 3 | ** Interface to Memory Manager 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lmem_h 8 | #define lmem_h 9 | 10 | 11 | #include 12 | 13 | #include "llimits.h" 14 | #include "lua.h" 15 | 16 | 17 | #define luaM_error(L) luaD_throw(L, LUA_ERRMEM) 18 | 19 | 20 | /* 21 | ** This macro tests whether it is safe to multiply 'n' by the size of 22 | ** type 't' without overflows. Because 'e' is always constant, it avoids 23 | ** the runtime division MAX_SIZET/(e). 24 | ** (The macro is somewhat complex to avoid warnings: The 'sizeof' 25 | ** comparison avoids a runtime comparison when overflow cannot occur. 26 | ** The compiler should be able to optimize the real test by itself, but 27 | ** when it does it, it may give a warning about "comparison is always 28 | ** false due to limited range of data type"; the +1 tricks the compiler, 29 | ** avoiding this warning but also this optimization.) 30 | */ 31 | #define luaM_testsize(n,e) \ 32 | (sizeof(n) >= sizeof(size_t) && cast_sizet((n)) + 1 > MAX_SIZET/(e)) 33 | 34 | #define luaM_checksize(L,n,e) \ 35 | (luaM_testsize(n,e) ? luaM_toobig(L) : cast_void(0)) 36 | 37 | 38 | /* 39 | ** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that 40 | ** the result is not larger than 'n' and cannot overflow a 'size_t' 41 | ** when multiplied by the size of type 't'. (Assumes that 'n' is an 42 | ** 'int' or 'unsigned int' and that 'int' is not larger than 'size_t'.) 43 | */ 44 | #define luaM_limitN(n,t) \ 45 | ((cast_sizet(n) <= MAX_SIZET/sizeof(t)) ? (n) : \ 46 | cast_uint((MAX_SIZET/sizeof(t)))) 47 | 48 | 49 | /* 50 | ** Arrays of chars do not need any test 51 | */ 52 | #define luaM_reallocvchar(L,b,on,n) \ 53 | cast_charp(luaM_saferealloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) 54 | 55 | #define luaM_freemem(L, b, s) luaM_free_(L, (b), (s)) 56 | #define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b))) 57 | #define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b))) 58 | 59 | #define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0)) 60 | #define luaM_newvector(L,n,t) cast(t*, luaM_malloc_(L, (n)*sizeof(t), 0)) 61 | #define luaM_newvectorchecked(L,n,t) \ 62 | (luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t)) 63 | 64 | #define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag) 65 | 66 | #define luaM_growvector(L,v,nelems,size,t,limit,e) \ 67 | ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \ 68 | luaM_limitN(limit,t),e))) 69 | 70 | #define luaM_reallocvector(L, v,oldn,n,t) \ 71 | (cast(t *, luaM_realloc_(L, v, cast_sizet(oldn) * sizeof(t), \ 72 | cast_sizet(n) * sizeof(t)))) 73 | 74 | #define luaM_shrinkvector(L,v,size,fs,t) \ 75 | ((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t)))) 76 | 77 | LUAI_FUNC l_noret luaM_toobig (lua_State *L); 78 | 79 | /* not to be called directly */ 80 | LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, 81 | size_t size); 82 | LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize, 83 | size_t size); 84 | LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize); 85 | LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems, 86 | int *size, int size_elem, int limit, 87 | const char *what); 88 | LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem, 89 | int final_n, int size_elem); 90 | LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag); 91 | 92 | #endif 93 | 94 | -------------------------------------------------------------------------------- /lopcodes.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lopcodes.c,v 1.79 2018/02/21 15:49:32 roberto Exp roberto $ 3 | ** Opcodes for Lua virtual machine 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lopcodes_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lopcodes.h" 16 | 17 | 18 | /* ORDER OP */ 19 | 20 | LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { 21 | "MOVE", 22 | "LOADI", 23 | "LOADF", 24 | "LOADK", 25 | "LOADKX", 26 | "LOADBOOL", 27 | "LOADNIL", 28 | "GETUPVAL", 29 | "SETUPVAL", 30 | "GETTABUP", 31 | "GETTABLE", 32 | "GETI", 33 | "GETFIELD", 34 | "SETTABUP", 35 | "SETTABLE", 36 | "SETI", 37 | "SETFIELD", 38 | "NEWTABLE", 39 | "SELF", 40 | "ADDI", 41 | "SUBI", 42 | "MULI", 43 | "MODI", 44 | "POWI", 45 | "DIVI", 46 | "IDIVI", 47 | "BANDK", 48 | "BORK", 49 | "BXORK", 50 | "SHRI", 51 | "SHLI", 52 | "ADD", 53 | "SUB", 54 | "MUL", 55 | "MOD", 56 | "POW", 57 | "DIV", 58 | "IDIV", 59 | "BAND", 60 | "BOR", 61 | "BXOR", 62 | "SHL", 63 | "SHR", 64 | "UNM", 65 | "BNOT", 66 | "NOT", 67 | "LEN", 68 | "CONCAT", 69 | "CLOSE", 70 | "JMP", 71 | "EQ", 72 | "LT", 73 | "LE", 74 | "EQK", 75 | "EQI", 76 | "LTI", 77 | "LEI", 78 | "GTI", 79 | "GEI", 80 | "TEST", 81 | "TESTSET", 82 | "UNDEF", 83 | "ISDEF", 84 | "CALL", 85 | "TAILCALL", 86 | "RETURN", 87 | "RETURN0", 88 | "RETURN1", 89 | "FORLOOP1", 90 | "FORPREP1", 91 | "FORLOOP", 92 | "FORPREP", 93 | "TFORCALL", 94 | "TFORLOOP", 95 | "SETLIST", 96 | "CLOSURE", 97 | "VARARG", 98 | "PREPVARARG", 99 | "EXTRAARG", 100 | NULL 101 | }; 102 | 103 | 104 | LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { 105 | /* OT IT T A mode opcode */ 106 | opmode(0, 0, 0, 1, iABC) /* OP_MOVE */ 107 | ,opmode(0, 0, 0, 1, iAsBx) /* OP_LOADI */ 108 | ,opmode(0, 0, 0, 1, iAsBx) /* OP_LOADF */ 109 | ,opmode(0, 0, 0, 1, iABx) /* OP_LOADK */ 110 | ,opmode(0, 0, 0, 1, iABx) /* OP_LOADKX */ 111 | ,opmode(0, 0, 0, 1, iABC) /* OP_LOADBOOL */ 112 | ,opmode(0, 0, 0, 1, iABC) /* OP_LOADNIL */ 113 | ,opmode(0, 0, 0, 1, iABC) /* OP_GETUPVAL */ 114 | ,opmode(0, 0, 0, 0, iABC) /* OP_SETUPVAL */ 115 | ,opmode(0, 0, 0, 1, iABC) /* OP_GETTABUP */ 116 | ,opmode(0, 0, 0, 1, iABC) /* OP_GETTABLE */ 117 | ,opmode(0, 0, 0, 1, iABC) /* OP_GETI */ 118 | ,opmode(0, 0, 0, 1, iABC) /* OP_GETFIELD */ 119 | ,opmode(0, 0, 0, 0, iABC) /* OP_SETTABUP */ 120 | ,opmode(0, 0, 0, 0, iABC) /* OP_SETTABLE */ 121 | ,opmode(0, 0, 0, 0, iABC) /* OP_SETI */ 122 | ,opmode(0, 0, 0, 0, iABC) /* OP_SETFIELD */ 123 | ,opmode(0, 0, 0, 1, iABC) /* OP_NEWTABLE */ 124 | ,opmode(0, 0, 0, 1, iABC) /* OP_SELF */ 125 | ,opmode(0, 0, 0, 1, iABC) /* OP_ADDI */ 126 | ,opmode(0, 0, 0, 1, iABC) /* OP_SUBI */ 127 | ,opmode(0, 0, 0, 1, iABC) /* OP_MULI */ 128 | ,opmode(0, 0, 0, 1, iABC) /* OP_MODI */ 129 | ,opmode(0, 0, 0, 1, iABC) /* OP_POWI */ 130 | ,opmode(0, 0, 0, 1, iABC) /* OP_DIVI */ 131 | ,opmode(0, 0, 0, 1, iABC) /* OP_IDIVI */ 132 | ,opmode(0, 0, 0, 1, iABC) /* OP_BANDK */ 133 | ,opmode(0, 0, 0, 1, iABC) /* OP_BORK */ 134 | ,opmode(0, 0, 0, 1, iABC) /* OP_BXORK */ 135 | ,opmode(0, 0, 0, 1, iABC) /* OP_SHRI */ 136 | ,opmode(0, 0, 0, 1, iABC) /* OP_SHLI */ 137 | ,opmode(0, 0, 0, 1, iABC) /* OP_ADD */ 138 | ,opmode(0, 0, 0, 1, iABC) /* OP_SUB */ 139 | ,opmode(0, 0, 0, 1, iABC) /* OP_MUL */ 140 | ,opmode(0, 0, 0, 1, iABC) /* OP_MOD */ 141 | ,opmode(0, 0, 0, 1, iABC) /* OP_POW */ 142 | ,opmode(0, 0, 0, 1, iABC) /* OP_DIV */ 143 | ,opmode(0, 0, 0, 1, iABC) /* OP_IDIV */ 144 | ,opmode(0, 0, 0, 1, iABC) /* OP_BAND */ 145 | ,opmode(0, 0, 0, 1, iABC) /* OP_BOR */ 146 | ,opmode(0, 0, 0, 1, iABC) /* OP_BXOR */ 147 | ,opmode(0, 0, 0, 1, iABC) /* OP_SHL */ 148 | ,opmode(0, 0, 0, 1, iABC) /* OP_SHR */ 149 | ,opmode(0, 0, 0, 1, iABC) /* OP_UNM */ 150 | ,opmode(0, 0, 0, 1, iABC) /* OP_BNOT */ 151 | ,opmode(0, 0, 0, 1, iABC) /* OP_NOT */ 152 | ,opmode(0, 0, 0, 1, iABC) /* OP_LEN */ 153 | ,opmode(0, 0, 0, 1, iABC) /* OP_CONCAT */ 154 | ,opmode(0, 0, 0, 0, iABC) /* OP_CLOSE */ 155 | ,opmode(0, 0, 0, 0, isJ) /* OP_JMP */ 156 | ,opmode(0, 0, 1, 0, iABC) /* OP_EQ */ 157 | ,opmode(0, 0, 1, 0, iABC) /* OP_LT */ 158 | ,opmode(0, 0, 1, 0, iABC) /* OP_LE */ 159 | ,opmode(0, 0, 1, 0, iABC) /* OP_EQK */ 160 | ,opmode(0, 0, 1, 0, iABC) /* OP_EQI */ 161 | ,opmode(0, 0, 1, 0, iABC) /* OP_LTI */ 162 | ,opmode(0, 0, 1, 0, iABC) /* OP_LEI */ 163 | ,opmode(0, 0, 1, 0, iABC) /* OP_GTI */ 164 | ,opmode(0, 0, 1, 0, iABC) /* OP_GEI */ 165 | ,opmode(0, 0, 1, 0, iABC) /* OP_TEST */ 166 | ,opmode(0, 0, 1, 1, iABC) /* OP_TESTSET */ 167 | ,opmode(0, 0, 0, 0, iABC) /* OP_UNDEF */ 168 | ,opmode(0, 0, 0, 1, iABC) /* OP_ISDEF */ 169 | ,opmode(1, 1, 0, 1, iABC) /* OP_CALL */ 170 | ,opmode(1, 1, 0, 1, iABC) /* OP_TAILCALL */ 171 | ,opmode(0, 1, 0, 0, iABC) /* OP_RETURN */ 172 | ,opmode(0, 0, 0, 0, iABC) /* OP_RETURN0 */ 173 | ,opmode(0, 0, 0, 0, iABC) /* OP_RETURN1 */ 174 | ,opmode(0, 0, 0, 1, iABx) /* OP_FORLOOP1 */ 175 | ,opmode(0, 0, 0, 1, iABx) /* OP_FORPREP1 */ 176 | ,opmode(0, 0, 0, 1, iABx) /* OP_FORLOOP */ 177 | ,opmode(0, 0, 0, 1, iABx) /* OP_FORPREP */ 178 | ,opmode(0, 0, 0, 0, iABC) /* OP_TFORCALL */ 179 | ,opmode(0, 0, 0, 1, iABx) /* OP_TFORLOOP */ 180 | ,opmode(0, 1, 0, 0, iABC) /* OP_SETLIST */ 181 | ,opmode(0, 0, 0, 1, iABx) /* OP_CLOSURE */ 182 | ,opmode(1, 0, 0, 1, iABC) /* OP_VARARG */ 183 | ,opmode(0, 0, 0, 1, iABC) /* OP_PREPVARARG */ 184 | ,opmode(0, 0, 0, 0, iAx) /* OP_EXTRAARG */ 185 | }; 186 | 187 | -------------------------------------------------------------------------------- /lopcodes.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lopcodes.h,v 1.189 2018/02/21 15:49:32 roberto Exp roberto $ 3 | ** Opcodes for Lua virtual machine 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lopcodes_h 8 | #define lopcodes_h 9 | 10 | #include "llimits.h" 11 | 12 | 13 | /*=========================================================================== 14 | We assume that instructions are unsigned 32-bit integers. 15 | All instructions have an opcode in the first 7 bits. 16 | Instructions can have the following formats: 17 | 18 | 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 19 | 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 20 | iABC C(8) | B(8) |k| A(8) | Op(7) | 21 | iABx Bx(17) | A(8) | Op(7) | 22 | iAsB sBx (signed)(17) | A(8) | Op(7) | 23 | iAx Ax(25) | Op(7) | 24 | isJ sJ(24) |m| Op(7) | 25 | 26 | A signed argument is represented in excess K: the represented value is 27 | the written unsigned value minus K, where K is half the maximum for the 28 | corresponding unsigned argument. 29 | ===========================================================================*/ 30 | 31 | 32 | enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */ 33 | 34 | 35 | /* 36 | ** size and position of opcode arguments. 37 | */ 38 | #define SIZE_C 8 39 | #define SIZE_B 8 40 | #define SIZE_Bx (SIZE_C + SIZE_B + 1) 41 | #define SIZE_A 8 42 | #define SIZE_Ax (SIZE_Bx + SIZE_A) 43 | #define SIZE_sJ (SIZE_Bx + SIZE_A - 1) 44 | 45 | #define SIZE_OP 7 46 | 47 | #define POS_OP 0 48 | 49 | #define POS_A (POS_OP + SIZE_OP) 50 | #define POS_k (POS_A + SIZE_A) 51 | #define POS_B (POS_k + 1) 52 | #define POS_C (POS_B + SIZE_B) 53 | 54 | #define POS_Bx POS_k 55 | 56 | #define POS_Ax POS_A 57 | 58 | #define POS_m POS_A 59 | #define POS_sJ (POS_A + 1) 60 | 61 | /* 62 | ** limits for opcode arguments. 63 | ** we use (signed) int to manipulate most arguments, 64 | ** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) 65 | */ 66 | #if SIZE_Bx < LUAI_BITSINT-1 67 | #define MAXARG_Bx ((1<>1) /* 'sBx' is signed */ 73 | 74 | 75 | #if SIZE_Ax < LUAI_BITSINT-1 76 | #define MAXARG_Ax ((1<> 1) 88 | 89 | 90 | #define MAXARG_A ((1<> 1) 94 | #define MAXARG_Cx ((1<<(SIZE_C + 1))-1) 95 | 96 | 97 | /* creates a mask with 'n' 1 bits at position 'p' */ 98 | #define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p)) 99 | 100 | /* creates a mask with 'n' 0 bits at position 'p' */ 101 | #define MASK0(n,p) (~MASK1(n,p)) 102 | 103 | /* 104 | ** the following macros help to manipulate instructions 105 | */ 106 | 107 | #define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0))) 108 | #define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ 109 | ((cast(Instruction, o)<>(pos)) & MASK1(size,0))) 115 | #define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ 116 | ((cast(Instruction, v)<> C */ 232 | OP_SHLI,/* A B C R(A) := C << R(B) */ 233 | 234 | OP_ADD,/* A B C R(A) := R(B) + R(C) */ 235 | OP_SUB,/* A B C R(A) := R(B) - R(C) */ 236 | OP_MUL,/* A B C R(A) := R(B) * R(C) */ 237 | OP_MOD,/* A B C R(A) := R(B) % R(C) */ 238 | OP_POW,/* A B C R(A) := R(B) ^ R(C) */ 239 | OP_DIV,/* A B C R(A) := R(B) / R(C) */ 240 | OP_IDIV,/* A B C R(A) := R(B) // R(C) */ 241 | OP_BAND,/* A B C R(A) := R(B) & R(C) */ 242 | OP_BOR,/* A B C R(A) := R(B) | R(C) */ 243 | OP_BXOR,/* A B C R(A) := R(B) ~ R(C) */ 244 | OP_SHL,/* A B C R(A) := R(B) << R(C) */ 245 | OP_SHR,/* A B C R(A) := R(B) >> R(C) */ 246 | OP_UNM,/* A B R(A) := -R(B) */ 247 | OP_BNOT,/* A B R(A) := ~R(B) */ 248 | OP_NOT,/* A B R(A) := not R(B) */ 249 | OP_LEN,/* A B R(A) := length of R(B) */ 250 | 251 | OP_CONCAT,/* A B R(A) := R(A).. ... ..R(A + B - 1) */ 252 | 253 | OP_CLOSE,/* A close all upvalues >= R(A) */ 254 | OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ 255 | OP_EQ,/* A B if ((R(A) == R(B)) ~= k) then pc++ */ 256 | OP_LT,/* A B if ((R(A) < R(B)) ~= k) then pc++ */ 257 | OP_LE,/* A B if ((R(A) <= R(B)) ~= k) then pc++ */ 258 | 259 | OP_EQK,/* A B if ((R(A) == K(B)) ~= k) then pc++ */ 260 | OP_EQI,/* A sB if ((R(A) == sB) ~= k) then pc++ */ 261 | OP_LTI,/* A sB if ((R(A) < sB) ~= k) then pc++ */ 262 | OP_LEI,/* A sB if ((R(A) <= sB) ~= k) then pc++ */ 263 | OP_GTI,/* A sB if ((R(A) > sB) ~= k) then pc++ */ 264 | OP_GEI,/* A sB if ((R(A) >= sB) ~= k) then pc++ */ 265 | 266 | OP_TEST,/* A if (not R(A) == k) then pc++ */ 267 | OP_TESTSET,/* A B if (not R(B) == k) then R(A) := R(B) else pc++ */ 268 | 269 | OP_UNDEF,/* A B R(A)[R(B)] = undef */ 270 | OP_ISDEF,/* A B C R(A) = (R(B)[R(C)] == undef */ 271 | 272 | OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ 273 | OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ 274 | 275 | OP_RETURN,/* A B C return R(A), ... ,R(A+B-2) (see note) */ 276 | OP_RETURN0,/* return */ 277 | OP_RETURN1,/* A return R(A) */ 278 | 279 | OP_FORLOOP1,/* A Bx R(A)++; 280 | if R(A) <= R(A+1) then { pc-=Bx; R(A+3)=R(A) } */ 281 | OP_FORPREP1,/* A Bx R(A)--; pc+=Bx */ 282 | 283 | OP_FORLOOP,/* A Bx R(A)+=R(A+2); 284 | if R(A) 0 means the function is vararg and (C - 1) is its number of 331 | fixed parameters. 332 | 333 | ===========================================================================*/ 334 | 335 | 336 | /* 337 | ** masks for instruction properties. The format is: 338 | ** bits 0-2: op mode 339 | ** bit 3: instruction set register A 340 | ** bit 4: operator is a test (next instruction must be a jump) 341 | ** bit 5: instruction uses 'L->top' set by previous instruction (when B == 0) 342 | ** bit 6: instruction sets 'L->top' for next instruction (when C == 0) 343 | */ 344 | 345 | LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES]; 346 | 347 | #define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7)) 348 | #define testAMode(m) (luaP_opmodes[m] & (1 << 3)) 349 | #define testTMode(m) (luaP_opmodes[m] & (1 << 4)) 350 | #define testITMode(m) (luaP_opmodes[m] & (1 << 5)) 351 | #define testOTMode(m) (luaP_opmodes[m] & (1 << 6)) 352 | 353 | /* "out top" (set top for next instruction) */ 354 | #define isOT(i) \ 355 | ((testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) || \ 356 | GET_OPCODE(i) == OP_TAILCALL) 357 | 358 | /* "in top" (uses top from previous instruction) */ 359 | #define isIT(i) (testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0) 360 | 361 | #define opmode(ot,it,t,a,m) (((ot)<<6) | ((it)<<5) | ((t)<<4) | ((a)<<3) | (m)) 362 | 363 | 364 | LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ 365 | 366 | 367 | /* number of list items to accumulate before a SETLIST instruction */ 368 | #define LFIELDS_PER_FLUSH 50 369 | 370 | 371 | #endif 372 | -------------------------------------------------------------------------------- /loslib.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: loslib.c,v 1.65 2016/07/18 17:58:58 roberto Exp roberto $ 3 | ** Standard Operating System library 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define loslib_c 8 | #define LUA_LIB 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "lua.h" 20 | 21 | #include "lauxlib.h" 22 | #include "lualib.h" 23 | 24 | 25 | /* 26 | ** {================================================================== 27 | ** List of valid conversion specifiers for the 'strftime' function; 28 | ** options are grouped by length; group of length 2 start with '||'. 29 | ** =================================================================== 30 | */ 31 | #if !defined(LUA_STRFTIMEOPTIONS) /* { */ 32 | 33 | /* options for ANSI C 89 (only 1-char options) */ 34 | #define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%" 35 | 36 | /* options for ISO C 99 and POSIX */ 37 | #define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \ 38 | "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */ 39 | 40 | /* options for Windows */ 41 | #define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \ 42 | "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */ 43 | 44 | #if defined(LUA_USE_WINDOWS) 45 | #define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN 46 | #elif defined(LUA_USE_C89) 47 | #define LUA_STRFTIMEOPTIONS L_STRFTIMEC89 48 | #else /* C99 specification */ 49 | #define LUA_STRFTIMEOPTIONS L_STRFTIMEC99 50 | #endif 51 | 52 | #endif /* } */ 53 | /* }================================================================== */ 54 | 55 | 56 | /* 57 | ** {================================================================== 58 | ** Configuration for time-related stuff 59 | ** =================================================================== 60 | */ 61 | 62 | #if !defined(l_time_t) /* { */ 63 | /* 64 | ** type to represent time_t in Lua 65 | */ 66 | #define l_timet lua_Integer 67 | #define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) 68 | 69 | static time_t l_checktime (lua_State *L, int arg) { 70 | lua_Integer t = luaL_checkinteger(L, arg); 71 | luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); 72 | return (time_t)t; 73 | } 74 | 75 | #endif /* } */ 76 | 77 | 78 | #if !defined(l_gmtime) /* { */ 79 | /* 80 | ** By default, Lua uses gmtime/localtime, except when POSIX is available, 81 | ** where it uses gmtime_r/localtime_r 82 | */ 83 | 84 | #if defined(LUA_USE_POSIX) /* { */ 85 | 86 | #define l_gmtime(t,r) gmtime_r(t,r) 87 | #define l_localtime(t,r) localtime_r(t,r) 88 | 89 | #else /* }{ */ 90 | 91 | /* ISO C definitions */ 92 | #define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t)) 93 | #define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t)) 94 | 95 | #endif /* } */ 96 | 97 | #endif /* } */ 98 | 99 | /* }================================================================== */ 100 | 101 | 102 | /* 103 | ** {================================================================== 104 | ** Configuration for 'tmpnam': 105 | ** By default, Lua uses tmpnam except when POSIX is available, where 106 | ** it uses mkstemp. 107 | ** =================================================================== 108 | */ 109 | #if !defined(lua_tmpnam) /* { */ 110 | 111 | #if defined(LUA_USE_POSIX) /* { */ 112 | 113 | #include 114 | 115 | #define LUA_TMPNAMBUFSIZE 32 116 | 117 | #if !defined(LUA_TMPNAMTEMPLATE) 118 | #define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX" 119 | #endif 120 | 121 | #define lua_tmpnam(b,e) { \ 122 | strcpy(b, LUA_TMPNAMTEMPLATE); \ 123 | e = mkstemp(b); \ 124 | if (e != -1) close(e); \ 125 | e = (e == -1); } 126 | 127 | #else /* }{ */ 128 | 129 | /* ISO C definitions */ 130 | #define LUA_TMPNAMBUFSIZE L_tmpnam 131 | #define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } 132 | 133 | #endif /* } */ 134 | 135 | #endif /* } */ 136 | /* }================================================================== */ 137 | 138 | 139 | 140 | 141 | static int os_execute (lua_State *L) { 142 | const char *cmd = luaL_optstring(L, 1, NULL); 143 | int stat = system(cmd); 144 | if (cmd != NULL) 145 | return luaL_execresult(L, stat); 146 | else { 147 | lua_pushboolean(L, stat); /* true if there is a shell */ 148 | return 1; 149 | } 150 | } 151 | 152 | 153 | static int os_remove (lua_State *L) { 154 | const char *filename = luaL_checkstring(L, 1); 155 | return luaL_fileresult(L, remove(filename) == 0, filename); 156 | } 157 | 158 | 159 | static int os_rename (lua_State *L) { 160 | const char *fromname = luaL_checkstring(L, 1); 161 | const char *toname = luaL_checkstring(L, 2); 162 | return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); 163 | } 164 | 165 | 166 | static int os_tmpname (lua_State *L) { 167 | char buff[LUA_TMPNAMBUFSIZE]; 168 | int err; 169 | lua_tmpnam(buff, err); 170 | if (err) 171 | return luaL_error(L, "unable to generate a unique filename"); 172 | lua_pushstring(L, buff); 173 | return 1; 174 | } 175 | 176 | 177 | static int os_getenv (lua_State *L) { 178 | lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ 179 | return 1; 180 | } 181 | 182 | 183 | static int os_clock (lua_State *L) { 184 | lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); 185 | return 1; 186 | } 187 | 188 | 189 | /* 190 | ** {====================================================== 191 | ** Time/Date operations 192 | ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, 193 | ** wday=%w+1, yday=%j, isdst=? } 194 | ** ======================================================= 195 | */ 196 | 197 | static void setfield (lua_State *L, const char *key, int value) { 198 | lua_pushinteger(L, value); 199 | lua_setfield(L, -2, key); 200 | } 201 | 202 | static void setboolfield (lua_State *L, const char *key, int value) { 203 | if (value < 0) /* undefined? */ 204 | return; /* does not set field */ 205 | lua_pushboolean(L, value); 206 | lua_setfield(L, -2, key); 207 | } 208 | 209 | 210 | /* 211 | ** Set all fields from structure 'tm' in the table on top of the stack 212 | */ 213 | static void setallfields (lua_State *L, struct tm *stm) { 214 | setfield(L, "sec", stm->tm_sec); 215 | setfield(L, "min", stm->tm_min); 216 | setfield(L, "hour", stm->tm_hour); 217 | setfield(L, "day", stm->tm_mday); 218 | setfield(L, "month", stm->tm_mon + 1); 219 | setfield(L, "year", stm->tm_year + 1900); 220 | setfield(L, "wday", stm->tm_wday + 1); 221 | setfield(L, "yday", stm->tm_yday + 1); 222 | setboolfield(L, "isdst", stm->tm_isdst); 223 | } 224 | 225 | 226 | static int getboolfield (lua_State *L, const char *key) { 227 | int res; 228 | res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); 229 | lua_pop(L, 1); 230 | return res; 231 | } 232 | 233 | 234 | /* maximum value for date fields (to avoid arithmetic overflows with 'int') */ 235 | #if !defined(L_MAXDATEFIELD) 236 | #define L_MAXDATEFIELD (INT_MAX / 2) 237 | #endif 238 | 239 | static int getfield (lua_State *L, const char *key, int d, int delta) { 240 | int isnum; 241 | int t = lua_getfield(L, -1, key); /* get field and its type */ 242 | lua_Integer res = lua_tointegerx(L, -1, &isnum); 243 | if (!isnum) { /* field is not an integer? */ 244 | if (t != LUA_TNIL) /* some other value? */ 245 | return luaL_error(L, "field '%s' is not an integer", key); 246 | else if (d < 0) /* absent field; no default? */ 247 | return luaL_error(L, "field '%s' missing in date table", key); 248 | res = d; 249 | } 250 | else { 251 | if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) 252 | return luaL_error(L, "field '%s' is out-of-bound", key); 253 | res -= delta; 254 | } 255 | lua_pop(L, 1); 256 | return (int)res; 257 | } 258 | 259 | 260 | static const char *checkoption (lua_State *L, const char *conv, 261 | ptrdiff_t convlen, char *buff) { 262 | const char *option = LUA_STRFTIMEOPTIONS; 263 | int oplen = 1; /* length of options being checked */ 264 | for (; *option != '\0' && oplen <= convlen; option += oplen) { 265 | if (*option == '|') /* next block? */ 266 | oplen++; /* will check options with next length (+1) */ 267 | else if (memcmp(conv, option, oplen) == 0) { /* match? */ 268 | memcpy(buff, conv, oplen); /* copy valid option to buffer */ 269 | buff[oplen] = '\0'; 270 | return conv + oplen; /* return next item */ 271 | } 272 | } 273 | luaL_argerror(L, 1, 274 | lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); 275 | return conv; /* to avoid warnings */ 276 | } 277 | 278 | 279 | /* maximum size for an individual 'strftime' item */ 280 | #define SIZETIMEFMT 250 281 | 282 | 283 | static int os_date (lua_State *L) { 284 | size_t slen; 285 | const char *s = luaL_optlstring(L, 1, "%c", &slen); 286 | time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); 287 | const char *se = s + slen; /* 's' end */ 288 | struct tm tmr, *stm; 289 | if (*s == '!') { /* UTC? */ 290 | stm = l_gmtime(&t, &tmr); 291 | s++; /* skip '!' */ 292 | } 293 | else 294 | stm = l_localtime(&t, &tmr); 295 | if (stm == NULL) /* invalid date? */ 296 | return luaL_error(L, 297 | "time result cannot be represented in this installation"); 298 | if (strcmp(s, "*t") == 0) { 299 | lua_createtable(L, 0, 9); /* 9 = number of fields */ 300 | setallfields(L, stm); 301 | } 302 | else { 303 | char cc[4]; /* buffer for individual conversion specifiers */ 304 | luaL_Buffer b; 305 | cc[0] = '%'; 306 | luaL_buffinit(L, &b); 307 | while (s < se) { 308 | if (*s != '%') /* not a conversion specifier? */ 309 | luaL_addchar(&b, *s++); 310 | else { 311 | size_t reslen; 312 | char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); 313 | s++; /* skip '%' */ 314 | s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ 315 | reslen = strftime(buff, SIZETIMEFMT, cc, stm); 316 | luaL_addsize(&b, reslen); 317 | } 318 | } 319 | luaL_pushresult(&b); 320 | } 321 | return 1; 322 | } 323 | 324 | 325 | static int os_time (lua_State *L) { 326 | time_t t; 327 | if (lua_isnoneornil(L, 1)) /* called without args? */ 328 | t = time(NULL); /* get current time */ 329 | else { 330 | struct tm ts; 331 | luaL_checktype(L, 1, LUA_TTABLE); 332 | lua_settop(L, 1); /* make sure table is at the top */ 333 | ts.tm_sec = getfield(L, "sec", 0, 0); 334 | ts.tm_min = getfield(L, "min", 0, 0); 335 | ts.tm_hour = getfield(L, "hour", 12, 0); 336 | ts.tm_mday = getfield(L, "day", -1, 0); 337 | ts.tm_mon = getfield(L, "month", -1, 1); 338 | ts.tm_year = getfield(L, "year", -1, 1900); 339 | ts.tm_isdst = getboolfield(L, "isdst"); 340 | t = mktime(&ts); 341 | setallfields(L, &ts); /* update fields with normalized values */ 342 | } 343 | if (t != (time_t)(l_timet)t || t == (time_t)(-1)) 344 | return luaL_error(L, 345 | "time result cannot be represented in this installation"); 346 | l_pushtime(L, t); 347 | return 1; 348 | } 349 | 350 | 351 | static int os_difftime (lua_State *L) { 352 | time_t t1 = l_checktime(L, 1); 353 | time_t t2 = l_checktime(L, 2); 354 | lua_pushnumber(L, (lua_Number)difftime(t1, t2)); 355 | return 1; 356 | } 357 | 358 | /* }====================================================== */ 359 | 360 | 361 | static int os_setlocale (lua_State *L) { 362 | static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, 363 | LC_NUMERIC, LC_TIME}; 364 | static const char *const catnames[] = {"all", "collate", "ctype", "monetary", 365 | "numeric", "time", NULL}; 366 | const char *l = luaL_optstring(L, 1, NULL); 367 | int op = luaL_checkoption(L, 2, "all", catnames); 368 | lua_pushstring(L, setlocale(cat[op], l)); 369 | return 1; 370 | } 371 | 372 | 373 | static int os_exit (lua_State *L) { 374 | int status; 375 | if (lua_isboolean(L, 1)) 376 | status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); 377 | else 378 | status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); 379 | if (lua_toboolean(L, 2)) 380 | lua_close(L); 381 | if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ 382 | return 0; 383 | } 384 | 385 | 386 | static const luaL_Reg syslib[] = { 387 | {"clock", os_clock}, 388 | {"date", os_date}, 389 | {"difftime", os_difftime}, 390 | {"execute", os_execute}, 391 | {"exit", os_exit}, 392 | {"getenv", os_getenv}, 393 | {"remove", os_remove}, 394 | {"rename", os_rename}, 395 | {"setlocale", os_setlocale}, 396 | {"time", os_time}, 397 | {"tmpname", os_tmpname}, 398 | {NULL, NULL} 399 | }; 400 | 401 | /* }====================================================== */ 402 | 403 | 404 | 405 | LUAMOD_API int luaopen_os (lua_State *L) { 406 | luaL_newlib(L, syslib); 407 | return 1; 408 | } 409 | 410 | -------------------------------------------------------------------------------- /lparser.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lparser.h,v 1.80 2017/12/14 14:24:02 roberto Exp roberto $ 3 | ** Lua Parser 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lparser_h 8 | #define lparser_h 9 | 10 | #include "llimits.h" 11 | #include "lobject.h" 12 | #include "lzio.h" 13 | 14 | 15 | /* 16 | ** Expression and variable descriptor. 17 | ** Code generation for variables and expressions can be delayed to allow 18 | ** optimizations; An 'expdesc' structure describes a potentially-delayed 19 | ** variable/expression. It has a description of its "main" value plus a 20 | ** list of conditional jumps that can also produce its value (generated 21 | ** by short-circuit operators 'and'/'or'). 22 | */ 23 | 24 | /* kinds of variables/expressions */ 25 | typedef enum { 26 | VVOID, /* when 'expdesc' describes the last expression a list, 27 | this kind means an empty list (so, no expression) */ 28 | VNIL, /* constant nil */ 29 | VTRUE, /* constant true */ 30 | VFALSE, /* constant false */ 31 | VK, /* constant in 'k'; info = index of constant in 'k' */ 32 | VKFLT, /* floating constant; nval = numerical float value */ 33 | VKINT, /* integer constant; nval = numerical integer value */ 34 | VNONRELOC, /* expression has its value in a fixed register; 35 | info = result register */ 36 | VLOCAL, /* local variable; info = local register */ 37 | VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ 38 | VINDEXED, /* indexed variable; 39 | ind.t = table register; 40 | ind.idx = key's R index */ 41 | VINDEXUP, /* indexed upvalue; 42 | ind.t = table upvalue; 43 | ind.idx = key's K index */ 44 | VINDEXI, /* indexed variable with constant integer; 45 | ind.t = table register; 46 | ind.idx = key's value */ 47 | VINDEXSTR, /* indexed variable with literal string; 48 | ind.t = table register; 49 | ind.idx = key's K index */ 50 | VJMP, /* expression is a test/comparison; 51 | info = pc of corresponding jump instruction */ 52 | VRELOC, /* expression can put result in any register; 53 | info = instruction pc */ 54 | VCALL, /* expression is a function call; info = instruction pc */ 55 | VVARARG, /* vararg expression; info = instruction pc */ 56 | VUNDEF /* the 'undef' "expression" */ 57 | } expkind; 58 | 59 | 60 | #define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXSTR) 61 | #define vkisindexed(k) (VINDEXED <= (k) && (k) <= VINDEXSTR) 62 | #define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) 63 | 64 | typedef struct expdesc { 65 | expkind k; 66 | union { 67 | lua_Integer ival; /* for VKINT */ 68 | lua_Number nval; /* for VKFLT */ 69 | int info; /* for generic use */ 70 | struct { /* for indexed variables */ 71 | short idx; /* index (R or "long" K) */ 72 | lu_byte t; /* table (register or upvalue) */ 73 | } ind; 74 | } u; 75 | int t; /* patch list of 'exit when true' */ 76 | int f; /* patch list of 'exit when false' */ 77 | } expdesc; 78 | 79 | 80 | /* description of active local variable */ 81 | typedef struct Vardesc { 82 | short idx; /* variable index in stack */ 83 | } Vardesc; 84 | 85 | 86 | /* description of pending goto statements and label statements */ 87 | typedef struct Labeldesc { 88 | TString *name; /* label identifier */ 89 | int pc; /* position in code */ 90 | int line; /* line where it appeared */ 91 | lu_byte nactvar; /* local level where it appears in current block */ 92 | } Labeldesc; 93 | 94 | 95 | /* list of labels or gotos */ 96 | typedef struct Labellist { 97 | Labeldesc *arr; /* array */ 98 | int n; /* number of entries in use */ 99 | int size; /* array size */ 100 | } Labellist; 101 | 102 | 103 | /* dynamic structures used by the parser */ 104 | typedef struct Dyndata { 105 | struct { /* list of active local variables */ 106 | Vardesc *arr; 107 | int n; 108 | int size; 109 | } actvar; 110 | Labellist gt; /* list of pending gotos */ 111 | Labellist label; /* list of active labels */ 112 | } Dyndata; 113 | 114 | 115 | /* control of blocks */ 116 | struct BlockCnt; /* defined in lparser.c */ 117 | 118 | 119 | /* state needed to generate code for a given function */ 120 | typedef struct FuncState { 121 | Proto *f; /* current function header */ 122 | struct FuncState *prev; /* enclosing function */ 123 | struct LexState *ls; /* lexical state */ 124 | struct BlockCnt *bl; /* chain of current blocks */ 125 | int pc; /* next position to code (equivalent to 'ncode') */ 126 | int lasttarget; /* 'label' of last 'jump label' */ 127 | int previousline; /* last line that was saved in 'lineinfo' */ 128 | int nk; /* number of elements in 'k' */ 129 | int np; /* number of elements in 'p' */ 130 | int nabslineinfo; /* number of elements in 'abslineinfo' */ 131 | int firstlocal; /* index of first local var (in Dyndata array) */ 132 | short nlocvars; /* number of elements in 'f->locvars' */ 133 | lu_byte nactvar; /* number of active local variables */ 134 | lu_byte nups; /* number of upvalues */ 135 | lu_byte freereg; /* first free register */ 136 | lu_byte iwthabs; /* instructions issued since last absolute line info */ 137 | } FuncState; 138 | 139 | 140 | LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, 141 | Dyndata *dyd, const char *name, int firstchar); 142 | 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /lprefix.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lprefix.h,v 1.1 2014/11/03 15:12:44 roberto Exp roberto $ 3 | ** Definitions for Lua code that must come before any other header file 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lprefix_h 8 | #define lprefix_h 9 | 10 | 11 | /* 12 | ** Allows POSIX/XSI stuff 13 | */ 14 | #if !defined(LUA_USE_C89) /* { */ 15 | 16 | #if !defined(_XOPEN_SOURCE) 17 | #define _XOPEN_SOURCE 600 18 | #elif _XOPEN_SOURCE == 0 19 | #undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ 20 | #endif 21 | 22 | /* 23 | ** Allows manipulation of large files in gcc and some other compilers 24 | */ 25 | #if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) 26 | #define _LARGEFILE_SOURCE 1 27 | #define _FILE_OFFSET_BITS 64 28 | #endif 29 | 30 | #endif /* } */ 31 | 32 | 33 | /* 34 | ** Windows stuff 35 | */ 36 | #if defined(_WIN32) /* { */ 37 | 38 | #if !defined(_CRT_SECURE_NO_WARNINGS) 39 | #define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ 40 | #endif 41 | 42 | #endif /* } */ 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /lstate.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lstate.c,v 2.150 2018/01/28 15:13:26 roberto Exp roberto $ 3 | ** Global State 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lstate_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | #include 15 | 16 | #include "lua.h" 17 | 18 | #include "lapi.h" 19 | #include "ldebug.h" 20 | #include "ldo.h" 21 | #include "lfunc.h" 22 | #include "lgc.h" 23 | #include "llex.h" 24 | #include "lmem.h" 25 | #include "lstate.h" 26 | #include "lstring.h" 27 | #include "ltable.h" 28 | #include "ltm.h" 29 | 30 | 31 | 32 | /* 33 | ** a macro to help the creation of a unique random seed when a state is 34 | ** created; the seed is used to randomize hashes. 35 | */ 36 | #if !defined(luai_makeseed) 37 | #include 38 | #define luai_makeseed() cast_uint(time(NULL)) 39 | #endif 40 | 41 | 42 | 43 | /* 44 | ** thread state + extra space 45 | */ 46 | typedef struct LX { 47 | lu_byte extra_[LUA_EXTRASPACE]; 48 | lua_State l; 49 | } LX; 50 | 51 | 52 | /* 53 | ** Main thread combines a thread state and the global state 54 | */ 55 | typedef struct LG { 56 | LX l; 57 | global_State g; 58 | } LG; 59 | 60 | 61 | 62 | #define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) 63 | 64 | 65 | /* 66 | ** Compute an initial seed as random as possible. Rely on Address Space 67 | ** Layout Randomization (if present) to increase randomness.. 68 | */ 69 | #define addbuff(b,p,e) \ 70 | { size_t t = cast_sizet(e); \ 71 | memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } 72 | 73 | static unsigned int makeseed (lua_State *L) { 74 | char buff[4 * sizeof(size_t)]; 75 | unsigned int h = luai_makeseed(); 76 | int p = 0; 77 | addbuff(buff, p, L); /* heap variable */ 78 | addbuff(buff, p, &h); /* local variable */ 79 | addbuff(buff, p, luaO_nilobject); /* global variable */ 80 | addbuff(buff, p, &lua_newstate); /* public function */ 81 | lua_assert(p == sizeof(buff)); 82 | return luaS_hash(buff, p, h); 83 | } 84 | 85 | 86 | /* 87 | ** set GCdebt to a new value keeping the value (totalbytes + GCdebt) 88 | ** invariant (and avoiding underflows in 'totalbytes') 89 | */ 90 | void luaE_setdebt (global_State *g, l_mem debt) { 91 | l_mem tb = gettotalbytes(g); 92 | lua_assert(tb > 0); 93 | if (debt < tb - MAX_LMEM) 94 | debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ 95 | g->totalbytes = tb - debt; 96 | g->GCdebt = debt; 97 | } 98 | 99 | 100 | /* 101 | ** Increment count of "C calls" and check for overflows. In case of 102 | ** a stack overflow, check appropriate error ("regular" overflow or 103 | ** overflow while handling stack overflow). If 'nCalls' is larger than 104 | ** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but 105 | ** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to 106 | ** allow overflow handling to work) 107 | */ 108 | void luaE_incCcalls (lua_State *L) { 109 | if (++L->nCcalls >= LUAI_MAXCCALLS) { 110 | if (L->nCcalls == LUAI_MAXCCALLS) 111 | luaG_runerror(L, "C stack overflow"); 112 | else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) 113 | luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ 114 | } 115 | } 116 | 117 | 118 | CallInfo *luaE_extendCI (lua_State *L) { 119 | CallInfo *ci; 120 | luaE_incCcalls(L); 121 | ci = luaM_new(L, CallInfo); 122 | lua_assert(L->ci->next == NULL); 123 | L->ci->next = ci; 124 | ci->previous = L->ci; 125 | ci->next = NULL; 126 | ci->u.l.trap = 0; 127 | L->nci++; 128 | return ci; 129 | } 130 | 131 | 132 | /* 133 | ** free all CallInfo structures not in use by a thread 134 | */ 135 | void luaE_freeCI (lua_State *L) { 136 | CallInfo *ci = L->ci; 137 | CallInfo *next = ci->next; 138 | ci->next = NULL; 139 | L->nCcalls -= L->nci; /* to subtract removed elements from 'nCcalls' */ 140 | while ((ci = next) != NULL) { 141 | next = ci->next; 142 | luaM_free(L, ci); 143 | L->nci--; 144 | } 145 | L->nCcalls += L->nci; /* to subtract removed elements from 'nCcalls' */ 146 | } 147 | 148 | 149 | /* 150 | ** free half of the CallInfo structures not in use by a thread 151 | */ 152 | void luaE_shrinkCI (lua_State *L) { 153 | CallInfo *ci = L->ci; 154 | CallInfo *next2; /* next's next */ 155 | L->nCcalls -= L->nci; /* to subtract removed elements from 'nCcalls' */ 156 | /* while there are two nexts */ 157 | while (ci->next != NULL && (next2 = ci->next->next) != NULL) { 158 | luaM_free(L, ci->next); /* free next */ 159 | L->nci--; 160 | ci->next = next2; /* remove 'next' from the list */ 161 | next2->previous = ci; 162 | ci = next2; /* keep next's next */ 163 | } 164 | L->nCcalls += L->nci; /* to subtract removed elements from 'nCcalls' */ 165 | } 166 | 167 | 168 | static void stack_init (lua_State *L1, lua_State *L) { 169 | int i; CallInfo *ci; 170 | /* initialize stack array */ 171 | L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, StackValue); 172 | L1->stacksize = BASIC_STACK_SIZE; 173 | for (i = 0; i < BASIC_STACK_SIZE; i++) 174 | setnilvalue(s2v(L1->stack + i)); /* erase new stack */ 175 | L1->top = L1->stack; 176 | L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; 177 | /* initialize first ci */ 178 | ci = &L1->base_ci; 179 | ci->next = ci->previous = NULL; 180 | ci->callstatus = CIST_C; 181 | ci->func = L1->top; 182 | setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */ 183 | L1->top++; 184 | ci->top = L1->top + LUA_MINSTACK; 185 | L1->ci = ci; 186 | } 187 | 188 | 189 | static void freestack (lua_State *L) { 190 | if (L->stack == NULL) 191 | return; /* stack not completely built yet */ 192 | L->ci = &L->base_ci; /* free the entire 'ci' list */ 193 | luaE_freeCI(L); 194 | lua_assert(L->nci == 0); 195 | luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ 196 | } 197 | 198 | 199 | /* 200 | ** Create registry table and its predefined values 201 | */ 202 | static void init_registry (lua_State *L, global_State *g) { 203 | TValue temp; 204 | /* create registry */ 205 | Table *registry = luaH_new(L); 206 | sethvalue(L, &g->l_registry, registry); 207 | luaH_resize(L, registry, LUA_RIDX_LAST, 0); 208 | /* registry[LUA_RIDX_MAINTHREAD] = L */ 209 | setthvalue(L, &temp, L); /* temp = L */ 210 | luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); 211 | /* registry[LUA_RIDX_GLOBALS] = table of globals */ 212 | sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ 213 | luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); 214 | } 215 | 216 | 217 | /* 218 | ** open parts of the state that may cause memory-allocation errors. 219 | ** ('g->version' != NULL flags that the state was completely build) 220 | */ 221 | static void f_luaopen (lua_State *L, void *ud) { 222 | global_State *g = G(L); 223 | UNUSED(ud); 224 | stack_init(L, L); /* init stack */ 225 | init_registry(L, g); 226 | luaS_init(L); 227 | luaT_init(L); 228 | luaX_init(L); 229 | g->gcrunning = 1; /* allow gc */ 230 | g->version = lua_version(NULL); 231 | luai_userstateopen(L); 232 | } 233 | 234 | 235 | /* 236 | ** preinitialize a thread with consistent values without allocating 237 | ** any memory (to avoid errors) 238 | */ 239 | static void preinit_thread (lua_State *L, global_State *g) { 240 | G(L) = g; 241 | L->stack = NULL; 242 | L->ci = NULL; 243 | L->nci = 0; 244 | L->stacksize = 0; 245 | L->twups = L; /* thread has no upvalues */ 246 | L->errorJmp = NULL; 247 | L->nCcalls = 0; 248 | L->hook = NULL; 249 | L->hookmask = 0; 250 | L->basehookcount = 0; 251 | L->allowhook = 1; 252 | resethookcount(L); 253 | L->openupval = NULL; 254 | L->nny = 1; 255 | L->status = LUA_OK; 256 | L->errfunc = 0; 257 | } 258 | 259 | 260 | static void close_state (lua_State *L) { 261 | global_State *g = G(L); 262 | luaF_close(L, L->stack); /* close all upvalues for this thread */ 263 | luaC_freeallobjects(L); /* collect all objects */ 264 | if (g->version) /* closing a fully built state? */ 265 | luai_userstateclose(L); 266 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); 267 | freestack(L); 268 | lua_assert(gettotalbytes(g) == sizeof(LG)); 269 | (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ 270 | } 271 | 272 | 273 | LUA_API lua_State *lua_newthread (lua_State *L) { 274 | global_State *g = G(L); 275 | lua_State *L1; 276 | lua_lock(L); 277 | luaC_checkGC(L); 278 | /* create new thread */ 279 | L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; 280 | L1->marked = luaC_white(g); 281 | L1->tt = LUA_TTHREAD; 282 | /* link it on list 'allgc' */ 283 | L1->next = g->allgc; 284 | g->allgc = obj2gco(L1); 285 | /* anchor it on L stack */ 286 | setthvalue2s(L, L->top, L1); 287 | api_incr_top(L); 288 | preinit_thread(L1, g); 289 | L1->hookmask = L->hookmask; 290 | L1->basehookcount = L->basehookcount; 291 | L1->hook = L->hook; 292 | resethookcount(L1); 293 | /* initialize L1 extra space */ 294 | memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), 295 | LUA_EXTRASPACE); 296 | luai_userstatethread(L, L1); 297 | stack_init(L1, L); /* init stack */ 298 | lua_unlock(L); 299 | return L1; 300 | } 301 | 302 | 303 | void luaE_freethread (lua_State *L, lua_State *L1) { 304 | LX *l = fromstate(L1); 305 | luaF_close(L1, L1->stack); /* close all upvalues for this thread */ 306 | lua_assert(L1->openupval == NULL); 307 | luai_userstatefree(L, L1); 308 | freestack(L1); 309 | luaM_free(L, l); 310 | } 311 | 312 | 313 | LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { 314 | int i; 315 | lua_State *L; 316 | global_State *g; 317 | LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); 318 | if (l == NULL) return NULL; 319 | L = &l->l.l; 320 | g = &l->g; 321 | L->tt = LUA_TTHREAD; 322 | g->currentwhite = bitmask(WHITE0BIT); 323 | L->marked = luaC_white(g); 324 | preinit_thread(L, g); 325 | g->allgc = obj2gco(L); /* by now, only object is the main thread */ 326 | L->next = NULL; 327 | g->frealloc = f; 328 | g->ud = ud; 329 | g->mainthread = L; 330 | g->seed = makeseed(L); 331 | g->gcrunning = 0; /* no GC while building state */ 332 | g->strt.size = g->strt.nuse = 0; 333 | g->strt.hash = NULL; 334 | setnilvalue(&g->l_registry); 335 | g->panic = NULL; 336 | g->version = NULL; 337 | g->gcstate = GCSpause; 338 | g->gckind = KGC_INC; 339 | g->gcemergency = 0; 340 | g->finobj = g->tobefnz = g->fixedgc = NULL; 341 | g->survival = g->old = g->reallyold = NULL; 342 | g->finobjsur = g->finobjold = g->finobjrold = NULL; 343 | g->sweepgc = NULL; 344 | g->gray = g->grayagain = NULL; 345 | g->weak = g->ephemeron = g->allweak = g->protogray = NULL; 346 | g->twups = NULL; 347 | g->totalbytes = sizeof(LG); 348 | g->GCdebt = 0; 349 | setgcparam(g->gcpause, LUAI_GCPAUSE); 350 | setgcparam(g->gcstepmul, LUAI_GCMUL); 351 | g->gcstepsize = LUAI_GCSTEPSIZE; 352 | setgcparam(g->genmajormul, LUAI_GENMAJORMUL); 353 | g->genminormul = LUAI_GENMINORMUL; 354 | for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; 355 | if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { 356 | /* memory allocation error: free partial state */ 357 | close_state(L); 358 | L = NULL; 359 | } 360 | return L; 361 | } 362 | 363 | 364 | LUA_API void lua_close (lua_State *L) { 365 | L = G(L)->mainthread; /* only the main thread can be closed */ 366 | lua_lock(L); 367 | close_state(L); 368 | } 369 | 370 | 371 | -------------------------------------------------------------------------------- /lstate.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lstate.h,v 2.156 2018/02/17 19:29:29 roberto Exp roberto $ 3 | ** Global State 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lstate_h 8 | #define lstate_h 9 | 10 | #include "lua.h" 11 | 12 | #include "lobject.h" 13 | #include "ltm.h" 14 | #include "lzio.h" 15 | 16 | 17 | /* 18 | 19 | ** Some notes about garbage-collected objects: All objects in Lua must 20 | ** be kept somehow accessible until being freed, so all objects always 21 | ** belong to one (and only one) of these lists, using field 'next' of 22 | ** the 'CommonHeader' for the link: 23 | ** 24 | ** 'allgc': all objects not marked for finalization; 25 | ** 'finobj': all objects marked for finalization; 26 | ** 'tobefnz': all objects ready to be finalized; 27 | ** 'fixedgc': all objects that are not to be collected (currently 28 | ** only small strings, such as reserved words). 29 | ** 30 | ** Moreover, there is another set of lists that control gray objects. 31 | ** These lists are linked by fields 'gclist'. (All objects that 32 | ** can become gray have such a field. The field is not the same 33 | ** in all objects, but it always has this name.) Any gray object 34 | ** must belong to one of these lists, and all objects in these lists 35 | ** must be gray: 36 | ** 37 | ** 'gray': regular gray objects, still waiting to be visited. 38 | ** 'grayagain': objects that must be revisited at the atomic phase. 39 | ** That includes 40 | ** - black objects got in a write barrier; 41 | ** - all kinds of weak tables during propagation phase; 42 | ** - all threads. 43 | ** 'weak': tables with weak values to be cleared; 44 | ** 'ephemeron': ephemeron tables with white->white entries; 45 | ** 'allweak': tables with weak keys and/or weak values to be cleared. 46 | ** There is also a list 'protogray' for prototypes that need to have 47 | ** their caches cleared. 48 | 49 | */ 50 | 51 | 52 | struct lua_longjmp; /* defined in ldo.c */ 53 | 54 | 55 | /* 56 | ** Atomic type (relative to signals) to better ensure that 'lua_sethook' 57 | ** is thread safe 58 | */ 59 | #if !defined(l_signalT) 60 | #include 61 | #define l_signalT sig_atomic_t 62 | #endif 63 | 64 | 65 | /* extra stack space to handle TM calls and some other extras */ 66 | #define EXTRA_STACK 5 67 | 68 | 69 | #define BASIC_STACK_SIZE (2*LUA_MINSTACK) 70 | 71 | 72 | /* kinds of Garbage Collection */ 73 | #define KGC_INC 0 /* incremental gc */ 74 | #define KGC_GEN 1 /* generational gc */ 75 | 76 | 77 | typedef struct stringtable { 78 | TString **hash; 79 | int nuse; /* number of elements */ 80 | int size; 81 | } stringtable; 82 | 83 | 84 | /* 85 | ** Information about a call. 86 | */ 87 | typedef struct CallInfo { 88 | StkId func; /* function index in the stack */ 89 | StkId top; /* top for this function */ 90 | struct CallInfo *previous, *next; /* dynamic call link */ 91 | union { 92 | struct { /* only for Lua functions */ 93 | const Instruction *savedpc; 94 | l_signalT trap; 95 | int nextraargs; /* # of extra arguments in vararg functions */ 96 | } l; 97 | struct { /* only for C functions */ 98 | lua_KFunction k; /* continuation in case of yields */ 99 | ptrdiff_t old_errfunc; 100 | lua_KContext ctx; /* context info. in case of yields */ 101 | } c; 102 | } u; 103 | union { 104 | int funcidx; /* called-function index */ 105 | int nyield; /* number of values yielded */ 106 | struct { /* info about transfered values (for call/return hooks) */ 107 | unsigned short fTransfer; /* offset of first value transfered */ 108 | unsigned short nTransfer; /* number of values transfered */ 109 | } transferinfo; 110 | } u2; 111 | short nresults; /* expected number of results from this function */ 112 | unsigned short callstatus; 113 | } CallInfo; 114 | 115 | 116 | /* 117 | ** Bits in CallInfo status 118 | */ 119 | #define CIST_OAH (1<<0) /* original value of 'allowhook' */ 120 | #define CIST_C (1<<1) /* call is running a C function */ 121 | #define CIST_HOOKED (1<<2) /* call is running a debug hook */ 122 | #define CIST_YPCALL (1<<3) /* call is a yieldable protected call */ 123 | #define CIST_TAIL (1<<4) /* call was tail called */ 124 | #define CIST_HOOKYIELD (1<<5) /* last hook called yielded */ 125 | #define CIST_LEQ (1<<6) /* using __lt for __le */ 126 | #define CIST_FIN (1<<7) /* call is running a finalizer */ 127 | #define CIST_TRAN (1<<8) /* 'ci' has transfer information */ 128 | 129 | /* active function is a Lua function */ 130 | #define isLua(ci) (!((ci)->callstatus & CIST_C)) 131 | 132 | /* call is running Lua code (not a hook) */ 133 | #define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED))) 134 | 135 | /* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ 136 | #define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) 137 | #define getoah(st) ((st) & CIST_OAH) 138 | 139 | 140 | /* 141 | ** 'global state', shared by all threads of this state 142 | */ 143 | typedef struct global_State { 144 | lua_Alloc frealloc; /* function to reallocate memory */ 145 | void *ud; /* auxiliary data to 'frealloc' */ 146 | l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ 147 | l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ 148 | lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ 149 | stringtable strt; /* hash table for strings */ 150 | TValue l_registry; 151 | unsigned int seed; /* randomized seed for hashes */ 152 | lu_byte currentwhite; 153 | lu_byte gcstate; /* state of garbage collector */ 154 | lu_byte gckind; /* kind of GC running */ 155 | lu_byte genminormul; /* control for minor generational collections */ 156 | lu_byte genmajormul; /* control for major generational collections */ 157 | lu_byte gcrunning; /* true if GC is running */ 158 | lu_byte gcemergency; /* true if this is an emergency collection */ 159 | lu_byte gcpause; /* size of pause between successive GCs */ 160 | lu_byte gcstepmul; /* GC "speed" */ 161 | lu_byte gcstepsize; /* (log2 of) GC granularity */ 162 | GCObject *allgc; /* list of all collectable objects */ 163 | GCObject **sweepgc; /* current position of sweep in list */ 164 | GCObject *finobj; /* list of collectable objects with finalizers */ 165 | GCObject *gray; /* list of gray objects */ 166 | GCObject *grayagain; /* list of objects to be traversed atomically */ 167 | GCObject *weak; /* list of tables with weak values */ 168 | GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ 169 | GCObject *allweak; /* list of all-weak tables */ 170 | GCObject *protogray; /* list of prototypes with "new" caches */ 171 | GCObject *tobefnz; /* list of userdata to be GC */ 172 | GCObject *fixedgc; /* list of objects not to be collected */ 173 | /* fields for generational collector */ 174 | GCObject *survival; /* start of objects that survived one GC cycle */ 175 | GCObject *old; /* start of old objects */ 176 | GCObject *reallyold; /* old objects with more than one cycle */ 177 | GCObject *finobjsur; /* list of survival objects with finalizers */ 178 | GCObject *finobjold; /* list of old objects with finalizers */ 179 | GCObject *finobjrold; /* list of really old objects with finalizers */ 180 | struct lua_State *twups; /* list of threads with open upvalues */ 181 | lua_CFunction panic; /* to be called in unprotected errors */ 182 | struct lua_State *mainthread; 183 | const lua_Number *version; /* pointer to version number */ 184 | TString *memerrmsg; /* message for memory-allocation errors */ 185 | TString *tmname[TM_N]; /* array with tag-method names */ 186 | struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ 187 | TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ 188 | } global_State; 189 | 190 | 191 | /* 192 | ** 'per thread' state 193 | */ 194 | struct lua_State { 195 | CommonHeader; 196 | unsigned short nci; /* number of items in 'ci' list */ 197 | lu_byte status; 198 | StkId top; /* first free slot in the stack */ 199 | global_State *l_G; 200 | CallInfo *ci; /* call info for current function */ 201 | const Instruction *oldpc; /* last pc traced */ 202 | StkId stack_last; /* last free slot in the stack */ 203 | StkId stack; /* stack base */ 204 | UpVal *openupval; /* list of open upvalues in this stack */ 205 | GCObject *gclist; 206 | struct lua_State *twups; /* list of threads with open upvalues */ 207 | struct lua_longjmp *errorJmp; /* current error recover point */ 208 | CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ 209 | volatile lua_Hook hook; 210 | ptrdiff_t errfunc; /* current error handling function (stack index) */ 211 | int stacksize; 212 | int basehookcount; 213 | int hookcount; 214 | unsigned short nny; /* number of non-yieldable calls in stack */ 215 | unsigned short nCcalls; /* number of nested C calls */ 216 | l_signalT hookmask; 217 | lu_byte allowhook; 218 | }; 219 | 220 | 221 | #define G(L) (L->l_G) 222 | 223 | 224 | /* 225 | ** Union of all collectable objects (only for conversions) 226 | */ 227 | union GCUnion { 228 | GCObject gc; /* common header */ 229 | struct TString ts; 230 | struct Udata u; 231 | union Closure cl; 232 | struct Table h; 233 | struct Proto p; 234 | struct lua_State th; /* thread */ 235 | struct UpVal upv; 236 | }; 237 | 238 | 239 | #define cast_u(o) cast(union GCUnion *, (o)) 240 | 241 | /* macros to convert a GCObject into a specific value */ 242 | #define gco2ts(o) \ 243 | check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) 244 | #define gco2u(o) check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u)) 245 | #define gco2lcl(o) check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l)) 246 | #define gco2ccl(o) check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c)) 247 | #define gco2cl(o) \ 248 | check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) 249 | #define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) 250 | #define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) 251 | #define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) 252 | #define gco2upv(o) check_exp((o)->tt == LUA_TUPVAL, &((cast_u(o))->upv)) 253 | 254 | 255 | /* 256 | ** macro to convert a Lua object into a GCObject 257 | ** (The access to 'tt' tries to ensure that 'v' is actually a Lua object.) 258 | */ 259 | #define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc)) 260 | 261 | 262 | /* actual number of total bytes allocated */ 263 | #define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) 264 | 265 | LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); 266 | LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); 267 | LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); 268 | LUAI_FUNC void luaE_freeCI (lua_State *L); 269 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); 270 | LUAI_FUNC void luaE_incCcalls (lua_State *L); 271 | 272 | 273 | #endif 274 | 275 | -------------------------------------------------------------------------------- /lstring.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lstring.c,v 2.64 2018/02/15 18:06:24 roberto Exp roberto $ 3 | ** String table (keeps all strings handled by Lua) 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lstring_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "ldebug.h" 18 | #include "ldo.h" 19 | #include "lmem.h" 20 | #include "lobject.h" 21 | #include "lstate.h" 22 | #include "lstring.h" 23 | 24 | 25 | /* 26 | ** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to 27 | ** compute its hash 28 | */ 29 | #if !defined(LUAI_HASHLIMIT) 30 | #define LUAI_HASHLIMIT 5 31 | #endif 32 | 33 | 34 | 35 | /* 36 | ** Maximum size for string table. 37 | */ 38 | #define MAXSTRTB cast_int(luaM_limitN(MAX_INT, TString*)) 39 | 40 | 41 | /* 42 | ** equality for long strings 43 | */ 44 | int luaS_eqlngstr (TString *a, TString *b) { 45 | size_t len = a->u.lnglen; 46 | lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); 47 | return (a == b) || /* same instance or... */ 48 | ((len == b->u.lnglen) && /* equal length and ... */ 49 | (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ 50 | } 51 | 52 | 53 | unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { 54 | unsigned int h = seed ^ cast_uint(l); 55 | size_t step = (l >> LUAI_HASHLIMIT) + 1; 56 | for (; l >= step; l -= step) 57 | h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); 58 | return h; 59 | } 60 | 61 | 62 | unsigned int luaS_hashlongstr (TString *ts) { 63 | lua_assert(ts->tt == LUA_TLNGSTR); 64 | if (ts->extra == 0) { /* no hash? */ 65 | ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash); 66 | ts->extra = 1; /* now it has its hash */ 67 | } 68 | return ts->hash; 69 | } 70 | 71 | 72 | static void tablerehash (TString **vect, int osize, int nsize) { 73 | int i; 74 | for (i = osize; i < nsize; i++) /* clear new elements */ 75 | vect[i] = NULL; 76 | for (i = 0; i < osize; i++) { /* rehash old part of the array */ 77 | TString *p = vect[i]; 78 | vect[i] = NULL; 79 | while (p) { /* for each string in the list */ 80 | TString *hnext = p->u.hnext; /* save next */ 81 | unsigned int h = lmod(p->hash, nsize); /* new position */ 82 | p->u.hnext = vect[h]; /* chain it into array */ 83 | vect[h] = p; 84 | p = hnext; 85 | } 86 | } 87 | } 88 | 89 | 90 | /* 91 | ** Resize the string table. If allocation fails, keep the current size. 92 | ** (This can degrade performance, but any non-zero size should work 93 | ** correctly.) 94 | */ 95 | void luaS_resize (lua_State *L, int nsize) { 96 | stringtable *tb = &G(L)->strt; 97 | int osize = tb->size; 98 | TString **newvect; 99 | if (nsize < osize) /* shrinking table? */ 100 | tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ 101 | newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); 102 | if (newvect == NULL) { /* reallocation failed? */ 103 | if (nsize < osize) /* was it shrinking table? */ 104 | tablerehash(tb->hash, nsize, osize); /* restore to original size */ 105 | /* leave table as it was */ 106 | } 107 | else { /* allocation succeeded */ 108 | tb->hash = newvect; 109 | tb->size = nsize; 110 | if (nsize > osize) 111 | tablerehash(newvect, osize, nsize); /* rehash for new size */ 112 | } 113 | } 114 | 115 | 116 | /* 117 | ** Clear API string cache. (Entries cannot be empty, so fill them with 118 | ** a non-collectable string.) 119 | */ 120 | void luaS_clearcache (global_State *g) { 121 | int i, j; 122 | for (i = 0; i < STRCACHE_N; i++) 123 | for (j = 0; j < STRCACHE_M; j++) { 124 | if (iswhite(g->strcache[i][j])) /* will entry be collected? */ 125 | g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ 126 | } 127 | } 128 | 129 | 130 | /* 131 | ** Initialize the string table and the string cache 132 | */ 133 | void luaS_init (lua_State *L) { 134 | global_State *g = G(L); 135 | int i, j; 136 | stringtable *tb = &G(L)->strt; 137 | tb->hash = luaM_newvector(L, MINSTRTABSIZE, TString*); 138 | tablerehash(tb->hash, 0, MINSTRTABSIZE); /* clear array */ 139 | tb->size = MINSTRTABSIZE; 140 | /* pre-create memory-error message */ 141 | g->memerrmsg = luaS_newliteral(L, MEMERRMSG); 142 | luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ 143 | for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ 144 | for (j = 0; j < STRCACHE_M; j++) 145 | g->strcache[i][j] = g->memerrmsg; 146 | } 147 | 148 | 149 | 150 | /* 151 | ** creates a new string object 152 | */ 153 | static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { 154 | TString *ts; 155 | GCObject *o; 156 | size_t totalsize; /* total size of TString object */ 157 | totalsize = sizelstring(l); 158 | o = luaC_newobj(L, tag, totalsize); 159 | ts = gco2ts(o); 160 | ts->hash = h; 161 | ts->extra = 0; 162 | getstr(ts)[l] = '\0'; /* ending 0 */ 163 | return ts; 164 | } 165 | 166 | 167 | TString *luaS_createlngstrobj (lua_State *L, size_t l) { 168 | TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed); 169 | ts->u.lnglen = l; 170 | return ts; 171 | } 172 | 173 | 174 | void luaS_remove (lua_State *L, TString *ts) { 175 | stringtable *tb = &G(L)->strt; 176 | TString **p = &tb->hash[lmod(ts->hash, tb->size)]; 177 | while (*p != ts) /* find previous element */ 178 | p = &(*p)->u.hnext; 179 | *p = (*p)->u.hnext; /* remove element from its list */ 180 | tb->nuse--; 181 | } 182 | 183 | 184 | static void growstrtab (lua_State *L, stringtable *tb) { 185 | if (tb->nuse == MAX_INT) { /* too many strings? */ 186 | luaC_fullgc(L, 1); /* try to free some... */ 187 | if (tb->nuse == MAX_INT) /* still too many? */ 188 | luaM_error(L); /* cannot even create a message... */ 189 | } 190 | if (tb->size <= MAXSTRTB / 2) /* can grow string table? */ 191 | luaS_resize(L, tb->size * 2); 192 | } 193 | 194 | 195 | /* 196 | ** Checks whether short string exists and reuses it or creates a new one. 197 | */ 198 | static TString *internshrstr (lua_State *L, const char *str, size_t l) { 199 | TString *ts; 200 | global_State *g = G(L); 201 | stringtable *tb = &g->strt; 202 | unsigned int h = luaS_hash(str, l, g->seed); 203 | TString **list = &tb->hash[lmod(h, tb->size)]; 204 | lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ 205 | for (ts = *list; ts != NULL; ts = ts->u.hnext) { 206 | if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { 207 | /* found! */ 208 | if (isdead(g, ts)) /* dead (but not collected yet)? */ 209 | changewhite(ts); /* resurrect it */ 210 | return ts; 211 | } 212 | } 213 | /* else must create a new string */ 214 | if (tb->nuse >= tb->size) { /* need to grow string table? */ 215 | growstrtab(L, tb); 216 | list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ 217 | } 218 | ts = createstrobj(L, l, LUA_TSHRSTR, h); 219 | memcpy(getstr(ts), str, l * sizeof(char)); 220 | ts->shrlen = cast_byte(l); 221 | ts->u.hnext = *list; 222 | *list = ts; 223 | tb->nuse++; 224 | return ts; 225 | } 226 | 227 | 228 | /* 229 | ** new string (with explicit length) 230 | */ 231 | TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { 232 | if (l <= LUAI_MAXSHORTLEN) /* short string? */ 233 | return internshrstr(L, str, l); 234 | else { 235 | TString *ts; 236 | if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char)) 237 | luaM_toobig(L); 238 | ts = luaS_createlngstrobj(L, l); 239 | memcpy(getstr(ts), str, l * sizeof(char)); 240 | return ts; 241 | } 242 | } 243 | 244 | 245 | /* 246 | ** Create or reuse a zero-terminated string, first checking in the 247 | ** cache (using the string address as a key). The cache can contain 248 | ** only zero-terminated strings, so it is safe to use 'strcmp' to 249 | ** check hits. 250 | */ 251 | TString *luaS_new (lua_State *L, const char *str) { 252 | unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ 253 | int j; 254 | TString **p = G(L)->strcache[i]; 255 | for (j = 0; j < STRCACHE_M; j++) { 256 | if (strcmp(str, getstr(p[j])) == 0) /* hit? */ 257 | return p[j]; /* that is it */ 258 | } 259 | /* normal route */ 260 | for (j = STRCACHE_M - 1; j > 0; j--) 261 | p[j] = p[j - 1]; /* move out last element */ 262 | /* new element is first in the list */ 263 | p[0] = luaS_newlstr(L, str, strlen(str)); 264 | return p[0]; 265 | } 266 | 267 | 268 | Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) { 269 | Udata *u; 270 | int i; 271 | GCObject *o; 272 | if (s > MAX_SIZE - udatamemoffset(nuvalue)) 273 | luaM_toobig(L); 274 | o = luaC_newobj(L, LUA_TUSERDATA, sizeudata(nuvalue, s)); 275 | u = gco2u(o); 276 | u->len = s; 277 | u->nuvalue = nuvalue; 278 | u->metatable = NULL; 279 | for (i = 0; i < nuvalue; i++) 280 | setnilvalue(&u->uv[i].uv); 281 | return u; 282 | } 283 | 284 | -------------------------------------------------------------------------------- /lstring.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lstring.h,v 1.63 2017/11/23 19:29:04 roberto Exp roberto $ 3 | ** String table (keep all strings handled by Lua) 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lstring_h 8 | #define lstring_h 9 | 10 | #include "lgc.h" 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | 14 | 15 | /* 16 | ** Memory-allocation error message must be preallocated (it cannot 17 | ** be created after memory is exhausted) 18 | */ 19 | #define MEMERRMSG "not enough memory" 20 | 21 | 22 | #define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) 23 | 24 | #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ 25 | (sizeof(s)/sizeof(char))-1)) 26 | 27 | 28 | /* 29 | ** test whether a string is a reserved word 30 | */ 31 | #define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0) 32 | 33 | 34 | /* 35 | ** equality for short strings, which are always internalized 36 | */ 37 | #define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) 38 | 39 | 40 | LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); 41 | LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); 42 | LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); 43 | LUAI_FUNC void luaS_resize (lua_State *L, int newsize); 44 | LUAI_FUNC void luaS_clearcache (global_State *g); 45 | LUAI_FUNC void luaS_init (lua_State *L); 46 | LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); 47 | LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue); 48 | LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); 49 | LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); 50 | LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /ltable.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltable.h,v 2.25 2017/06/09 16:48:44 roberto Exp roberto $ 3 | ** Lua tables (hash) 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ltable_h 8 | #define ltable_h 9 | 10 | #include "lobject.h" 11 | 12 | 13 | #define gnode(t,i) (&(t)->node[i]) 14 | #define gval(n) (&(n)->i_val) 15 | #define gnext(n) ((n)->u.next) 16 | 17 | 18 | #define invalidateTMcache(t) ((t)->flags = 0) 19 | 20 | 21 | /* true when 't' is using 'dummynode' as its hash part */ 22 | #define isdummy(t) ((t)->lastfree == NULL) 23 | 24 | #define luaH_emptyobject (&luaH_emptyobject_) 25 | 26 | 27 | /* allocated size for hash nodes */ 28 | #define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) 29 | 30 | 31 | /* returns the Node, given the value of a table entry */ 32 | #define nodefromval(v) cast(Node *, (v)) 33 | 34 | 35 | LUAI_DDEC const TValue luaH_emptyobject_; 36 | 37 | 38 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); 39 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, 40 | TValue *value); 41 | LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); 42 | LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); 43 | LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); 44 | LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); 45 | LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); 46 | LUAI_FUNC Table *luaH_new (lua_State *L); 47 | LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, 48 | unsigned int nhsize); 49 | LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); 50 | LUAI_FUNC void luaH_free (lua_State *L, Table *t); 51 | LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); 52 | LUAI_FUNC lua_Unsigned luaH_getn (Table *t); 53 | 54 | 55 | #if defined(LUA_DEBUG) 56 | LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); 57 | LUAI_FUNC int luaH_isdummy (const Table *t); 58 | #endif 59 | 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /ltests.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltests.h,v 2.55 2017/12/18 13:01:49 roberto Exp roberto $ 3 | ** Internal Header for Debugging of the Lua Implementation 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ltests_h 8 | #define ltests_h 9 | 10 | 11 | #include 12 | #include 13 | 14 | /* test Lua with compatibility code */ 15 | #define LUA_COMPAT_MATHLIB 16 | 17 | 18 | #define LUA_DEBUG 19 | 20 | 21 | /* turn on assertions */ 22 | #undef NDEBUG 23 | #include 24 | #define lua_assert(c) assert(c) 25 | 26 | 27 | /* compiled with -O0, Lua uses a lot of C stack space... */ 28 | #undef LUAI_MAXCCALLS 29 | #define LUAI_MAXCCALLS 200 30 | 31 | /* to avoid warnings, and to make sure value is really unused */ 32 | #define UNUSED(x) (x=0, (void)(x)) 33 | 34 | 35 | /* test for sizes in 'l_sprintf' (make sure whole buffer is available) */ 36 | #undef l_sprintf 37 | #if !defined(LUA_USE_C89) 38 | #define l_sprintf(s,sz,f,i) (memset(s,0xAB,sz), snprintf(s,sz,f,i)) 39 | #else 40 | #define l_sprintf(s,sz,f,i) (memset(s,0xAB,sz), sprintf(s,f,i)) 41 | #endif 42 | 43 | 44 | /* memory-allocator control variables */ 45 | typedef struct Memcontrol { 46 | unsigned long numblocks; 47 | unsigned long total; 48 | unsigned long maxmem; 49 | unsigned long memlimit; 50 | unsigned long countlimit; 51 | unsigned long objcount[LUA_NUMTAGS]; 52 | } Memcontrol; 53 | 54 | LUA_API Memcontrol l_memcontrol; 55 | 56 | 57 | /* 58 | ** generic variable for debug tricks 59 | */ 60 | extern void *l_Trick; 61 | 62 | 63 | 64 | /* 65 | ** Function to traverse and check all memory used by Lua 66 | */ 67 | int lua_checkmemory (lua_State *L); 68 | 69 | 70 | /* test for lock/unlock */ 71 | 72 | struct L_EXTRA { int lock; int *plock; }; 73 | #undef LUA_EXTRASPACE 74 | #define LUA_EXTRASPACE sizeof(struct L_EXTRA) 75 | #define getlock(l) cast(struct L_EXTRA*, lua_getextraspace(l)) 76 | #define luai_userstateopen(l) \ 77 | (getlock(l)->lock = 0, getlock(l)->plock = &(getlock(l)->lock)) 78 | #define luai_userstateclose(l) \ 79 | lua_assert(getlock(l)->lock == 1 && getlock(l)->plock == &(getlock(l)->lock)) 80 | #define luai_userstatethread(l,l1) \ 81 | lua_assert(getlock(l1)->plock == getlock(l)->plock) 82 | #define luai_userstatefree(l,l1) \ 83 | lua_assert(getlock(l)->plock == getlock(l1)->plock) 84 | #define lua_lock(l) lua_assert((*getlock(l)->plock)++ == 0) 85 | #define lua_unlock(l) lua_assert(--(*getlock(l)->plock) == 0) 86 | 87 | 88 | 89 | LUA_API int luaB_opentests (lua_State *L); 90 | 91 | LUA_API void *debug_realloc (void *ud, void *block, 92 | size_t osize, size_t nsize); 93 | 94 | #if defined(lua_c) 95 | #define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol) 96 | #define luaL_openlibs(L) \ 97 | { (luaL_openlibs)(L); \ 98 | luaL_requiref(L, "T", luaB_opentests, 1); \ 99 | lua_pop(L, 1); } 100 | #endif 101 | 102 | 103 | 104 | /* change some sizes to give some bugs a chance */ 105 | 106 | #undef LUAL_BUFFERSIZE 107 | #define LUAL_BUFFERSIZE 23 108 | #define MINSTRTABSIZE 2 109 | #define MAXINDEXRK 1 110 | #define MAXIWTHABS 3 111 | 112 | 113 | /* make stack-overflow tests run faster */ 114 | #undef LUAI_MAXSTACK 115 | #define LUAI_MAXSTACK 50000 116 | 117 | 118 | #undef LUAI_USER_ALIGNMENT_T 119 | #define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; } 120 | 121 | 122 | #define STRCACHE_N 23 123 | #define STRCACHE_M 5 124 | 125 | #endif 126 | 127 | -------------------------------------------------------------------------------- /ltm.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltm.c,v 2.65 2018/02/26 14:16:05 roberto Exp roberto $ 3 | ** Tag methods 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define ltm_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "ldebug.h" 18 | #include "ldo.h" 19 | #include "lgc.h" 20 | #include "lobject.h" 21 | #include "lstate.h" 22 | #include "lstring.h" 23 | #include "ltable.h" 24 | #include "ltm.h" 25 | #include "lvm.h" 26 | 27 | 28 | static const char udatatypename[] = "userdata"; 29 | 30 | LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { 31 | "no value", 32 | "nil", "boolean", udatatypename, "number", 33 | "string", "table", "function", udatatypename, "thread", 34 | "upvalue", "proto" /* these last cases are used for tests only */ 35 | }; 36 | 37 | 38 | void luaT_init (lua_State *L) { 39 | static const char *const luaT_eventname[] = { /* ORDER TM */ 40 | "__index", "__newindex", 41 | "__undef", "__isdef", 42 | "__gc", "__mode", "__len", "__eq", 43 | "__add", "__sub", "__mul", "__mod", "__pow", 44 | "__div", "__idiv", 45 | "__band", "__bor", "__bxor", "__shl", "__shr", 46 | "__unm", "__bnot", "__lt", "__le", 47 | "__concat", "__call" 48 | }; 49 | int i; 50 | for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); 52 | luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ 53 | } 54 | } 55 | 56 | 57 | /* 58 | ** function to be used with macro "fasttm": optimized for absence of 59 | ** tag methods 60 | */ 61 | const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { 62 | const TValue *tm = luaH_getshortstr(events, ename); 63 | lua_assert(event <= TM_EQ); 64 | if (notm(tm)) { /* no tag method? */ 65 | events->flags |= cast_byte(1u<metatable; 77 | break; 78 | case LUA_TUSERDATA: 79 | mt = uvalue(o)->metatable; 80 | break; 81 | default: 82 | mt = G(L)->mt[ttype(o)]; 83 | } 84 | return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); 85 | } 86 | 87 | 88 | /* 89 | ** Return the name of the type of an object. For tables and userdata 90 | ** with metatable, use their '__name' metafield, if present. 91 | */ 92 | const char *luaT_objtypename (lua_State *L, const TValue *o) { 93 | Table *mt; 94 | if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || 95 | (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { 96 | const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name")); 97 | if (ttisstring(name)) /* is '__name' a string? */ 98 | return getstr(tsvalue(name)); /* use it as type name */ 99 | } 100 | return ttypename(ttype(o)); /* else use standard type name */ 101 | } 102 | 103 | 104 | void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, 105 | const TValue *p2, const TValue *p3) { 106 | StkId func = L->top; 107 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ 108 | setobj2s(L, func + 1, p1); /* 1st argument */ 109 | setobj2s(L, func + 2, p2); /* 2nd argument */ 110 | setobj2s(L, func + 3, p3); /* 3rd argument */ 111 | L->top = func + 4; 112 | /* metamethod may yield only when called from Lua code */ 113 | if (isLuacode(L->ci)) 114 | luaD_call(L, func, 0); 115 | else 116 | luaD_callnoyield(L, func, 0); 117 | } 118 | 119 | 120 | void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, 121 | const TValue *p2, StkId res) { 122 | ptrdiff_t result = savestack(L, res); 123 | StkId func = L->top; 124 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ 125 | setobj2s(L, func + 1, p1); /* 1st argument */ 126 | setobj2s(L, func + 2, p2); /* 2nd argument */ 127 | L->top += 3; 128 | /* metamethod may yield only when called from Lua code */ 129 | if (isLuacode(L->ci)) 130 | luaD_call(L, func, 1); 131 | else 132 | luaD_callnoyield(L, func, 1); 133 | res = restorestack(L, result); 134 | setobjs2s(L, res, --L->top); /* move result to its place */ 135 | } 136 | 137 | 138 | static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, 139 | StkId res, TMS event) { 140 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ 141 | if (notm(tm)) 142 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ 143 | if (notm(tm)) return 0; 144 | luaT_callTMres(L, tm, p1, p2, res); 145 | return 1; 146 | } 147 | 148 | 149 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, 150 | StkId res, TMS event) { 151 | if (!callbinTM(L, p1, p2, res, event)) { 152 | switch (event) { 153 | case TM_CONCAT: 154 | luaG_concaterror(L, p1, p2); 155 | /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ 156 | case TM_BAND: case TM_BOR: case TM_BXOR: 157 | case TM_SHL: case TM_SHR: case TM_BNOT: { 158 | if (ttisnumber(p1) && ttisnumber(p2)) 159 | luaG_tointerror(L, p1, p2); 160 | else 161 | luaG_opinterror(L, p1, p2, "perform bitwise operation on"); 162 | } 163 | /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ 164 | default: 165 | luaG_opinterror(L, p1, p2, "perform arithmetic on"); 166 | } 167 | } 168 | } 169 | 170 | 171 | void luaT_trybinassocTM (lua_State *L, const TValue *p1, const TValue *p2, 172 | StkId res, int inv, TMS event) { 173 | if (inv) 174 | luaT_trybinTM(L, p2, p1, res, event); 175 | else 176 | luaT_trybinTM(L, p1, p2, res, event); 177 | } 178 | 179 | 180 | void luaT_trybiniTM (lua_State *L, const TValue *p1, int i2, 181 | int inv, StkId res, TMS event) { 182 | TValue aux; 183 | setivalue(&aux, i2); 184 | luaT_trybinassocTM(L, p1, &aux, res, inv, event); 185 | } 186 | 187 | 188 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, 189 | TMS event) { 190 | if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ 191 | return !l_isfalse(s2v(L->top)); 192 | else if (event == TM_LE) { 193 | /* try '!(p2 < p1)' for '(p1 <= p2)' */ 194 | L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ 195 | if (callbinTM(L, p2, p1, L->top, TM_LT)) { 196 | L->ci->callstatus ^= CIST_LEQ; /* clear mark */ 197 | return l_isfalse(s2v(L->top)); 198 | } 199 | /* else error will remove this 'ci'; no need to clear mark */ 200 | } 201 | luaG_ordererror(L, p1, p2); /* no metamethod found */ 202 | return 0; /* to avoid warnings */ 203 | } 204 | 205 | 206 | int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, 207 | int inv, TMS event) { 208 | TValue aux; const TValue *p2; 209 | setivalue(&aux, v2); 210 | if (inv) { /* arguments were exchanged? */ 211 | p2 = p1; p1 = &aux; /* correct them */ 212 | } 213 | else 214 | p2 = &aux; 215 | return luaT_callorderTM(L, p1, p2, event); 216 | } 217 | 218 | 219 | void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci, 220 | Proto *p) { 221 | int i; 222 | int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */ 223 | int nextra = actual - nfixparams; /* number of extra arguments */ 224 | ci->u.l.nextraargs = nextra; 225 | checkstackGC(L, p->maxstacksize + 1); 226 | /* copy function to the top of the stack */ 227 | setobjs2s(L, L->top++, ci->func); 228 | /* move fixed parameters to the top of the stack */ 229 | for (i = 1; i <= nfixparams; i++) { 230 | setobjs2s(L, L->top++, ci->func + i); 231 | setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */ 232 | } 233 | ci->func += actual + 1; 234 | ci->top += actual + 1; 235 | lua_assert(L->top <= ci->top && ci->top <= L->stack_last); 236 | } 237 | 238 | 239 | void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) { 240 | int i; 241 | int nextra = ci->u.l.nextraargs; 242 | if (wanted < 0) { 243 | wanted = nextra; /* get all extra arguments available */ 244 | checkstackp(L, nextra, where); /* ensure stack space */ 245 | L->top = where + nextra; /* next instruction will need top */ 246 | } 247 | for (i = 0; i < wanted && i < nextra; i++) 248 | setobjs2s(L, where + i, ci->func - nextra + i); 249 | for (; i < wanted; i++) /* complete required results with nil */ 250 | setnilvalue(s2v(where + i)); 251 | } 252 | 253 | 254 | int luaT_keydef (lua_State *L, TValue *obj, TValue *key, int remove) { 255 | const TValue *tm; 256 | TMS event = remove ? TM_UNDEF : TM_ISDEF; 257 | if (!ttistable(obj)) { /* not a table? */ 258 | tm = luaT_gettmbyobj(L, obj, event); /* get its metamethod */ 259 | if (notm(tm)) { /* no metamethod? */ 260 | const char *msg = remove ? "remove key from" : "check key from"; 261 | luaG_typeerror(L, obj, msg); /* error */ 262 | } 263 | /* else will call metamethod 'tm' */ 264 | } 265 | else { /* 'obj' is a table */ 266 | Table *t = hvalue(obj); 267 | tm = fasttm(L, t->metatable, event); 268 | if (tm == NULL) { /* no metamethod? */ 269 | const TValue *val = luaH_get(t, key); /* get entry */ 270 | int res = !isempty(val); /* true if entry is not empty */ 271 | if (remove && res) { /* key is present and should be removed? */ 272 | setempty(cast(TValue*, val)); /* remove it */ 273 | /* decrement array size */ 274 | t->sizeused--; 275 | } 276 | return res; 277 | } 278 | /* else will call metamethod 'tm' */ 279 | } 280 | luaT_callTMres(L, tm, obj, key, L->top); 281 | return !l_isfalse(s2v(L->top)); 282 | } 283 | -------------------------------------------------------------------------------- /ltm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltm.h,v 2.33 2018/02/23 13:13:31 roberto Exp roberto $ 3 | ** Tag methods 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ltm_h 8 | #define ltm_h 9 | 10 | 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | 14 | 15 | /* 16 | * WARNING: if you change the order of this enumeration, 17 | * grep "ORDER TM" and "ORDER OP" 18 | */ 19 | typedef enum { 20 | TM_INDEX, 21 | TM_NEWINDEX, 22 | TM_UNDEF, 23 | TM_ISDEF, 24 | TM_GC, 25 | TM_MODE, 26 | TM_LEN, 27 | TM_EQ, /* last tag method with fast access */ 28 | TM_ADD, 29 | TM_SUB, 30 | TM_MUL, 31 | TM_MOD, 32 | TM_POW, 33 | TM_DIV, 34 | TM_IDIV, 35 | TM_BAND, 36 | TM_BOR, 37 | TM_BXOR, 38 | TM_SHL, 39 | TM_SHR, 40 | TM_UNM, 41 | TM_BNOT, 42 | TM_LT, 43 | TM_LE, 44 | TM_CONCAT, 45 | TM_CALL, 46 | TM_N /* number of elements in the enum */ 47 | } TMS; 48 | 49 | 50 | /* 51 | ** Test whether there is no tagmethod. 52 | ** (Because tagmethods use raw accesses, the result may be an "empty" nil.) 53 | */ 54 | #define notm(tm) ttisnilorempty(tm) 55 | 56 | 57 | #define gfasttm(g,et,e) ((et) == NULL ? NULL : \ 58 | ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) 59 | 60 | #define fasttm(l,et,e) gfasttm(G(l), et, e) 61 | 62 | #define ttypename(x) luaT_typenames_[(x) + 1] 63 | 64 | LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; 65 | 66 | 67 | LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o); 68 | 69 | LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); 70 | LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, 71 | TMS event); 72 | LUAI_FUNC void luaT_init (lua_State *L); 73 | 74 | LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, 75 | const TValue *p2, const TValue *p3); 76 | LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f, 77 | const TValue *p1, const TValue *p2, StkId p3); 78 | LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, 79 | StkId res, TMS event); 80 | LUAI_FUNC void luaT_trybinassocTM (lua_State *L, const TValue *p1, 81 | const TValue *p2, StkId res, int inv, TMS event); 82 | LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, int i2, 83 | int inv, StkId res, TMS event); 84 | LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, 85 | const TValue *p2, TMS event); 86 | LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, 87 | int inv, TMS event); 88 | 89 | LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, 90 | struct CallInfo *ci, Proto *p); 91 | LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, 92 | StkId where, int wanted); 93 | 94 | LUAI_FUNC int luaT_keydef (lua_State *L, TValue *obj, TValue *key, int remove); 95 | 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /lualib.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lualib.h,v 1.45 2017/01/12 17:14:26 roberto Exp roberto $ 3 | ** Lua standard libraries 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lualib_h 9 | #define lualib_h 10 | 11 | #include "lua.h" 12 | 13 | 14 | /* version suffix for environment variable names */ 15 | #define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR 16 | 17 | 18 | LUAMOD_API int (luaopen_base) (lua_State *L); 19 | 20 | #define LUA_COLIBNAME "coroutine" 21 | LUAMOD_API int (luaopen_coroutine) (lua_State *L); 22 | 23 | #define LUA_TABLIBNAME "table" 24 | LUAMOD_API int (luaopen_table) (lua_State *L); 25 | 26 | #define LUA_IOLIBNAME "io" 27 | LUAMOD_API int (luaopen_io) (lua_State *L); 28 | 29 | #define LUA_OSLIBNAME "os" 30 | LUAMOD_API int (luaopen_os) (lua_State *L); 31 | 32 | #define LUA_STRLIBNAME "string" 33 | LUAMOD_API int (luaopen_string) (lua_State *L); 34 | 35 | #define LUA_UTF8LIBNAME "utf8" 36 | LUAMOD_API int (luaopen_utf8) (lua_State *L); 37 | 38 | #define LUA_MATHLIBNAME "math" 39 | LUAMOD_API int (luaopen_math) (lua_State *L); 40 | 41 | #define LUA_DBLIBNAME "debug" 42 | LUAMOD_API int (luaopen_debug) (lua_State *L); 43 | 44 | #define LUA_LOADLIBNAME "package" 45 | LUAMOD_API int (luaopen_package) (lua_State *L); 46 | 47 | 48 | /* open all previous libraries */ 49 | LUALIB_API void (luaL_openlibs) (lua_State *L); 50 | 51 | 52 | 53 | #if !defined(lua_assert) 54 | #define lua_assert(x) ((void)0) 55 | #endif 56 | 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /lundump.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lundump.c,v 2.48 2017/11/28 11:19:07 roberto Exp roberto $ 3 | ** load precompiled Lua chunks 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lundump_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "ldebug.h" 18 | #include "ldo.h" 19 | #include "lfunc.h" 20 | #include "lmem.h" 21 | #include "lobject.h" 22 | #include "lstring.h" 23 | #include "lundump.h" 24 | #include "lzio.h" 25 | 26 | 27 | #if !defined(luai_verifycode) 28 | #define luai_verifycode(L,b,f) /* empty */ 29 | #endif 30 | 31 | 32 | typedef struct { 33 | lua_State *L; 34 | ZIO *Z; 35 | const char *name; 36 | } LoadState; 37 | 38 | 39 | static l_noret error(LoadState *S, const char *why) { 40 | luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why); 41 | luaD_throw(S->L, LUA_ERRSYNTAX); 42 | } 43 | 44 | 45 | /* 46 | ** All high-level loads go through LoadVector; you can change it to 47 | ** adapt to the endianness of the input 48 | */ 49 | #define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0])) 50 | 51 | static void LoadBlock (LoadState *S, void *b, size_t size) { 52 | if (luaZ_read(S->Z, b, size) != 0) 53 | error(S, "truncated"); 54 | } 55 | 56 | 57 | #define LoadVar(S,x) LoadVector(S,&x,1) 58 | 59 | 60 | static lu_byte LoadByte (LoadState *S) { 61 | int b = zgetc(S->Z); 62 | if (b == EOZ) 63 | error(S, "truncated"); 64 | return cast_byte(b); 65 | } 66 | 67 | 68 | static size_t LoadSize (LoadState *S) { 69 | size_t x = 0; 70 | int b; 71 | do { 72 | b = LoadByte(S); 73 | x = (x << 7) | (b & 0x7f); 74 | } while ((b & 0x80) == 0); 75 | return x; 76 | } 77 | 78 | 79 | static int LoadInt (LoadState *S) { 80 | return cast_int(LoadSize(S)); 81 | } 82 | 83 | 84 | static lua_Number LoadNumber (LoadState *S) { 85 | lua_Number x; 86 | LoadVar(S, x); 87 | return x; 88 | } 89 | 90 | 91 | static lua_Integer LoadInteger (LoadState *S) { 92 | lua_Integer x; 93 | LoadVar(S, x); 94 | return x; 95 | } 96 | 97 | 98 | static TString *LoadString (LoadState *S) { 99 | size_t size = LoadSize(S); 100 | if (size == 0) 101 | return NULL; 102 | else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ 103 | char buff[LUAI_MAXSHORTLEN]; 104 | LoadVector(S, buff, size); 105 | return luaS_newlstr(S->L, buff, size); 106 | } 107 | else { /* long string */ 108 | TString *ts = luaS_createlngstrobj(S->L, size); 109 | LoadVector(S, getstr(ts), size); /* load directly in final place */ 110 | return ts; 111 | } 112 | } 113 | 114 | 115 | static void LoadCode (LoadState *S, Proto *f) { 116 | int n = LoadInt(S); 117 | f->code = luaM_newvectorchecked(S->L, n, Instruction); 118 | f->sizecode = n; 119 | LoadVector(S, f->code, n); 120 | } 121 | 122 | 123 | static void LoadFunction(LoadState *S, Proto *f, TString *psource); 124 | 125 | 126 | static void LoadConstants (LoadState *S, Proto *f) { 127 | int i; 128 | int n = LoadInt(S); 129 | f->k = luaM_newvectorchecked(S->L, n, TValue); 130 | f->sizek = n; 131 | for (i = 0; i < n; i++) 132 | setnilvalue(&f->k[i]); 133 | for (i = 0; i < n; i++) { 134 | TValue *o = &f->k[i]; 135 | int t = LoadByte(S); 136 | switch (t) { 137 | case LUA_TNIL: 138 | setnilvalue(o); 139 | break; 140 | case LUA_TBOOLEAN: 141 | setbvalue(o, LoadByte(S)); 142 | break; 143 | case LUA_TNUMFLT: 144 | setfltvalue(o, LoadNumber(S)); 145 | break; 146 | case LUA_TNUMINT: 147 | setivalue(o, LoadInteger(S)); 148 | break; 149 | case LUA_TSHRSTR: 150 | case LUA_TLNGSTR: 151 | setsvalue2n(S->L, o, LoadString(S)); 152 | break; 153 | default: lua_assert(0); 154 | } 155 | } 156 | } 157 | 158 | 159 | static void LoadProtos (LoadState *S, Proto *f) { 160 | int i; 161 | int n = LoadInt(S); 162 | f->p = luaM_newvectorchecked(S->L, n, Proto *); 163 | f->sizep = n; 164 | for (i = 0; i < n; i++) 165 | f->p[i] = NULL; 166 | for (i = 0; i < n; i++) { 167 | f->p[i] = luaF_newproto(S->L); 168 | LoadFunction(S, f->p[i], f->source); 169 | } 170 | } 171 | 172 | 173 | static void LoadUpvalues (LoadState *S, Proto *f) { 174 | int i, n; 175 | n = LoadInt(S); 176 | f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc); 177 | f->sizeupvalues = n; 178 | for (i = 0; i < n; i++) 179 | f->upvalues[i].name = NULL; 180 | for (i = 0; i < n; i++) { 181 | f->upvalues[i].instack = LoadByte(S); 182 | f->upvalues[i].idx = LoadByte(S); 183 | } 184 | } 185 | 186 | 187 | static void LoadDebug (LoadState *S, Proto *f) { 188 | int i, n; 189 | n = LoadInt(S); 190 | f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); 191 | f->sizelineinfo = n; 192 | LoadVector(S, f->lineinfo, n); 193 | n = LoadInt(S); 194 | f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); 195 | f->sizeabslineinfo = n; 196 | for (i = 0; i < n; i++) { 197 | f->abslineinfo[i].pc = LoadInt(S); 198 | f->abslineinfo[i].line = LoadInt(S); 199 | } 200 | n = LoadInt(S); 201 | f->locvars = luaM_newvectorchecked(S->L, n, LocVar); 202 | f->sizelocvars = n; 203 | for (i = 0; i < n; i++) 204 | f->locvars[i].varname = NULL; 205 | for (i = 0; i < n; i++) { 206 | f->locvars[i].varname = LoadString(S); 207 | f->locvars[i].startpc = LoadInt(S); 208 | f->locvars[i].endpc = LoadInt(S); 209 | } 210 | n = LoadInt(S); 211 | for (i = 0; i < n; i++) 212 | f->upvalues[i].name = LoadString(S); 213 | } 214 | 215 | 216 | static void LoadFunction (LoadState *S, Proto *f, TString *psource) { 217 | f->source = LoadString(S); 218 | if (f->source == NULL) /* no source in dump? */ 219 | f->source = psource; /* reuse parent's source */ 220 | f->linedefined = LoadInt(S); 221 | f->lastlinedefined = LoadInt(S); 222 | f->numparams = LoadByte(S); 223 | f->is_vararg = LoadByte(S); 224 | f->maxstacksize = LoadByte(S); 225 | LoadCode(S, f); 226 | LoadConstants(S, f); 227 | LoadUpvalues(S, f); 228 | LoadProtos(S, f); 229 | LoadDebug(S, f); 230 | } 231 | 232 | 233 | static void checkliteral (LoadState *S, const char *s, const char *msg) { 234 | char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ 235 | size_t len = strlen(s); 236 | LoadVector(S, buff, len); 237 | if (memcmp(s, buff, len) != 0) 238 | error(S, msg); 239 | } 240 | 241 | 242 | static void fchecksize (LoadState *S, size_t size, const char *tname) { 243 | if (LoadByte(S) != size) 244 | error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname)); 245 | } 246 | 247 | 248 | #define checksize(S,t) fchecksize(S,sizeof(t),#t) 249 | 250 | static void checkHeader (LoadState *S) { 251 | checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */ 252 | if (LoadByte(S) != LUAC_VERSION) 253 | error(S, "version mismatch in"); 254 | if (LoadByte(S) != LUAC_FORMAT) 255 | error(S, "format mismatch in"); 256 | checkliteral(S, LUAC_DATA, "corrupted"); 257 | checksize(S, int); 258 | checksize(S, size_t); 259 | checksize(S, Instruction); 260 | checksize(S, lua_Integer); 261 | checksize(S, lua_Number); 262 | if (LoadInteger(S) != LUAC_INT) 263 | error(S, "endianness mismatch in"); 264 | if (LoadNumber(S) != LUAC_NUM) 265 | error(S, "float format mismatch in"); 266 | } 267 | 268 | 269 | /* 270 | ** load precompiled chunk 271 | */ 272 | LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { 273 | LoadState S; 274 | LClosure *cl; 275 | if (*name == '@' || *name == '=') 276 | S.name = name + 1; 277 | else if (*name == LUA_SIGNATURE[0]) 278 | S.name = "binary string"; 279 | else 280 | S.name = name; 281 | S.L = L; 282 | S.Z = Z; 283 | checkHeader(&S); 284 | cl = luaF_newLclosure(L, LoadByte(&S)); 285 | setclLvalue2s(L, L->top, cl); 286 | luaD_inctop(L); 287 | cl->p = luaF_newproto(L); 288 | LoadFunction(&S, cl->p, NULL); 289 | lua_assert(cl->nupvalues == cl->p->sizeupvalues); 290 | luai_verifycode(L, buff, cl->p); 291 | return cl; 292 | } 293 | 294 | -------------------------------------------------------------------------------- /lundump.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lundump.h,v 1.44 2014/06/19 18:27:20 roberto Exp roberto $ 3 | ** load precompiled Lua chunks 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lundump_h 8 | #define lundump_h 9 | 10 | #include "llimits.h" 11 | #include "lobject.h" 12 | #include "lzio.h" 13 | 14 | 15 | /* data to catch conversion errors */ 16 | #define LUAC_DATA "\x19\x93\r\n\x1a\n" 17 | 18 | #define LUAC_INT 0x5678 19 | #define LUAC_NUM cast_num(370.5) 20 | 21 | #define MYINT(s) (s[0]-'0') 22 | #define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) 23 | #define LUAC_FORMAT 0 /* this is the official format */ 24 | 25 | /* load one chunk; from lundump.c */ 26 | LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); 27 | 28 | /* dump one chunk; from ldump.c */ 29 | LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, 30 | void* data, int strip); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /lutf8lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp roberto $ 3 | ** Standard library for UTF-8 manipulation 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lutf8lib_c 8 | #define LUA_LIB 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "lua.h" 19 | 20 | #include "lauxlib.h" 21 | #include "lualib.h" 22 | 23 | #define MAXUNICODE 0x10FFFF 24 | 25 | #define iscont(p) ((*(p) & 0xC0) == 0x80) 26 | 27 | 28 | /* from strlib */ 29 | /* translate a relative string position: negative means back from end */ 30 | static lua_Integer u_posrelat (lua_Integer pos, size_t len) { 31 | if (pos >= 0) return pos; 32 | else if (0u - (size_t)pos > len) return 0; 33 | else return (lua_Integer)len + pos + 1; 34 | } 35 | 36 | 37 | /* 38 | ** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. 39 | */ 40 | static const char *utf8_decode (const char *o, int *val) { 41 | static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; 42 | const unsigned char *s = (const unsigned char *)o; 43 | unsigned int c = s[0]; 44 | unsigned int res = 0; /* final result */ 45 | if (c < 0x80) /* ascii? */ 46 | res = c; 47 | else { 48 | int count = 0; /* to count number of continuation bytes */ 49 | while (c & 0x40) { /* still have continuation bytes? */ 50 | int cc = s[++count]; /* read next byte */ 51 | if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ 52 | return NULL; /* invalid byte sequence */ 53 | res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ 54 | c <<= 1; /* to test next bit */ 55 | } 56 | res |= ((c & 0x7F) << (count * 5)); /* add first byte */ 57 | if (count > 3 || res > MAXUNICODE || res <= limits[count]) 58 | return NULL; /* invalid byte sequence */ 59 | s += count; /* skip continuation bytes read */ 60 | } 61 | if (val) *val = res; 62 | return (const char *)s + 1; /* +1 to include first byte */ 63 | } 64 | 65 | 66 | /* 67 | ** utf8len(s [, i [, j]]) --> number of characters that start in the 68 | ** range [i,j], or nil + current position if 's' is not well formed in 69 | ** that interval 70 | */ 71 | static int utflen (lua_State *L) { 72 | int n = 0; 73 | size_t len; 74 | const char *s = luaL_checklstring(L, 1, &len); 75 | lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); 76 | lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); 77 | luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, 78 | "initial position out of string"); 79 | luaL_argcheck(L, --posj < (lua_Integer)len, 3, 80 | "final position out of string"); 81 | while (posi <= posj) { 82 | const char *s1 = utf8_decode(s + posi, NULL); 83 | if (s1 == NULL) { /* conversion error? */ 84 | lua_pushnil(L); /* return nil ... */ 85 | lua_pushinteger(L, posi + 1); /* ... and current position */ 86 | return 2; 87 | } 88 | posi = s1 - s; 89 | n++; 90 | } 91 | lua_pushinteger(L, n); 92 | return 1; 93 | } 94 | 95 | 96 | /* 97 | ** codepoint(s, [i, [j]]) -> returns codepoints for all characters 98 | ** that start in the range [i,j] 99 | */ 100 | static int codepoint (lua_State *L) { 101 | size_t len; 102 | const char *s = luaL_checklstring(L, 1, &len); 103 | lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); 104 | lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); 105 | int n; 106 | const char *se; 107 | luaL_argcheck(L, posi >= 1, 2, "out of range"); 108 | luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); 109 | if (posi > pose) return 0; /* empty interval; return no values */ 110 | if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ 111 | return luaL_error(L, "string slice too long"); 112 | n = (int)(pose - posi) + 1; 113 | luaL_checkstack(L, n, "string slice too long"); 114 | n = 0; 115 | se = s + pose; 116 | for (s += posi - 1; s < se;) { 117 | int code; 118 | s = utf8_decode(s, &code); 119 | if (s == NULL) 120 | return luaL_error(L, "invalid UTF-8 code"); 121 | lua_pushinteger(L, code); 122 | n++; 123 | } 124 | return n; 125 | } 126 | 127 | 128 | static void pushutfchar (lua_State *L, int arg) { 129 | lua_Integer code = luaL_checkinteger(L, arg); 130 | luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); 131 | lua_pushfstring(L, "%U", (long)code); 132 | } 133 | 134 | 135 | /* 136 | ** utfchar(n1, n2, ...) -> char(n1)..char(n2)... 137 | */ 138 | static int utfchar (lua_State *L) { 139 | int n = lua_gettop(L); /* number of arguments */ 140 | if (n == 1) /* optimize common case of single char */ 141 | pushutfchar(L, 1); 142 | else { 143 | int i; 144 | luaL_Buffer b; 145 | luaL_buffinit(L, &b); 146 | for (i = 1; i <= n; i++) { 147 | pushutfchar(L, i); 148 | luaL_addvalue(&b); 149 | } 150 | luaL_pushresult(&b); 151 | } 152 | return 1; 153 | } 154 | 155 | 156 | /* 157 | ** offset(s, n, [i]) -> index where n-th character counting from 158 | ** position 'i' starts; 0 means character at 'i'. 159 | */ 160 | static int byteoffset (lua_State *L) { 161 | size_t len; 162 | const char *s = luaL_checklstring(L, 1, &len); 163 | lua_Integer n = luaL_checkinteger(L, 2); 164 | lua_Integer posi = (n >= 0) ? 1 : len + 1; 165 | posi = u_posrelat(luaL_optinteger(L, 3, posi), len); 166 | luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, 167 | "position out of range"); 168 | if (n == 0) { 169 | /* find beginning of current byte sequence */ 170 | while (posi > 0 && iscont(s + posi)) posi--; 171 | } 172 | else { 173 | if (iscont(s + posi)) 174 | return luaL_error(L, "initial position is a continuation byte"); 175 | if (n < 0) { 176 | while (n < 0 && posi > 0) { /* move back */ 177 | do { /* find beginning of previous character */ 178 | posi--; 179 | } while (posi > 0 && iscont(s + posi)); 180 | n++; 181 | } 182 | } 183 | else { 184 | n--; /* do not move for 1st character */ 185 | while (n > 0 && posi < (lua_Integer)len) { 186 | do { /* find beginning of next character */ 187 | posi++; 188 | } while (iscont(s + posi)); /* (cannot pass final '\0') */ 189 | n--; 190 | } 191 | } 192 | } 193 | if (n == 0) /* did it find given character? */ 194 | lua_pushinteger(L, posi + 1); 195 | else /* no such character */ 196 | lua_pushnil(L); 197 | return 1; 198 | } 199 | 200 | 201 | static int iter_aux (lua_State *L) { 202 | size_t len; 203 | const char *s = luaL_checklstring(L, 1, &len); 204 | lua_Integer n = lua_tointeger(L, 2) - 1; 205 | if (n < 0) /* first iteration? */ 206 | n = 0; /* start from here */ 207 | else if (n < (lua_Integer)len) { 208 | n++; /* skip current byte */ 209 | while (iscont(s + n)) n++; /* and its continuations */ 210 | } 211 | if (n >= (lua_Integer)len) 212 | return 0; /* no more codepoints */ 213 | else { 214 | int code; 215 | const char *next = utf8_decode(s + n, &code); 216 | if (next == NULL || iscont(next)) 217 | return luaL_error(L, "invalid UTF-8 code"); 218 | lua_pushinteger(L, n + 1); 219 | lua_pushinteger(L, code); 220 | return 2; 221 | } 222 | } 223 | 224 | 225 | static int iter_codes (lua_State *L) { 226 | luaL_checkstring(L, 1); 227 | lua_pushcfunction(L, iter_aux); 228 | lua_pushvalue(L, 1); 229 | lua_pushinteger(L, 0); 230 | return 3; 231 | } 232 | 233 | 234 | /* pattern to match a single UTF-8 character */ 235 | #define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" 236 | 237 | 238 | static const luaL_Reg funcs[] = { 239 | {"offset", byteoffset}, 240 | {"codepoint", codepoint}, 241 | {"char", utfchar}, 242 | {"len", utflen}, 243 | {"codes", iter_codes}, 244 | /* placeholders */ 245 | {"charpattern", NULL}, 246 | {NULL, NULL} 247 | }; 248 | 249 | 250 | LUAMOD_API int luaopen_utf8 (lua_State *L) { 251 | luaL_newlib(L, funcs); 252 | lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); 253 | lua_setfield(L, -2, "charpattern"); 254 | return 1; 255 | } 256 | 257 | -------------------------------------------------------------------------------- /lvm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lvm.h,v 2.50 2018/02/21 12:54:26 roberto Exp roberto $ 3 | ** Lua virtual machine 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lvm_h 8 | #define lvm_h 9 | 10 | 11 | #include "ldo.h" 12 | #include "lobject.h" 13 | #include "ltm.h" 14 | 15 | 16 | #if !defined(LUA_NOCVTN2S) 17 | #define cvt2str(o) ttisnumber(o) 18 | #else 19 | #define cvt2str(o) 0 /* no conversion from numbers to strings */ 20 | #endif 21 | 22 | 23 | #if !defined(LUA_NOCVTS2N) 24 | #define cvt2num(o) ttisstring(o) 25 | #else 26 | #define cvt2num(o) 0 /* no conversion from strings to numbers */ 27 | #endif 28 | 29 | 30 | /* 31 | ** You can define LUA_FLOORN2I if you want to convert floats to integers 32 | ** by flooring them (instead of raising an error if they are not 33 | ** integral values) 34 | */ 35 | #if !defined(LUA_FLOORN2I) 36 | #define LUA_FLOORN2I 0 37 | #endif 38 | 39 | 40 | /* convert an object to a float (including string coercion) */ 41 | #define tonumber(o,n) \ 42 | (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) 43 | 44 | 45 | /* convert an object to a float (without string coercion) */ 46 | #define tonumberns(o,n) \ 47 | (ttisfloat(o) ? ((n) = fltvalue(o), 1) : \ 48 | (ttisinteger(o) ? ((n) = cast_num(ivalue(o)), 1) : 0)) 49 | 50 | 51 | /* convert an object to an integer (including string coercion) */ 52 | #define tointeger(o,i) \ 53 | (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) 54 | 55 | 56 | /* convert an object to an integer (without string coercion) */ 57 | #define tointegerns(o,i) \ 58 | (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointegerns(o,i,LUA_FLOORN2I)) 59 | 60 | 61 | #define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) 62 | 63 | #define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) 64 | 65 | 66 | /* 67 | ** fast track for 'gettable': if 't' is a table and 't[k]' is present, 68 | ** return 1 with 'slot' pointing to 't[k]' (position of final result). 69 | ** Otherwise, return 0 (meaning it will have to check metamethod) 70 | ** with 'slot' pointing to an empty 't[k]' (if 't' is a table) or NULL 71 | ** (otherwise). 'f' is the raw get function to use. 72 | */ 73 | #define luaV_fastget(L,t,k,slot,f) \ 74 | (!ttistable(t) \ 75 | ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ 76 | : (slot = f(hvalue(t), k), /* else, do raw access */ \ 77 | !isempty(slot))) /* result not empty? */ 78 | 79 | 80 | /* 81 | ** Special case of 'luaV_fastget' for integers, inlining the fast case 82 | ** of 'luaH_getint'. 83 | */ 84 | #define luaV_fastgeti(L,t,k,slot) \ 85 | (!ttistable(t) \ 86 | ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ 87 | : (slot = (l_castS2U(k) - 1u < hvalue(t)->sizearray) \ 88 | ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ 89 | !isempty(slot))) /* result not empty? */ 90 | 91 | 92 | /* 93 | ** Finish a fast set operation (when fast get succeeds). In that case, 94 | ** 'slot' points to the place to put the value. 95 | */ 96 | #define luaV_finishfastset(L,t,slot,v) \ 97 | { setobj2t(L, cast(TValue *,slot), v); \ 98 | luaC_barrierback(L, gcvalue(t), v); } 99 | 100 | 101 | 102 | 103 | LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); 104 | LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); 105 | LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); 106 | LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); 107 | LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); 108 | LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p, int mode); 109 | LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, int mode); 110 | LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, 111 | StkId val, const TValue *slot); 112 | LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, 113 | TValue *val, const TValue *slot); 114 | LUAI_FUNC void luaV_finishOp (lua_State *L); 115 | LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci); 116 | LUAI_FUNC void luaV_concat (lua_State *L, int total); 117 | LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); 118 | LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); 119 | LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); 120 | LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /lzio.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lzio.c,v 1.36 2014/11/02 19:19:04 roberto Exp roberto $ 3 | ** Buffered streams 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lzio_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "llimits.h" 18 | #include "lmem.h" 19 | #include "lstate.h" 20 | #include "lzio.h" 21 | 22 | 23 | int luaZ_fill (ZIO *z) { 24 | size_t size; 25 | lua_State *L = z->L; 26 | const char *buff; 27 | lua_unlock(L); 28 | buff = z->reader(L, z->data, &size); 29 | lua_lock(L); 30 | if (buff == NULL || size == 0) 31 | return EOZ; 32 | z->n = size - 1; /* discount char being returned */ 33 | z->p = buff; 34 | return cast_uchar(*(z->p++)); 35 | } 36 | 37 | 38 | void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { 39 | z->L = L; 40 | z->reader = reader; 41 | z->data = data; 42 | z->n = 0; 43 | z->p = NULL; 44 | } 45 | 46 | 47 | /* --------------------------------------------------------------- read --- */ 48 | size_t luaZ_read (ZIO *z, void *b, size_t n) { 49 | while (n) { 50 | size_t m; 51 | if (z->n == 0) { /* no bytes in buffer? */ 52 | if (luaZ_fill(z) == EOZ) /* try to read more */ 53 | return n; /* no more input; return number of missing bytes */ 54 | else { 55 | z->n++; /* luaZ_fill consumed first byte; put it back */ 56 | z->p--; 57 | } 58 | } 59 | m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ 60 | memcpy(b, z->p, m); 61 | z->n -= m; 62 | z->p += m; 63 | b = (char *)b + m; 64 | n -= m; 65 | } 66 | return 0; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /lzio.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lzio.h,v 1.30 2014/12/19 17:26:14 roberto Exp roberto $ 3 | ** Buffered streams 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lzio_h 9 | #define lzio_h 10 | 11 | #include "lua.h" 12 | 13 | #include "lmem.h" 14 | 15 | 16 | #define EOZ (-1) /* end of stream */ 17 | 18 | typedef struct Zio ZIO; 19 | 20 | #define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) 21 | 22 | 23 | typedef struct Mbuffer { 24 | char *buffer; 25 | size_t n; 26 | size_t buffsize; 27 | } Mbuffer; 28 | 29 | #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) 30 | 31 | #define luaZ_buffer(buff) ((buff)->buffer) 32 | #define luaZ_sizebuffer(buff) ((buff)->buffsize) 33 | #define luaZ_bufflen(buff) ((buff)->n) 34 | 35 | #define luaZ_buffremove(buff,i) ((buff)->n -= (i)) 36 | #define luaZ_resetbuffer(buff) ((buff)->n = 0) 37 | 38 | 39 | #define luaZ_resizebuffer(L, buff, size) \ 40 | ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ 41 | (buff)->buffsize, size), \ 42 | (buff)->buffsize = size) 43 | 44 | #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) 45 | 46 | 47 | LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, 48 | void *data); 49 | LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ 50 | 51 | 52 | 53 | /* --------- Private Part ------------------ */ 54 | 55 | struct Zio { 56 | size_t n; /* bytes still unread */ 57 | const char *p; /* current position in buffer */ 58 | lua_Reader reader; /* reader function */ 59 | void *data; /* additional data */ 60 | lua_State *L; /* Lua state (for reader) */ 61 | }; 62 | 63 | 64 | LUAI_FUNC int luaZ_fill (ZIO *z); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # makefile for building Lua 2 | # see INSTALL for installation instructions 3 | # see ../Makefile and luaconf.h for further customization 4 | 5 | # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= 6 | 7 | # Warnings valid for both C and C++ 8 | CWARNSCPP= \ 9 | # -pedantic \ /* warns if we use jump tables */ 10 | -Wextra \ 11 | -Wshadow \ 12 | -Wsign-compare \ 13 | -Wundef \ 14 | -Wwrite-strings \ 15 | -Wredundant-decls \ 16 | -Wdisabled-optimization \ 17 | -Wdouble-promotion \ 18 | -Wstrict-aliasing=3 # not accepted by clang \ 19 | -Wno-aggressive-loop-optimizations # not accepted by clang \ 20 | -Wlogical-op # not accepted by clang \ 21 | # the next warnings generate too much noise, so they are disabled 22 | # -Wconversion -Wno-sign-conversion \ 23 | # -Wsign-conversion \ 24 | # -Wstrict-overflow=2 \ 25 | # -Wformat=2 \ 26 | # -Wcast-qual \ 27 | 28 | # The next warnings are neither valid nor needed for C++ 29 | CWARNSC= -Wdeclaration-after-statement \ 30 | -Wmissing-prototypes \ 31 | -Wnested-externs \ 32 | -Wstrict-prototypes \ 33 | -Wc++-compat \ 34 | -Wold-style-definition \ 35 | 36 | 37 | CWARNS= $(CWARNSCPP) $(CWARNSC) 38 | 39 | 40 | # -DEXTERNMEMCHECK -DHARDSTACKTESTS -DHARDMEMTESTS -DTRACEMEM='"tempmem"' 41 | # -g -DLUA_USER_H='"ltests.h"' 42 | # -pg -malign-double 43 | # -DLUA_USE_CTYPE -DLUA_USE_APICHECK 44 | # (in clang, '-ftrapv' for runtime checks of integer overflows) 45 | # -fsanitize=undefined -ftrapv -fno-inline 46 | TESTS= 47 | # PH: disabled tests -DLUA_USER_H='"ltests.h"' -O0 48 | 49 | # -mtune=native -fomit-frame-pointer 50 | # -fno-stack-protector 51 | # -DLUA_NILINTABLE 52 | LOCAL = $(TESTS) $(CWARNS) -g 53 | # PH: disabled -DEXTERNMEMCHECK 54 | 55 | 56 | 57 | # enable Linux goodies 58 | MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX -DLUA_USE_READLINE 59 | #MYLDFLAGS= $(LOCAL) -Wl,-E 60 | # PH: removed "-E" flag, otherwise 'make' failed on macOS 61 | MYLDFLAGS= $(LOCAL) -Wl 62 | MYLIBS= -ldl -lreadline 63 | 64 | 65 | CC= gcc 66 | CFLAGS= -Wall -O2 $(MYCFLAGS) -Wfatal-errors 67 | AR= ar rcu 68 | RANLIB= ranlib 69 | RM= rm -f 70 | 71 | 72 | 73 | # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= 74 | 75 | 76 | LIBS = -lm 77 | 78 | CORE_T= liblua.a 79 | CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \ 80 | lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \ 81 | ltm.o lundump.o lvm.o lzio.o ltests.o 82 | AUX_O= lauxlib.o 83 | LIB_O= lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o lstrlib.o \ 84 | lutf8lib.o loadlib.o lcorolib.o linit.o 85 | 86 | LUA_T= lua 87 | LUA_O= lua.o 88 | 89 | # LUAC_T= luac 90 | # LUAC_O= luac.o print.o 91 | 92 | ALL_T= $(CORE_T) $(LUA_T) $(LUAC_T) 93 | ALL_O= $(CORE_O) $(LUA_O) $(LUAC_O) $(AUX_O) $(LIB_O) 94 | ALL_A= $(CORE_T) 95 | 96 | all: $(ALL_T) 97 | 98 | o: $(ALL_O) 99 | 100 | a: $(ALL_A) 101 | 102 | $(CORE_T): $(CORE_O) $(AUX_O) $(LIB_O) 103 | $(AR) $@ $? 104 | $(RANLIB) $@ 105 | 106 | $(LUA_T): $(LUA_O) $(CORE_T) 107 | $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(CORE_T) $(LIBS) $(MYLIBS) $(DL) 108 | 109 | $(LUAC_T): $(LUAC_O) $(CORE_T) 110 | $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(CORE_T) $(LIBS) $(MYLIBS) 111 | 112 | clean: 113 | rcsclean -u 114 | $(RM) $(ALL_T) $(ALL_O) 115 | 116 | depend: 117 | @$(CC) $(CFLAGS) -MM *.c 118 | 119 | echo: 120 | @echo "CC = $(CC)" 121 | @echo "CFLAGS = $(CFLAGS)" 122 | @echo "AR = $(AR)" 123 | @echo "RANLIB = $(RANLIB)" 124 | @echo "RM = $(RM)" 125 | @echo "MYCFLAGS = $(MYCFLAGS)" 126 | @echo "MYLDFLAGS = $(MYLDFLAGS)" 127 | @echo "MYLIBS = $(MYLIBS)" 128 | @echo "DL = $(DL)" 129 | 130 | $(ALL_O): makefile 131 | 132 | # DO NOT EDIT 133 | # automatically made with 'gcc -MM l*.c' 134 | 135 | lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ 136 | lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \ 137 | ltable.h lundump.h lvm.h 138 | lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h 139 | lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 140 | lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \ 141 | llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \ 142 | ldo.h lgc.h lstring.h ltable.h lvm.h 143 | lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 144 | lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h 145 | ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 146 | ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ 147 | lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \ 148 | ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h 149 | ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ 150 | lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \ 151 | lparser.h lstring.h ltable.h lundump.h lvm.h 152 | ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \ 153 | ltm.h lzio.h lmem.h lundump.h 154 | lfunc.o: lfunc.c lprefix.h lua.h luaconf.h lfunc.h lobject.h llimits.h \ 155 | lgc.h lstate.h ltm.h lzio.h lmem.h 156 | lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ 157 | llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h 158 | linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h 159 | liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 160 | llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \ 161 | lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \ 162 | lstring.h ltable.h 163 | lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 164 | lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ 165 | llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h 166 | loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 167 | lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \ 168 | ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \ 169 | lvm.h 170 | lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h 171 | loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 172 | lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \ 173 | llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \ 174 | ldo.h lfunc.h lstring.h lgc.h ltable.h 175 | lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ 176 | lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \ 177 | lstring.h ltable.h 178 | lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \ 179 | lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h 180 | lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 181 | ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ 182 | llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h 183 | ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 184 | ltests.o: ltests.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ 185 | lobject.h ltm.h lzio.h lmem.h lauxlib.h lcode.h llex.h lopcodes.h \ 186 | lparser.h lctype.h ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h \ 187 | lualib.h 188 | ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ 189 | llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h 190 | lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 191 | lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \ 192 | lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \ 193 | lundump.h 194 | lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h 195 | lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ 196 | llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \ 197 | ltable.h lvm.h ljumptab.h 198 | lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \ 199 | lobject.h ltm.h lzio.h 200 | 201 | # (end of Makefile) 202 | -------------------------------------------------------------------------------- /tests/benchmark1.lua: -------------------------------------------------------------------------------- 1 | repeat_count = 1 -- how many times to repeat tests 2 | 3 | function printf(...) 4 | print(string.format(...)) 5 | end 6 | 7 | function print_results(results) 8 | local tests = { "Insert", "Write", "Read", "Push", "Scatter-write", "Scatter-read", "Length" } 9 | for i=1,#results do 10 | if results[i] then 11 | printf("%-16s %fs", tests[i], results[i]) 12 | end 13 | end 14 | end 15 | 16 | function run_benchmarks(table_ctor) 17 | -- accumulated results 18 | local acc = {} 19 | 20 | for cnt=1,repeat_count do 21 | io.write(string.format("\r%.1f%%", (cnt-1) * 100 / repeat_count)) 22 | io.flush() 23 | collectgarbage() 24 | collectgarbage() 25 | 26 | local t = table_ctor() 27 | local t2 = table_ctor() 28 | local t3 = table_ctor() 29 | local results = {} 30 | 31 | -- insert 32 | local start = os.clock() 33 | for i=1,10000000 do 34 | t[i] = i 35 | end 36 | results[1] = os.clock() - start 37 | 38 | -- write 39 | local start = os.clock() 40 | for i=1,10000000 do 41 | t[i] = 1 42 | t[i] = 2 43 | t[i] = 3 44 | t[i] = 4 45 | t[i] = 5 46 | end 47 | results[2] = os.clock() - start 48 | 49 | -- read 50 | local start = os.clock() 51 | local x 52 | for i=1,10000000 do 53 | x = t[i] 54 | x = t[i] 55 | x = t[i] 56 | x = t[i] 57 | x = t[i] 58 | end 59 | results[3] = os.clock() - start 60 | 61 | -- push back 62 | local start = os.clock() 63 | for i=1,10000000/5 do 64 | t2[#t2+1] = i 65 | t2[#t2+1] = i 66 | t2[#t2+1] = i 67 | t2[#t2+1] = i 68 | t2[#t2+1] = i 69 | end 70 | results[4] = os.clock() - start 71 | 72 | -- init random number for scatter read/write benchmarks 73 | math.randomseed(12345) 74 | for i=1,10000000 do 75 | local j = math.random(1, #t) 76 | t[i],t[j] = t[j],t[i] 77 | end 78 | 79 | -- scatter write 80 | local start = os.clock() 81 | for i=1,10000000,4 do 82 | local pos = t[i] 83 | t3[pos] = i 84 | local pos = t[i+1] 85 | t3[pos] = i 86 | local pos = t[i+2] 87 | t3[pos] = i 88 | local pos = t[i+3] 89 | t3[pos] = i 90 | end 91 | results[5] = os.clock() - start 92 | 93 | -- scatter read 94 | local start = os.clock() 95 | math.randomseed(12345) 96 | local x 97 | for i=1,10000000,4 do 98 | local pos = t[i] 99 | x = t3[pos] 100 | local pos = t[i+1] 101 | x = t3[pos] 102 | local pos = t[i+2] 103 | x = t3[pos] 104 | local pos = t[i+3] 105 | x = t3[pos] 106 | end 107 | results[6] = os.clock() - start 108 | 109 | -- length 110 | local start = os.clock() 111 | math.randomseed(12345) 112 | local x 113 | for i=1,2000000 do 114 | x = #t 115 | x = #t2 116 | x = #t3 117 | x = #t 118 | x = #t2 119 | x = #t3 120 | end 121 | results[7] = os.clock() - start 122 | 123 | -- accumulate 124 | for i=1,#results do 125 | acc[i] = (acc[i] or 0.0) + results[i] 126 | end 127 | end 128 | 129 | io.write("\r") 130 | 131 | -- normalize results 132 | for i=1,#acc do 133 | acc[i] = acc[i] / repeat_count 134 | end 135 | 136 | print_results(acc) 137 | end 138 | 139 | print("Running benchmarks using tables...") 140 | run_benchmarks(function() return {} end) 141 | 142 | print("") 143 | 144 | if table.resize then 145 | print("Running benchmarks using arrays...") 146 | local newarray = load("return function() return [] end")() 147 | run_benchmarks(newarray) 148 | else 149 | print("No arrays available; array benchmarks skipped!") 150 | end 151 | -------------------------------------------------------------------------------- /tests/benchmark_results.txt: -------------------------------------------------------------------------------- 1 | System info: 2 | 3 | macOS 10.13.3 4 | 2,3 GHz Intel Core i7 5 | 8 GB 1600 MHz DDR3 6 | 7 | --- 8 | 9 | best of four, patched lua: 10 | 11 | ~/lua-array$ ./lua tests/benchmark1.lua 12 | Running benchmarks using tables... 13 | Insert 0.359120s 14 | Write 0.478326s 15 | Read 0.423190s 16 | Push 2.323120s 17 | Scatter-write 0.202547s 18 | Scatter-read 0.208194s 19 | Length 1.968719s 20 | 21 | Running benchmarks using arrays... 22 | Insert 0.318659s 23 | Write 0.455939s 24 | Read 0.419555s 25 | Push 0.419424s 26 | Scatter-write 0.180237s 27 | Scatter-read 0.169806s 28 | Length 0.124237s 29 | 30 | --- 31 | 32 | best of four, unmodified lua: 33 | 34 | ~/lua5.4$ ./lua ../lua-array/tests/benchmark1.lua 35 | Running benchmarks using tables... 36 | Insert 0.352277s 37 | Write 0.470449s 38 | Read 0.428825s 39 | Push 2.268131s 40 | Scatter-write 0.216821s 41 | Scatter-read 0.199516s 42 | Length 1.999133s 43 | 44 | No arrays available; array benchmarks skipped! 45 | -------------------------------------------------------------------------------- /tests/test.lua: -------------------------------------------------------------------------------- 1 | local errors = false 2 | 3 | function assert(cond) 4 | if not cond then 5 | local line = debug.getinfo(2).currentline 6 | print("test failed at line " .. line) 7 | errors = true 8 | end 9 | end 10 | 11 | -- test array constructor 12 | do 13 | local a = [1, 2, 3] 14 | assert(a[1] == 1) 15 | assert(a[2] == 2) 16 | assert(a[3] == 3) 17 | assert(#a == 3) 18 | end 19 | 20 | -- test nested array constructor 21 | do 22 | local a = [1, 2, 3, [4, 5]] 23 | assert(a[1] == 1) 24 | assert(a[2] == 2) 25 | assert(a[3] == 3) 26 | assert(a[4][1] == 4) 27 | assert(a[4][2] == 5) 28 | assert(#a == 4) 29 | end 30 | 31 | -- test array write 32 | do 33 | local a = [1, 2, 3] 34 | a[1] = -1 35 | assert(a[1] == -1) 36 | assert(#a == 3) 37 | end 38 | 39 | -- test array extend 40 | do 41 | local a = [1, 2, 3] 42 | a[5] = 5 43 | assert(a[5] == 5) 44 | assert(#a == 5) 45 | end 46 | 47 | -- test array extend 2 48 | do 49 | local a = [] 50 | for i=5,15 do 51 | a[i] = i 52 | assert(a[i] == i) 53 | assert(#a == i) 54 | end 55 | end 56 | 57 | -- test setting element to nil (should not affect array size) 58 | do 59 | local a = [1, 2, 3] 60 | a[3] = nil 61 | assert(a[3] == nil) 62 | assert(#a == 3) 63 | end 64 | 65 | -- test array with holes 66 | do 67 | local a = [1, nil, 3] 68 | assert(a[1] == 1) 69 | assert(a[2] == nil) 70 | assert(a[3] == 3) 71 | assert(#a == 3) 72 | a[1] = nil 73 | assert(#a == 3) 74 | end 75 | 76 | -- test filling hole in array 77 | do 78 | local a = [1, nil, 3] 79 | a[2] = 2 80 | assert(a[2] == 2) 81 | assert(#a == 3) 82 | end 83 | 84 | -- test filling hole in array 2 85 | do 86 | local a = [1, nil, 3] 87 | local i = 2 88 | a[i] = 2 89 | assert(a[2] == 2) 90 | assert(#a == 3) 91 | end 92 | 93 | -- test read out of bounds 94 | do 95 | local a = [1, 2, 3] 96 | assert(#a == 3) 97 | assert(a[0] == nil) 98 | assert(a[4] == nil) 99 | assert(#a == 3) 100 | end 101 | 102 | -- test array resize (array growing) 103 | do 104 | local a = [1, 2, 3] 105 | table.resize(a, 1000) 106 | assert(a[4] == nil) 107 | assert(#a == 1000) 108 | a[1] = 4 109 | a[10] = 10 110 | a[11] = 11 111 | assert(#a == 1000) 112 | end 113 | 114 | -- test array resize (array shrinking) 115 | do 116 | local a = [1, 2, 3, 4, 5] 117 | table.resize(a, 3) 118 | assert(a[1] == 1) 119 | assert(a[2] == 2) 120 | assert(a[3] == 3) 121 | assert(a[4] == nil) 122 | assert(a[5] == nil) 123 | assert(#a == 3) 124 | end 125 | 126 | -- test non-const integer 127 | do 128 | local a = [] 129 | local y = 3 130 | a[y] = 66 131 | assert(a[3] == 66) 132 | assert(#a == 3) 133 | end 134 | 135 | -- test table.insert() 136 | do 137 | local a = [1, 2, 3] 138 | table.insert(a, 1, "new") 139 | assert(a[1] == "new") 140 | assert(a[2] == 1) 141 | assert(a[3] == 2) 142 | assert(a[4] == 3) 143 | assert(#a == 4) 144 | end 145 | 146 | -- test table.remove() 147 | do 148 | local a = [1, 2, 3] 149 | table.remove(a, 1) 150 | assert(a[1] == 2) 151 | assert(a[2] == 3) 152 | assert(#a == 2) 153 | end 154 | 155 | -- test ipairs 156 | -- expected behavior: equivalent to for i=1,#a do print(i, a[i]) end 157 | do 158 | local a = [1, nil, 3, nil] 159 | local cnt = 0 160 | for k,v in ipairs(a) do 161 | assert(v == a[k]) 162 | cnt = cnt + 1 163 | end 164 | assert(cnt == #a) 165 | end 166 | 167 | -- test pairs 168 | -- expected behavior: same as ipairs? 169 | do 170 | local a = [1, nil, 3] 171 | local cnt = 0 172 | for k,v in pairs(a) do 173 | assert(v == a[k]) 174 | cnt = cnt + 1 175 | end 176 | assert(cnt == 3) 177 | end 178 | 179 | if not errors then 180 | print("All tests passed!") 181 | end 182 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | - pack/unpack to use arrays 2 | 3 | issues: 4 | - had to remove "-E" liner option from makefile, otherwise running 'make' produces a linker error on macOS 5 | --------------------------------------------------------------------------------