Merge branch 'master' into v2.1
[luajit-2.0.git] / src / host / genminilua.lua
blob04c55188720963abef45ab9bfe79603088072c41
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-2014 Mike Pall. All rights reserved.
6 -- Released under the MIT license. See Copyright Notice in luajit.h
7 ----------------------------------------------------------------------------
9 local sub, match, gsub = string.sub, string.match, string.gsub
11 local LUA_VERSION = "5.1.5"
12 local LUA_SOURCE
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
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
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",
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)
58 local REMOVE_EXTINC = { ["<assert.h>"] = true, ["<locale.h>"] = true, }
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;
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;
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}
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;
137 lua_close(L);
138 return 0;
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())
149 t[#t+1] = CUSTOM_MAIN
150 return table.concat(t)
153 local includes = {}
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)
168 local function get_license(src)
169 return match(src, "/%*+\n%* Copyright %(.-%*/\n")
172 local function fold_lines(src)
173 return gsub(src, "\\\n", " ")
176 local strings = {}
178 local function save_str(str)
179 local n = #strings+1
180 strings[n] = str
181 return "\1"..n.."\2"
184 local function save_strings(src)
185 src = gsub(src, '"[^"\n]*"', save_str)
186 return gsub(src, "'[^'\n]*'", save_str)
189 local function restore_strings(src)
190 return gsub(src, "\1(%d+)\2", function(numstr)
191 return strings[tonumber(numstr)]
192 end)
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"
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 ]]}, {}
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
228 elseif pp == "elif" then
229 if oldon[lvl] then
230 on = def_istrue(def)
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"
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"
250 elseif pp ~= "undef" then
251 error("unexpected directive: "..pp.." "..def)
254 if on then t[#t+1] = txt end
256 return gsub(table.concat(t), "%a[%w_]*", function(tok)
257 return defs[tok] or tok
258 end)
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
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)
275 local function strip_unused2(src)
276 return gsub(src, "Symbolic Execution.-}=", "")
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 return gsub(src, "\n\n+", "\n")
306 local function strip_comments(src)
307 return gsub(src, "/%*.-%*/", " ")
310 local function strip_whitespace(src)
311 src = gsub(src, "^%s+", "")
312 src = gsub(src, "%s*\n%s*", "\n")
313 src = gsub(src, "[ \t]+", " ")
314 src = gsub(src, "(%W) ", "%1")
315 return gsub(src, " (%W)", "%1")
318 local function rename_tokens1(src)
319 src = gsub(src, "getline", "getline_")
320 src = gsub(src, "struct ([%w_]+)", "ZX%1")
321 return gsub(src, "union ([%w_]+)", "ZY%1")
324 local function rename_tokens2(src)
325 src = gsub(src, "ZX([%w_]+)", "struct %1")
326 return gsub(src, "ZY([%w_]+)", "union %1")
329 local function func_gather(src)
330 local nodes, list = {}, {}
331 local pos, len = 1, #src
332 while pos < len do
333 local d, w = match(src, "^(#define ([%w_]+)[^\n]*\n)", pos)
334 if d then
335 local n = #list+1
336 list[n] = d
337 nodes[w] = n
338 else
339 local s
340 d, w, s = match(src, "^(([%w_]+)[^\n]*([{;])\n)", pos)
341 if not d then
342 d, w, s = match(src, "^(([%w_]+)[^(]*%b()([{;])\n)", pos)
343 if not d then d = match(src, "^[^\n]*\n", pos) end
345 if s == "{" then
346 d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
347 if sub(d, -2) == "{\n" then
348 d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
351 local k, v = nil, d
352 if w == "typedef" then
353 if match(d, "^typedef enum") then
354 head[#head+1] = d
355 else
356 k = match(d, "([%w_]+);\n$")
357 if not k then k = match(d, "^.-%(.-([%w_]+)%)%(") end
359 elseif w == "enum" then
360 head[#head+1] = v
361 elseif w ~= nil then
362 k = match(d, "^[^\n]-([%w_]+)[(%[=]")
363 if k then
364 if w ~= "static" and k ~= "main" then v = "static "..d end
365 else
366 k = w
369 if w and k then
370 local o = nodes[k]
371 if o then nodes["*"..k] = o end
372 local n = #list+1
373 list[n] = v
374 nodes[k] = n
377 pos = pos + #d
379 return nodes, list
382 local function func_visit(nodes, list, used, n)
383 local i = nodes[n]
384 for m in string.gmatch(list[i], "[%w_]+") do
385 if nodes[m] then
386 local j = used[m]
387 if not j then
388 used[m] = i
389 func_visit(nodes, list, used, m)
390 elseif i < j then
391 used[m] = i
397 local function func_collect(src)
398 local nodes, list = func_gather(src)
399 local used = {}
400 func_visit(nodes, list, used, "main")
401 for n,i in pairs(nodes) do
402 local j = used[n]
403 if j and j < i then used["*"..n] = j end
405 for n,i in pairs(nodes) do
406 if not used[n] then list[i] = "" end
408 return table.concat(list)
411 find_sources()
412 local src = read_sources()
413 src = merge_includes(src)
414 local license = get_license(src)
415 src = fold_lines(src)
416 src = strip_unused1(src)
417 src = save_strings(src)
418 src = strip_unused2(src)
419 src = strip_comments(src)
420 src = preprocess(src)
421 src = strip_whitespace(src)
422 src = strip_unused3(src)
423 src = rename_tokens1(src)
424 src = func_collect(src)
425 src = rename_tokens2(src)
426 src = restore_strings(src)
427 src = merge_header(src, license)
428 io.write(src)