aboutsummaryrefslogtreecommitdiff
path: root/src/3rdParty/LuaMinify.h
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2023-07-24 17:55:21 +0800
committerLi Jin <dragon-fly@qq.com>2023-07-24 17:55:21 +0800
commitc03b88e6210818e604d7c755fe8f54fe53696ee1 (patch)
tree3d297ce64171481caeb0e86f42a206e8322abeca /src/3rdParty/LuaMinify.h
parent00c4bee811b3c92d9885959db30790b01f8cb3e2 (diff)
downloadyuescript-c03b88e6210818e604d7c755fe8f54fe53696ee1.tar.gz
yuescript-c03b88e6210818e604d7c755fe8f54fe53696ee1.tar.bz2
yuescript-c03b88e6210818e604d7c755fe8f54fe53696ee1.zip
try fixing issue #141. fix an AST object life expired before accessing issue.
Diffstat (limited to 'src/3rdParty/LuaMinify.h')
-rw-r--r--src/3rdParty/LuaMinify.h428
1 files changed, 408 insertions, 20 deletions
diff --git a/src/3rdParty/LuaMinify.h b/src/3rdParty/LuaMinify.h
index d01a8fe..5512f5b 100644
--- a/src/3rdParty/LuaMinify.h
+++ b/src/3rdParty/LuaMinify.h
@@ -319,8 +319,6 @@ R"lua_codes(
319-- ParseLua returns an AST, internally relying on LexLua. 319-- ParseLua returns an AST, internally relying on LexLua.
320-- 320--
321 321
322local WhiteChars = lookupify{' ', '\n', '\t', '\r'}
323local EscapeLookup = {['\r'] = '\\r', ['\n'] = '\\n', ['\t'] = '\\t', ['"'] = '\\"', ["'"] = "\\'"}
324local LowerChars = lookupify{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 322local LowerChars = lookupify{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
325 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 323 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
326 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'} 324 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
@@ -549,7 +547,7 @@ local function LexLua(src)
549 --get the initial char 547 --get the initial char
550 local thisLine = line 548 local thisLine = line
551 local thisChar = char 549 local thisChar = char
552 local errorAt = ":"..line..":"..char..":> " 550 --local errorAt = ":"..line..":"..char..":> "
553 local c = peek() 551 local c = peek()
554 552
555 --symbol to emit 553 --symbol to emit
@@ -822,9 +820,9 @@ local function ParseLua(src)
822 return err 820 return err
823 end 821 end
824 -- 822 --
825 local VarUid = 0 823 -- local VarUid = 0
826 -- No longer needed: handled in Scopes now local GlobalVarGetMap = {} 824 -- No longer needed: handled in Scopes now local GlobalVarGetMap = {}
827 local VarDigits = {'_', 'a', 'b', 'c', 'd'} 825 -- local VarDigits = {'_', 'a', 'b', 'c', 'd'}
828 local function CreateScope(parent) 826 local function CreateScope(parent)
829 --[[ 827 --[[
830 local scope = {} 828 local scope = {}
@@ -1736,15 +1734,6 @@ R"lua_codes(
1736-- - All local variables are renamed 1734-- - All local variables are renamed
1737-- 1735--
1738 1736
1739local LowerChars = lookupify{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
1740 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
1741 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
1742local UpperChars = lookupify{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
1743 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
1744 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}
1745local Digits = lookupify{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
1746local Symbols = lookupify{'+', '-', '*', '/', '^', '%', ',', '{', '}', '[', ']', '(', ')', ';', '#'}
1747
1748local function Format_Mini(ast) 1737local function Format_Mini(ast)
1749 local formatStatlist, formatExpr; 1738 local formatStatlist, formatExpr;
1750 --local count = 0 1739 --local count = 0
@@ -2092,14 +2081,413 @@ local function Format_Mini(ast)
2092 ast.Scope:ObfuscateVariables() 2081 ast.Scope:ObfuscateVariables()
2093 return formatStatlist(ast) 2082 return formatStatlist(ast)
2094end 2083end
2084)lua_codes"
2095 2085
2096return function(src) 2086R"lua_codes(
2097 local st, ast = ParseLua(src) 2087local function FormatYue(ast, lineMap)
2098 if st then 2088 local currentLine = 1
2099 return Format_Mini(ast) 2089 local formatStatlist, formatExpr
2100 else 2090
2101 return nil, ast 2091 local function joinStatementsSafe(out, b, sep)
2092 local aa = ''
2093 for i = #out, 1, -1 do
2094 local a = out[i]
2095 aa = a:match("([^%s])%s*$")
2096 if aa then
2097 break
2098 end
2099 end
2100 sep = sep or ' '
2101 if (out[#out] or ''):sub(-1,-1) == ' ' then
2102 sep = ''
2103 end
2104 local bb = b:match("^%s*([^%s])")
2105 if UpperChars[aa] or LowerChars[aa] or aa == '_' then
2106 if not (UpperChars[bb] or LowerChars[bb] or bb == '_' or Digits[bb]) then
2107 --bb is a symbol, can join without sep
2108 out[#out + 1] = b
2109 elseif bb == '(' then
2110 --prevent ambiguous syntax
2111 out[#out + 1] = sep
2112 out[#out + 1] = b
2113 else
2114 out[#out + 1] = sep
2115 out[#out + 1] = b
2116 end
2117 elseif Digits[aa] then
2118 if bb == '(' then
2119 --can join statements directly
2120 out[#out + 1] = b
2121 elseif Symbols[bb] then
2122 out[#out + 1] = b
2123 else
2124 out[#out + 1] = sep
2125 out[#out + 1] = b
2126 end
2127 elseif aa == '' then
2128 out[#out + 1] = b
2129 else
2130 if bb == '(' then
2131 --don't want to accidentally call last statement, can't join directly
2132 out[#out + 1] = sep
2133 out[#out + 1] = b
2134 else
2135 out[#out + 1] = b
2136 end
2137 end
2102 end 2138 end
2139
2140 formatExpr = function(expr)
2141 local out = {string.rep('(', expr.ParenCount or 0)}
2142 if expr.Tokens then
2143 local line = expr.Tokens[1].Line
2144 local targetLine = lineMap[line]
2145 if targetLine and currentLine < targetLine then
2146 out[#out + 1] = string.rep('\n', targetLine - currentLine)
2147 currentLine = targetLine
2148 end
2149 elseif expr.Value then
2150 local line = expr.Value.Line
2151 local targetLine = lineMap[line]
2152 if targetLine and currentLine < targetLine then
2153 out[#out + 1] = string.rep('\n', targetLine - currentLine)
2154 currentLine = targetLine
2155 end
2156 end
2157 if expr.AstType == 'VarExpr' then
2158 if expr.Variable then
2159 out[#out + 1] = expr.Variable.Name
2160 else
2161 out[#out + 1] = expr.Name
2162 end
2163
2164 elseif expr.AstType == 'NumberExpr' then
2165 out[#out + 1] = expr.Value.Data
2166
2167 elseif expr.AstType == 'StringExpr' then
2168 out[#out + 1] = expr.Value.Data
2169
2170 elseif expr.AstType == 'BooleanExpr' then
2171 out[#out + 1] = tostring(expr.Value)
2172
2173 elseif expr.AstType == 'NilExpr' then
2174 joinStatementsSafe(out, "nil", nil)
2175
2176 elseif expr.AstType == 'BinopExpr' then
2177 joinStatementsSafe(out, formatExpr(expr.Lhs), nil)
2178 out[#out + 1] = " "
2179 joinStatementsSafe(out, expr.Op, nil)
2180 out[#out + 1] = " "
2181 joinStatementsSafe(out, formatExpr(expr.Rhs), nil)
2182
2183 elseif expr.AstType == 'UnopExpr' then
2184 joinStatementsSafe(out, expr.Op, nil)
2185 out[#out + 1] = (#expr.Op ~= 1 and " " or "")
2186 joinStatementsSafe(out, formatExpr(expr.Rhs), nil)
2187
2188 elseif expr.AstType == 'DotsExpr' then
2189 out[#out + 1] = "..."
2190
2191 elseif expr.AstType == 'CallExpr' then
2192 out[#out + 1] = formatExpr(expr.Base)
2193 out[#out + 1] = "("
2194 for i = 1, #expr.Arguments do
2195 out[#out + 1] = formatExpr(expr.Arguments[i])
2196 if i ~= #expr.Arguments then
2197 out[#out + 1] = ", "
2198 end
2199 end
2200 out[#out + 1] = ")"
2201
2202 elseif expr.AstType == 'TableCallExpr' then
2203 out[#out + 1] = formatExpr(expr.Base)
2204 out[#out + 1] = " "
2205 out[#out + 1] = formatExpr(expr.Arguments[1])
2206
2207 elseif expr.AstType == 'StringCallExpr' then
2208 out[#out + 1] = formatExpr(expr.Base)
2209 out[#out + 1] = " "
2210 out[#out + 1] = expr.Arguments[1].Data
2211
2212 elseif expr.AstType == 'IndexExpr' then
2213 out[#out + 1] = formatExpr(expr.Base)
2214 out[#out + 1] = "["
2215 out[#out + 1] = formatExpr(expr.Index)
2216 out[#out + 1] = "]"
2217
2218 elseif expr.AstType == 'MemberExpr' then
2219 out[#out + 1] = formatExpr(expr.Base)
2220 out[#out + 1] = expr.Indexer
2221 out[#out + 1] = expr.Ident.Data
2222
2223 elseif expr.AstType == 'Function' then
2224 -- anonymous function
2225 out[#out + 1] = "function("
2226 if #expr.Arguments > 0 then
2227 for i = 1, #expr.Arguments do
2228 out[#out + 1] = expr.Arguments[i].Name
2229 if i ~= #expr.Arguments then
2230 out[#out + 1] = ", "
2231 elseif expr.VarArg then
2232 out[#out + 1] = ", ..."
2233 end
2234 end
2235 elseif expr.VarArg then
2236 out[#out + 1] = "..."
2237 end
2238 out[#out + 1] = ")"
2239 joinStatementsSafe(out, formatStatlist(expr.Body), nil)
2240 joinStatementsSafe(out, "end", nil)
2241 elseif expr.AstType == 'ConstructorExpr' then
2242 out[#out + 1] = "{ "
2243 for i = 1, #expr.EntryList do
2244 local entry = expr.EntryList[i]
2245 if entry.Type == 'Key' then
2246 out[#out + 1] = "["
2247 out[#out + 1] = formatExpr(entry.Key)
2248 out[#out + 1] = "] = "
2249 out[#out + 1] = formatExpr(entry.Value)
2250 elseif entry.Type == 'Value' then
2251 out[#out + 1] = formatExpr(entry.Value)
2252 elseif entry.Type == 'KeyString' then
2253 out[#out + 1] = entry.Key
2254 out[#out + 1] = " = "
2255 out[#out + 1] = formatExpr(entry.Value)
2256 end
2257 if i ~= #expr.EntryList then
2258 out[#out + 1] = ", "
2259 end
2260 end
2261 out[#out + 1] = " }"
2262
2263 elseif expr.AstType == 'Parentheses' then
2264 out[#out + 1] = "("
2265 out[#out + 1] = formatExpr(expr.Inner)
2266 out[#out + 1] = ")"
2267
2268 end
2269 out[#out + 1] = string.rep(')', expr.ParenCount or 0)
2270 return table.concat(out)
2271 end
2272
2273 local formatStatement = function(statement)
2274 local out = {""}
2275 if statement.Tokens and statement.Tokens[1] then
2276 local line = statement.Tokens[1].Line
2277 local targetLine = lineMap[line]
2278 if targetLine and currentLine < targetLine then
2279 out[#out + 1] = string.rep('\n', targetLine - currentLine)
2280 currentLine = targetLine
2281 end
2282 end
2283 if statement.AstType == 'AssignmentStatement' then
2284 for i = 1, #statement.Lhs do
2285 out[#out + 1] = formatExpr(statement.Lhs[i])
2286 if i ~= #statement.Lhs then
2287 out[#out + 1] = ", "
2288 end
2289 end
2290 if #statement.Rhs > 0 then
2291 out[#out + 1] = " = "
2292 for i = 1, #statement.Rhs do
2293 out[#out + 1] = formatExpr(statement.Rhs[i])
2294 if i ~= #statement.Rhs then
2295 out[#out + 1] = ", "
2296 end
2297 end
2298 end
2299 elseif statement.AstType == 'CallStatement' then
2300 out[#out + 1] = formatExpr(statement.Expression)
2301 elseif statement.AstType == 'LocalStatement' then
2302 out[#out + 1] = "local "
2303 for i = 1, #statement.LocalList do
2304 out[#out + 1] = statement.LocalList[i].Name
2305 if statement.AttrList[i] then
2306 out[#out + 1] = " <"
2307 out[#out + 1] = statement.AttrList[i]
2308 out[#out + 1] = ">"
2309 end
2310 if i ~= #statement.LocalList then
2311 out[#out + 1] = ","
2312 end
2313 end
2314 if #statement.InitList > 0 then
2315 out[#out + 1] = " = "
2316 for i = 1, #statement.InitList do
2317 out[#out + 1] = formatExpr(statement.InitList[i])
2318 if i ~= #statement.InitList then
2319 out[#out + 1] = ", "
2320 end
2321 end
2322 end
2323 elseif statement.AstType == 'IfStatement' then
2324 out[#out + 1] = "if "
2325 joinStatementsSafe(out, formatExpr(statement.Clauses[1].Condition), nil)
2326 joinStatementsSafe(out, " then", nil)
2327 joinStatementsSafe(out, formatStatlist(statement.Clauses[1].Body), nil)
2328 for i = 2, #statement.Clauses do
2329 local st = statement.Clauses[i]
2330 if st.Condition then
2331 joinStatementsSafe(out, "elseif ", nil)
2332 joinStatementsSafe(out, formatExpr(st.Condition), nil)
2333 joinStatementsSafe(out, " then", nil)
2334 else
2335 joinStatementsSafe(out, "else", nil)
2336 end
2337 joinStatementsSafe(out, formatStatlist(st.Body), nil)
2338 end
2339 joinStatementsSafe(out, "end", nil)
2340 elseif statement.AstType == 'WhileStatement' then
2341 out[#out + 1] = "while "
2342 joinStatementsSafe(out, formatExpr(statement.Condition), nil)
2343 joinStatementsSafe(out, " do", nil)
2344 joinStatementsSafe(out, formatStatlist(statement.Body), nil)
2345 joinStatementsSafe(out, "end", nil)
2346 elseif statement.AstType == 'DoStatement' then
2347 joinStatementsSafe(out, "do", nil)
2348 joinStatementsSafe(out, formatStatlist(statement.Body), nil)
2349 joinStatementsSafe(out, "end", nil)
2350 elseif statement.AstType == 'ReturnStatement' then
2351 out[#out + 1] = "return "
2352 for i = 1, #statement.Arguments do
2353 joinStatementsSafe(out, formatExpr(statement.Arguments[i]), nil)
2354 if i ~= #statement.Arguments then
2355 out[#out + 1] = ", "
2356 end
2357 end
2358 elseif statement.AstType == 'BreakStatement' then
2359 out[#out + 1] = "break"
2360 elseif statement.AstType == 'RepeatStatement' then
2361 out[#out + 1] = "repeat"
2362 joinStatementsSafe(out, formatStatlist(statement.Body), nil)
2363 joinStatementsSafe(out, "until ", nil)
2364 joinStatementsSafe(out, formatExpr(statement.Condition), nil)
2365 elseif statement.AstType == 'Function' then
2366 if statement.IsLocal then
2367 out[#out + 1] = "local "
2368 end
2369 joinStatementsSafe(out, "function ", nil)
2370 if statement.IsLocal then
2371 out[#out + 1] = statement.Name.Name
2372 else
2373 out[#out + 1] = formatExpr(statement.Name)
2374 end
2375 out[#out + 1] = "("
2376 if #statement.Arguments > 0 then
2377 for i = 1, #statement.Arguments do
2378 out[#out + 1] = statement.Arguments[i].Name
2379 if i ~= #statement.Arguments then
2380 out[#out + 1] = ", "
2381 elseif statement.VarArg then
2382 out[#out + 1] = ",..."
2383 end
2384 end
2385 elseif statement.VarArg then
2386 out[#out + 1] = "..."
2387 end
2388 out[#out + 1] = ")"
2389 joinStatementsSafe(out, formatStatlist(statement.Body), nil)
2390 joinStatementsSafe(out, "end", nil)
2391 elseif statement.AstType == 'GenericForStatement' then
2392 out[#out + 1] = "for "
2393 for i = 1, #statement.VariableList do
2394 out[#out + 1] = statement.VariableList[i].Name
2395 if i ~= #statement.VariableList then
2396 out[#out + 1] = ", "
2397 end
2398 end
2399 out[#out + 1] = " in "
2400 for i = 1, #statement.Generators do
2401 joinStatementsSafe(out, formatExpr(statement.Generators[i]), nil)
2402 if i ~= #statement.Generators then
2403 joinStatementsSafe(out, ', ', nil)
2404 end
2405 end
2406 joinStatementsSafe(out, " do", nil)
2407 joinStatementsSafe(out, formatStatlist(statement.Body), nil)
2408 joinStatementsSafe(out, "end", nil)
2409 elseif statement.AstType == 'NumericForStatement' then
2410 out[#out + 1] = "for "
2411 out[#out + 1] = statement.Variable.Name
2412 out[#out + 1] = " = "
2413 out[#out + 1] = formatExpr(statement.Start)
2414 out[#out + 1] = ", "
2415 out[#out + 1] = formatExpr(statement.End)
2416 if statement.Step then
2417 out[#out + 1] = ", "
2418 out[#out + 1] = formatExpr(statement.Step)
2419 end
2420 joinStatementsSafe(out, " do", nil)
2421 joinStatementsSafe(out, formatStatlist(statement.Body), nil)
2422 joinStatementsSafe(out, "end", nil)
2423 elseif statement.AstType == 'LabelStatement' then
2424 out[#out + 1] = "::"
2425 out[#out + 1] = statement.Label
2426 out[#out + 1] = "::"
2427 elseif statement.AstType == 'GotoStatement' then
2428 out[#out + 1] = "goto "
2429 out[#out + 1] = statement.Label
2430 elseif statement.AstType == 'Comment' then
2431 -- Ignore
2432 elseif statement.AstType == 'Eof' then
2433 -- Ignore
2434 else
2435 print("Unknown AST Type: ", statement.AstType)
2436 end
2437 return table.concat(out)
2438 end
2439
2440 formatStatlist = function(statList)
2441 local out = {""}
2442 for _, stat in pairs(statList.Body) do
2443 joinStatementsSafe(out, formatStatement(stat), ';')
2444 end
2445 return table.concat(out)
2446 end
2447
2448 return formatStatlist(ast)
2449end
2450
2451local function GetYueLineMap(luaCodes)
2452 local current = 1
2453 local lastLine = 1
2454 local lineMap = { }
2455 for lineCode in luaCodes:gmatch("[^\n\r]*") do
2456 local num = lineCode:match("--%s*(%d+)%s*$")
2457 if num then
2458 local line = tonumber(num)
2459 if line > lastLine then
2460 lastLine = line
2461 end
2462 end
2463 lineMap[current] = lastLine
2464 current = current + 1
2465 end
2466 return lineMap
2103end 2467end
2468
2469return {
2470 FormatMini = function(src)
2471 local st, ast = ParseLua(src)
2472 if st then
2473 return Format_Mini(ast)
2474 else
2475 return nil, ast
2476 end
2477 end,
2478
2479 FormatYue = function(src)
2480 local st, ast = ParseLua(src)
2481 if st then
2482 local lineMap = GetYueLineMap(src)
2483 if #lineMap == 0 then
2484 return src
2485 end
2486 return FormatYue(ast, lineMap)
2487 else
2488 return nil, ast
2489 end
2490 end
2491}
2104)lua_codes"; 2492)lua_codes";
2105 2493