uglify/squish.uglify.lua

changeset 8
f62f83d9dc43
child 36
bbfbc08d568f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uglify/squish.uglify.lua	Sat Jul 25 16:44:47 2009 +0100
@@ -0,0 +1,94 @@
+local llex = require "llex"
+
+local base_char = 128;
+local keywords = { "and", "break", "do", "else", "elseif",
+    "end", "false", "for", "function", "if",
+        "in", "local", "nil", "not", "or", "repeat",
+            "return", "then", "true", "until", "while" }
+
+function uglify_file(infile_fn, outfile_fn)
+	local infile, err = io.open(infile_fn);
+	if not infile then
+		print_err("Can't open input file for reading: "..tostring(err));
+		return;
+	end
+	
+	local outfile, err = io.open(outfile_fn..".uglified", "w+");
+	if not outfile then
+		print_err("Can't open output file for writing: "..tostring(err));
+		return;
+	end
+	
+	local data = infile:read("*a");
+	infile:close();
+	
+	local shebang, newdata = data:match("^(#.-\n)(.+)$");
+	local code = newdata or data;
+	if shebang then
+		outfile:write(shebang)
+	end
+
+	
+	while base_char + #keywords < 255 and code:find("["..string.char(base_char).."-"..string.char(base_char+#keywords-1).."]") do
+		base_char = base_char + 1;
+	end
+	if base_char == 255 then
+		-- Sorry, can't uglify this file :(
+		-- We /could/ use a multi-byte marker, but that would complicate
+		-- things and lower the compression ratio (there are quite a few 
+		-- 2-letter keywords)
+		outfile:write(code);
+		outfile:close();
+		os.rename(outfile_fn..".uglified", outfile_fn);
+		return;
+	end
+
+	local keyword_map_to_char = {}
+	for i, keyword in ipairs(keywords) do
+		keyword_map_to_char[keyword] = string.char(base_char + i);
+	end
+	
+	outfile:write("local base_char,keywords=", tostring(base_char), ",{");
+	for _, keyword in ipairs(keywords) do
+		outfile:write('"', keyword, '",');
+	end
+	outfile:write[[}; function prettify(code) return code:gsub("["..string.char(base_char).."-"..string.char(base_char+#keywords).."]", 
+	function (c) return keywords[c:byte()-base_char]; end) end ]]
+	
+	-- Write loadstring and open string
+	local maxequals = 0;
+	data:gsub("(=+)", function (equals_string) maxequals = math.max(maxequals, #equals_string); end);
+	
+	outfile:write [[assert(loadstring(prettify]]
+	outfile:write("[", string.rep("=", maxequals+1), "[");
+	
+	-- Write code, substituting tokens as we go
+	llex.init(code, "@"..infile_fn);
+	llex.llex()
+	local seminfo = llex.seminfo;
+	for k,v in ipairs(llex.tok) do
+		if v == "TK_KEYWORD" then
+			local keyword_char = keyword_map_to_char[seminfo[k]];
+			if keyword_char then
+				outfile:write(keyword_char);
+			else -- Those who think Lua shouldn't have 'continue, fix this please :)
+				outfile:write(seminfo[k]);
+			end
+		else
+			outfile:write(seminfo[k]);
+		end
+	end
+
+	-- Close string/functions	
+	outfile:write("]", string.rep("=", maxequals+1), "]");
+	outfile:write("))()");
+	outfile:close();
+	os.rename(outfile_fn..".uglified", outfile_fn);
+end
+
+if opts.uglify then
+	print_info("Uglifying "..out_fn.."...");
+	uglify_file(out_fn, out_fn);
+	print_info("OK!");
+end
+

mercurial