45 |
45 |
46 local keyword_map_to_char = {} |
46 local keyword_map_to_char = {} |
47 for i, keyword in ipairs(keywords) do |
47 for i, keyword in ipairs(keywords) do |
48 keyword_map_to_char[keyword] = string.char(base_char + i); |
48 keyword_map_to_char[keyword] = string.char(base_char + i); |
49 end |
49 end |
|
50 |
|
51 -- Write loadstring and open string |
|
52 local maxequals = 0; |
|
53 data:gsub("(=+)", function (equals_string) maxequals = math.max(maxequals, #equals_string); end); |
|
54 |
|
55 -- Go lexer! |
|
56 llex.init(code, "@"..infile_fn); |
|
57 llex.llex() |
|
58 local seminfo = llex.seminfo; |
|
59 |
|
60 if opts.uglify_level == "full" then |
|
61 -- Find longest TK_NAME and TK_STRING tokens |
|
62 local scores = {}; |
|
63 for k,v in ipairs(llex.tok) do |
|
64 if v == "TK_NAME" or v == "TK_STRING" then |
|
65 local key = string.format("%q,%q", v, seminfo[k]); |
|
66 if not scores[key] then |
|
67 scores[key] = { type = v, value = seminfo[k], count = 0 }; |
|
68 scores[#scores+1] = scores[key]; |
|
69 end |
|
70 scores[key].count = scores[key].count + 1; |
|
71 end |
|
72 end |
|
73 for i=1,#scores do |
|
74 local v = scores[i]; |
|
75 v.score = (v.count)*(#v.value-1)- #string.format("%q", v.value) - 1; |
|
76 end |
|
77 table.sort(scores, function (a, b) return a.score > b.score; end); |
|
78 local free_space = 255-(base_char+#keywords); |
|
79 for i=free_space+1,#scores do |
|
80 scores[i] = nil; -- Drop any over the limit |
|
81 end |
|
82 |
|
83 local base_keywords_len = #keywords; |
|
84 for k,v in ipairs(scores) do |
|
85 if v.score > 0 then |
|
86 table.insert(keywords, v.value); |
|
87 keyword_map_to_char[v.value] = string.char(base_char+base_keywords_len+k); |
|
88 end |
|
89 end |
|
90 end |
50 |
91 |
51 outfile:write("local base_char,keywords=", tostring(base_char), ",{"); |
92 outfile:write("local base_char,keywords=", tostring(base_char), ",{"); |
52 for _, keyword in ipairs(keywords) do |
93 for _, keyword in ipairs(keywords) do |
53 outfile:write('"', keyword, '",'); |
94 outfile:write(string.format("%q", keyword), ','); |
54 end |
95 end |
55 outfile:write[[}; function prettify(code) return code:gsub("["..string.char(base_char).."-"..string.char(base_char+#keywords).."]", |
96 outfile:write[[}; function prettify(code) return code:gsub("["..string.char(base_char).."-"..string.char(base_char+#keywords).."]", |
56 function (c) return keywords[c:byte()-base_char]; end) end ]] |
97 function (c) return keywords[c:byte()-base_char]; end) end ]] |
57 |
|
58 -- Write loadstring and open string |
|
59 local maxequals = 0; |
|
60 data:gsub("(=+)", function (equals_string) maxequals = math.max(maxequals, #equals_string); end); |
|
61 |
98 |
62 outfile:write [[return assert(loadstring(prettify]] |
99 outfile:write [[return assert(loadstring(prettify]] |
63 outfile:write("[", string.rep("=", maxequals+1), "["); |
100 outfile:write("[", string.rep("=", maxequals+1), "["); |
64 |
101 |
65 -- Write code, substituting tokens as we go |
102 -- Write code, substituting tokens as we go |
66 llex.init(code, "@"..infile_fn); |
|
67 llex.llex() |
|
68 local seminfo = llex.seminfo; |
|
69 for k,v in ipairs(llex.tok) do |
103 for k,v in ipairs(llex.tok) do |
70 if v == "TK_KEYWORD" then |
104 if v == "TK_KEYWORD" or v == "TK_NAME" or v == "TK_STRING" then |
71 local keyword_char = keyword_map_to_char[seminfo[k]]; |
105 local keyword_char = keyword_map_to_char[seminfo[k]]; |
72 if keyword_char then |
106 if keyword_char then |
73 outfile:write(keyword_char); |
107 outfile:write(keyword_char); |
74 else -- Those who think Lua shouldn't have 'continue, fix this please :) |
108 else -- Those who think Lua shouldn't have 'continue, fix this please :) |
75 outfile:write(seminfo[k]); |
109 outfile:write(seminfo[k]); |