ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

genminilua.lua (12039B)


      1 ----------------------------------------------------------------------------
      2 -- Lua script to generate a customized, minified version of Lua.
      3 -- The resulting 'minilua' is used for the build process of LuaJIT.
      4 ----------------------------------------------------------------------------
      5 -- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
      6 -- Released under the MIT license. See Copyright Notice in luajit.h
      7 ----------------------------------------------------------------------------
      8 
      9 local sub, match, gsub = string.sub, string.match, string.gsub
     10 
     11 local LUA_VERSION = "5.1.5"
     12 local LUA_SOURCE
     13 
     14 local function usage()
     15   io.stderr:write("Usage: ", arg and arg[0] or "genminilua",
     16 		  " lua-", LUA_VERSION, "-source-dir\n")
     17   os.exit(1)
     18 end
     19 
     20 local function find_sources()
     21   LUA_SOURCE = arg and arg[1]
     22   if not LUA_SOURCE then usage() end
     23   if sub(LUA_SOURCE, -1) ~= "/" then LUA_SOURCE = LUA_SOURCE.."/" end
     24   local fp = io.open(LUA_SOURCE .. "lua.h")
     25   if not fp then
     26     LUA_SOURCE = LUA_SOURCE.."src/"
     27     fp = io.open(LUA_SOURCE .. "lua.h")
     28     if not fp then usage() end
     29   end
     30   local all = fp:read("*a")
     31   fp:close()
     32   if not match(all, 'LUA_RELEASE%s*"Lua '..LUA_VERSION..'"') then
     33     io.stderr:write("Error: version mismatch\n")
     34     usage()
     35   end
     36 end
     37 
     38 local LUA_FILES = {
     39 "lmem.c", "lobject.c", "ltm.c", "lfunc.c", "ldo.c", "lstring.c", "ltable.c",
     40 "lgc.c", "lstate.c", "ldebug.c", "lzio.c", "lopcodes.c",
     41 "llex.c", "lcode.c", "lparser.c", "lvm.c", "lapi.c", "lauxlib.c",
     42 "lbaselib.c", "ltablib.c", "liolib.c", "loslib.c", "lstrlib.c", "linit.c",
     43 }
     44 
     45 local REMOVE_LIB = {}
     46 gsub([[
     47 collectgarbage dofile gcinfo getfenv getmetatable load print rawequal rawset
     48 select tostring xpcall
     49 foreach foreachi getn maxn setn
     50 popen tmpfile seek setvbuf __tostring
     51 clock date difftime execute getenv rename setlocale time tmpname
     52 dump gfind len reverse
     53 LUA_LOADLIBNAME LUA_MATHLIBNAME LUA_DBLIBNAME
     54 ]], "%S+", function(name)
     55   REMOVE_LIB[name] = true
     56 end)
     57 
     58 local REMOVE_EXTINC = { ["<assert.h>"] = true, ["<locale.h>"] = true, }
     59 
     60 local CUSTOM_MAIN = [[
     61 typedef unsigned int UB;
     62 static UB barg(lua_State *L,int idx){
     63 union{lua_Number n;U64 b;}bn;
     64 bn.n=lua_tonumber(L,idx)+6755399441055744.0;
     65 if (bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number");
     66 return(UB)bn.b;
     67 }
     68 #define BRET(b) lua_pushnumber(L,(lua_Number)(int)(b));return 1;
     69 static int tobit(lua_State *L){
     70 BRET(barg(L,1))}
     71 static int bnot(lua_State *L){
     72 BRET(~barg(L,1))}
     73 static int band(lua_State *L){
     74 int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)}
     75 static int bor(lua_State *L){
     76 int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)}
     77 static int bxor(lua_State *L){
     78 int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)}
     79 static int lshift(lua_State *L){
     80 UB b=barg(L,1),n=barg(L,2)&31;BRET(b<<n)}
     81 static int rshift(lua_State *L){
     82 UB b=barg(L,1),n=barg(L,2)&31;BRET(b>>n)}
     83 static int arshift(lua_State *L){
     84 UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)}
     85 static int rol(lua_State *L){
     86 UB b=barg(L,1),n=barg(L,2)&31;BRET((b<<n)|(b>>(32-n)))}
     87 static int ror(lua_State *L){
     88 UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))}
     89 static int bswap(lua_State *L){
     90 UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)}
     91 static int tohex(lua_State *L){
     92 UB b=barg(L,1);
     93 int n=lua_isnone(L,2)?8:(int)barg(L,2);
     94 const char *hexdigits="0123456789abcdef";
     95 char buf[8];
     96 int i;
     97 if(n<0){n=-n;hexdigits="0123456789ABCDEF";}
     98 if(n>8)n=8;
     99 for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;}
    100 lua_pushlstring(L,buf,(size_t)n);
    101 return 1;
    102 }
    103 static const struct luaL_Reg bitlib[] = {
    104 {"tobit",tobit},
    105 {"bnot",bnot},
    106 {"band",band},
    107 {"bor",bor},
    108 {"bxor",bxor},
    109 {"lshift",lshift},
    110 {"rshift",rshift},
    111 {"arshift",arshift},
    112 {"rol",rol},
    113 {"ror",ror},
    114 {"bswap",bswap},
    115 {"tohex",tohex},
    116 {NULL,NULL}
    117 };
    118 int main(int argc, char **argv){
    119   lua_State *L = luaL_newstate();
    120   int i;
    121   luaL_openlibs(L);
    122   luaL_register(L, "bit", bitlib);
    123   if (argc < 2) return sizeof(void *);
    124   lua_createtable(L, 0, 1);
    125   lua_pushstring(L, argv[1]);
    126   lua_rawseti(L, -2, 0);
    127   lua_setglobal(L, "arg");
    128   if (luaL_loadfile(L, argv[1]))
    129     goto err;
    130   for (i = 2; i < argc; i++)
    131     lua_pushstring(L, argv[i]);
    132   if (lua_pcall(L, argc - 2, 0, 0)) {
    133   err:
    134     fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
    135     return 1;
    136   }
    137   lua_close(L);
    138   return 0;
    139 }
    140 ]]
    141 
    142 local function read_sources()
    143   local t = {}
    144   for i, name in ipairs(LUA_FILES) do
    145     local fp = assert(io.open(LUA_SOURCE..name, "r"))
    146     t[i] = fp:read("*a")
    147     assert(fp:close())
    148   end
    149   t[#t+1] = CUSTOM_MAIN
    150   return table.concat(t)
    151 end
    152 
    153 local includes = {}
    154 
    155 local function merge_includes(src)
    156   return gsub(src, '#include%s*"([^"]*)"%s*\n', function(name)
    157     if includes[name] then return "" end
    158     includes[name] = true
    159     local fp = assert(io.open(LUA_SOURCE..name, "r"))
    160     local src = fp:read("*a")
    161     assert(fp:close())
    162     src = gsub(src, "#ifndef%s+%w+_h\n#define%s+%w+_h\n", "")
    163     src = gsub(src, "#endif%s*$", "")
    164     return merge_includes(src)
    165   end)
    166 end
    167 
    168 local function get_license(src)
    169   return match(src, "/%*+\n%* Copyright %(.-%*/\n")
    170 end
    171 
    172 local function fold_lines(src)
    173   return gsub(src, "\\\n", " ")
    174 end
    175 
    176 local strings = {}
    177 
    178 local function save_str(str)
    179   local n = #strings+1
    180   strings[n] = str
    181   return "\1"..n.."\2"
    182 end
    183 
    184 local function save_strings(src)
    185   src = gsub(src, '"[^"\n]*"', save_str)
    186   return gsub(src, "'[^'\n]*'", save_str)
    187 end
    188 
    189 local function restore_strings(src)
    190   return gsub(src, "\1(%d+)\2", function(numstr)
    191     return strings[tonumber(numstr)]
    192   end)
    193 end
    194 
    195 local function def_istrue(def)
    196   return def == "INT_MAX > 2147483640L" or
    197 	 def == "LUAI_BITSINT >= 32" or
    198 	 def == "SIZE_Bx < LUAI_BITSINT-1" or
    199 	 def == "cast" or
    200 	 def == "defined(LUA_CORE)" or
    201 	 def == "MINSTRTABSIZE" or
    202 	 def == "LUA_MINBUFFER" or
    203 	 def == "HARDSTACKTESTS" or
    204 	 def == "UNUSED"
    205 end
    206 
    207 local head, defs = {[[
    208 #ifdef _MSC_VER
    209 typedef unsigned __int64 U64;
    210 #else
    211 typedef unsigned long long U64;
    212 #endif
    213 int _CRT_glob = 0;
    214 ]]}, {}
    215 
    216 local function preprocess(src)
    217   local t = { match(src, "^(.-)#") }
    218   local lvl, on, oldon = 0, true, {}
    219   for pp, def, txt in string.gmatch(src, "#(%w+) *([^\n]*)\n([^#]*)") do
    220     if pp == "if" or pp == "ifdef" or pp == "ifndef" then
    221       lvl = lvl + 1
    222       oldon[lvl] = on
    223       on = def_istrue(def)
    224     elseif pp == "else" then
    225       if oldon[lvl] then
    226 	if on == false then on = true else on = false end
    227       end
    228     elseif pp == "elif" then
    229       if oldon[lvl] then
    230 	on = def_istrue(def)
    231       end
    232     elseif pp == "endif" then
    233       on = oldon[lvl]
    234       lvl = lvl - 1
    235     elseif on then
    236       if pp == "include" then
    237 	if not head[def] and not REMOVE_EXTINC[def] then
    238 	  head[def] = true
    239 	  head[#head+1] = "#include "..def.."\n"
    240 	end
    241       elseif pp == "define" then
    242 	local k, sp, v = match(def, "([%w_]+)(%s*)(.*)")
    243 	if k and not (sp == "" and sub(v, 1, 1) == "(") then
    244 	  defs[k] = gsub(v, "%a[%w_]*", function(tok)
    245 	    return defs[tok] or tok
    246 	  end)
    247 	else
    248 	  t[#t+1] = "#define "..def.."\n"
    249 	end
    250       elseif pp ~= "undef" then
    251 	error("unexpected directive: "..pp.." "..def)
    252       end
    253     end
    254     if on then t[#t+1] = txt end
    255   end
    256   return gsub(table.concat(t), "%a[%w_]*", function(tok)
    257     return defs[tok] or tok
    258   end)
    259 end
    260 
    261 local function merge_header(src, license)
    262   local hdr = string.format([[
    263 /* This is a heavily customized and minimized copy of Lua %s. */
    264 /* It's only used to build LuaJIT. It does NOT have all standard functions! */
    265 ]], LUA_VERSION)
    266   return hdr..license..table.concat(head)..src
    267 end
    268 
    269 local function strip_unused1(src)
    270   return gsub(src, '(  {"?([%w_]+)"?,%s+%a[%w_]*},\n)', function(line, func)
    271     return REMOVE_LIB[func] and "" or line
    272   end)
    273 end
    274 
    275 local function strip_unused2(src)
    276   return gsub(src, "Symbolic Execution.-}=", "")
    277 end
    278 
    279 local function strip_unused3(src)
    280   src = gsub(src, "extern", "static")
    281   src = gsub(src, "\nstatic([^\n]-)%(([^)]*)%)%(", "\nstatic%1 %2(")
    282   src = gsub(src, "#define lua_assert[^\n]*\n", "")
    283   src = gsub(src, "lua_assert%b();?", "")
    284   src = gsub(src, "default:\n}", "default:;\n}")
    285   src = gsub(src, "lua_lock%b();", "")
    286   src = gsub(src, "lua_unlock%b();", "")
    287   src = gsub(src, "luai_threadyield%b();", "")
    288   src = gsub(src, "luai_userstateopen%b();", "{}")
    289   src = gsub(src, "luai_userstate%w+%b();", "")
    290   src = gsub(src, "%(%(c==.*luaY_parser%)", "luaY_parser")
    291   src = gsub(src, "trydecpoint%(ls,seminfo%)",
    292 		  "luaX_lexerror(ls,\"malformed number\",TK_NUMBER)")
    293   src = gsub(src, "int c=luaZ_lookahead%b();", "")
    294   src = gsub(src, "luaL_register%(L,[^,]*,co_funcs%);\nreturn 2;",
    295 		  "return 1;")
    296   src = gsub(src, "getfuncname%b():", "NULL:")
    297   src = gsub(src, "getobjname%b():", "NULL:")
    298   src = gsub(src, "if%([^\n]*hookmask[^\n]*%)\n[^\n]*\n", "")
    299   src = gsub(src, "if%([^\n]*hookmask[^\n]*%)%b{}\n", "")
    300   src = gsub(src, "if%([^\n]*hookmask[^\n]*&&\n[^\n]*%b{}\n", "")
    301   src = gsub(src, "(twoto%b()%()", "%1(size_t)")
    302   src = gsub(src, "i<sizenode", "i<(int)sizenode")
    303   src = gsub(src, "cast%(unsigned int,key%-1%)", "cast(unsigned int,key)-1")
    304   return gsub(src, "\n\n+", "\n")
    305 end
    306 
    307 local function strip_comments(src)
    308   return gsub(src, "/%*.-%*/", " ")
    309 end
    310 
    311 local function strip_whitespace(src)
    312   src = gsub(src, "^%s+", "")
    313   src = gsub(src, "%s*\n%s*", "\n")
    314   src = gsub(src, "[ \t]+", " ")
    315   src = gsub(src, "(%W) ", "%1")
    316   return gsub(src, " (%W)", "%1")
    317 end
    318 
    319 local function rename_tokens1(src)
    320   src = gsub(src, "getline", "getline_")
    321   src = gsub(src, "struct ([%w_]+)", "ZX%1")
    322   return gsub(src, "union ([%w_]+)", "ZY%1")
    323 end
    324 
    325 local function rename_tokens2(src)
    326   src = gsub(src, "ZX([%w_]+)", "struct %1")
    327   return gsub(src, "ZY([%w_]+)", "union %1")
    328 end
    329 
    330 local function func_gather(src)
    331   local nodes, list = {}, {}
    332   local pos, len = 1, #src
    333   while pos < len do
    334     local d, w = match(src, "^(#define ([%w_]+)[^\n]*\n)", pos)
    335     if d then
    336       local n = #list+1
    337       list[n] = d
    338       nodes[w] = n
    339     else
    340       local s
    341       d, w, s = match(src, "^(([%w_]+)[^\n]*([{;])\n)", pos)
    342       if not d then
    343 	d, w, s = match(src, "^(([%w_]+)[^(]*%b()([{;])\n)", pos)
    344 	if not d then d = match(src, "^[^\n]*\n", pos) end
    345       end
    346       if s == "{" then
    347 	d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
    348 	if sub(d, -2) == "{\n" then
    349 	  d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
    350 	end
    351       end
    352       local k, v = nil, d
    353       if w == "typedef" then
    354 	if match(d, "^typedef enum") then
    355 	  head[#head+1] = d
    356 	else
    357 	  k = match(d, "([%w_]+);\n$")
    358 	  if not k then k = match(d, "^.-%(.-([%w_]+)%)%(") end
    359 	end
    360       elseif w == "enum" then
    361 	head[#head+1] = v
    362       elseif w ~= nil then
    363 	k = match(d, "^[^\n]-([%w_]+)[(%[=]")
    364 	if k then
    365 	  if w ~= "static" and k ~= "main" then v = "static "..d end
    366 	else
    367 	  k = w
    368 	end
    369       end
    370       if w and k then
    371 	local o = nodes[k]
    372 	if o then nodes["*"..k] = o end
    373 	local n = #list+1
    374 	list[n] = v
    375 	nodes[k] = n
    376       end
    377     end
    378     pos = pos + #d
    379   end
    380   return nodes, list
    381 end
    382 
    383 local function func_visit(nodes, list, used, n)
    384   local i = nodes[n]
    385   for m in string.gmatch(list[i], "[%w_]+") do
    386     if nodes[m] then
    387       local j = used[m]
    388       if not j then
    389 	used[m] = i
    390 	func_visit(nodes, list, used, m)
    391       elseif i < j then
    392 	used[m] = i
    393       end
    394     end
    395   end
    396 end
    397 
    398 local function func_collect(src)
    399   local nodes, list = func_gather(src)
    400   local used = {}
    401   func_visit(nodes, list, used, "main")
    402   for n,i in pairs(nodes) do
    403     local j = used[n]
    404     if j and j < i then used["*"..n] = j end
    405   end
    406   for n,i in pairs(nodes) do
    407     if not used[n] then list[i] = "" end
    408   end
    409   return table.concat(list)
    410 end
    411 
    412 find_sources()
    413 local src = read_sources()
    414 src = merge_includes(src)
    415 local license = get_license(src)
    416 src = fold_lines(src)
    417 src = strip_unused1(src)
    418 src = save_strings(src)
    419 src = strip_unused2(src)
    420 src = strip_comments(src)
    421 src = preprocess(src)
    422 src = strip_whitespace(src)
    423 src = strip_unused3(src)
    424 src = rename_tokens1(src)
    425 src = func_collect(src)
    426 src = rename_tokens2(src)
    427 src = restore_strings(src)
    428 src = merge_header(src, license)
    429 io.write(src)