├── src ├── modules │ ├── WrapInFunction.lua │ ├── watermark.lua │ ├── Compiler │ │ ├── bit.lua │ │ ├── Serializer.lua │ │ ├── VMStrings.lua │ │ ├── Deserializer.lua │ │ ├── Opcode.lua │ │ └── Compiler.lua │ ├── bytecode_encoder.lua │ ├── dynamic_code_generator.lua │ ├── function_inliner.lua │ ├── StringToExpressions.lua │ ├── garbage_code_inserter.lua │ ├── control_flow_obfuscator.lua │ ├── VMGenerator.lua │ ├── opaque_predicate_injector.lua │ ├── compressor.lua │ ├── antitamper.lua │ ├── string_encoder.lua │ └── variable_renamer.lua ├── config.lua ├── pipeline.lua └── hercules.lua ├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── pull_request_template.md └── LICENSE /src/modules/WrapInFunction.lua: -------------------------------------------------------------------------------- 1 | local Wrapper = {} 2 | function Wrapper.process(code) 3 | return [[return (function(...) ]]..code..[[ end)(...)]] 4 | end 5 | return Wrapper 6 | -------------------------------------------------------------------------------- /src/modules/watermark.lua: -------------------------------------------------------------------------------- 1 | -- modules/watermark.lua 2 | local Watermark = {} 3 | 4 | function Watermark.process(code) 5 | return "--[Obfuscated by Hercules v1.6.2 | hercules-obfuscator.xyz/discord | hercules-obfuscator.xyz/source]\n" .. code 6 | end 7 | 8 | return Watermark -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .AppleDouble 3 | .LSOverride 4 | 5 | Icon 6 | 7 | ._* 8 | 9 | .DocumentRevisions-V100 10 | .fseventsd 11 | .Spotlight-V100 12 | .TemporaryItems 13 | .Trashes 14 | .VolumeIcon.icns 15 | .com.apple.timemachine.donotpresent 16 | 17 | .AppleDB 18 | .AppleDesktop 19 | Network Trash Folder 20 | Temporary Items 21 | .apdisk 22 | 23 | /.vs 24 | file_obfuscated.lua 25 | file.lua 26 | tests/ -------------------------------------------------------------------------------- /src/modules/Compiler/bit.lua: -------------------------------------------------------------------------------- 1 | local bit = {} 2 | function bit.band(a, b) 3 | local result = 0 4 | local bitval = 1 5 | while a > 0 and b > 0 do 6 | if (a % 2 == 1) and (b % 2 == 1) then 7 | result = result + bitval 8 | end 9 | bitval = bitval * 2 10 | a = math.floor(a / 2) 11 | b = math.floor(b / 2) 12 | end 13 | return result 14 | end 15 | function bit.lshift(x, n) 16 | return x * 2 ^ n 17 | end 18 | function bit.rshift(x, n) 19 | return math.floor(x / 2 ^ n) 20 | end 21 | return bit 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 1. Go to '...' 15 | 2. Click on '....' 16 | 3. Scroll down to '....' 17 | 4. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Provide a brief description of the changes in this pull request. 4 | 5 | ## Related Issues 6 | 7 | Link any related issues, e.g., `Fixes #{issue number}` or `Closes #{issue number}`. 8 | 9 | ## Changes Made 10 | 11 | - List 12 | - Key 13 | - Changes 14 | 15 | ## Testing Done 16 | 17 | Explain what testing was performed, or steps to reproduce for reviewers. 18 | 19 | ## Checklist 20 | 21 | - Code follows the project's coding guidelines. [Y/N] 22 | - Relevant documentation has been updated (if needed). [Y/N] 23 | - Tests have been added/updated (if applicable). [Y/N] 24 | - All checks pass locally. [Y/N] 25 | 26 | ## Additional Notes 27 | 28 | Include any extra information reviewers should know. 29 | -------------------------------------------------------------------------------- /src/modules/bytecode_encoder.lua: -------------------------------------------------------------------------------- 1 | local BytecodeEncoder = {} 2 | -- will be replaced with a better module 3 | local function encodeBytecode(bytecode, offset) 4 | local encoded = {} 5 | for i = 1, #bytecode do 6 | local byte = bytecode:byte(i) 7 | local shifted_byte = (byte + offset) % 256 8 | table.insert(encoded, string.format("%02X", shifted_byte)) 9 | end 10 | return table.concat(encoded) 11 | end 12 | 13 | function BytecodeEncoder.process(code) 14 | local bytecode = string.dump(assert(load(code))) 15 | local offset = math.random(1, 255) 16 | local encoded_bytecode = encodeBytecode(bytecode, offset) 17 | local alpha = [[ 18 | local e, o, d = "%s", %d, {} 19 | for i = 1, #e, 2 do 20 | local b = tonumber(e:sub(i, i + 1), 16) 21 | b = (b - o + 256) % 256 22 | d[#d + 1] = string.char(b) 23 | end 24 | local f = assert(load(table.concat(d))) 25 | f() 26 | ]] 27 | return string.format(alpha, encoded_bytecode, offset) 28 | end 29 | 30 | return BytecodeEncoder 31 | -------------------------------------------------------------------------------- /src/modules/dynamic_code_generator.lua: -------------------------------------------------------------------------------- 1 | local DynamicCodeGenerator = {} 2 | -- TODO : make it work 3 | function DynamicCodeGenerator.process(code) 4 | local function dynamicWrapper(block) 5 | local func, err = load("return " .. block) 6 | if not func then 7 | error("Failed to load block: " .. err) 8 | end 9 | return func() 10 | end 11 | 12 | local processed_code = {} 13 | local position = 1 14 | 15 | while position <= #code do 16 | local next_position = code:find("[%s%p]", position) 17 | if not next_position then 18 | next_position = #code + 1 19 | end 20 | local block = code:sub(position, next_position - 1) 21 | if #block > 0 then 22 | local success, result = pcall(dynamicWrapper, block) 23 | if success then 24 | table.insert(processed_code, tostring(result)) 25 | else 26 | error("Error processing block '" .. block .. "': " .. result) 27 | end 28 | end 29 | if next_position <= #code then 30 | table.insert(processed_code, code:sub(next_position, next_position)) 31 | end 32 | 33 | position = next_position + 1 34 | end 35 | 36 | return table.concat(processed_code) 37 | end 38 | 39 | return DynamicCodeGenerator 40 | -------------------------------------------------------------------------------- /src/modules/function_inliner.lua: -------------------------------------------------------------------------------- 1 | local FunctionInliner = {} 2 | -- TODO : make it work 3 | function FunctionInliner.process(code) 4 | if code:match("^%s*%-%-.*Obfuscated") then return code end 5 | 6 | local functions = {} 7 | local output = code 8 | 9 | output = output:gsub("%-%-[^\n]*", "") 10 | 11 | output = output:gsub("local%s+function%s+([%w_]+)%s*%(([^)]*)%)(.-)end", function(name, params, body) 12 | functions[name] = {params = params, body = body} 13 | return "" 14 | end) 15 | 16 | output = output:gsub("function%s+([%w_]+)%s*%(([^)]*)%)(.-)end", function(name, params, body) 17 | functions[name] = {params = params, body = body} 18 | return "" 19 | end) 20 | 21 | for name, func in pairs(functions) do 22 | output = output:gsub(name .. "%s*(%b())", function(call) 23 | local args = call:sub(2, -2) 24 | local body = func.body 25 | 26 | local params = {} 27 | for param in func.params:gmatch("[^,%s]+") do 28 | params[#params+1] = param 29 | end 30 | 31 | local arguments = {} 32 | for arg in (args..","):gmatch("([^,]*),") do 33 | arguments[#arguments+1] = arg:match("^%s*(.-)%s*$") 34 | end 35 | 36 | for i, param in ipairs(params) do 37 | local arg = arguments[i] or "nil" 38 | body = body:gsub("%f[%w_]"..param.."%f[^%w_]", arg) 39 | end 40 | 41 | if body:match("^%s*return%s+.+") then 42 | body = body:gsub("^%s*return%s+", "") 43 | end 44 | 45 | return "(" .. body:match("^%s*(.-)%s*$") .. ")" 46 | end) 47 | end 48 | 49 | output = output:gsub("end%s*$", "") 50 | output = output:gsub("end%s*\n", "\n") 51 | output = output:gsub("\n%s*\n", "\n") 52 | 53 | return output 54 | end 55 | 56 | return FunctionInliner 57 | -------------------------------------------------------------------------------- /src/config.lua: -------------------------------------------------------------------------------- 1 | -- config.lua 2 | 3 | local config = {} 4 | 5 | config.settings = { 6 | output_suffix = "_obfuscated.lua", 7 | watermark_enabled = true, 8 | final_print = true, 9 | VirtualMachine = { 10 | enabled = true, 11 | }, 12 | antitamper = { 13 | enabled = true, 14 | }, 15 | control_flow = { 16 | enabled = true, 17 | max_fake_blocks = 6, 18 | }, 19 | StringToExpressions = { 20 | enabled = false, 21 | min_number_length = 100, 22 | max_number_length = 999, 23 | }, 24 | string_encoding = { 25 | enabled = false, 26 | }, 27 | WrapInFunction = { 28 | enabled = true, 29 | }, 30 | variable_renaming = { 31 | enabled = true, 32 | min_name_length = 8, 33 | max_name_length = 12, 34 | }, 35 | garbage_code = { 36 | enabled = true, 37 | garbage_blocks = 20, 38 | }, 39 | opaque_predicates = { 40 | enabled = true, 41 | }, 42 | function_inlining = { 43 | enabled = false, 44 | }, 45 | dynamic_code = { 46 | enabled = false, 47 | }, 48 | bytecode_encoding = { 49 | enabled = false, 50 | }, 51 | compressor = { 52 | enabled = true, 53 | } 54 | } 55 | 56 | function config.get(key) 57 | local keys = {} 58 | for k in key:gmatch("[^.]+") do table.insert(keys, k) end 59 | 60 | local value = config 61 | for _, k in ipairs(keys) do 62 | value = value[k] 63 | if value == nil then 64 | return nil 65 | end 66 | end 67 | return value 68 | end 69 | 70 | function config.set(key, new_value) 71 | local keys = {} 72 | for k in key:gmatch("[^.]+") do table.insert(keys, k) end 73 | 74 | local value = config 75 | for i = 1, #keys - 1 do 76 | value = value[keys[i]] 77 | if value == nil then 78 | return false 79 | end 80 | end 81 | 82 | local last_key = keys[#keys] 83 | if value[last_key] ~= nil then 84 | value[last_key] = new_value 85 | return true 86 | else 87 | return false 88 | end 89 | end 90 | 91 | return config 92 | -------------------------------------------------------------------------------- /src/modules/StringToExpressions.lua: -------------------------------------------------------------------------------- 1 | local StringToExpressions = {} 2 | local math_methods = { 3 | addSub = function(char, base1, base2) 4 | local base = math.random(base1, base2) 5 | local chance = math.random(0, 1) 6 | return chance == 1 and string.format("%d - (%d)", base, base - char) or string.format("%d + %d", char - base, base) 7 | end, 8 | } 9 | 10 | local used_ascii = {} 11 | 12 | local function insertChar(obfuscated, ascii_code, base1, base2) 13 | used_ascii[ascii_code] = true 14 | local part = math_methods.addSub(ascii_code, base1, base2) 15 | table.insert(obfuscated, "chars[" .. part .. "]") 16 | end 17 | 18 | local function formatChar(ascii_code) 19 | if ascii_code < 32 or ascii_code > 126 then 20 | return string.format("\\%03d", ascii_code) 21 | else 22 | return string.char(ascii_code) 23 | end 24 | end 25 | 26 | local function obfuscateStringLiteral(str, base1, base2) 27 | if #str == 0 then 28 | return '""' 29 | end 30 | local escape_chars = { n = 10, r = 13, t = 9, ["'"] = 39, ['"'] = 34 } 31 | local obfuscated = {} 32 | local i = 1 33 | while i <= #str do 34 | local char_code = str:byte(i) 35 | if char_code == 92 and i < #str then 36 | local next_char = str:sub(i + 1, i + 1) 37 | if next_char == "2" and str:sub(i + 2, i + 2) == "7" then 38 | insertChar(obfuscated, 27, base1, base2) 39 | i = i + 2 40 | elseif escape_chars[next_char] then 41 | insertChar(obfuscated, escape_chars[next_char], base1, base2) 42 | i = i + 1 43 | else 44 | insertChar(obfuscated, char_code, base1, base2) 45 | insertChar(obfuscated, str:sub(i + 1, i + 1):byte(), base1, base2) 46 | i = i + 1 47 | end 48 | else 49 | insertChar(obfuscated, char_code, base1, base2) 50 | end 51 | i = i + 1 52 | end 53 | return table.concat(obfuscated, "..") 54 | end 55 | 56 | function StringToExpressions.process(script_content, base1, base2) 57 | script_content = script_content:gsub('\\"', '!@!'):gsub("\\'", "@!@") 58 | local obfuscated_script = script_content:gsub("(['\"])(.-)%1", function(quote, str) 59 | str = str:gsub('!@!', '\\"'):gsub('@!@', "\\'") 60 | local obf = obfuscateStringLiteral(str, base1, base2) 61 | return obf 62 | end) 63 | 64 | local chars_table_parts = {} 65 | for ascii_code, _ in pairs(used_ascii) do 66 | chars_table_parts[#chars_table_parts + 1] = string.format("[%d]=%q", ascii_code, formatChar(ascii_code)) 67 | end 68 | local chars_table = "local chars = {" .. table.concat(chars_table_parts, ",") .. "}\n" 69 | return chars_table .. obfuscated_script 70 | end 71 | 72 | return StringToExpressions 73 | -------------------------------------------------------------------------------- /src/modules/garbage_code_inserter.lua: -------------------------------------------------------------------------------- 1 | local GarbageCodeInserter = {} 2 | 3 | local LOWERCASE_A, LOWERCASE_Z = 97, 122 4 | local MAX_RANDOM_NUMBER = 100 5 | local MAX_LOOP_COUNT = 10 6 | local VARIABLE_NAME_LENGTH = 6 7 | 8 | local function generateRandomVariableName() 9 | local name = {} 10 | for i = 1, VARIABLE_NAME_LENGTH do 11 | table.insert(name, string.char(math.random(LOWERCASE_A, LOWERCASE_Z))) 12 | end 13 | return table.concat(name) 14 | end 15 | 16 | local function generateRandomNumber(max) 17 | return math.random(1, max or MAX_RANDOM_NUMBER) 18 | end 19 | 20 | local code_types = { 21 | variable = function() 22 | return string.format("local %s = %d", generateRandomVariableName(), generateRandomNumber()) 23 | end, 24 | while_loop = function() 25 | return string.format("while %s do local _ = %d break end", 26 | tostring(math.random() > 0.5), 27 | generateRandomNumber(100) 28 | ) 29 | end, 30 | for_loop = function() 31 | return string.format("for %s = 1, %d do local _ = %d end", 32 | generateRandomVariableName(), 33 | generateRandomNumber(MAX_LOOP_COUNT), 34 | generateRandomNumber() 35 | ) 36 | end, 37 | if_statement = function() 38 | return string.format("if %s then local _ = %d end", 39 | tostring(math.random() > 0.5), 40 | generateRandomNumber() 41 | ) 42 | end, 43 | function_def = function() 44 | return string.format("local function %s(%s) local _ = %d end", 45 | generateRandomVariableName(), 46 | generateRandomVariableName(), 47 | generateRandomNumber() 48 | ) 49 | end 50 | } 51 | 52 | local code_type_keys = {} 53 | for k in pairs(code_types) do table.insert(code_type_keys, k) end 54 | 55 | local function generateRandomCode() 56 | return code_types[code_type_keys[math.random(#code_type_keys)]]() 57 | end 58 | 59 | local function generateGarbage(blocks, sep) 60 | sep = sep or "\n" 61 | local garbage_code = {} 62 | for i = 1, blocks do 63 | local code = generateRandomCode() 64 | if not code:match("while true") and not code:match("for %w+ = %d+, %d+ do local _ = %d+ end") then 65 | table.insert(garbage_code, code) 66 | end 67 | end 68 | return table.concat(garbage_code, sep) 69 | end 70 | 71 | function GarbageCodeInserter.process(code, garbage_blocks) 72 | if type(code) ~= "string" or #code == 0 then 73 | error("Input code must be a non-empty string", 2) 74 | end 75 | if type(garbage_blocks) ~= "number" then 76 | error("garbage_blocks must be a number", 2) 77 | end 78 | local prefix_garbage = generateGarbage(garbage_blocks) 79 | local suffix_garbage = generateGarbage(garbage_blocks) 80 | return table.concat({prefix_garbage, code, suffix_garbage}, "\n") 81 | end 82 | 83 | function GarbageCodeInserter.setSeed(seed) 84 | math.randomseed(seed) 85 | end 86 | 87 | return GarbageCodeInserter -------------------------------------------------------------------------------- /src/modules/control_flow_obfuscator.lua: -------------------------------------------------------------------------------- 1 | local ControlFlowObfuscator = {} 2 | -- TODO : make it better 3 | 4 | math.randomseed(os.time()) 5 | 6 | local function controlFlow(code, n, a, depth, depth_values) 7 | n = n or math.floor(math.random() * 7000) 8 | a = n 9 | depth = depth or 0 10 | depth_values = depth_values or {} 11 | depth_values[#depth_values + 1] = {n, a} 12 | 13 | local operators = {">", "<", "=="} 14 | local while_operator = operators[math.random(1, 3)] 15 | 16 | local step = math.floor(math.random() * 990) + 10 17 | local max_iterations = 3 18 | if while_operator == "<" then 19 | a = n + (step * max_iterations) 20 | elseif while_operator == ">" then 21 | a = n - (step * max_iterations) 22 | if a < 0 then a = 0 end 23 | step = -step 24 | elseif while_operator == "==" then 25 | a = n 26 | if math.random() > 0.5 then step = -step end 27 | end 28 | 29 | local threshold = (n + step) 30 | 31 | local src = depth == 0 and string.format( 32 | "local thing = %d;\nlocal thing2 = %d;\nlocal counter = 0;\nlocal threshold = %d;\n", 33 | n, a, threshold 34 | ) or "" 35 | 36 | src = src .. string.format( 37 | "while thing %s thing2 and counter < %d do\n", 38 | while_operator, max_iterations 39 | ) 40 | src = src .. string.format(" thing = thing + %d;\n", step) 41 | src = src .. " counter = counter + 1;\n" 42 | src = src .. " if thing < threshold then\n" 43 | 44 | local function generateSpoof() 45 | local spoof_lines = { 46 | string.format("local temp = %d; temp = temp * 2;", math.floor(math.random() * 100)), 47 | "local str = 'dummy'; str = str .. str;", 48 | string.format("local x = %d; x = x - %d;", math.floor(math.random() * 50), math.floor(math.random() * 10)), 49 | "local tbl = {1, 2, 3}; table.sort(tbl, function(a, b) return a > b end);" 50 | } 51 | return spoof_lines[math.random(1, #spoof_lines)] 52 | end 53 | 54 | if depth == (#code - 1) then 55 | src = src .. string.format(" %s\n", generateSpoof()) 56 | src = src .. string.format(" else\n %s\n break\n", code[1]) 57 | table.remove(code, 1) 58 | else 59 | local sub_src, new_n, new_a = controlFlow(code, n, a, depth + 1, depth_values) 60 | src = src .. string.format(" %s\n", generateSpoof()) 61 | src = src .. string.format(" else\n %s\n break\n", sub_src) 62 | n = new_n 63 | a = new_a 64 | end 65 | 66 | src = src .. " end\nend\n" 67 | 68 | if math.random() > 0.5 then 69 | src = src .. string.format("local dummy = 1; dummy = dummy + %d;\n", math.floor(math.random() * 10)) 70 | end 71 | 72 | return depth == 0 and src or {src, n, a} 73 | end 74 | 75 | function ControlFlowObfuscator.process(code, max_fake_blocks) 76 | if type(code) ~= "string" then 77 | error("Input code must be a string") 78 | end 79 | 80 | local code_table = {code} 81 | return controlFlow(code_table) 82 | end 83 | 84 | return ControlFlowObfuscator -------------------------------------------------------------------------------- /src/modules/VMGenerator.lua: -------------------------------------------------------------------------------- 1 | local Parts = require("modules/Compiler/VMStrings") 2 | local GetOpcodeCode = require("modules/Compiler/Opcode") 3 | local compile = require("modules/Compiler/Compiler") 4 | math.randomseed(os.time()) 5 | local function generate(...) 6 | local data = { 7 | ... 8 | } 9 | local bytecode = data[1] 10 | local used_opcodes = data[2] 11 | local lines = {} 12 | local function add(line) 13 | lines[#lines+1] = line 14 | end; 15 | local function generateVariable(length) 16 | local charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 17 | local result = {} 18 | for i = 1, length do 19 | local rand = math.random(1, # charset) 20 | table.insert(result, charset:sub(rand, rand)) 21 | end; 22 | return table.concat(result) 23 | end; 24 | local function stringShuffle(str) 25 | local n = #str 26 | local codes = {} 27 | for i = 1, n do codes[i] = str:byte(i) end 28 | for i = n, 2, -1 do 29 | local j = math.random(1, i) 30 | codes[i], codes[j] = codes[j], codes[i] 31 | end 32 | for i = 1, n do codes[i] = string.char(codes[i]) end 33 | return table.concat(codes) 34 | end; 35 | local function getChar(n) 36 | local out = {} 37 | for i = 1, n do 38 | out[#out + 1] = string.char(i) 39 | end 40 | return table.concat(out) 41 | end 42 | local charset = stringShuffle(getChar(94)) 43 | local base, encode_lookup, decode_lookup = # charset, {}, {} 44 | for i = 1, base do 45 | local c = charset:sub(i, i) 46 | encode_lookup[i - 1], decode_lookup[c] = c, i - 1 47 | end; 48 | local function encodeNumber(n) 49 | local e = {} 50 | repeat 51 | local r = n % base; 52 | table.insert(e, 1, encode_lookup[r]) 53 | n = math.floor(n / base) 54 | until n == 0; 55 | return table.concat(e) 56 | end; 57 | local function encodeString(str) 58 | local encoded = {} 59 | for i = 1, # str do 60 | local char = str:sub(i, i) 61 | table.insert(encoded, encodeNumber(char:byte())) 62 | end; 63 | return table.concat(encoded, "_") 64 | end; 65 | local function encode(str_param, yes) 66 | yes = yes or false 67 | if not yes then 68 | str_param = encodeString(str_param) 69 | end 70 | local out = {} 71 | for i = 1, #str_param do 72 | local b = string.byte(str_param, i) 73 | table.insert(out, "\\" .. b) 74 | end 75 | 76 | return table.concat(out) 77 | end 78 | add("hercules,v1,alpha,__,_ = 'Protected By Hercules V1.6 | github.com/zeusssz/hercules-obfuscator', function()end, true, 1, 0") 79 | add(Parts.Variables) 80 | add(Parts.Deserializer) 81 | add(Parts.Wrapper_1) 82 | local k = "if" 83 | for i, v in pairs(used_opcodes) do 84 | local op = used_opcodes[v] 85 | add(k .. " (S == " .. op .. ") then\n") 86 | add(GetOpcodeCode(op)) 87 | k = "elseif" 88 | end; 89 | add("end") 90 | add(Parts.Wrapper_2) 91 | add("WrapState(BcToState('" .. encode(bytecode) .. "','" .. encode(charset,true) .. "'),(getfenv and getfenv(0)) or _ENV)()") 92 | return table.concat(lines, "\n") 93 | end; 94 | local VM = {} 95 | function VM.process(source) 96 | _G.UsedOps = _G.UsedOps or {} 97 | _G.UsedOps[0] = 0; 98 | _G.UsedOps[4] = 4; 99 | source = generate(compile(source), _G.UsedOps) 100 | return source 101 | end; 102 | return VM 103 | -------------------------------------------------------------------------------- /src/modules/Compiler/Serializer.lua: -------------------------------------------------------------------------------- 1 | local bit = require("modules/Compiler/bit") 2 | function Serialize(Chunk) 3 | local Buffer = {} 4 | local function AddByte(Value) 5 | table.insert(Buffer, string.char(Value).."\\") 6 | end; 7 | local function WriteBits8(Value) 8 | AddByte(Value) 9 | end; 10 | local function WriteBits16(Value) 11 | for i = 0, 1 do 12 | AddByte(bit.band(bit.rshift(Value, i * 8), 255)) 13 | end 14 | end; 15 | local function WriteBits32(Value) 16 | for i = 0, 3 do 17 | AddByte(bit.band(bit.rshift(Value, i * 8), 255)) 18 | end 19 | end; 20 | local function WriteFloat64(value) 21 | local sign = 0; 22 | if value < 0 or (value == 0 and 1 / value == - math.huge) then 23 | sign = 1 24 | end; 25 | local mantissa, exponent = math.frexp(math.abs(value)) 26 | if value == 0 then 27 | exponent, mantissa = 0, 0 28 | elseif value == math.huge then 29 | exponent, mantissa = 2047, 0 30 | elseif value ~= value then 31 | exponent, mantissa = 2047, 1 32 | else 33 | mantissa = (mantissa * 2 - 1) * 2 ^ 52; 34 | exponent = exponent + 1022 35 | end; 36 | local high = sign * 2 ^ 31 + exponent * 2 ^ 20 + math.floor(mantissa / 2 ^ 32) 37 | local low = mantissa % 2 ^ 32; 38 | WriteBits32(low) 39 | WriteBits32(high) 40 | end; 41 | local function WriteString(Str) 42 | WriteBits32(# Str) 43 | for i = 1, # Str do 44 | WriteBits8(string.byte(Str, i)) 45 | end 46 | end; 47 | local function WriteChunk(SubChunk) 48 | WriteBits8(SubChunk.Upvals) 49 | WriteBits8(SubChunk.Parameters) 50 | WriteBits8(SubChunk.MaxStack) 51 | WriteBits32(# SubChunk.Instructions) 52 | for i = 1, # SubChunk.Instructions do 53 | local Inst = SubChunk.Instructions[i] 54 | local Data = Inst.Value; 55 | local Enum = Inst.Enum; 56 | local Type = Inst.Type; 57 | local Mode = Inst.Mode; 58 | WriteBits32(Data) 59 | WriteBits8(Enum) 60 | WriteBits8((Type == "ABC" and 1) or (Type == "ABx" and 2) or (Type == "AsBx" and 3)) 61 | WriteBits16(Inst.A) 62 | if (Mode.b == "OpArgK") then 63 | WriteBits8(1) 64 | elseif (Mode.b == "OpArgN") then 65 | WriteBits8(0) 66 | elseif (Mode.b == "OpArgU") then 67 | WriteBits8(0) 68 | elseif (Mode.b == "OpArgR") then 69 | WriteBits8(0) 70 | end; 71 | if (Mode.c == "OpArgK") then 72 | WriteBits8(1) 73 | elseif (Mode.c == "OpArgN") then 74 | WriteBits8(0) 75 | elseif (Mode.c == "OpArgU") then 76 | WriteBits8(0) 77 | elseif (Mode.c == "OpArgR") then 78 | WriteBits8(0) 79 | end; 80 | if (Type == "ABC") then 81 | WriteBits16(Inst.B) 82 | WriteBits16(Inst.C) 83 | elseif (Type == "ABx") then 84 | WriteBits32(Inst.Bx) 85 | elseif (Type == "AsBx") then 86 | WriteBits32(Inst.sBx + 131071) 87 | end 88 | end; 89 | WriteBits32(# SubChunk.Constants) 90 | for i = 1, # SubChunk.Constants do 91 | local Const = SubChunk.Constants[i] 92 | local Type = type(Const) 93 | if (Type == "boolean") then 94 | WriteBits8(1) 95 | WriteBits8(Const and 1 or 0) 96 | elseif (Type == "number") then 97 | WriteBits8(3) 98 | WriteFloat64(Const) 99 | elseif (Type == "string") then 100 | WriteBits8(4) 101 | WriteString(Const) 102 | end 103 | end; 104 | WriteBits32(# SubChunk.Protos) 105 | for i = 1, # SubChunk.Protos do 106 | WriteChunk(SubChunk.Protos[i]) 107 | end 108 | end; 109 | WriteChunk(Chunk) 110 | return table.concat(Buffer) 111 | end; 112 | return Serialize 113 | -------------------------------------------------------------------------------- /src/modules/opaque_predicate_injector.lua: -------------------------------------------------------------------------------- 1 | local OpaquePredicateInjector = {} 2 | -- TODO : make it better 3 | local function generatePredicates() 4 | local predicates = { 5 | function() 6 | local n = math.random(10, 100) 7 | return string.format("if (%d %% 1 == 0 and %d >= %d) then", n, n, n) 8 | end, 9 | function() 10 | local x = math.random(1, 10) 11 | return string.format("if (%d %% %d == 0) then", x, x) 12 | end, 13 | function() 14 | local angle = math.random(0, 360) 15 | return string.format("if (math.sin(%d)^2 + math.cos(%d)^2 >= 0.99999) then", 16 | angle, angle) 17 | end, 18 | function() 19 | local str = string.format("%x", math.random(1000, 9999)) 20 | return string.format("if (select(2, pcall(function() return tonumber('%s', 16) end)) ~= nil) then", str) 21 | end, 22 | function() 23 | local size = math.random(2, 5) 24 | return string.format("if (#{%s} == %d) then", 25 | string.rep("1,", size-1) .. "1", size) 26 | end, 27 | function() 28 | local a, b = math.random(1, 10), math.random(11, 20) 29 | return string.format("if ((%d < %d) == not (%d >= %d)) then", a, b, a, b) 30 | end 31 | } 32 | return predicates[math.random(#predicates)]() 33 | end 34 | 35 | local function isInjectSafe(statement) 36 | if statement:match("^%s*[%{%}]%s*$") or 37 | statement:match("^%s*$") or 38 | not statement:match(".+;") then 39 | return false 40 | end 41 | local unsafes = { 42 | "^%s*for%s+", 43 | "^%s*while%s+", 44 | "^%s*if%s+", 45 | "^%s*repeat%s+", 46 | "^%s*until%s+", 47 | "^%s*function%s+", 48 | "^%s*local%s+function", 49 | "^%s*do%s+", 50 | } 51 | for _, pattern in ipairs(unsafes) do 52 | if statement:match(pattern) then 53 | return false 54 | end 55 | end 56 | if statement:match("^%s*if%s+.+%s+then%s+.+%s+end%s*;?$") then 57 | return false 58 | end 59 | return true 60 | end 61 | 62 | local function injectPredicates(block) 63 | if block:match("%s*end%s*;?$") or block:match("^%s*return") then 64 | return block 65 | else 66 | local predicate = generatePredicates() 67 | return predicate .. block .. " end;" 68 | end 69 | end 70 | 71 | function OpaquePredicateInjector.process(code) 72 | if type(code) ~= "string" then 73 | error("Input must be a string") 74 | end 75 | local success, processed_code = pcall(function() 76 | local result = code:gsub("([ \t]*)([^\n;]*;)", function(ws, statement) 77 | if isInjectSafe(statement) then 78 | return ws .. injectPredicates(statement) 79 | else 80 | return ws .. statement 81 | end 82 | end) 83 | result = result:gsub("([ \t]*)(return%s+[^\n;]+;)", function(ws, return_stmt) 84 | return ws .. return_stmt 85 | end) 86 | return result 87 | end) 88 | if not success then 89 | error("Failed to process code: " .. tostring(processed_code)) 90 | end 91 | return processed_code 92 | end 93 | 94 | function OpaquePredicateInjector.validateCode(code) 95 | local f, err = load(code) 96 | return f ~= nil, err 97 | end 98 | 99 | return OpaquePredicateInjector 100 | -------------------------------------------------------------------------------- /src/pipeline.lua: -------------------------------------------------------------------------------- 1 | --pipeline.lua 2 | local config = require("config") 3 | 4 | local StringEncoder = require("modules/string_encoder") 5 | local VariableRenamer = require("modules/variable_renamer") 6 | local ControlFlowObfuscator = require("modules/control_flow_obfuscator") 7 | local GarbageCodeInserter = require("modules/garbage_code_inserter") 8 | local OpaquePredicateInjector = require("modules/opaque_predicate_injector") 9 | local FunctionInliner = require("modules/function_inliner") 10 | local DynamicCodeGenerator = require("modules/dynamic_code_generator") 11 | local BytecodeEncoder = require("modules/bytecode_encoder") 12 | local Watermarker = require("modules/watermark") 13 | local Compressor = require("modules/compressor") 14 | local StringToExpressions = require("modules/StringToExpressions") 15 | local WrapInFunction = require("modules/WrapInFunction") 16 | local VirtualMachinery = require("modules/VMGenerator") 17 | local AntiTamper = require("modules/antitamper") 18 | 19 | local Pipeline = {} 20 | 21 | function Pipeline.process(code) 22 | if config.get("settings.string_encoding.enabled") then 23 | code = StringEncoder.process(code) 24 | end 25 | 26 | if config.get("settings.garbage_code.enabled") then 27 | local garbage_blocks = config.get("settings.garbage_code.garbage_blocks") 28 | code = GarbageCodeInserter.process(code, garbage_blocks) 29 | end 30 | 31 | if config.get("settings.dynamic_code.enabled") then 32 | code = DynamicCodeGenerator.process(code) 33 | end 34 | 35 | if config.get("settings.opaque_predicates.enabled") then 36 | code = OpaquePredicateInjector.process(code) 37 | end 38 | 39 | if config.get("settings.bytecode_encoding.enabled") then 40 | code = BytecodeEncoder.process(code) 41 | end 42 | 43 | if config.get("settings.function_inlining.enabled") then 44 | code = FunctionInliner.process(code) 45 | end 46 | 47 | if config.get("settings.StringToExpressions.enabled") then 48 | local min_length = config.get("settings.StringToExpressions.min_number_length") 49 | local max_length = config.get("settings.StringToExpressions.max_number_length") 50 | code = StringToExpressions.process(code, min_length, max_length) 51 | end 52 | if config.get("settings.antitamper.enabled") then 53 | code = AntiTamper.process(code) 54 | end 55 | if config.get("settings.VirtualMachine.enabled") then 56 | code = VirtualMachinery.process(code) 57 | end 58 | 59 | if config.get("settings.control_flow.enabled") then 60 | local max_fake_blocks = config.get("settings.control_flow.max_fake_blocks") 61 | code = ControlFlowObfuscator.process(code, max_fake_blocks) 62 | end 63 | if config.get("settings.garbage_code.enabled") then 64 | local garbage_blocks = config.get("settings.garbage_code.garbage_blocks") 65 | code = GarbageCodeInserter.process(code, garbage_blocks) 66 | end 67 | if config.get("settings.variable_renaming.enabled") then 68 | local min_length = config.get("settings.variable_renaming.min_name_length") 69 | local max_length = config.get("settings.variable_renaming.max_name_length") 70 | code = VariableRenamer.process(code, { min_length = min_length, max_length = max_length }) 71 | end 72 | 73 | if config.get("settings.compressor.enabled") then 74 | code = Compressor.process(code) 75 | end 76 | 77 | if config.get("settings.WrapInFunction.enabled") then 78 | code = WrapInFunction.process(code) 79 | end 80 | 81 | if config.get("settings.watermark_enabled") then 82 | code = Watermarker.process(code) 83 | end 84 | 85 | return code 86 | end 87 | 88 | return Pipeline 89 | -------------------------------------------------------------------------------- /src/modules/compressor.lua: -------------------------------------------------------------------------------- 1 | local Compressor = {} 2 | 3 | local LUA_KEYWORDS = { 4 | "and", "break", "do", "else", "elseif", "end", "false", "for", "function", 5 | "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", 6 | "then", "true", "until", "while" 7 | } 8 | 9 | local KW_PLACEHOLDER_PRE = "@@KW_" 10 | local KW_PLACEHOLDER_POST = "_KW@@" 11 | local STR_PLACEHOLDER_PRE = "@@S_" 12 | local STR_PLACEHOLDER_POST = "_S@@" 13 | 14 | function Compressor.process(code) 15 | if type(code) ~= "string" then 16 | error("Input code must be a string.", 2) 17 | end 18 | if #code < 10 or code:match("^[%s%d%p]*$") then 19 | return code:match("^%s*(.-)%s*$") or "" 20 | end 21 | 22 | local strings = {} 23 | local string_count = 0 24 | local keywords_map = {} 25 | 26 | local function preserveStrings(c) 27 | c = c:gsub("%[(=*)%[(.-)%]%1%]", function(equals, str) 28 | string_count = string_count + 1 29 | local key = STR_PLACEHOLDER_PRE .. string_count .. STR_PLACEHOLDER_POST 30 | strings[key] = "[" .. equals .. "[" .. str .. "]" .. equals .. "]" 31 | return key 32 | end) 33 | c = c:gsub('"(.-)"', function(str) 34 | if not str:find("\\", 1, true) and str:find(STR_PLACEHOLDER_PRE, 1, true) then 35 | return '"'..str..'"' 36 | end 37 | string_count = string_count + 1 38 | local key = STR_PLACEHOLDER_PRE .. string_count .. STR_PLACEHOLDER_POST 39 | strings[key] = '"' .. str .. '"' 40 | return key 41 | end) 42 | c = c:gsub("('.-')", function(str) 43 | if not str:find("\\", 1, true) and str:find(STR_PLACEHOLDER_PRE, 1, true) then 44 | return "'"..str.."'" 45 | end 46 | string_count = string_count + 1 47 | local key = STR_PLACEHOLDER_PRE .. string_count .. STR_PLACEHOLDER_POST 48 | strings[key] = str 49 | return key 50 | end) 51 | return c 52 | end 53 | 54 | local function preserveKeywords(c) 55 | for _, keyword in ipairs(LUA_KEYWORDS) do 56 | local placeholder = KW_PLACEHOLDER_PRE .. keyword .. KW_PLACEHOLDER_POST 57 | keywords_map[placeholder] = keyword 58 | c = c:gsub("([^%w_])(" .. keyword .. ")([^%w_])", "%1"..placeholder.."%3") 59 | c = c:gsub("^(" .. keyword .. ")([^%w_])", placeholder.."%2") 60 | c = c:gsub("([^%w_])(" .. keyword .. ")$", "%1"..placeholder) 61 | c = c:gsub("^(" .. keyword .. ")$", placeholder) 62 | end 63 | return c 64 | end 65 | 66 | local function restoreKeywords(c) 67 | for placeholder, keyword in pairs(keywords_map) do 68 | c = string.gsub(c, placeholder, function() return keyword end) 69 | end 70 | return c 71 | end 72 | 73 | local function restoreStrings(c) 74 | for i = string_count, 1, -1 do 75 | local key = STR_PLACEHOLDER_PRE .. i .. STR_PLACEHOLDER_POST 76 | c = string.gsub(c, key, function() return strings[key] end) 77 | end 78 | return c 79 | end 80 | 81 | code = preserveStrings(code) 82 | code = preserveKeywords(code) 83 | 84 | code = code:gsub("--%[%[.-%]%]", "") 85 | code = code:gsub("%-%-[^\n]*", "") 86 | 87 | code = code:gsub("[\n\r]+", " ") 88 | code = code:gsub("%s+", " ") 89 | 90 | code = code:gsub("%s*%.%.%s*", "..") 91 | code = code:gsub("%s*([%+%-%*/%%\\^#%<%>%~%=%,%;:%(%){}%[%]])%s*", "%1") 92 | code = code:gsub("%s*%.%s*", ".") 93 | code = code:gsub("%.%.", "..") 94 | 95 | code = code:match("^%s*(.-)%s*$") or "" 96 | 97 | code = restoreKeywords(code) 98 | code = restoreStrings(code) 99 | 100 | return code 101 | end 102 | 103 | return Compressor -------------------------------------------------------------------------------- /src/modules/antitamper.lua: -------------------------------------------------------------------------------- 1 | local AntiTamper = {} 2 | -- anti beautify + simple anti tamper for now 3 | function AntiTamper.process(code) 4 | local anti_tamper_code = [[ 5 | do 6 | local D,T,P,X,S,E,R,Pa,GM,SM,RG,RS,RE,CG,Sel,C,G= 7 | debug,type,pcall,xpcall,tostring,error,rawget,pairs, 8 | getmetatable,setmetatable,rawget,rawset,rawequal,collectgarbage,select,coroutine,_G 9 | 10 | local function dbgOK() 11 | if T(D)~="table" then return false end 12 | for _,k in Pa{"getinfo","getlocal","getupvalue","traceback","sethook","setupvalue","getregistry"} do 13 | if T(D[k])~="function" then return false end 14 | end 15 | return true 16 | end 17 | if not dbgOK() then E("Tamper Detected! Reason: Debug library incomplete") return end 18 | 19 | local function isNative(f) 20 | local i=D.getinfo(f) 21 | return i and i.what=="C" 22 | end 23 | 24 | local function checkNativeFuncs() 25 | local natives={ 26 | P,X,assert,E,print,RG,RS,RE,tonumber,S,T, 27 | Sel,next,ipairs,Pa,CG,GM,SM, 28 | load,loadstring,loadfile,dofile,collectgarbage, 29 | D.getinfo,D.getlocal,D.getupvalue,D.sethook,D.setupvalue,D.traceback, 30 | C.create,C.resume,C.yield,C.status, 31 | math.abs,math.acos,math.asin,math.atan,math.ceil,math.cos,math.deg,math.exp, 32 | math.floor,math.fmod,math.huge,math.log,math.max,math.min,math.modf,math.pi, 33 | math.rad,math.random,math.sin,math.sqrt,math.tan, 34 | os.clock,os.date,os.difftime,os.execute,os.exit,os.getenv,os.remove, 35 | os.rename,os.setlocale,os.time,os.tmpname, 36 | string.byte,string.char,string.dump,string.find,string.format,string.gmatch, 37 | string.gsub,string.len,string.lower,string.match,string.rep,string.reverse, 38 | string.sub,string.upper, 39 | table.insert,table.maxn,table.remove,table.sort 40 | } 41 | local mts={string,table,math,os,G,package} 42 | for _,t in Pa(mts) do 43 | local mt=GM(t) 44 | if mt then 45 | for _,m in Pa{"__index","__newindex","__call","__metatable"} do 46 | local mf=mt[m] 47 | if mf and T(mf)=="function" and not isNative(mf) then 48 | return false,"Metamethod tampered: "..m 49 | end 50 | end 51 | end 52 | end 53 | for _,fn in Pa(natives) do 54 | if T(fn)=="function" and not isNative(fn) then 55 | return false,"Native function replaced or wrapped" 56 | end 57 | end 58 | return true 59 | end 60 | 61 | local function isMinified(f) 62 | local i=D.getinfo(f,"Sl") 63 | return i and i.linedefined==i.lastlinedefined 64 | end 65 | 66 | local function scanUp(f) 67 | local i=1 68 | while true do 69 | local n,v=D.getupvalue(f,i) 70 | if not n then break end 71 | if T(v)=="function" and not isMinified(v) then return false,"Suspicious upvalue: "..n end 72 | i=i+1 73 | end 74 | return true 75 | end 76 | 77 | local function scanLocals(l) 78 | local i=1 79 | while true do 80 | local n,v=D.getlocal(l,i) 81 | if not n then break end 82 | if T(v)=="function" and not isMinified(v) then return false,"Suspicious local: "..n end 83 | i=i+1 84 | end 85 | return true 86 | end 87 | 88 | local function checkGlobals() 89 | local essentials={"pcall","xpcall","type","tostring","string","table","debug","coroutine","math","os","package"} 90 | for _,k in Pa(essentials) do 91 | if T(G[k])~=T(_G[k]) then return false,"Global modified: "..k end 92 | end 93 | if package and package.loaded and T(package.loaded.debug)~="table" then 94 | return false,"Package.debug modified" 95 | end 96 | return true 97 | end 98 | 99 | local function run() 100 | local ok,r=checkNativeFuncs() 101 | if not ok then return false,r end 102 | ok,r=checkGlobals() 103 | if not ok then return false,r end 104 | for l=2,4 do 105 | local i=D.getinfo(l,"f") 106 | if i and i.func then 107 | ok,r=scanUp(i.func) 108 | if not ok then return false,r.." @lvl "..l end 109 | end 110 | ok,r=scanLocals(l) 111 | if not ok then return false,r.." @lvl "..l end 112 | end 113 | return true 114 | end 115 | 116 | local ok,r=run() 117 | if not ok then 118 | E("Tamper Detected! Reason: "..S(r)) 119 | while true do E("Tamper Detected! Reason: "..S(r)) end 120 | end 121 | end 122 | ]] 123 | return anti_tamper_code .. "\n" .. code 124 | end 125 | 126 | return AntiTamper 127 | -------------------------------------------------------------------------------- /src/modules/string_encoder.lua: -------------------------------------------------------------------------------- 1 | local StringEncoder = {} 2 | 3 | local function generateRandomName(len) 4 | len = len or math.random(8, 12) 5 | local charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 6 | local name = "" 7 | for _ = 1, len do 8 | local index = math.random(1, #charset) 9 | name = name .. charset:sub(index, index) 10 | end 11 | return name 12 | end 13 | 14 | local function isValidChar(byte) 15 | return (byte >= 48 and byte <= 57) or (byte >= 65 and byte <= 90) or (byte >= 97 and byte <= 122) 16 | end 17 | 18 | local function caesarCipher(data, offset) 19 | local result = {} 20 | local i = 1 21 | while i <= #data do 22 | local byte = data:byte(i) 23 | if byte == 92 and i < #data then 24 | local next_char = data:sub(i + 1, i + 1) 25 | if next_char == "2" and data:sub(i+2,i+2) == "7" then 26 | table.insert(result, string.char(byte)) 27 | table.insert(result, next_char) 28 | table.insert(result, data:sub(i+2,i+2)) 29 | i = i + 2 30 | else 31 | table.insert(result, string.char(byte)) 32 | table.insert(result, next_char) 33 | i = i + 1 34 | end 35 | elseif isValidChar(byte) then 36 | local new_byte 37 | if byte >= 48 and byte <= 57 then 38 | new_byte = ((byte - 48 + offset) % 10) + 48 39 | elseif byte >= 65 and byte <= 90 then 40 | new_byte = ((byte - 65 + offset) % 26) + 65 41 | elseif byte >= 97 and byte <= 122 then 42 | new_byte = ((byte - 97 + offset) % 26) + 97 43 | end 44 | table.insert(result, string.char(new_byte)) 45 | else 46 | table.insert(result, string.char(byte)) 47 | end 48 | 49 | i = i + 1 50 | end 51 | return table.concat(result) 52 | end 53 | 54 | function StringEncoder.process(code) 55 | local random_decrypt_name = generateRandomName() 56 | local random_isvalidchar_name = generateRandomName() 57 | local random_result_name = generateRandomName() 58 | local random_code_name = generateRandomName() 59 | local random_offset_name = generateRandomName() 60 | local random_byte_name = generateRandomName() 61 | local random_new_byte_name = generateRandomName() 62 | 63 | local decode_function = [[ 64 | local function ]] .. random_isvalidchar_name .. [[(]] .. random_byte_name .. [[) 65 | return (]] .. random_byte_name .. [[ >= 48 and ]] .. random_byte_name .. [[ <= 57) or (]] .. random_byte_name .. [[ >= 65 and ]] .. random_byte_name .. [[ <= 90) or (]] .. random_byte_name .. [[ >= 97 and ]] .. random_byte_name .. [[ <= 122) 66 | end 67 | 68 | local function ]] .. random_decrypt_name .. [[(]] .. random_code_name .. [[, ]] .. random_offset_name .. [[) 69 | local ]] .. random_result_name .. [[ = {} 70 | for i = 1, #]] .. random_code_name .. [[ do 71 | local ]] .. random_byte_name .. [[ = ]] .. random_code_name .. [[:byte(i) 72 | if ]] .. random_isvalidchar_name .. [[(]] .. random_byte_name .. [[) then 73 | local ]] .. random_new_byte_name .. [[ 74 | if ]] .. random_byte_name .. [[ >= 48 and ]] .. random_byte_name .. [[ <= 57 then 75 | ]] .. random_new_byte_name .. [[ = ((]] .. random_byte_name .. [[ - 48 - ]] .. random_offset_name .. [[ + 10) % 10) + 48 76 | elseif ]] .. random_byte_name .. [[ >= 65 and ]] .. random_byte_name .. [[ <= 90 then 77 | ]] .. random_new_byte_name .. [[ = ((]] .. random_byte_name .. [[ - 65 - ]] .. random_offset_name .. [[ + 26) % 26) + 65 78 | elseif ]] .. random_byte_name .. [[ >= 97 and ]] .. random_byte_name .. [[ <= 122 then 79 | ]] .. random_new_byte_name .. [[ = ((]] .. random_byte_name .. [[ - 97 - ]] .. random_offset_name .. [[ + 26) % 26) + 97 80 | end 81 | table.insert(]] .. random_result_name .. [[, string.char(]] .. random_new_byte_name .. [[)) 82 | else 83 | table.insert(]] .. random_result_name .. [[, string.char(]] .. random_byte_name .. [[)) 84 | end 85 | end 86 | return table.concat(]] .. random_result_name .. [[) 87 | end 88 | 89 | local function ]] .. random_isvalidchar_name .. [[(]] .. random_byte_name .. [[) 90 | return (]] .. random_byte_name .. [[ >= 48 and ]] .. random_byte_name .. [[ <= 57) or (]] .. random_byte_name .. [[ >= 65 and ]] .. random_byte_name .. [[ <= 90) or (]] .. random_byte_name .. [[ >= 97 and ]] .. random_byte_name .. [[ <= 122) 91 | end 92 | ]] 93 | code = code:gsub('\\"', '!@!'):gsub("\\'", "@!@") 94 | 95 | code = code:gsub("(['\"])(.-)%1", function(quote,str) 96 | if type(str) == "string" then 97 | str = str:gsub('!@!', '\\"'):gsub('@!@', "\\'") 98 | 99 | local offset = math.random(1, 9) 100 | if str:match("%a") then 101 | offset = math.random(1, 25) 102 | end 103 | local encoded_str = caesarCipher(str, offset) 104 | return string.format("%s(" .. quote .. "%s" .. quote .. ", %d)", random_decrypt_name, encoded_str, offset) 105 | else 106 | return str 107 | end 108 | end) 109 | 110 | return decode_function .. "\n" .. code 111 | end 112 | 113 | return StringEncoder 114 | -------------------------------------------------------------------------------- /src/modules/variable_renamer.lua: -------------------------------------------------------------------------------- 1 | local VariableRenamer = {} 2 | local varenc_names = {} 3 | local lua_functions = { 4 | "assert", "collectgarbage", "dofile", "loadfile", "loadstring", 5 | "ipairs", "pairs", "tonumber", "tostring", "type", "print", 6 | "_G", "_VERSION", "write", "sort", 7 | "math.abs", "math.acos", "math.asin", "math.atan", "math.atan2", 8 | "math.ceil", "math.cos", "math.cosh", "math.deg", "math.exp", 9 | "math.floor", "math.fmod", "math.frexp", "math.ldexp", "math.log", 10 | "math.log10", "math.max", "math.min", "math.modf", "math.pi", 11 | "math.pow", "math.rad", "math.random", "math.randomseed", "math.sin", 12 | "math.sinh", "math.sqrt", "math.tan", "math.tanh", 13 | "string.byte", "string.char", "string.dump", "string.find", 14 | "string.format", "string.gmatch", "string.gsub", "string.len", 15 | "string.lower", "string.match", "string.rep", "string.reverse", 16 | "string.sub", "string.upper", 17 | "table.concat", "table.insert", "table.remove", "table.sort", 18 | "table.pack", "table.unpack", "game:GetService", 19 | } 20 | 21 | local reserved_words = { 22 | ["if"] = true, ["then"] = true, ["else"] = true, ["elseif"] = true, ["end"] = true, 23 | ["for"] = true, ["while"] = true, ["do"] = true, ["repeat"] = true, ["until"] = true, 24 | ["function"] = true, ["local"] = true, ["return"] = true, ["break"] = true, ["continue"] = true, 25 | ["and"] = true, ["or"] = true, ["not"] = true, ["in"] = true, ["nil"] = true, 26 | ["true"] = true, ["false"] = true 27 | } 28 | 29 | local DEFAULT_MIN_NAME_LENGTH, DEFAULT_MAX_NAME_LENGTH = 8, 12 30 | local name_min, name_max = DEFAULT_MIN_NAME_LENGTH, DEFAULT_MAX_NAME_LENGTH 31 | 32 | local function generateRandomName() 33 | local len = math.random(name_min, name_max) 34 | local charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 35 | local name = "" 36 | for _ = 1, len do 37 | local index = math.random(1, #charset) 38 | name = name .. charset:sub(index, index) 39 | end 40 | return name 41 | end 42 | 43 | local function replaceUnquoted(input, target, replacement) 44 | local placeholder = "!!!" 45 | local protected_input = input:gsub('(["\'])(.-)%1', function(q, content) 46 | content = content:gsub('\\"', '!@!'):gsub("\\'", "@!@") 47 | content = content:gsub(target, placeholder) 48 | content = content:gsub('!@!', '\\"'):gsub('@!@', "\\'") 49 | return q .. content .. q 50 | end) 51 | local result = protected_input:gsub('(%f[%w_])' .. target .. '(%f[^%w_])', function(before, after) 52 | return before .. replacement .. after 53 | end) 54 | result = result:gsub(placeholder, target) 55 | return result 56 | end 57 | 58 | local function obfuscateLocalVariables(code) 59 | local local_var_pattern = "local%s+([%w_,%s]+)%s*=%s*" 60 | local var_map = {} 61 | local obfuscated_code = code 62 | for local_vars in code:gmatch(local_var_pattern) do 63 | for var in local_vars:gmatch("[%w_]+") do 64 | if #var > 1 and not varenc_names[var] and not reserved_words[var] then 65 | var_map[var] = generateRandomName() 66 | end 67 | end 68 | end 69 | for original_var, obfuscated_var in pairs(var_map) do 70 | obfuscated_code = replaceUnquoted(obfuscated_code, original_var, obfuscated_var) 71 | end 72 | return obfuscated_code, var_map 73 | end 74 | 75 | local function obfuscateFunctions(code) 76 | local func_map = {} 77 | local arg_map = {} 78 | local obfuscated_code = code 79 | for func_name, args in code:gmatch("function%s+([%w_]+)%s*%(([%w_,%s]*)%)") do 80 | if not reserved_words[func_name] and not func_map[func_name] then 81 | func_map[func_name] = generateRandomName() 82 | end 83 | for arg in args:gmatch("[%w_]+") do 84 | if not reserved_words[arg] and not arg_map[arg] then 85 | arg_map[arg] = generateRandomName() 86 | end 87 | end 88 | end 89 | obfuscated_code = obfuscated_code:gsub("function%s+([%w_]+)", function(func_name) 90 | return "function " .. (func_map[func_name] or func_name) 91 | end) 92 | for original_func, obfuscated_func in pairs(func_map) do 93 | obfuscated_code = obfuscated_code:gsub(original_func .. "%(", obfuscated_func .. "(") 94 | end 95 | for original_arg, obfuscated_arg in pairs(arg_map) do 96 | obfuscated_code = replaceUnquoted(obfuscated_code, original_arg, obfuscated_arg) 97 | end 98 | return obfuscated_code 99 | end 100 | 101 | function VariableRenamer.process(code, options) 102 | options = options or {} 103 | -- apply custom name length range 104 | name_min = options.min_length or DEFAULT_MIN_NAME_LENGTH 105 | name_max = options.max_length or DEFAULT_MAX_NAME_LENGTH 106 | local renamed_vars = {} 107 | local assignment_lines = {} 108 | local obfuscated_code, var_map = obfuscateLocalVariables(code) 109 | obfuscated_code = obfuscateFunctions(obfuscated_code) 110 | for _, function_name in ipairs(lua_functions) do 111 | if string.find(code, function_name, 1, true) then 112 | if not varenc_names[function_name] then 113 | local new_name = generateRandomName() 114 | varenc_names[function_name] = new_name 115 | table.insert(renamed_vars, new_name) 116 | table.insert(assignment_lines, new_name .. " = " .. function_name .. ";") 117 | end 118 | obfuscated_code = obfuscated_code:gsub(function_name .. "%(", varenc_names[function_name] .. "(") 119 | end 120 | end 121 | local local_declaration = #renamed_vars > 0 and "local " .. table.concat(renamed_vars, ", ") or "" 122 | local assignments = #assignment_lines > 0 and "\n" .. table.concat(assignment_lines, " ") or "" 123 | local result = local_declaration .. assignments .. "\n" .. obfuscated_code 124 | -- reset to defaults 125 | name_min, name_max = DEFAULT_MIN_NAME_LENGTH, DEFAULT_MAX_NAME_LENGTH 126 | return result 127 | end 128 | 129 | return VariableRenamer 130 | -------------------------------------------------------------------------------- /src/modules/Compiler/VMStrings.lua: -------------------------------------------------------------------------------- 1 | local Parts = { 2 | Variables = [=[ 3 | -- Generic Helpers 4 | local LuaFunc, WrapState, BcToState, gChunk; 5 | local FIELDS_PER_FLUSH = 50 6 | local Select = select; 7 | -- Array Helpers 8 | local function CreateTbl(_) return {} end; 9 | local Unpack = unpack or table.unpack 10 | local function Pack(...) 11 | return { 12 | n = Select('#', ...), ... 13 | } 14 | end 15 | local function Move(src, First, Last, Offset, Dst) 16 | for i = _, Last - First do 17 | Dst[Offset + i] = src[First + i] 18 | end 19 | end 20 | -- Mini Bit Library 21 | local function BAnd(a, b) 22 | local result = _ 23 | local bitval = __ 24 | while a > _ and b > _ do 25 | if (a % 2 == __) and (b % 2 == __) then 26 | result = result + bitval 27 | end 28 | bitval = bitval * 2 29 | a = math.floor(a / 2) 30 | b = math.floor(b / 2) 31 | end 32 | return result 33 | end 34 | local function LShift(x, n) 35 | return x * 2 ^ n 36 | end 37 | local function RShift(x, n) 38 | return math.floor(x / 2 ^ n) 39 | end 40 | local function BOr(a, b) 41 | local result = _ 42 | local shift = __ 43 | while a > _ or b > _ do 44 | local abit = a % 2 45 | local bbit = b % 2 46 | if abit == __ or bbit == __ then 47 | result = result + shift 48 | end 49 | a = math.floor(a / 2) 50 | b = math.floor(b / 2) 51 | shift = shift * 2 52 | end 53 | return result 54 | end 55 | -- Upvalue Helpers 56 | local function CloseLuaUpvalues(B, N) 57 | for i, uv in pairs(B) do 58 | if uv.N >= N then 59 | uv.m = uv.M[uv.N]; 60 | uv.M = uv; 61 | uv.N = 'm' 62 | B[i] = nil; 63 | end; 64 | end; 65 | end; 66 | local function SenLuaUpvalue(B, N, X) 67 | local Prev = B[N] 68 | if not Prev then 69 | Prev = { N = N, M = X } 70 | B[N] = Prev; 71 | end; 72 | return Prev 73 | end; 74 | local function NormalizeNumber(value) 75 | if value % 1 == 0 then 76 | return value 77 | end 78 | return value 79 | end 80 | 81 | -- losing sanity, please help 82 | local _orig_tostring = tostring 83 | function tostring(v) 84 | if type(v) == 'number' then 85 | local s = _orig_tostring(v) 86 | -- if no dot or exponent, assume a whole number and append .0 87 | if not s:find('[%.eE]') then 88 | return s .. '.0' 89 | end 90 | return s 91 | end 92 | return _orig_tostring(v) 93 | end 94 | local asciilookup = {} 95 | for i = 0, 255 do 96 | asciilookup[string.char(i)] = i 97 | end 98 | 99 | local function chartoascii(str, pos) 100 | pos = pos or 1 101 | local ch = str:sub(pos, pos) 102 | return asciilookup[ch] 103 | end 104 | ]=], 105 | Deserializer = [=[ 106 | function BcToState(Bytecode, charset) 107 | local base, decoded = #charset, {} 108 | local decode_lookup = {} 109 | for i = 1, base do decode_lookup[charset:sub(i, i)] = i - 1 end 110 | -- do not FUCKING change the "_" 111 | for encoded_char in Bytecode:gmatch("([^_]+)") do 112 | local n = 0 113 | for i = 1, #encoded_char do n = n * base + decode_lookup[encoded_char:sub(i, i)] end 114 | decoded[#decoded + 1] = string.char(n) 115 | end 116 | local bytes = {} 117 | for char in table.concat(decoded):gmatch("(.?)\\") do 118 | if #char > 0 then 119 | bytes[#bytes + 1] = chartoascii(char) 120 | end 121 | end 122 | 123 | local Pos = 1 124 | local function gBits8() 125 | local Val = bytes[Pos] 126 | Pos = Pos + 1 127 | return Val 128 | end 129 | local function gBits16() 130 | local Val1, Val2 = bytes[Pos], bytes[Pos + 1] 131 | Pos = Pos + 2 132 | return (Val2 * 256) + Val1 133 | end 134 | local function gBits32() 135 | local Val1, Val2, Val3, Val4 = bytes[Pos], bytes[Pos + 1], bytes[Pos + 2], bytes[Pos + 3] 136 | Pos = Pos + 4 137 | return (Val4 * 16777216) + (Val3 * 65536) + (Val2 * 256) + Val1 138 | end 139 | 140 | function gChunk() 141 | local Chunk = { 142 | n = gBits8(), 143 | c = gBits8(), 144 | d = gBits8(), 145 | x = {}, 146 | D = {}, 147 | V = {} 148 | } 149 | for i = __, gBits32() do 150 | local Data = gBits32() 151 | local Sco = gBits8() 152 | local Type = gBits8() 153 | local Inst = { 154 | m = Data, 155 | S = Sco, 156 | A = gBits16() 157 | } 158 | local Mode = { 159 | b = gBits8(), 160 | c = gBits8() 161 | } 162 | if (Type == __) then 163 | Inst.B = gBits16() 164 | Inst.C = gBits16() 165 | Inst.s = Mode.b == __ and Inst.B > 0xFF 166 | Inst.a = Mode.c == __ and Inst.C > 0xFF 167 | elseif (Type == 2) then 168 | Inst.F = gBits32() 169 | Inst.g = Mode.b == __ 170 | elseif (Type == 3) then 171 | Inst.f = gBits32() - 131071 172 | end 173 | Chunk.x[i] = Inst 174 | end 175 | for i = __, gBits32() do 176 | local Type = gBits8() 177 | if (Type == __) then 178 | Chunk.D[i - __] = (gBits8() ~= _) 179 | elseif (Type == 3) then 180 | Chunk.D[i - __] = (function() 181 | local Left = gBits32() 182 | local Right = gBits32() 183 | local IsNormal = __ 184 | local Mantissa = BOr(LShift(BAnd(Right, 0xFFFFF), 32), Left) 185 | local Exponent = BAnd(RShift(Right, 20), 0x7FF) 186 | local Sign = (-__) ^ RShift(Right, 31) 187 | if Exponent == _ then 188 | if Mantissa == _ then 189 | return Sign * _ 190 | else 191 | Exponent = __ 192 | IsNormal = _ 193 | end 194 | elseif Exponent == 2047 then 195 | if Mantissa == _ then 196 | return Sign * (__ / _) 197 | else 198 | return Sign * (_ / _) 199 | end 200 | end 201 | local raw = math.ldexp(Sign, Exponent - 1023) * (IsNormal + (Mantissa / (2 ^ 52))) 202 | return NormalizeNumber(raw) 203 | end)() 204 | elseif (Type == 4) then 205 | Chunk.D[i - __] = (function() 206 | local Str 207 | local baik = gBits32() 208 | if (baik == _) then return end 209 | local chars = {} 210 | for j = 1, baik do 211 | chars[#chars + 1] = string.char(gBits8()) 212 | end 213 | return table.concat(chars) 214 | end)() 215 | end 216 | end 217 | for i = __, gBits32() do 218 | Chunk.V[i - __] = gChunk() 219 | end 220 | 221 | for _, v in ipairs(Chunk.x) do 222 | if v.g then 223 | v.D = Chunk.D[v.F] 224 | else 225 | if v.s then 226 | v.A = Chunk.D[v.B - 256] 227 | end 228 | if v.a then 229 | v.C = Chunk.D[v.C - 256] 230 | end 231 | end 232 | end 233 | return Chunk 234 | end 235 | 236 | return gChunk() 237 | end 238 | ]=], 239 | Wrapper_1 = [=[ 240 | function LuaFunc(State, Env, n) 241 | local x = State.x; 242 | local V = State.Z; 243 | local v = State.v; 244 | local Top = -__; 245 | local SenB = {} 246 | local X = State.X; 247 | local z = State.z; 248 | while alpha do 249 | local Inst = x[z] 250 | local S = Inst.S; 251 | local C = Inst.C; 252 | local A = Inst.A; 253 | local B = Inst.B; 254 | local D = Inst.D; 255 | local F = Inst.F; 256 | z = z + __; 257 | ]=], 258 | Wrapper_2 = [=[ 259 | State.z = z; 260 | end; 261 | end; 262 | function WrapState(V, Env, Upval) 263 | local function Wrapped(...) 264 | local Passed = Pack(...) 265 | local X = CreateTbl(V.d) 266 | local v = { b = _, B = {} } 267 | Move(Passed, __, V.c, _, X) 268 | if (V.c < Passed.n) then 269 | local Start = V.c + __ 270 | local b = Passed.n - V.c; 271 | v.b = b; 272 | Move(Passed, Start, Start + b - __, __, v.B) 273 | end; 274 | local State = { 275 | v = v, 276 | X = X, 277 | x = V.x, 278 | Z = V.V, 279 | z = __ 280 | } 281 | return LuaFunc(State, Env, Upval) 282 | end; 283 | return Wrapped; 284 | end; 285 | ]=] 286 | } 287 | return Parts 288 | -------------------------------------------------------------------------------- /src/modules/Compiler/Deserializer.lua: -------------------------------------------------------------------------------- 1 | local bit = require("modules/Compiler/bit") 2 | _G.UsedOps = {} 3 | if not table.create then 4 | function table.create(_) 5 | return {} 6 | end 7 | end; 8 | local lua_bc_to_state; 9 | local stm_lua_func; 10 | local OPCODE_T = { 11 | [0] = 'ABC', 12 | 'ABx', 13 | 'ABC', 14 | 'ABC', 15 | 'ABC', 16 | 'ABx', 17 | 'ABC', 18 | 'ABx', 19 | 'ABC', 20 | 'ABC', 21 | 'ABC', 22 | 'ABC', 23 | 'ABC', 24 | 'ABC', 25 | 'ABC', 26 | 'ABC', 27 | 'ABC', 28 | 'ABC', 29 | 'ABC', 30 | 'ABC', 31 | 'ABC', 32 | 'ABC', 33 | 'AsBx', 34 | 'ABC', 35 | 'ABC', 36 | 'ABC', 37 | 'ABC', 38 | 'ABC', 39 | 'ABC', 40 | 'ABC', 41 | 'ABC', 42 | 'AsBx', 43 | 'AsBx', 44 | 'ABC', 45 | 'ABC', 46 | 'ABC', 47 | 'ABx', 48 | 'ABC' 49 | } 50 | local OPCODE_M = { 51 | [0] = { 52 | b = 'OpArgR', 53 | c = 'OpArgN' 54 | }, 55 | { 56 | b = 'OpArgK', 57 | c = 'OpArgN' 58 | }, 59 | { 60 | b = 'OpArgU', 61 | c = 'OpArgU' 62 | }, 63 | { 64 | b = 'OpArgR', 65 | c = 'OpArgN' 66 | }, 67 | { 68 | b = 'OpArgU', 69 | c = 'OpArgN' 70 | }, 71 | { 72 | b = 'OpArgK', 73 | c = 'OpArgN' 74 | }, 75 | { 76 | b = 'OpArgR', 77 | c = 'OpArgK' 78 | }, 79 | { 80 | b = 'OpArgK', 81 | c = 'OpArgN' 82 | }, 83 | { 84 | b = 'OpArgU', 85 | c = 'OpArgN' 86 | }, 87 | { 88 | b = 'OpArgK', 89 | c = 'OpArgK' 90 | }, 91 | { 92 | b = 'OpArgU', 93 | c = 'OpArgU' 94 | }, 95 | { 96 | b = 'OpArgR', 97 | c = 'OpArgK' 98 | }, 99 | { 100 | b = 'OpArgK', 101 | c = 'OpArgK' 102 | }, 103 | { 104 | b = 'OpArgK', 105 | c = 'OpArgK' 106 | }, 107 | { 108 | b = 'OpArgK', 109 | c = 'OpArgK' 110 | }, 111 | { 112 | b = 'OpArgK', 113 | c = 'OpArgK' 114 | }, 115 | { 116 | b = 'OpArgK', 117 | c = 'OpArgK' 118 | }, 119 | { 120 | b = 'OpArgK', 121 | c = 'OpArgK' 122 | }, 123 | { 124 | b = 'OpArgR', 125 | c = 'OpArgN' 126 | }, 127 | { 128 | b = 'OpArgR', 129 | c = 'OpArgN' 130 | }, 131 | { 132 | b = 'OpArgR', 133 | c = 'OpArgN' 134 | }, 135 | { 136 | b = 'OpArgR', 137 | c = 'OpArgR' 138 | }, 139 | { 140 | b = 'OpArgR', 141 | c = 'OpArgN' 142 | }, 143 | { 144 | b = 'OpArgK', 145 | c = 'OpArgK' 146 | }, 147 | { 148 | b = 'OpArgK', 149 | c = 'OpArgK' 150 | }, 151 | { 152 | b = 'OpArgK', 153 | c = 'OpArgK' 154 | }, 155 | { 156 | b = 'OpArgR', 157 | c = 'OpArgU' 158 | }, 159 | { 160 | b = 'OpArgR', 161 | c = 'OpArgU' 162 | }, 163 | { 164 | b = 'OpArgU', 165 | c = 'OpArgU' 166 | }, 167 | { 168 | b = 'OpArgU', 169 | c = 'OpArgU' 170 | }, 171 | { 172 | b = 'OpArgU', 173 | c = 'OpArgN' 174 | }, 175 | { 176 | b = 'OpArgR', 177 | c = 'OpArgN' 178 | }, 179 | { 180 | b = 'OpArgR', 181 | c = 'OpArgN' 182 | }, 183 | { 184 | b = 'OpArgN', 185 | c = 'OpArgU' 186 | }, 187 | { 188 | b = 'OpArgU', 189 | c = 'OpArgU' 190 | }, 191 | { 192 | b = 'OpArgN', 193 | c = 'OpArgN' 194 | }, 195 | { 196 | b = 'OpArgU', 197 | c = 'OpArgN' 198 | }, 199 | { 200 | b = 'OpArgU', 201 | c = 'OpArgN' 202 | } 203 | } 204 | local function rd_int_basic(src, s, e, d) 205 | local num = 0; 206 | for i = s, e, d do 207 | local mul = 256 ^ math.abs(i - s) 208 | num = num + mul * string.byte(src, i, i) 209 | end; 210 | return num 211 | end; 212 | local function rd_flt_basic(f1, f2, f3, f4) 213 | local sign = (- 1) ^ bit.rshift(f4, 7) 214 | local exp = bit.rshift(f3, 7) + bit.lshift(bit.band(f4, 127), 1) 215 | local frac = f1 + bit.lshift(f2, 8) + bit.lshift(bit.band(f3, 127), 16) 216 | local normal = 1; 217 | if exp == 0 then 218 | if frac == 0 then 219 | return sign * 0 220 | else 221 | normal = 0; 222 | exp = 1 223 | end 224 | elseif exp == 127 then 225 | if frac == 0 then 226 | return sign * (1 / 0) 227 | else 228 | return sign * (0 / 0) 229 | end 230 | end; 231 | return sign * 2 ^ (exp - 127) * (1 + normal / 2 ^ 23) 232 | end; 233 | local function rd_dbl_basic(f1, f2, f3, f4, f5, f6, f7, f8) 234 | local sign = (- 1) ^ bit.rshift(f8, 7) 235 | local exp = bit.lshift(bit.band(f8, 127), 4) + bit.rshift(f7, 4) 236 | local frac = bit.band(f7, 15) * 2 ^ 48; 237 | local normal = 1; 238 | frac = frac + (f6 * 2 ^ 40) + (f5 * 2 ^ 32) + (f4 * 2 ^ 24) + (f3 * 2 ^ 16) + (f2 * 2 ^ 8) + f1; 239 | if exp == 0 then 240 | if frac == 0 then 241 | return sign * 0 242 | else 243 | normal = 0; 244 | exp = 1 245 | end 246 | elseif exp == 2047 then 247 | if frac == 0 then 248 | return sign * (1 / 0) 249 | else 250 | return sign * (0 / 0) 251 | end 252 | end; 253 | return sign * 2 ^ (exp - 1023) * (normal + frac / 2 ^ 52) 254 | end; 255 | local function rd_int_le(src, s, e) 256 | return rd_int_basic(src, s, e - 1, 1) 257 | end; 258 | local function rd_int_be(src, s, e) 259 | return rd_int_basic(src, e - 1, s, - 1) 260 | end; 261 | local function rd_flt_le(src, s) 262 | return rd_flt_basic(string.byte(src, s, s + 3)) 263 | end; 264 | local function rd_flt_be(src, s) 265 | local f1, f2, f3, f4 = string.byte(src, s, s + 3) 266 | return rd_flt_basic(f4, f3, f2, f1) 267 | end; 268 | local function rd_dbl_le(src, s) 269 | return rd_dbl_basic(string.byte(src, s, s + 7)) 270 | end; 271 | local function rd_dbl_be(src, s) 272 | local f1, f2, f3, f4, f5, f6, f7, f8 = string.byte(src, s, s + 7) 273 | return rd_dbl_basic(f8, f7, f6, f5, f4, f3, f2, f1) 274 | end; 275 | local float_types = { 276 | [4] = { 277 | little = rd_flt_le, 278 | big = rd_flt_be 279 | }, 280 | [8] = { 281 | little = rd_dbl_le, 282 | big = rd_dbl_be 283 | } 284 | } 285 | local function stm_byte(S) 286 | local idx = S.index; 287 | local bt = string.byte(S.source, idx, idx) 288 | S.index = idx + 1; 289 | return bt 290 | end; 291 | local function stm_string(S, len) 292 | local pos = S.index + len; 293 | local str = string.sub(S.source, S.index, pos - 1) 294 | S.index = pos; 295 | return str 296 | end; 297 | local function stm_lstring(S) 298 | local len = S:s_szt() 299 | local str; 300 | if len ~= 0 then 301 | str = string.sub(stm_string(S, len), 1, - 2) 302 | end; 303 | return str 304 | end; 305 | local function cst_int_rdr(len, func) 306 | return function(S) 307 | local pos = S.index + len; 308 | local int = func(S.source, S.index, pos) 309 | S.index = pos; 310 | return int 311 | end 312 | end; 313 | local function cst_flt_rdr(len, func) 314 | return function(S) 315 | local flt = func(S.source, S.index) 316 | S.index = S.index + len; 317 | return flt 318 | end 319 | end; 320 | local function stm_inst_list(S) 321 | local len = S:s_int() 322 | local list = table.create(len) 323 | for i = 1, len do 324 | local ins = S:s_ins() 325 | local op = bit.band(ins, 63) 326 | local args = OPCODE_T[op] 327 | local mode = OPCODE_M[op] 328 | local data = { 329 | Value = ins, 330 | Enum = op, 331 | Type = args, 332 | Mode = mode, 333 | A = bit.band(bit.rshift(ins, 6), 255) 334 | } 335 | if args == 'ABC' then 336 | data.B = bit.band(bit.rshift(ins, 23), 511) 337 | data.C = bit.band(bit.rshift(ins, 14), 511) 338 | elseif args == 'ABx' then 339 | data.Bx = bit.band(bit.rshift(ins, 14), 262143) 340 | elseif args == 'AsBx' then 341 | data.sBx = bit.band(bit.rshift(ins, 14), 262143) - 131071 342 | end; 343 | if not _G.UsedOps[op] then 344 | _G.UsedOps[op] = op 345 | end; 346 | list[i] = data 347 | end; 348 | return list 349 | end; 350 | local function stm_const_list(S) 351 | local len = S:s_int() 352 | local list = table.create(len) 353 | for i = 1, len do 354 | local tt = stm_byte(S) 355 | local k; 356 | if tt == 1 then 357 | k = stm_byte(S) ~= 0 358 | elseif tt == 3 then 359 | k = S:s_num() 360 | elseif tt == 4 then 361 | k = stm_lstring(S) 362 | end; 363 | list[i] = k 364 | end; 365 | return list 366 | end; 367 | local function stm_sub_list(S, src) 368 | local len = S:s_int() 369 | local list = table.create(len) 370 | for i = 1, len do 371 | list[i] = stm_lua_func(S, src) 372 | end; 373 | return list 374 | end; 375 | local function stm_line_list(S) 376 | local len = S:s_int() 377 | local list = table.create(len) 378 | for i = 1, len do 379 | list[i] = S:s_int() 380 | end; 381 | return list 382 | end; 383 | local function stm_loc_list(S) 384 | local len = S:s_int() 385 | local list = table.create(len) 386 | for i = 1, len do 387 | list[i] = { 388 | varname = stm_lstring(S), 389 | startpc = S:s_int(), 390 | endpc = S:s_int() 391 | } 392 | end; 393 | return list 394 | end; 395 | local function stm_upval_list(S) 396 | local len = S:s_int() 397 | local list = table.create(len) 398 | for i = 1, len do 399 | list[i] = stm_lstring(S) 400 | end; 401 | return list 402 | end; 403 | function stm_lua_func(S, psrc) 404 | local proto = {} 405 | local src = stm_lstring(S) or psrc; 406 | proto.SourceName = src; 407 | S:s_int() 408 | S:s_int() 409 | proto.Upvals = stm_byte(S) 410 | proto.Parameters = stm_byte(S) 411 | stm_byte(S) 412 | proto.MaxStack = stm_byte(S) 413 | proto.Instructions = stm_inst_list(S) 414 | proto.Constants = stm_const_list(S) 415 | proto.Protos = stm_sub_list(S, src) 416 | stm_line_list(S) 417 | stm_loc_list(S) 418 | stm_upval_list(S) 419 | return proto 420 | end; 421 | function Deserialize(src) 422 | local rdr_func; 423 | local little; 424 | local size_int; 425 | local size_szt; 426 | local size_ins; 427 | local size_num; 428 | local flag_int; 429 | local stream = { 430 | index = 1, 431 | source = src 432 | } 433 | assert(stm_string(stream, 4) == '\27Lua', 'invalid Lua signature') 434 | assert(stm_byte(stream) == 81, 'invalid Lua version') 435 | assert(stm_byte(stream) == 0, 'invalid Lua format') 436 | little = stm_byte(stream) ~= 0; 437 | size_int = stm_byte(stream) 438 | size_szt = stm_byte(stream) 439 | size_ins = stm_byte(stream) 440 | size_num = stm_byte(stream) 441 | flag_int = stm_byte(stream) ~= 0; 442 | rdr_func = little and rd_int_le or rd_int_be; 443 | stream.s_int = cst_int_rdr(size_int, rdr_func) 444 | stream.s_szt = cst_int_rdr(size_szt, rdr_func) 445 | stream.s_ins = cst_int_rdr(size_ins, rdr_func) 446 | if flag_int then 447 | stream.s_num = cst_int_rdr(size_num, rdr_func) 448 | elseif float_types[size_num] then 449 | stream.s_num = cst_flt_rdr(size_num, float_types[size_num][little and 'little' or 'big']) 450 | else 451 | error('unsupported float size') 452 | end; 453 | return stm_lua_func(stream, '@virtual') 454 | end; 455 | return Deserialize 456 | -------------------------------------------------------------------------------- /src/modules/Compiler/Opcode.lua: -------------------------------------------------------------------------------- 1 | function GetOpcodeCode(S) 2 | if (S == 0) then 3 | return [=[X[Inst.A] = X[Inst.B];]=] 4 | elseif (S == 1) then 5 | return [=[X[Inst.A] = (type(Inst.D) == "number" and Inst.D % 1 == 0) and math.floor(Inst.D) or Inst.D]=] 6 | elseif (S == 2) then 7 | return [=[ 8 | X[Inst.A] = Inst.B ~= 0 9 | if Inst.C ~= 0 then z = z + 1 end; 10 | ]=] 11 | elseif (S == 3) then 12 | return [=[ 13 | for i = Inst.A, Inst.B do X[i] = nil end; 14 | ]=] 15 | elseif (S == 4) then 16 | return [=[ 17 | local Uv = n[Inst.B] 18 | X[Inst.A] = Uv.M[Uv.N] 19 | ]=] 20 | elseif (S == 5) then 21 | return [=[ 22 | X[Inst.A] = Env[Inst.D] 23 | ]=] 24 | elseif (S == 6) then 25 | return [=[ 26 | local N 27 | if Inst.a then 28 | N = Inst.C; 29 | else 30 | N = X[Inst.C] 31 | end 32 | X[Inst.A] = X[Inst.B][N] 33 | ]=] 34 | elseif (S == 7) then 35 | return [=[ 36 | Env[Inst.D] = X[Inst.A] 37 | ]=] 38 | elseif (S == 8) then 39 | return [=[ 40 | local Uv = n[Inst.B] 41 | Uv.M[Uv.N] = X[Inst.A] 42 | ]=] 43 | elseif (S == 9) then 44 | return [=[ 45 | local N, m 46 | if Inst.s then 47 | N = Inst.A 48 | else 49 | N = X[Inst.B] 50 | end 51 | if Inst.a then 52 | m = Inst.C 53 | else 54 | m = X[Inst.C] 55 | end 56 | X[Inst.A][N] = m 57 | ]=] 58 | elseif (S == 10) then 59 | return [=[ 60 | X[Inst.A] = {} 61 | ]=] 62 | elseif (S == 11) then 63 | return [=[ 64 | local A = Inst.A 65 | local B = Inst.B 66 | local N; 67 | if Inst.a then 68 | N = Inst.C 69 | else 70 | N = X[Inst.C] 71 | end 72 | X[A + 1] = X[B] 73 | X[A] = X[B][N] 74 | ]=] 75 | elseif (S == 12) then 76 | return [=[ 77 | local Lhs, Rhs; 78 | if Inst.s then 79 | Lhs = Inst.A 80 | else 81 | Lhs = X[Inst.B] 82 | end 83 | if Inst.a then 84 | Rhs = Inst.C 85 | else 86 | Rhs = X[Inst.C] 87 | end 88 | X[Inst.A] = NormalizeNumber(Lhs + Rhs) 89 | ]=] 90 | elseif (S == 13) then 91 | return [=[ 92 | local Lhs, Rhs; 93 | if Inst.s then 94 | Lhs = Inst.A 95 | else 96 | Lhs = X[Inst.B] 97 | end 98 | if Inst.a then 99 | Rhs = Inst.C 100 | else 101 | Rhs = X[Inst.C] 102 | end 103 | X[Inst.A] = NormalizeNumber(Lhs - Rhs) 104 | ]=] 105 | elseif (S == 14) then 106 | return [=[ 107 | local Lhs, Rhs; 108 | if Inst.s then 109 | Lhs = Inst.A 110 | else 111 | Lhs = X[Inst.B] 112 | end 113 | if Inst.a then 114 | Rhs = Inst.C 115 | else 116 | Rhs = X[Inst.C] 117 | end 118 | X[Inst.A] = NormalizeNumber(Lhs * Rhs) 119 | ]=] 120 | elseif (S == 15) then 121 | return [=[ 122 | local Lhs, Rhs; 123 | if Inst.s then 124 | Lhs = Inst.A 125 | else 126 | Lhs = X[Inst.B] 127 | end 128 | if Inst.a then 129 | Rhs = Inst.C 130 | else 131 | Rhs = X[Inst.C] 132 | end 133 | X[Inst.A] = NormalizeNumber(Lhs / Rhs) 134 | ]=] 135 | elseif (S == 16) then 136 | return [=[ 137 | local Lhs, Rhs; 138 | if Inst.s then 139 | Lhs = Inst.A 140 | else 141 | Lhs = X[Inst.B] 142 | end 143 | if Inst.a then 144 | Rhs = Inst.C 145 | else 146 | Rhs = X[Inst.C] 147 | end 148 | X[Inst.A] = NormalizeNumber(Lhs % Rhs) 149 | ]=] 150 | elseif (S == 17) then 151 | return [=[ 152 | local Lhs, Rhs; 153 | if Inst.s then 154 | Lhs = Inst.A 155 | else 156 | Lhs = X[Inst.B] 157 | end 158 | if Inst.a then 159 | Rhs = Inst.C 160 | else 161 | Rhs = X[Inst.C] 162 | end 163 | X[Inst.A] = NormalizeNumber(Lhs ^ Rhs) 164 | ]=] 165 | elseif (S == 18) then 166 | return [=[ 167 | X[Inst.A] = NormalizeNumber(-X[Inst.B]) 168 | ]=] 169 | elseif (S == 19) then 170 | return [=[ 171 | X[Inst.A] = not X[Inst.B] 172 | ]=] 173 | elseif (S == 20) then 174 | return [=[X[Inst.A] = #X[Inst.B]]=] 175 | elseif (S == 21) then 176 | return [=[ 177 | local B, C = Inst.B, Inst.C; 178 | local Str = ""; 179 | for i = B, C do 180 | local v = X[i]; 181 | if type(v) == "number" then 182 | if v % 1 == 0 then 183 | Str = Str .. string.format("%d", v) 184 | else 185 | Str = Str .. string.format("%g", v) 186 | end 187 | else 188 | Str = Str .. tostring(v) 189 | end 190 | end 191 | X[Inst.A] = Str; 192 | ]=] 193 | elseif (S == 22) then 194 | return [=[z = z + Inst.f]=] 195 | elseif (S == 23) then 196 | return [=[ 197 | local Lhs, Rhs; 198 | if Inst.s then 199 | Lhs = Inst.A 200 | else 201 | Lhs = X[Inst.B] 202 | end 203 | if Inst.a then 204 | Rhs = Inst.C 205 | else 206 | Rhs = X[Inst.C] 207 | end 208 | if (Lhs == Rhs) == (Inst.A ~= 0) then z = z + x[z].f end; 209 | z = z + 1 210 | ]=] 211 | elseif (S == 24) then 212 | return [=[ 213 | local Lhs, Rhs; 214 | if Inst.s then 215 | Lhs = Inst.A 216 | else 217 | Lhs = X[Inst.B] 218 | end 219 | if Inst.a then 220 | Rhs = Inst.C 221 | else 222 | Rhs = X[Inst.C] 223 | end 224 | if (Lhs < Rhs) == (Inst.A ~= 0) then z = z + x[z].f end; 225 | z = z + 1 226 | ]=] 227 | elseif (S == 25) then 228 | return [=[ 229 | local Lhs, Rhs; 230 | if Inst.s then 231 | Lhs = Inst.A 232 | else 233 | Lhs = X[Inst.B] 234 | end 235 | if Inst.a then 236 | Rhs = Inst.C 237 | else 238 | Rhs = X[Inst.C] 239 | end 240 | if (Lhs <= Rhs) == (Inst.A ~= 0) then z = z + x[z].f end; 241 | z = z + 1 242 | ]=] 243 | elseif (S == 26) then 244 | return [=[ 245 | if (not X[Inst.A]) ~= (Inst.C ~= 0) then z = z + x[z].f end 246 | z = z + 1 247 | ]=] 248 | elseif (S == 27) then 249 | return [=[ 250 | local A = Inst.A 251 | local B = Inst.B; 252 | if (not X[B]) ~= (Inst.C ~= 0) then 253 | X[A] = X[B] 254 | z = z + x[z].f 255 | end; 256 | z = z + 1 257 | ]=] 258 | elseif (S == 28) then 259 | return [=[ 260 | local A = Inst.A; 261 | local B = Inst.B; 262 | local Params; 263 | if B == 0 then 264 | Params = Top - A; 265 | else 266 | Params = B - 1; 267 | end; 268 | local RetB = Pack(X[A](Unpack(X, A + 1, A + Params))) 269 | local RetNum = RetB.n; 270 | if C == 0 then 271 | Top = A + RetNum - 1; 272 | else 273 | RetNum = C - 1; 274 | end; 275 | Move(RetB, 1, RetNum, A, X) 276 | ]=] 277 | elseif (S == 29) then 278 | return [=[ 279 | local A = Inst.A; 280 | local B = Inst.B; 281 | local Params; 282 | if B == 0 then 283 | Params = Top - A; 284 | else 285 | Params = B - 1; 286 | end; 287 | CloseLuaUpvalues(SenB, 0) 288 | return X[A](Unpack(X, A + 1, A + Params)) 289 | ]=] 290 | elseif (S == 30) then 291 | return [=[ 292 | local A = Inst.A; 293 | local b = Inst.B; 294 | if B == 0 then 295 | b = Top - A + 1; 296 | else 297 | b = B - 1; 298 | end; 299 | CloseLuaUpvalues(SenB, 0) 300 | return Unpack(X, A, A + b - 1) 301 | ]=] 302 | elseif (S == 31) then 303 | return [=[ 304 | local A = Inst.A; 305 | local Step = X[A + 2] 306 | local N = X[A] + Step; 307 | local Limit = X[A + 1] 308 | local Loops 309 | if Step == math.abs(Step) then 310 | Loops = N <= Limit; 311 | else 312 | Loops = N >= Limit; 313 | end; 314 | if Loops then 315 | X[A] = N; 316 | X[A + 3] = N; 317 | z = z + Inst.f; 318 | end; 319 | ]=] 320 | elseif (S == 32) then 321 | return [=[ 322 | local A = Inst.A; 323 | local Init, Limit, Step; 324 | Init = tonumber(X[A]) 325 | Limit = tonumber(X[A + 1]) 326 | Step = tonumber(X[A + 2]) 327 | X[A] = Init - Step; 328 | X[A + 1] = Limit; 329 | X[A + 2] = Step; 330 | z = z + Inst.f; 331 | ]=] 332 | elseif (S == 33) then 333 | return [=[ 334 | local A = Inst.A; 335 | local Base = A + 3; 336 | local Vals = {X[A](X[A + 1], X[A + 2])} 337 | Move(Vals, 1, Inst.C, Base, X) 338 | if X[Base] ~= nil then 339 | X[A + 2] = X[Base] 340 | z = z + x[z].f; 341 | end; 342 | z = z + 1 343 | ]=] 344 | elseif (S == 34) then 345 | return [=[ 346 | local A = Inst.A 347 | local C = Inst.C 348 | local b = Inst.B; 349 | local Tab = X[A] 350 | local Offset; 351 | if b == 0 then b = Top - A end 352 | if C == 0 then 353 | C = x[z].m; 354 | z = z + 1 355 | end; 356 | Offset = (C - 1) * FIELDS_PER_FLUSH 357 | Move(X, A + 1, A + b, Offset + 1, Tab) 358 | ]=] 359 | elseif (S == 35) then 360 | return [=[CloseLuaUpvalues(SenB, Inst.A)]=] 361 | elseif (S == 36) then 362 | return [=[ 363 | local Sub = V[Inst.F] 364 | local Nups = Sub.n; 365 | local UvB; 366 | if Nups ~= 0 then 367 | UvB = CreateTbl(Nups - 1) 368 | for i = 1, Nups do 369 | local Pseudo = x[z + i - 1] 370 | if (Pseudo.S == 0) then 371 | UvB[i - 1] = SenLuaUpvalue(SenB, Pseudo.B, X) 372 | elseif (Pseudo.S == 4) then 373 | UvB[i - 1] = n[Pseudo.B] 374 | end; 375 | end; 376 | z = z + Nups 377 | end; 378 | X[Inst.A] = WrapState(Sub, Env, UvB) 379 | ]=] 380 | elseif (S == 37) then 381 | return [=[ 382 | local A = Inst.A; 383 | local b = Inst.B; 384 | if (b == 0) then 385 | b = v.b; 386 | Top = A + b - 1; 387 | end; 388 | Move(v.B, 1, b, A, X) 389 | ]=] 390 | end 391 | end; 392 | return GetOpcodeCode 393 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2024-2025 zeusssz 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | -------------------------------------------------------------------------------- /src/hercules.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | local Pipeline = require("pipeline") 4 | local config = require("config") 5 | -- utils 6 | 7 | local function filesize(file) 8 | local f = io.open(file, "r") 9 | if not f then return 0 end 10 | local sz 11 | local success, err = pcall(function() 12 | sz = f:seek("end") 13 | end) 14 | f:close() 15 | if not success then return 0 end 16 | return sz 17 | end 18 | 19 | local function map(func, tbl) 20 | local mapped = {} 21 | for k, v in pairs(tbl) do 22 | mapped[k] = func(v, k) 23 | end 24 | return mapped 25 | end 26 | 27 | local colors = { 28 | reset = "\27[0m", 29 | green = "\27[32m", 30 | red = "\27[31m", 31 | white = "\27[37m", 32 | cyan = "\27[36m", 33 | blue = "\27[34m", 34 | yellow = "\27[33m" 35 | } 36 | 37 | local obfuscated_list = {} 38 | 39 | local BANNER = colors.blue .. [[ 40 | _ _ __ 41 | /\ /\ ___ _ __ ___ _ _ | | ___ ___ __ __/ | / /_ 42 | / /_/ // _ \| '__|/ __|| | | || | / _ \/ __| \ \ / /| | | '_ \ 43 | / __ /| __/| | | (__ | |_| || || __/\__ \ \ V / | | _ | (_) | 44 | \/ /_/ \___||_| \___| \__,_||_| \___||___/ \_/ |_| (_) \___/ 45 | ]] .. colors.reset 46 | 47 | local function runSanityCheck(original_code, obfuscated_code) 48 | local function captureOutput(code) 49 | local output = {} 50 | local ogprint = _G.print 51 | local success, result = pcall(function() 52 | _G.print = function(...) 53 | local args = {...} 54 | local str = table.concat(map(tostring, args), "\t") 55 | table.insert(output, str) 56 | end 57 | local func, err = load(code) 58 | if not func then 59 | error("Compilation error: " .. tostring(err)) 60 | end 61 | local status, run_result = pcall(func) 62 | if not status then 63 | error("Runtime error: " .. tostring(run_result)) 64 | end 65 | end) 66 | _G.print = ogprint 67 | if not success then 68 | return "", result 69 | end 70 | return table.concat(output, "\n"), nil 71 | end 72 | 73 | local original_output, original_err = captureOutput(original_code) 74 | local obfuscated_output, obfuscated_err = captureOutput(obfuscated_code) 75 | 76 | if original_err or obfuscated_err then 77 | return false, { expected = original_err or original_output, got = obfuscated_err or obfuscated_output } 78 | end 79 | 80 | return original_output == obfuscated_output, { expected = original_output, got = obfuscated_output } 81 | end 82 | 83 | local function printCliResult(input, output, time, options) 84 | local original_size = filesize(input) 85 | local obfuscated_size = output and filesize(output) or 0 86 | local size_diff_percent 87 | if original_size > 0 then 88 | size_diff_percent = string.format("%.2f", ((obfuscated_size - original_size) / original_size) * 100 + 100) 89 | else 90 | size_diff_percent = "N/A" 91 | end 92 | 93 | local line = colors.white .. string.rep("═", 65) .. colors.reset 94 | print("\n" .. line) 95 | print(BANNER) 96 | print(colors.white .. "Obfuscation Complete!" .. colors.reset) 97 | print(colors.white .. "Details:" .. colors.reset) 98 | print(line) 99 | print(colors.white .. "Time Taken : " .. string.format("%.2f", time) .. " seconds" .. colors.reset) 100 | print(colors.cyan .. "Original Size : " .. original_size .. " bytes" .. colors.reset) 101 | print(colors.cyan .. "Obfuscated Size : " .. obfuscated_size .. " bytes" .. colors.reset) 102 | print(colors.cyan .. "Size Difference : " .. (obfuscated_size - original_size) .. " bytes (" .. size_diff_percent .. "%)" .. colors.reset) 103 | 104 | local function formatBool(val) 105 | return val and colors.green .. "True" .. colors.reset or colors.red .. "False" .. colors.reset 106 | end 107 | 108 | print(colors.cyan .. "Overwrite : " .. formatBool(options.overwrite)) 109 | print(colors.cyan .. "Folder Mode : " .. formatBool(options.folder_mode)) 110 | if options.folder_mode then 111 | if not output then 112 | print(colors.white .. "Output File : " .. colors.reset 113 | .. colors.cyan .. table.concat(obfuscated_list, ", ") .. colors.reset) 114 | end 115 | else 116 | print(colors.white .. "Output File : " .. output .. colors.reset) 117 | end 118 | 119 | if options.sanity_check then 120 | if options.sanity_failed then 121 | print(colors.red .. "Sanity Check : Failed" .. colors.reset) 122 | print(colors.yellow .. "\nExpected output:" .. colors.reset) 123 | print(colors.white .. options.sanity_info.expected .. colors.reset) 124 | print(colors.yellow .. "\nGot output:" .. colors.reset) 125 | print(colors.white .. options.sanity_info.got .. colors.reset) 126 | print(colors.red .. "Please dm 'zeusssz_' on Discord with with the file, or make an issue on the GitHub" .. colors.reset) 127 | print(colors.red .. "You may also join the Discord Server using the invite link" .. colors.reset) 128 | else 129 | print(colors.green .. "Sanity Check : Passed" .. colors.reset) 130 | end 131 | end 132 | 133 | print(line) 134 | 135 | local settings = { 136 | { "Watermark", config.get("settings.watermark_enabled") }, 137 | { "String To Expressions", config.get("settings.StringToExpressions.enabled") }, 138 | { "Control Flow", config.get("settings.control_flow.enabled") }, 139 | { "String Encoding", config.get("settings.string_encoding.enabled") }, 140 | { "Variable Renaming", config.get("settings.variable_renaming.enabled") }, 141 | { "Garbage Code", config.get("settings.garbage_code.enabled") }, 142 | { "Opaque Predicates", config.get("settings.opaque_predicates.enabled") }, 143 | { "Function Inlining", config.get("settings.function_inlining.enabled") }, 144 | { "Dynamic Code", config.get("settings.dynamic_code.enabled") }, 145 | { "Bytecode Encoding", config.get("settings.bytecode_encoding.enabled") }, 146 | { "Compressor", config.get("settings.compressor.enabled") }, 147 | { "Function Wrapping", config.get("settings.WrapInFunction.enabled") }, 148 | { "Virtual Machine", config.get("settings.VirtualMachine.enabled") }, 149 | { "Anti Tamper", config.get("settings.antitamper.enabled") }, 150 | } 151 | 152 | local max_length = 0 153 | for _, setting in ipairs(settings) do 154 | if #setting[1] > max_length then 155 | max_length = #setting[1] 156 | end 157 | end 158 | 159 | for _, setting in ipairs(settings) do 160 | local name = setting[1] 161 | local status = (setting[2] and colors.green .. "Enabled" or colors.red .. "Disabled") 162 | local padding = string.rep(" ", max_length - #name + 1) 163 | print(colors.white .. name .. padding .. ":" .. " " .. status .. colors.reset) 164 | end 165 | 166 | print(line .. "\n") 167 | end 168 | 169 | local function applyPreset(level) 170 | if level == "min" then 171 | config.set("settings.variable_renaming.min_name_length", 10) 172 | config.set("settings.variable_renaming.max_name_length", 20) 173 | config.set("settings.garbage_code.garbage_blocks", 5) 174 | config.set("settings.control_flow.max_fake_blocks", 2) 175 | 176 | elseif level == "mid" then 177 | config.set("settings.variable_renaming.min_name_length", 40) 178 | config.set("settings.variable_renaming.max_name_length", 60) 179 | config.set("settings.garbage_code.garbage_blocks", 25) 180 | config.set("settings.control_flow.max_fake_blocks", 8) 181 | 182 | elseif level == "max" then 183 | config.set("settings.variable_renaming.min_name_length", 90) 184 | config.set("settings.variable_renaming.max_name_length", 120) 185 | config.set("settings.garbage_code.garbage_blocks", 50) 186 | config.set("settings.control_flow.max_fake_blocks", 12) 187 | config.set("settings.StringToExpressions.min_number_length", 800) 188 | config.set("settings.StringToExpressions.max_number_length", 999) 189 | end 190 | end 191 | 192 | local function printUsage() 193 | print(colors.white .. "Usage: " .. colors.reset .. colors.cyan .. "./hercules.lua *.lua (+ any options)" .. colors.reset) 194 | print(colors.white .. "\nOptional Presets:" .. colors.reset) 195 | print(colors.cyan .. "--min" .. string.rep(" ", 17) .. colors.green .. "Minimal parameters for lighter obfuscation" .. colors.reset) 196 | print(colors.cyan .. "--mid" .. string.rep(" ", 17) .. colors.green .. "Moderate parameters for balanced obfuscation" .. colors.reset) 197 | print(colors.cyan .. "--max" .. string.rep(" ", 17) .. colors.green .. "Maximum parameters for heavy obfuscation" .. colors.reset) 198 | 199 | print(colors.white .. "\nGeneral Flags:" .. colors.reset) 200 | local general_flags = { 201 | { flags = {"--overwrite", ""}, description = "Overwrites the original file with obfuscated code" }, 202 | { flags = {"--folder", ""}, description = "Process all Lua files in the given folder" }, 203 | { flags = {"--sanity", ""}, description = "Check if obfuscated code output matches original" } 204 | } 205 | for _, flag in ipairs(general_flags) do 206 | print(colors.cyan .. flag.flags[1] .. flag.flags[2] .. colors.green .. string.rep(" ", 20 - #flag.flags[1] - #flag.flags[2]) .. flag.description .. colors.reset) 207 | end 208 | 209 | print(colors.white .. "\nObfuscation Flags:" .. colors.reset) 210 | 211 | local obfuscation_flags = { 212 | { flags = {"-cf", "--control_flow"}, description = "Enable control flow obfuscation" }, 213 | { flags = {"-se", "--string_encoding"}, description = "Enable string encoding" }, 214 | { flags = {"-vr", "--variable_renaming"}, description = "Enable variable renaming" }, 215 | { flags = {"-gci", "--garbage_code"}, description = "Enable garbage code injection" }, 216 | { flags = {"-opi", "--opaque_preds"}, description = "Enable opaque predicates injection" }, 217 | { flags = {"-be", "--bytecode_encoder"}, description = "Enable bytecode encoding" }, 218 | { flags = {"-st", "--string_to_expr"}, description = "Enable string to expression conversion" }, 219 | { flags = {"-vm", "--virtual_machine"}, description = "Enable virtual machine transformation" }, 220 | { flags = {"-wif", "--wrap_in_func"}, description = "Enable function wrapping" }, 221 | { flags = {"-fi", "--func_inlining"}, description = "Enable function inlining" }, 222 | { flags = {"-dc", "--dynamic_code"}, description = "Enable dynamic code generation" }, 223 | { flags = {"-c", "--compressor"}, description = "Enable compressor" }, 224 | { flags = {"-at", "--antitamper"}, description = "Enable antitamper" } 225 | } 226 | 227 | local max_flag_length = 0 228 | for _, flag in ipairs(obfuscation_flags) do 229 | local short_flag = flag.flags[1] 230 | local long_flag = flag.flags[2] 231 | max_flag_length = math.max(max_flag_length, #short_flag + #long_flag + 2) 232 | end 233 | for _, flag in ipairs(obfuscation_flags) do 234 | local short_flag = flag.flags[1] 235 | local long_flag = flag.flags[2] 236 | local padding = string.rep(" ", max_flag_length - (#short_flag + #long_flag + 2)) 237 | print(colors.cyan .. short_flag .. ", " .. long_flag .. padding .. colors.white .. ": " .. colors.green .. flag.description .. colors.reset) 238 | end 239 | os.exit(1) 240 | end 241 | 242 | local function main() 243 | if #arg < 1 then 244 | print(colors.red .. "Error: No input file specified" .. colors.reset) 245 | printUsage() 246 | os.exit(1) 247 | end 248 | 249 | local input = arg[1] 250 | if input:sub(1,1) == "-" then 251 | print(colors.red .. "Error: Unexpected flag '" .. input .. "'" .. colors.reset) 252 | printUsage() 253 | os.exit(1) 254 | end 255 | 256 | local options = { 257 | overwrite = false, 258 | custom_file = nil, 259 | folder_mode = false, 260 | sanity_check = false 261 | } 262 | 263 | local features = { 264 | control_flow = false, 265 | string_encoding = false, 266 | variable_renaming = false, 267 | garbage_code = false, 268 | opaque_predicates = false, 269 | bytecode_encoding = false, 270 | compressor = false, 271 | StringToExpressions = false, 272 | VirtualMachine = false, 273 | WrapInFunction = false, 274 | function_inlining = false, 275 | dynamic_code = false, 276 | antitamper = false, 277 | } 278 | 279 | for i = 2, #arg do 280 | if arg[i] == "--overwrite" then 281 | options.overwrite = true 282 | elseif arg[i] == "--folder" then 283 | options.folder_mode = true 284 | elseif arg[i] == "--sanity" then 285 | options.sanity_check = true 286 | elseif arg[i] == "-cf" or arg[i] == "--control_flow" then 287 | features.control_flow = true 288 | elseif arg[i] == "-c" or arg[i] == "--compressor" then 289 | features.compressor = true 290 | elseif arg[i] == "-se" or arg[i] == "--string_encoding" then 291 | features.string_encoding = true 292 | elseif arg[i] == "-vr" or arg[i] == "--variable_renaming" then 293 | features.variable_renaming = true 294 | elseif arg[i] == "-gci" or arg[i] == "--garbage_code" then 295 | features.garbage_code = true 296 | elseif arg[i] == "-opi" or arg[i] == "--opaque_preds" then 297 | features.opaque_predicates = true 298 | elseif arg[i] == "-be" or arg[i] == "--bytecode_encoder" then 299 | features.bytecode_encoding = true 300 | elseif arg[i] == "-st" or arg[i] == "--string_to_expr" then 301 | features.StringToExpressions = true 302 | elseif arg[i] == "-vm" or arg[i] == "--virtual_machine" then 303 | features.VirtualMachine = true 304 | elseif arg[i] == "-wif" or arg[i] == "--wrap_in_func" then 305 | features.WrapInFunction = true 306 | elseif arg[i] == "-fi" or arg[i] == "--func_inlining" then 307 | features.function_inlining = true 308 | elseif arg[i] == "-dc" or arg[i] == "--dynamic_code" then 309 | features.dynamic_code = true 310 | elseif arg[i] == "-at" or arg[i] == "--antitamper" then 311 | features.antitamper = true 312 | elseif arg[i] == "--min" then 313 | options.preset_level = "min" 314 | elseif arg[i] == "--mid" then 315 | options.preset_level = "mid" 316 | elseif arg[i] == "--max" then 317 | options.preset_level = "max" 318 | else 319 | print(colors.red .. "Error: Unknown option '" .. arg[i] .. "'" .. colors.reset) 320 | printUsage() 321 | os.exit(1) 322 | end 323 | end 324 | if not options.folder_mode and not input:match("%.lua$") then 325 | print(colors.red .. "Error: Invalid file extension for '" .. input .. "'" .. colors.reset) 326 | printUsage() 327 | os.exit(1) 328 | end 329 | if options.folder_mode then 330 | if not os.rename(input, input) then 331 | print(colors.red .. "Error: Folder '" .. input .. "' does not exist or could not be found" .. colors.reset) 332 | printUsage() 333 | os.exit(1) 334 | end 335 | else 336 | local fh = io.open(input, "r") 337 | if not fh then 338 | print(colors.red .. "Error: File '" .. input .. "' does not exist or could not be found" .. colors.reset) 339 | printUsage() 340 | os.exit(1) 341 | end 342 | fh:close() 343 | end 344 | 345 | local single_enabled = false 346 | for feature in pairs(features) do 347 | if features[feature] then 348 | single_enabled = true 349 | break 350 | end 351 | end 352 | 353 | if single_enabled then 354 | for feature, enabled in pairs(features) do 355 | config.settings[feature].enabled = enabled 356 | end 357 | end 358 | 359 | local files = {} 360 | if options.folder_mode then 361 | local find_command 362 | if package.config:sub(1,1) == "\\" then 363 | -- windows 364 | local pattern = input .. "\\*.lua" 365 | find_command = string.format('dir %q /b /s 2>nul', pattern) 366 | else 367 | -- mac/linux 368 | find_command = string.format('find %q -type f -name "*.lua"', input) 369 | end 370 | local p = io.popen(find_command) 371 | if not p then 372 | error("Error: Failed to execute find command: " .. find_command) 373 | end 374 | for file in p:lines() do 375 | table.insert(files, file) 376 | end 377 | p:close() 378 | else 379 | table.insert(files, input) 380 | end 381 | 382 | obfuscated_list = {} 383 | local batch_start = os.clock() 384 | for _, file_path in ipairs(files) do 385 | local file = io.open(file_path, "r") 386 | if not file then 387 | print("Error: Could not open file " .. file_path) 388 | os.exit(1) 389 | end 390 | 391 | local code = file:read("*all") 392 | file:close() 393 | 394 | local start_time = os.clock() 395 | local obfuscated_code, sanity_failed, sanity_info 396 | local attempts, success = 0, false 397 | 398 | repeat 399 | attempts = attempts + 1 400 | if options.custom_file then 401 | local ok, custom = pcall(require, options.custom_file) 402 | if not ok then 403 | print("Error: Could not load custom pipeline module: " .. tostring(custom)) 404 | os.exit(1) 405 | end 406 | obfuscated_code = custom.process(code) 407 | else 408 | obfuscated_code = Pipeline.process(code) 409 | end 410 | 411 | if options.sanity_check then 412 | success, sanity_info = runSanityCheck(code, obfuscated_code) 413 | if not success and attempts >= 3 then 414 | sanity_failed = true 415 | break 416 | end 417 | else 418 | success = true 419 | end 420 | until success or attempts >= 3 421 | 422 | local output_file = options.overwrite and file_path or file_path:gsub("%.lua$", "_obfuscated.lua") 423 | local out_file_handle = assert(io.open(output_file, "w")) 424 | out_file_handle:write(obfuscated_code) 425 | out_file_handle:close() 426 | 427 | table.insert(obfuscated_list, output_file) 428 | local file_time = os.clock() - start_time 429 | options.sanity_failed = sanity_failed 430 | options.sanity_info = sanity_info 431 | if not options.folder_mode then 432 | printCliResult(file_path, output_file, file_time, options) 433 | end 434 | end 435 | if options.folder_mode then 436 | local total_time = os.clock() - batch_start 437 | printCliResult(input, nil, total_time, options) 438 | end 439 | end 440 | main() 441 | -------------------------------------------------------------------------------- /src/modules/Compiler/Compiler.lua: -------------------------------------------------------------------------------- 1 | -- i seriously need help 2 | local Serialize = require("modules/Compiler/Serializer") 3 | local Deserialize = require("modules/Compiler/Deserializer") 4 | local luaZ = {} 5 | local luaY = {} 6 | local luaX = {} 7 | local luaP = {} 8 | local luaU = {} 9 | local luaK = {} 10 | local size_size_t = 8; 11 | local function lua_assert(test) 12 | if not test then 13 | error("assertion failed!") 14 | end 15 | end; 16 | function luaZ:make_getS(buff) 17 | local b = buff; 18 | return function() 19 | if not b then 20 | return nil 21 | end; 22 | local data = b; 23 | b = nil; 24 | return data 25 | end 26 | end; 27 | function luaZ:make_getF(source) 28 | local LUAL_BUFFERSIZE = 512; 29 | local pos = 1; 30 | return function() 31 | local buff = source:sub(pos, pos + LUAL_BUFFERSIZE - 1) 32 | pos = math.min(# source + 1, pos + LUAL_BUFFERSIZE) 33 | return buff 34 | end 35 | end; 36 | function luaZ:init(reader, data) 37 | if not reader then 38 | return 39 | end; 40 | local z = {} 41 | z.reader = reader; 42 | z.data = data or "" 43 | z.name = "" 44 | if not data or data == "" then 45 | z.n = 0 46 | else 47 | z.n = # data 48 | end; 49 | z.p = 0; 50 | return z 51 | end; 52 | function luaZ:fill(z) 53 | local buff = z.reader() 54 | z.data = buff; 55 | if not buff or buff == "" then 56 | return "EOZ" 57 | end; 58 | z.n, z.p = # buff - 1, 1; 59 | return string.sub(buff, 1, 1) 60 | end; 61 | function luaZ:zgetc(z) 62 | local n, p = z.n, z.p + 1; 63 | if n > 0 then 64 | z.n, z.p = n - 1, p; 65 | return string.sub(z.data, p, p) 66 | else 67 | return self:fill(z) 68 | end 69 | end; 70 | luaX.RESERVED = [[ 71 | TK_AND and 72 | TK_BREAK break 73 | TK_DO do 74 | TK_ELSE else 75 | TK_ELSEIF elseif 76 | TK_END end 77 | TK_FALSE false 78 | TK_FOR for 79 | TK_FUNCTION function 80 | TK_IF if 81 | TK_IN in 82 | TK_LOCAL local 83 | TK_NIL nil 84 | TK_NOT not 85 | TK_OR or 86 | TK_REPEAT repeat 87 | TK_RETURN return 88 | TK_THEN then 89 | TK_TRUE true 90 | TK_UNTIL until 91 | TK_WHILE while 92 | TK_CONCAT .. 93 | TK_DOTS ... 94 | TK_EQ == 95 | TK_GE >= 96 | TK_LE <= 97 | TK_NE ~= 98 | TK_NAME 99 | TK_NUMBER 100 | TK_STRING 101 | TK_EOS ]] 102 | luaX.MAXSRC = 80; 103 | luaX.MAX_INT = 2147483645; 104 | luaX.LUA_QS = "'%s'" 105 | luaX.LUA_COMPAT_LSTR = 1; 106 | function luaX:init() 107 | local tokens, enums = {}, {} 108 | for v in string.gmatch(self.RESERVED, "[^\n]+") do 109 | local _, _, tok, str = string.find(v, "(%S+)%s+(%S+)") 110 | tokens[tok] = str; 111 | enums[str] = tok 112 | end; 113 | self.tokens = tokens; 114 | self.enums = enums 115 | end; 116 | function luaX:chunkid(source, bufflen) 117 | local out; 118 | local first = string.sub(source, 1, 1) 119 | if first == "=" then 120 | out = string.sub(source, 2, bufflen) 121 | else 122 | if first == "@" then 123 | source = string.sub(source, 2) 124 | bufflen = bufflen - # " '...' " 125 | local l = # source; 126 | out = "" 127 | if l > bufflen then 128 | source = string.sub(source, 1 + l - bufflen) 129 | out = out .. "..." 130 | end; 131 | out = out .. source 132 | else 133 | local len = string.find(source, "[\n\r]") 134 | len = len and (len - 1) or # source; 135 | bufflen = bufflen - # (" [string \"...\"] ") 136 | if len > bufflen then 137 | len = bufflen 138 | end; 139 | out = "[string \"" 140 | if len < # source then 141 | out = out .. string.sub(source, 1, len) .. "..." 142 | else 143 | out = out .. source 144 | end; 145 | out = out .. "\"]" 146 | end 147 | end; 148 | return out 149 | end; 150 | function luaX:token2str(ls, token) 151 | if string.sub(token, 1, 3) ~= "TK_" then 152 | if string.find(token, "%c") then 153 | return string.format("char(%d)", string.byte(token)) 154 | end; 155 | return token 156 | else 157 | return self.tokens[token] 158 | end 159 | end; 160 | function luaX:lexerror(ls, msg, token) 161 | local function txtToken(ls, token) 162 | if token == "TK_NAME" or token == "TK_STRING" or token == "TK_NUMBER" then 163 | return ls.buff 164 | else 165 | return self:token2str(ls, token) 166 | end 167 | end; 168 | local buff = self:chunkid(ls.source, self.MAXSRC) 169 | local msg = string.format("%s:%d: %s", buff, ls.linenumber, msg) 170 | if token then 171 | msg = string.format("%s near " .. self.LUA_QS, msg, txtToken(ls, token)) 172 | end; 173 | error(msg) 174 | end; 175 | function luaX:syntaxerror(ls, msg) 176 | self:lexerror(ls, msg, ls.t.token) 177 | end; 178 | function luaX:currIsNewline(ls) 179 | return ls.current == "\n" or ls.current == "\r" 180 | end; 181 | function luaX:inclinenumber(ls) 182 | local old = ls.current; 183 | self:nextc(ls) 184 | if self:currIsNewline(ls) and ls.current ~= old then 185 | self:nextc(ls) 186 | end; 187 | ls.linenumber = ls.linenumber + 1; 188 | if ls.linenumber >= self.MAX_INT then 189 | self:syntaxerror(ls, "chunk has too many lines") 190 | end 191 | end; 192 | function luaX:setinput(L, ls, z, source) 193 | if not ls then 194 | ls = {} 195 | end; 196 | if not ls.lookahead then 197 | ls.lookahead = {} 198 | end; 199 | if not ls.t then 200 | ls.t = {} 201 | end; 202 | ls.decpoint = "." 203 | ls.L = L; 204 | ls.lookahead.token = "TK_EOS" 205 | ls.z = z; 206 | ls.fs = nil; 207 | ls.linenumber = 1; 208 | ls.lastline = 1; 209 | ls.source = source; 210 | self:nextc(ls) 211 | end; 212 | function luaX:check_next(ls, set) 213 | if not string.find(set, ls.current, 1, 1) then 214 | return false 215 | end; 216 | self:save_and_next(ls) 217 | return true 218 | end; 219 | function luaX:next(ls) 220 | ls.lastline = ls.linenumber; 221 | if ls.lookahead.token ~= "TK_EOS" then 222 | ls.t.seminfo = ls.lookahead.seminfo; 223 | ls.t.token = ls.lookahead.token; 224 | ls.lookahead.token = "TK_EOS" 225 | else 226 | ls.t.token = self:llex(ls, ls.t) 227 | end 228 | end; 229 | function luaX:lookahead(ls) 230 | ls.lookahead.token = self:llex(ls, ls.lookahead) 231 | end; 232 | function luaX:nextc(ls) 233 | local c = luaZ:zgetc(ls.z) 234 | ls.current = c; 235 | return c 236 | end; 237 | function luaX:save(ls, c) 238 | local buff = ls.buff; 239 | ls.buff = buff .. c 240 | end; 241 | function luaX:save_and_next(ls) 242 | self:save(ls, ls.current) 243 | return self:nextc(ls) 244 | end; 245 | function luaX:str2d(s) 246 | local result = tonumber(s) 247 | if result then 248 | return result 249 | end; 250 | if string.lower(string.sub(s, 1, 2)) == "0x" then 251 | result = tonumber(s, 16) 252 | if result then 253 | return result 254 | end 255 | end; 256 | return nil 257 | end; 258 | function luaX:buffreplace(ls, from, to) 259 | local result, buff = "", ls.buff; 260 | for p = 1, # buff do 261 | local c = string.sub(buff, p, p) 262 | if c == from then 263 | c = to 264 | end; 265 | result = result .. c 266 | end; 267 | ls.buff = result 268 | end; 269 | function luaX:trydecpoint(ls, Token) 270 | local old = ls.decpoint; 271 | self:buffreplace(ls, old, ls.decpoint) 272 | local seminfo = self:str2d(ls.buff) 273 | Token.seminfo = seminfo; 274 | if not seminfo then 275 | self:buffreplace(ls, ls.decpoint, ".") 276 | self:lexerror(ls, "malformed number", "TK_NUMBER") 277 | end 278 | end; 279 | function luaX:read_numeral(ls, Token) 280 | repeat 281 | self:save_and_next(ls) 282 | until string.find(ls.current, "%D") and ls.current ~= "." 283 | if self:check_next(ls, "Ee") then 284 | self:check_next(ls, "+-") 285 | end; 286 | while string.find(ls.current, "^%w$") or ls.current == "_" do 287 | self:save_and_next(ls) 288 | end; 289 | self:buffreplace(ls, ".", ls.decpoint) 290 | local seminfo = self:str2d(ls.buff) 291 | Token.seminfo = seminfo; 292 | if not seminfo then 293 | self:trydecpoint(ls, Token) 294 | end 295 | end; 296 | function luaX:skip_sep(ls) 297 | local count = 0; 298 | local s = ls.current; 299 | self:save_and_next(ls) 300 | while ls.current == "=" do 301 | self:save_and_next(ls) 302 | count = count + 1 303 | end; 304 | return (ls.current == s) and count or (- count) - 1 305 | end; 306 | function luaX:read_long_string(ls, Token, sep) 307 | local cont = 0; 308 | self:save_and_next(ls) 309 | if self:currIsNewline(ls) then 310 | self:inclinenumber(ls) 311 | end; 312 | while true do 313 | local c = ls.current; 314 | if c == "EOZ" then 315 | self:lexerror(ls, Token and "unfinished long string" or "unfinished long comment", "TK_EOS") 316 | elseif c == "[" then 317 | if self.LUA_COMPAT_LSTR then 318 | if self:skip_sep(ls) == sep then 319 | self:save_and_next(ls) 320 | cont = cont + 1; 321 | if self.LUA_COMPAT_LSTR == 1 then 322 | if sep == 0 then 323 | self:lexerror(ls, "nesting of [[...]] is deprecated", "[") 324 | end 325 | end 326 | end 327 | end 328 | elseif c == "]" then 329 | if self:skip_sep(ls) == sep then 330 | self:save_and_next(ls) 331 | if self.LUA_COMPAT_LSTR and self.LUA_COMPAT_LSTR == 2 then 332 | cont = cont - 1; 333 | if sep == 0 and cont >= 0 then 334 | break 335 | end 336 | end; 337 | break 338 | end 339 | elseif self:currIsNewline(ls) then 340 | self:save(ls, "\n") 341 | self:inclinenumber(ls) 342 | if not Token then 343 | ls.buff = "" 344 | end 345 | else 346 | if Token then 347 | self:save_and_next(ls) 348 | else 349 | self:nextc(ls) 350 | end 351 | end 352 | end; 353 | if Token then 354 | local p = 3 + sep; 355 | Token.seminfo = string.sub(ls.buff, p, - p) 356 | end 357 | end; 358 | function luaX:read_string(ls, del, Token) 359 | self:save_and_next(ls) 360 | while ls.current ~= del do 361 | local c = ls.current; 362 | if c == "EOZ" then 363 | self:lexerror(ls, "unfinished string", "TK_EOS") 364 | elseif self:currIsNewline(ls) then 365 | self:lexerror(ls, "unfinished string", "TK_STRING") 366 | elseif c == "\\" then 367 | c = self:nextc(ls) 368 | if self:currIsNewline(ls) then 369 | self:save(ls, "\n") 370 | self:inclinenumber(ls) 371 | elseif c ~= "EOZ" then 372 | local i = string.find("abfnrtv", c, 1, 1) 373 | if i then 374 | self:save(ls, string.sub("\a\b\f\n\r\t\v", i, i)) 375 | self:nextc(ls) 376 | elseif not string.find(c, "%d") then 377 | self:save_and_next(ls) 378 | else 379 | c, i = 0, 0; 380 | repeat 381 | c = 10 * c + ls.current; 382 | self:nextc(ls) 383 | i = i + 1 384 | until i >= 3 or not string.find(ls.current, "%d") 385 | if c > 255 then 386 | self:lexerror(ls, "escape sequence too large", "TK_STRING") 387 | end; 388 | self:save(ls, string.char(c)) 389 | end 390 | end 391 | else 392 | self:save_and_next(ls) 393 | end 394 | end; 395 | self:save_and_next(ls) 396 | Token.seminfo = string.sub(ls.buff, 2, - 2) 397 | end; 398 | function luaX:llex(ls, Token) 399 | ls.buff = "" 400 | while true do 401 | local c = ls.current; 402 | if self:currIsNewline(ls) then 403 | self:inclinenumber(ls) 404 | elseif c == "-" then 405 | c = self:nextc(ls) 406 | if c ~= "-" then 407 | return "-" 408 | end; 409 | local sep = - 1; 410 | if self:nextc(ls) == '[' then 411 | sep = self:skip_sep(ls) 412 | ls.buff = "" 413 | end; 414 | if sep >= 0 then 415 | self:read_long_string(ls, nil, sep) 416 | ls.buff = "" 417 | else 418 | while not self:currIsNewline(ls) and ls.current ~= "EOZ" do 419 | self:nextc(ls) 420 | end 421 | end 422 | elseif c == "[" then 423 | local sep = self:skip_sep(ls) 424 | if sep >= 0 then 425 | self:read_long_string(ls, Token, sep) 426 | return "TK_STRING" 427 | elseif sep == - 1 then 428 | return "[" 429 | else 430 | self:lexerror(ls, "invalid long string delimiter", "TK_STRING") 431 | end 432 | elseif c == "=" then 433 | c = self:nextc(ls) 434 | if c ~= "=" then 435 | return "=" 436 | else 437 | self:nextc(ls) 438 | return "TK_EQ" 439 | end 440 | elseif c == "<" then 441 | c = self:nextc(ls) 442 | if c ~= "=" then 443 | return "<" 444 | else 445 | self:nextc(ls) 446 | return "TK_LE" 447 | end 448 | elseif c == ">" then 449 | c = self:nextc(ls) 450 | if c ~= "=" then 451 | return ">" 452 | else 453 | self:nextc(ls) 454 | return "TK_GE" 455 | end 456 | elseif c == "~" then 457 | c = self:nextc(ls) 458 | if c ~= "=" then 459 | return "~" 460 | else 461 | self:nextc(ls) 462 | return "TK_NE" 463 | end 464 | elseif c == "\"" or c == "'" then 465 | self:read_string(ls, c, Token) 466 | return "TK_STRING" 467 | elseif c == "." then 468 | c = self:save_and_next(ls) 469 | if self:check_next(ls, ".") then 470 | if self:check_next(ls, ".") then 471 | return "TK_DOTS" 472 | else 473 | return "TK_CONCAT" 474 | end 475 | elseif not string.find(c, "%d") then 476 | return "." 477 | else 478 | self:read_numeral(ls, Token) 479 | return "TK_NUMBER" 480 | end 481 | elseif c == "EOZ" then 482 | return "TK_EOS" 483 | else 484 | if string.find(c, "%s") then 485 | self:nextc(ls) 486 | elseif string.find(c, "%d") then 487 | self:read_numeral(ls, Token) 488 | return "TK_NUMBER" 489 | elseif string.find(c, "[_%a]") then 490 | repeat 491 | c = self:save_and_next(ls) 492 | until c == "EOZ" or not string.find(c, "[_%w]") 493 | local ts = ls.buff; 494 | local tok = self.enums[ts] 495 | if tok then 496 | return tok 497 | end; 498 | Token.seminfo = ts; 499 | return "TK_NAME" 500 | else 501 | self:nextc(ls) 502 | return c 503 | end 504 | end 505 | end 506 | end; 507 | luaP.OpMode = { 508 | iABC = 0, 509 | iABx = 1, 510 | iAsBx = 2 511 | } 512 | luaP.SIZE_C = 9; 513 | luaP.SIZE_B = 9; 514 | luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B; 515 | luaP.SIZE_A = 8; 516 | luaP.SIZE_OP = 6; 517 | luaP.POS_OP = 0; 518 | luaP.POS_A = luaP.POS_OP + luaP.SIZE_OP; 519 | luaP.POS_C = luaP.POS_A + luaP.SIZE_A; 520 | luaP.POS_B = luaP.POS_C + luaP.SIZE_C; 521 | luaP.POS_Bx = luaP.POS_C; 522 | luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1; 523 | luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) 524 | luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1; 525 | luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1; 526 | luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1; 527 | function luaP:GET_OPCODE(i) 528 | return self.ROpCode[i.OP] 529 | end; 530 | function luaP:SET_OPCODE(i, o) 531 | i.OP = self.OpCode[o] 532 | end; 533 | function luaP:GETARG_A(i) 534 | return i.A 535 | end; 536 | function luaP:SETARG_A(i, u) 537 | i.A = u 538 | end; 539 | function luaP:GETARG_B(i) 540 | return i.B 541 | end; 542 | function luaP:SETARG_B(i, b) 543 | i.B = b 544 | end; 545 | function luaP:GETARG_C(i) 546 | return i.C 547 | end; 548 | function luaP:SETARG_C(i, b) 549 | i.C = b 550 | end; 551 | function luaP:GETARG_Bx(i) 552 | return i.Bx 553 | end; 554 | function luaP:SETARG_Bx(i, b) 555 | i.Bx = b 556 | end; 557 | function luaP:GETARG_sBx(i) 558 | return i.Bx - self.MAXARG_sBx 559 | end; 560 | function luaP:SETARG_sBx(i, b) 561 | i.Bx = b + self.MAXARG_sBx 562 | end; 563 | function luaP:CREATE_ABC(o, a, b, c) 564 | return { 565 | OP = self.OpCode[o], 566 | A = a, 567 | B = b, 568 | C = c 569 | } 570 | end; 571 | function luaP:CREATE_ABx(o, a, bc) 572 | return { 573 | OP = self.OpCode[o], 574 | A = a, 575 | Bx = bc 576 | } 577 | end; 578 | function luaP:CREATE_Inst(c) 579 | local o = c % 64; 580 | c = (c - o) / 64; 581 | local a = c % 256; 582 | c = (c - a) / 256; 583 | return self:CREATE_ABx(o, a, c) 584 | end; 585 | function luaP:Instruction(i) 586 | if i.Bx then 587 | i.C = i.Bx % 512; 588 | i.B = (i.Bx - i.C) / 512 589 | end; 590 | local I = i.A * 64 + i.OP; 591 | local c0 = I % 256; 592 | I = i.C * 64 + (I - c0) / 256; 593 | local c1 = I % 256; 594 | I = i.B * 128 + (I - c1) / 256; 595 | local c2 = I % 256; 596 | local c3 = (I - c2) / 256; 597 | return string.char(c0, c1, c2, c3) 598 | end; 599 | function luaP:DecodeInst(x) 600 | local byte = string.byte; 601 | local i = {} 602 | local I = byte(x, 1) 603 | local op = I % 64; 604 | i.OP = op; 605 | I = byte(x, 2) * 4 + (I - op) / 64; 606 | local a = I % 256; 607 | i.A = a; 608 | I = byte(x, 3) * 4 + (I - a) / 256; 609 | local c = I % 512; 610 | i.C = c; 611 | i.B = byte(x, 4) * 2 + (I - c) / 512; 612 | local opmode = self.OpMode[tonumber(string.sub(self.opmodes[op + 1], 7, 7))] 613 | if opmode ~= "iABC" then 614 | i.Bx = i.B * 512 + i.C 615 | end; 616 | return i 617 | end; 618 | luaP.BITRK = math.ldexp(1, luaP.SIZE_B - 1) 619 | function luaP:ISK(x) 620 | return x >= self.BITRK 621 | end; 622 | function luaP:INDEXK(r) 623 | return r - self.BITRK 624 | end; 625 | luaP.MAXINDEXRK = luaP.BITRK - 1; 626 | function luaP:RKASK(x) 627 | return x + self.BITRK 628 | end; 629 | luaP.NO_REG = luaP.MAXARG_A; 630 | luaP.opnames = {} 631 | luaP.OpCode = {} 632 | luaP.ROpCode = {} 633 | local i = 0; 634 | for v in string.gmatch([[ 635 | MOVE LOADK LOADBOOL LOADNIL GETUPVAL 636 | GETGLOBAL GETTABLE SETGLOBAL SETUPVAL SETTABLE 637 | NEWTABLE SELF ADD SUB MUL 638 | DIV MOD POW UNM NOT 639 | LEN CONCAT JMP EQ LT 640 | LE TEST TESTSET CALL TAILCALL 641 | RETURN FORLOOP FORPREP TFORLOOP SETLIST 642 | CLOSE CLOSURE VARARG 643 | ]], "%S+") do 644 | local n = "OP_" .. v; 645 | luaP.opnames[i] = v; 646 | luaP.OpCode[n] = i; 647 | luaP.ROpCode[i] = n; 648 | i = i + 1 649 | end; 650 | luaP.NUM_OPCODES = i; 651 | luaP.OpArgMask = { 652 | OpArgN = 0, 653 | OpArgU = 1, 654 | OpArgR = 2, 655 | OpArgK = 3 656 | } 657 | function luaP:getOpMode(m) 658 | return self.opmodes[self.OpCode[m]] % 4 659 | end; 660 | function luaP:getBMode(m) 661 | return math.floor(self.opmodes[self.OpCode[m]] / 16) % 4 662 | end; 663 | function luaP:getCMode(m) 664 | return math.floor(self.opmodes[self.OpCode[m]] / 4) % 4 665 | end; 666 | function luaP:testAMode(m) 667 | return math.floor(self.opmodes[self.OpCode[m]] / 64) % 2 668 | end; 669 | function luaP:testTMode(m) 670 | return math.floor(self.opmodes[self.OpCode[m]] / 128) 671 | end; 672 | luaP.LFIELDS_PER_FLUSH = 50; 673 | local function opmode(t, a, b, c, m) 674 | local luaP = luaP; 675 | return t * 128 + a * 64 + luaP.OpArgMask[b] * 16 + luaP.OpArgMask[c] * 4 + luaP.OpMode[m] 676 | end; 677 | luaP.opmodes = { 678 | opmode(0, 1, "OpArgK", "OpArgN", "iABx"), 679 | opmode(0, 1, "OpArgU", "OpArgU", "iABC"), 680 | opmode(0, 1, "OpArgR", "OpArgN", "iABC"), 681 | opmode(0, 1, "OpArgU", "OpArgN", "iABC"), 682 | opmode(0, 1, "OpArgK", "OpArgN", "iABx"), 683 | opmode(0, 1, "OpArgR", "OpArgK", "iABC"), 684 | opmode(0, 0, "OpArgK", "OpArgN", "iABx"), 685 | opmode(0, 0, "OpArgU", "OpArgN", "iABC"), 686 | opmode(0, 0, "OpArgK", "OpArgK", "iABC"), 687 | opmode(0, 1, "OpArgU", "OpArgU", "iABC"), 688 | opmode(0, 1, "OpArgR", "OpArgK", "iABC"), 689 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), 690 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), 691 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), 692 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), 693 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), 694 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), 695 | opmode(0, 1, "OpArgR", "OpArgN", "iABC"), 696 | opmode(0, 1, "OpArgR", "OpArgN", "iABC"), 697 | opmode(0, 1, "OpArgR", "OpArgN", "iABC"), 698 | opmode(0, 1, "OpArgR", "OpArgR", "iABC"), 699 | opmode(0, 0, "OpArgR", "OpArgN", "iAsBx"), 700 | opmode(1, 0, "OpArgK", "OpArgK", "iABC"), 701 | opmode(1, 0, "OpArgK", "OpArgK", "iABC"), 702 | opmode(1, 0, "OpArgK", "OpArgK", "iABC"), 703 | opmode(1, 1, "OpArgR", "OpArgU", "iABC"), 704 | opmode(1, 1, "OpArgR", "OpArgU", "iABC"), 705 | opmode(0, 1, "OpArgU", "OpArgU", "iABC"), 706 | opmode(0, 1, "OpArgU", "OpArgU", "iABC"), 707 | opmode(0, 0, "OpArgU", "OpArgN", "iABC"), 708 | opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), 709 | opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), 710 | opmode(1, 0, "OpArgN", "OpArgU", "iABC"), 711 | opmode(0, 0, "OpArgU", "OpArgU", "iABC"), 712 | opmode(0, 0, "OpArgN", "OpArgN", "iABC"), 713 | opmode(0, 1, "OpArgU", "OpArgN", "iABx"), 714 | opmode(0, 1, "OpArgU", "OpArgN", "iABC") 715 | } 716 | luaP.opmodes[0] = opmode(0, 1, "OpArgR", "OpArgN", "iABC") 717 | luaU.LUA_SIGNATURE = "\27Lua" 718 | luaU.LUA_TNUMBER = 3; 719 | luaU.LUA_TSTRING = 4; 720 | luaU.LUA_TNIL = 0; 721 | luaU.LUA_TBOOLEAN = 1; 722 | luaU.LUA_TNONE = - 1; 723 | luaU.LUAC_VERSION = 81; 724 | luaU.LUAC_FORMAT = 0; 725 | luaU.LUAC_HEADERSIZE = 12; 726 | function luaU:make_setS() 727 | local buff = {} 728 | buff.data = "" 729 | local writer = function(s, buff) 730 | if not s then 731 | return 0 732 | end; 733 | buff.data = buff.data .. s; 734 | return 0 735 | end; 736 | return writer, buff 737 | end; 738 | function luaU:make_setF(filename) 739 | local buff = {} 740 | buff.h = io.open(filename, "wb") 741 | if not buff.h then 742 | return nil 743 | end; 744 | local writer = function(s, buff) 745 | if not buff.h then 746 | return 0 747 | end; 748 | if not s then 749 | if buff.h:close() then 750 | return 0 751 | end 752 | else 753 | if buff.h:write(s) then 754 | return 0 755 | end 756 | end; 757 | return 1 758 | end; 759 | return writer, buff 760 | end; 761 | function luaU:ttype(o) 762 | local tt = type(o.value) 763 | if tt == "number" then 764 | return self.LUA_TNUMBER 765 | elseif tt == "string" then 766 | return self.LUA_TSTRING 767 | elseif tt == "nil" then 768 | return self.LUA_TNIL 769 | elseif tt == "boolean" then 770 | return self.LUA_TBOOLEAN 771 | else 772 | return self.LUA_TNONE 773 | end 774 | end; 775 | function luaU:from_double(x) 776 | local function grab_byte(v) 777 | local c = v % 256; 778 | return (v - c) / 256, string.char(c) 779 | end; 780 | local sign = 0; 781 | if x < 0 then 782 | sign = 1; 783 | x = - x 784 | end; 785 | local mantissa, exponent = math.frexp(x) 786 | if x == 0 then 787 | mantissa, exponent = 0, 0 788 | elseif x == 1 / 0 then 789 | mantissa, exponent = 0, 2047 790 | else 791 | mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53) 792 | exponent = exponent + 1022 793 | end; 794 | local v = "" 795 | local byte; 796 | x = math.floor(mantissa) 797 | for i = 1, 6 do 798 | x, byte = grab_byte(x) 799 | v = v .. byte 800 | end; 801 | x, byte = grab_byte(exponent * 16 + x) 802 | v = v .. byte; 803 | x, byte = grab_byte(sign * 128 + x) 804 | v = v .. byte; 805 | return v 806 | end; 807 | function luaU:from_int(x) 808 | local v = "" 809 | x = math.floor(x) 810 | if x < 0 then 811 | x = 4294967296 + x 812 | end; 813 | for i = 1, 4 do 814 | local c = x % 256; 815 | v = v .. string.char(c) 816 | x = math.floor(x / 256) 817 | end; 818 | return v 819 | end; 820 | function luaU:DumpBlock(b, D) 821 | if D.status == 0 then 822 | D.status = D.write(b, D.data) 823 | end 824 | end; 825 | function luaU:DumpChar(y, D) 826 | self:DumpBlock(string.char(y), D) 827 | end; 828 | function luaU:DumpInt(x, D) 829 | self:DumpBlock(self:from_int(x), D) 830 | end; 831 | function luaU:DumpSizeT(x, D) 832 | self:DumpBlock(self:from_int(x), D) 833 | if size_size_t == 8 then 834 | self:DumpBlock(self:from_int(0), D) 835 | end 836 | end; 837 | function luaU:DumpNumber(x, D) 838 | self:DumpBlock(self:from_double(x), D) 839 | end; 840 | function luaU:DumpString(s, D) 841 | if s == nil then 842 | self:DumpSizeT(0, D) 843 | else 844 | s = s .. "\0" 845 | self:DumpSizeT(# s, D) 846 | self:DumpBlock(s, D) 847 | end 848 | end; 849 | function luaU:DumpCode(f, D) 850 | local n = f.sizecode; 851 | self:DumpInt(n, D) 852 | for i = 0, n - 1 do 853 | self:DumpBlock(luaP:Instruction(f.code[i]), D) 854 | end 855 | end; 856 | function luaU:DumpConstants(f, D) 857 | local n = f.sizek; 858 | self:DumpInt(n, D) 859 | for i = 0, n - 1 do 860 | local o = f.k[i] 861 | local tt = self:ttype(o) 862 | self:DumpChar(tt, D) 863 | if tt == self.LUA_TNIL then 864 | elseif tt == self.LUA_TBOOLEAN then 865 | self:DumpChar(o.value and 1 or 0, D) 866 | elseif tt == self.LUA_TNUMBER then 867 | self:DumpNumber(o.value, D) 868 | elseif tt == self.LUA_TSTRING then 869 | self:DumpString(o.value, D) 870 | else 871 | end 872 | end; 873 | n = f.sizep; 874 | self:DumpInt(n, D) 875 | for i = 0, n - 1 do 876 | self:DumpFunction(f.p[i], f.source, D) 877 | end 878 | end; 879 | function luaU:DumpDebug(f, D) 880 | local n; 881 | n = D.strip and 0 or f.sizelineinfo; 882 | self:DumpInt(n, D) 883 | for i = 0, n - 1 do 884 | self:DumpInt(f.lineinfo[i], D) 885 | end; 886 | n = D.strip and 0 or f.sizelocvars; 887 | self:DumpInt(n, D) 888 | for i = 0, n - 1 do 889 | self:DumpString(f.locvars[i].varname, D) 890 | self:DumpInt(f.locvars[i].startpc, D) 891 | self:DumpInt(f.locvars[i].endpc, D) 892 | end; 893 | n = D.strip and 0 or f.sizeupvalues; 894 | self:DumpInt(n, D) 895 | for i = 0, n - 1 do 896 | self:DumpString(f.upvalues[i], D) 897 | end 898 | end; 899 | function luaU:DumpFunction(f, p, D) 900 | local source = f.source; 901 | if source == p or D.strip then 902 | source = nil 903 | end; 904 | self:DumpString(source, D) 905 | self:DumpInt(f.lineDefined, D) 906 | self:DumpInt(f.lastlinedefined, D) 907 | self:DumpChar(f.nups, D) 908 | self:DumpChar(f.numparams, D) 909 | self:DumpChar(f.is_vararg, D) 910 | self:DumpChar(f.maxstacksize, D) 911 | self:DumpCode(f, D) 912 | self:DumpConstants(f, D) 913 | self:DumpDebug(f, D) 914 | end; 915 | function luaU:DumpHeader(D) 916 | local h = self:header() 917 | assert(# h == self.LUAC_HEADERSIZE) 918 | self:DumpBlock(h, D) 919 | end; 920 | function luaU:header() 921 | local x = 1; 922 | return self.LUA_SIGNATURE .. string.char(self.LUAC_VERSION, self.LUAC_FORMAT, x, 4, size_size_t, 4, 8, 0) 923 | end; 924 | function luaU:dump(L, f, w, data, strip) 925 | local D = {} 926 | D.L = L; 927 | D.write = w; 928 | D.data = data; 929 | D.strip = strip; 930 | D.status = 0; 931 | self:DumpHeader(D) 932 | self:DumpFunction(f, nil, D) 933 | D.write(nil, D.data) 934 | return D.status 935 | end; 936 | luaK.MAXSTACK = 250; 937 | function luaK:ttisnumber(o) 938 | if o then 939 | return type(o.value) == "number" 940 | else 941 | return false 942 | end 943 | end; 944 | function luaK:nvalue(o) 945 | return o.value 946 | end; 947 | function luaK:setnilvalue(o) 948 | o.value = nil 949 | end; 950 | function luaK:setsvalue(o, x) 951 | o.value = x 952 | end; 953 | luaK.setnvalue = luaK.setsvalue; 954 | luaK.sethvalue = luaK.setsvalue; 955 | luaK.setbvalue = luaK.setsvalue; 956 | function luaK:numadd(a, b) 957 | return a + b 958 | end; 959 | function luaK:numsub(a, b) 960 | return a - b 961 | end; 962 | function luaK:nummul(a, b) 963 | return a * b 964 | end; 965 | function luaK:numdiv(a, b) 966 | return a / b 967 | end; 968 | function luaK:nummod(a, b) 969 | return a % b 970 | end; 971 | function luaK:numpow(a, b) 972 | return a ^ b 973 | end; 974 | function luaK:numunm(a) 975 | return - a 976 | end; 977 | function luaK:numisnan(a) 978 | return not a == a 979 | end; 980 | luaK.NO_JUMP = - 1; 981 | luaK.BinOpr = { 982 | OPR_ADD = 0, 983 | OPR_SUB = 1, 984 | OPR_MUL = 2, 985 | OPR_DIV = 3, 986 | OPR_MOD = 4, 987 | OPR_POW = 5, 988 | OPR_CONCAT = 6, 989 | OPR_NE = 7, 990 | OPR_EQ = 8, 991 | OPR_LT = 9, 992 | OPR_LE = 10, 993 | OPR_GT = 11, 994 | OPR_GE = 12, 995 | OPR_AND = 13, 996 | OPR_OR = 14, 997 | OPR_NOBINOPR = 15 998 | } 999 | luaK.UnOpr = { 1000 | OPR_MINUS = 0, 1001 | OPR_NOT = 1, 1002 | OPR_LEN = 2, 1003 | OPR_NOUNOPR = 3 1004 | } 1005 | function luaK:getcode(fs, e) 1006 | return fs.f.code[e.info] 1007 | end; 1008 | function luaK:codeAsBx(fs, o, A, sBx) 1009 | return self:codeABx(fs, o, A, sBx + luaP.MAXARG_sBx) 1010 | end; 1011 | function luaK:setmultret(fs, e) 1012 | self:setreturns(fs, e, luaY.LUA_MULTRET) 1013 | end; 1014 | function luaK:hasjumps(e) 1015 | return e.t ~= e.f 1016 | end; 1017 | function luaK:isnumeral(e) 1018 | return e.k == "VKNUM" and e.t == self.NO_JUMP and e.f == self.NO_JUMP 1019 | end; 1020 | function luaK:_nil(fs, from, n) 1021 | if fs.pc > fs.lasttarget then 1022 | if fs.pc == 0 then 1023 | if from >= fs.nactvar then 1024 | return 1025 | end 1026 | else 1027 | local previous = fs.f.code[fs.pc - 1] 1028 | if luaP:GET_OPCODE(previous) == "OP_LOADNIL" then 1029 | local pfrom = luaP:GETARG_A(previous) 1030 | local pto = luaP:GETARG_B(previous) 1031 | if pfrom <= from and from <= pto + 1 then 1032 | if from + n - 1 > pto then 1033 | luaP:SETARG_B(previous, from + n - 1) 1034 | end; 1035 | return 1036 | end 1037 | end 1038 | end 1039 | end; 1040 | self:codeABC(fs, "OP_LOADNIL", from, from + n - 1, 0) 1041 | end; 1042 | function luaK:jump(fs) 1043 | local jpc = fs.jpc; 1044 | fs.jpc = self.NO_JUMP; 1045 | local j = self:codeAsBx(fs, "OP_JMP", 0, self.NO_JUMP) 1046 | j = self:concat(fs, j, jpc) 1047 | return j 1048 | end; 1049 | function luaK:ret(fs, first, nret) 1050 | self:codeABC(fs, "OP_RETURN", first, nret + 1, 0) 1051 | end; 1052 | function luaK:condjump(fs, op, A, B, C) 1053 | self:codeABC(fs, op, A, B, C) 1054 | return self:jump(fs) 1055 | end; 1056 | function luaK:fixjump(fs, pc, dest) 1057 | local jmp = fs.f.code[pc] 1058 | local offset = dest - (pc + 1) 1059 | lua_assert(dest ~= self.NO_JUMP) 1060 | if math.abs(offset) > luaP.MAXARG_sBx then 1061 | luaX:syntaxerror(fs.ls, "control structure too long") 1062 | end; 1063 | luaP:SETARG_sBx(jmp, offset) 1064 | end; 1065 | function luaK:getlabel(fs) 1066 | fs.lasttarget = fs.pc; 1067 | return fs.pc 1068 | end; 1069 | function luaK:getjump(fs, pc) 1070 | local offset = luaP:GETARG_sBx(fs.f.code[pc]) 1071 | if offset == self.NO_JUMP then 1072 | return self.NO_JUMP 1073 | else 1074 | return (pc + 1) + offset 1075 | end 1076 | end; 1077 | function luaK:getjumpcontrol(fs, pc) 1078 | local pi = fs.f.code[pc] 1079 | local ppi = fs.f.code[pc - 1] 1080 | if pc >= 1 and luaP:testTMode(luaP:GET_OPCODE(ppi)) ~= 0 then 1081 | return ppi 1082 | else 1083 | return pi 1084 | end 1085 | end; 1086 | function luaK:need_value(fs, list) 1087 | while list ~= self.NO_JUMP do 1088 | local i = self:getjumpcontrol(fs, list) 1089 | if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then 1090 | return true 1091 | end; 1092 | list = self:getjump(fs, list) 1093 | end; 1094 | return false 1095 | end; 1096 | function luaK:patchtestreg(fs, node, reg) 1097 | local i = self:getjumpcontrol(fs, node) 1098 | if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then 1099 | return false 1100 | end; 1101 | if reg ~= luaP.NO_REG and reg ~= luaP:GETARG_B(i) then 1102 | luaP:SETARG_A(i, reg) 1103 | else 1104 | luaP:SET_OPCODE(i, "OP_TEST") 1105 | local b = luaP:GETARG_B(i) 1106 | luaP:SETARG_A(i, b) 1107 | luaP:SETARG_B(i, 0) 1108 | end; 1109 | return true 1110 | end; 1111 | function luaK:removevalues(fs, list) 1112 | while list ~= self.NO_JUMP do 1113 | self:patchtestreg(fs, list, luaP.NO_REG) 1114 | list = self:getjump(fs, list) 1115 | end 1116 | end; 1117 | function luaK:patchlistaux(fs, list, vtarget, reg, dtarget) 1118 | while list ~= self.NO_JUMP do 1119 | local _next = self:getjump(fs, list) 1120 | if self:patchtestreg(fs, list, reg) then 1121 | self:fixjump(fs, list, vtarget) 1122 | else 1123 | self:fixjump(fs, list, dtarget) 1124 | end; 1125 | list = _next 1126 | end 1127 | end; 1128 | function luaK:dischargejpc(fs) 1129 | self:patchlistaux(fs, fs.jpc, fs.pc, luaP.NO_REG, fs.pc) 1130 | fs.jpc = self.NO_JUMP 1131 | end; 1132 | function luaK:patchlist(fs, list, target) 1133 | if target == fs.pc then 1134 | self:patchtohere(fs, list) 1135 | else 1136 | lua_assert(target < fs.pc) 1137 | self:patchlistaux(fs, list, target, luaP.NO_REG, target) 1138 | end 1139 | end; 1140 | function luaK:patchtohere(fs, list) 1141 | self:getlabel(fs) 1142 | fs.jpc = self:concat(fs, fs.jpc, list) 1143 | end; 1144 | function luaK:concat(fs, l1, l2) 1145 | if l2 == self.NO_JUMP then 1146 | return l1 1147 | elseif l1 == self.NO_JUMP then 1148 | return l2 1149 | else 1150 | local list = l1; 1151 | local _next = self:getjump(fs, list) 1152 | while _next ~= self.NO_JUMP do 1153 | list = _next; 1154 | _next = self:getjump(fs, list) 1155 | end; 1156 | self:fixjump(fs, list, l2) 1157 | end; 1158 | return l1 1159 | end; 1160 | function luaK:checkstack(fs, n) 1161 | local newstack = fs.freereg + n; 1162 | if newstack > fs.f.maxstacksize then 1163 | if newstack >= self.MAXSTACK then 1164 | luaX:syntaxerror(fs.ls, "function or expression too complex") 1165 | end; 1166 | fs.f.maxstacksize = newstack 1167 | end 1168 | end; 1169 | function luaK:reserveregs(fs, n) 1170 | self:checkstack(fs, n) 1171 | fs.freereg = fs.freereg + n 1172 | end; 1173 | function luaK:freereg(fs, reg) 1174 | if not luaP:ISK(reg) and reg >= fs.nactvar then 1175 | fs.freereg = fs.freereg - 1; 1176 | lua_assert(reg == fs.freereg) 1177 | end 1178 | end; 1179 | function luaK:freeexp(fs, e) 1180 | if e.k == "VNONRELOC" then 1181 | self:freereg(fs, e.info) 1182 | end 1183 | end; 1184 | function luaK:addk(fs, k, v) 1185 | local L = fs.L; 1186 | local idx = fs.h[k.value] 1187 | local f = fs.f; 1188 | if self:ttisnumber(idx) then 1189 | return self:nvalue(idx) 1190 | else 1191 | idx = {} 1192 | self:setnvalue(idx, fs.nk) 1193 | fs.h[k.value] = idx; 1194 | luaY:growvector(L, f.k, fs.nk, f.sizek, nil, luaP.MAXARG_Bx, "constant table overflow") 1195 | f.k[fs.nk] = v; 1196 | local nk = fs.nk; 1197 | fs.nk = fs.nk + 1; 1198 | return nk 1199 | end 1200 | end; 1201 | function luaK:stringK(fs, s) 1202 | local o = {} 1203 | self:setsvalue(o, s) 1204 | return self:addk(fs, o, o) 1205 | end; 1206 | function luaK:numberK(fs, r) 1207 | local o = {} 1208 | self:setnvalue(o, r) 1209 | return self:addk(fs, o, o) 1210 | end; 1211 | function luaK:boolK(fs, b) 1212 | local o = {} 1213 | self:setbvalue(o, b) 1214 | return self:addk(fs, o, o) 1215 | end; 1216 | function luaK:nilK(fs) 1217 | local k, v = {}, {} 1218 | self:setnilvalue(v) 1219 | self:sethvalue(k, fs.h) 1220 | return self:addk(fs, k, v) 1221 | end; 1222 | function luaK:setreturns(fs, e, nresults) 1223 | if e.k == "VCALL" then 1224 | luaP:SETARG_C(self:getcode(fs, e), nresults + 1) 1225 | elseif e.k == "VVARARG" then 1226 | luaP:SETARG_B(self:getcode(fs, e), nresults + 1) 1227 | luaP:SETARG_A(self:getcode(fs, e), fs.freereg) 1228 | luaK:reserveregs(fs, 1) 1229 | end 1230 | end; 1231 | function luaK:setoneret(fs, e) 1232 | if e.k == "VCALL" then 1233 | e.k = "VNONRELOC" 1234 | e.info = luaP:GETARG_A(self:getcode(fs, e)) 1235 | elseif e.k == "VVARARG" then 1236 | luaP:SETARG_B(self:getcode(fs, e), 2) 1237 | e.k = "VRELOCABLE" 1238 | end 1239 | end; 1240 | function luaK:dischargevars(fs, e) 1241 | local k = e.k; 1242 | if k == "VLOCAL" then 1243 | e.k = "VNONRELOC" 1244 | elseif k == "VUPVAL" then 1245 | e.info = self:codeABC(fs, "OP_GETUPVAL", 0, e.info, 0) 1246 | e.k = "VRELOCABLE" 1247 | elseif k == "VGLOBAL" then 1248 | e.info = self:codeABx(fs, "OP_GETGLOBAL", 0, e.info) 1249 | e.k = "VRELOCABLE" 1250 | elseif k == "VINDEXED" then 1251 | self:freereg(fs, e.aux) 1252 | self:freereg(fs, e.info) 1253 | e.info = self:codeABC(fs, "OP_GETTABLE", 0, e.info, e.aux) 1254 | e.k = "VRELOCABLE" 1255 | elseif k == "VVARARG" or k == "VCALL" then 1256 | self:setoneret(fs, e) 1257 | else 1258 | end 1259 | end; 1260 | function luaK:code_label(fs, A, b, jump) 1261 | self:getlabel(fs) 1262 | return self:codeABC(fs, "OP_LOADBOOL", A, b, jump) 1263 | end; 1264 | function luaK:discharge2reg(fs, e, reg) 1265 | self:dischargevars(fs, e) 1266 | local k = e.k; 1267 | if k == "VNIL" then 1268 | self:_nil(fs, reg, 1) 1269 | elseif k == "VFALSE" or k == "VTRUE" then 1270 | self:codeABC(fs, "OP_LOADBOOL", reg, (e.k == "VTRUE") and 1 or 0, 0) 1271 | elseif k == "VK" then 1272 | self:codeABx(fs, "OP_LOADK", reg, e.info) 1273 | elseif k == "VKNUM" then 1274 | self:codeABx(fs, "OP_LOADK", reg, self:numberK(fs, e.nval)) 1275 | elseif k == "VRELOCABLE" then 1276 | local pc = self:getcode(fs, e) 1277 | luaP:SETARG_A(pc, reg) 1278 | elseif k == "VNONRELOC" then 1279 | if reg ~= e.info then 1280 | self:codeABC(fs, "OP_MOVE", reg, e.info, 0) 1281 | end 1282 | else 1283 | lua_assert(e.k == "VVOID" or e.k == "VJMP") 1284 | return 1285 | end; 1286 | e.info = reg; 1287 | e.k = "VNONRELOC" 1288 | end; 1289 | function luaK:discharge2anyreg(fs, e) 1290 | if e.k ~= "VNONRELOC" then 1291 | self:reserveregs(fs, 1) 1292 | self:discharge2reg(fs, e, fs.freereg - 1) 1293 | end 1294 | end; 1295 | function luaK:exp2reg(fs, e, reg) 1296 | self:discharge2reg(fs, e, reg) 1297 | if e.k == "VJMP" then 1298 | e.t = self:concat(fs, e.t, e.info) 1299 | end; 1300 | if self:hasjumps(e) then 1301 | local final; 1302 | local p_f = self.NO_JUMP; 1303 | local p_t = self.NO_JUMP; 1304 | if self:need_value(fs, e.t) or self:need_value(fs, e.f) then 1305 | local fj = (e.k == "VJMP") and self.NO_JUMP or self:jump(fs) 1306 | p_f = self:code_label(fs, reg, 0, 1) 1307 | p_t = self:code_label(fs, reg, 1, 0) 1308 | self:patchtohere(fs, fj) 1309 | end; 1310 | final = self:getlabel(fs) 1311 | self:patchlistaux(fs, e.f, final, reg, p_f) 1312 | self:patchlistaux(fs, e.t, final, reg, p_t) 1313 | end; 1314 | e.f, e.t = self.NO_JUMP, self.NO_JUMP; 1315 | e.info = reg; 1316 | e.k = "VNONRELOC" 1317 | end; 1318 | function luaK:exp2nextreg(fs, e) 1319 | self:dischargevars(fs, e) 1320 | self:freeexp(fs, e) 1321 | self:reserveregs(fs, 1) 1322 | self:exp2reg(fs, e, fs.freereg - 1) 1323 | end; 1324 | function luaK:exp2anyreg(fs, e) 1325 | self:dischargevars(fs, e) 1326 | if e.k == "VNONRELOC" then 1327 | if not self:hasjumps(e) then 1328 | return e.info 1329 | end; 1330 | if e.info >= fs.nactvar then 1331 | self:exp2reg(fs, e, e.info) 1332 | return e.info 1333 | end 1334 | end; 1335 | self:exp2nextreg(fs, e) 1336 | return e.info 1337 | end; 1338 | function luaK:exp2val(fs, e) 1339 | if self:hasjumps(e) then 1340 | self:exp2anyreg(fs, e) 1341 | else 1342 | self:dischargevars(fs, e) 1343 | end 1344 | end; 1345 | function luaK:exp2RK(fs, e) 1346 | self:exp2val(fs, e) 1347 | local k = e.k; 1348 | if k == "VKNUM" or k == "VTRUE" or k == "VFALSE" or k == "VNIL" then 1349 | if fs.nk <= luaP.MAXINDEXRK then 1350 | if e.k == "VNIL" then 1351 | e.info = self:nilK(fs) 1352 | else 1353 | e.info = (e.k == "VKNUM") and self:numberK(fs, e.nval) or self:boolK(fs, e.k == "VTRUE") 1354 | end; 1355 | e.k = "VK" 1356 | return luaP:RKASK(e.info) 1357 | end 1358 | elseif k == "VK" then 1359 | if e.info <= luaP.MAXINDEXRK then 1360 | return luaP:RKASK(e.info) 1361 | end 1362 | else 1363 | end; 1364 | return self:exp2anyreg(fs, e) 1365 | end; 1366 | function luaK:storevar(fs, var, ex) 1367 | local k = var.k; 1368 | if k == "VLOCAL" then 1369 | self:freeexp(fs, ex) 1370 | self:exp2reg(fs, ex, var.info) 1371 | return 1372 | elseif k == "VUPVAL" then 1373 | local e = self:exp2anyreg(fs, ex) 1374 | self:codeABC(fs, "OP_SETUPVAL", e, var.info, 0) 1375 | elseif k == "VGLOBAL" then 1376 | local e = self:exp2anyreg(fs, ex) 1377 | self:codeABx(fs, "OP_SETGLOBAL", e, var.info) 1378 | elseif k == "VINDEXED" then 1379 | local e = self:exp2RK(fs, ex) 1380 | self:codeABC(fs, "OP_SETTABLE", var.info, var.aux, e) 1381 | else 1382 | lua_assert(0) 1383 | end; 1384 | self:freeexp(fs, ex) 1385 | end; 1386 | function luaK:_self(fs, e, key) 1387 | self:exp2anyreg(fs, e) 1388 | self:freeexp(fs, e) 1389 | local func = fs.freereg; 1390 | self:reserveregs(fs, 2) 1391 | self:codeABC(fs, "OP_SELF", func, e.info, self:exp2RK(fs, key)) 1392 | self:freeexp(fs, key) 1393 | e.info = func; 1394 | e.k = "VNONRELOC" 1395 | end; 1396 | function luaK:invertjump(fs, e) 1397 | local pc = self:getjumpcontrol(fs, e.info) 1398 | lua_assert(luaP:testTMode(luaP:GET_OPCODE(pc)) ~= 0 and luaP:GET_OPCODE(pc) ~= "OP_TESTSET" and luaP:GET_OPCODE(pc) ~= "OP_TEST") 1399 | luaP:SETARG_A(pc, (luaP:GETARG_A(pc) == 0) and 1 or 0) 1400 | end; 1401 | function luaK:jumponcond(fs, e, cond) 1402 | if e.k == "VRELOCABLE" then 1403 | local ie = self:getcode(fs, e) 1404 | if luaP:GET_OPCODE(ie) == "OP_NOT" then 1405 | fs.pc = fs.pc - 1; 1406 | return self:condjump(fs, "OP_TEST", luaP:GETARG_B(ie), 0, cond and 0 or 1) 1407 | end 1408 | end; 1409 | self:discharge2anyreg(fs, e) 1410 | self:freeexp(fs, e) 1411 | return self:condjump(fs, "OP_TESTSET", luaP.NO_REG, e.info, cond and 1 or 0) 1412 | end; 1413 | function luaK:goiftrue(fs, e) 1414 | local pc; 1415 | self:dischargevars(fs, e) 1416 | local k = e.k; 1417 | if k == "VK" or k == "VKNUM" or k == "VTRUE" then 1418 | pc = self.NO_JUMP 1419 | elseif k == "VFALSE" then 1420 | pc = self:jump(fs) 1421 | elseif k == "VJMP" then 1422 | self:invertjump(fs, e) 1423 | pc = e.info 1424 | else 1425 | pc = self:jumponcond(fs, e, false) 1426 | end; 1427 | e.f = self:concat(fs, e.f, pc) 1428 | self:patchtohere(fs, e.t) 1429 | e.t = self.NO_JUMP 1430 | end; 1431 | function luaK:goiffalse(fs, e) 1432 | local pc; 1433 | self:dischargevars(fs, e) 1434 | local k = e.k; 1435 | if k == "VNIL" or k == "VFALSE" then 1436 | pc = self.NO_JUMP 1437 | elseif k == "VTRUE" then 1438 | pc = self:jump(fs) 1439 | elseif k == "VJMP" then 1440 | pc = e.info 1441 | else 1442 | pc = self:jumponcond(fs, e, true) 1443 | end; 1444 | e.t = self:concat(fs, e.t, pc) 1445 | self:patchtohere(fs, e.f) 1446 | e.f = self.NO_JUMP 1447 | end; 1448 | function luaK:codenot(fs, e) 1449 | self:dischargevars(fs, e) 1450 | local k = e.k; 1451 | if k == "VNIL" or k == "VFALSE" then 1452 | e.k = "VTRUE" 1453 | elseif k == "VK" or k == "VKNUM" or k == "VTRUE" then 1454 | e.k = "VFALSE" 1455 | elseif k == "VJMP" then 1456 | self:invertjump(fs, e) 1457 | elseif k == "VRELOCABLE" or k == "VNONRELOC" then 1458 | self:discharge2anyreg(fs, e) 1459 | self:freeexp(fs, e) 1460 | e.info = self:codeABC(fs, "OP_NOT", 0, e.info, 0) 1461 | e.k = "VRELOCABLE" 1462 | else 1463 | lua_assert(0) 1464 | end; 1465 | e.f, e.t = e.t, e.f; 1466 | self:removevalues(fs, e.f) 1467 | self:removevalues(fs, e.t) 1468 | end; 1469 | function luaK:indexed(fs, t, k) 1470 | t.aux = self:exp2RK(fs, k) 1471 | t.k = "VINDEXED" 1472 | end; 1473 | function luaK:constfolding(op, e1, e2) 1474 | local r; 1475 | if not self:isnumeral(e1) or not self:isnumeral(e2) then 1476 | return false 1477 | end; 1478 | local v1 = e1.nval; 1479 | local v2 = e2.nval; 1480 | if op == "OP_ADD" then 1481 | r = self:numadd(v1, v2) 1482 | elseif op == "OP_SUB" then 1483 | r = self:numsub(v1, v2) 1484 | elseif op == "OP_MUL" then 1485 | r = self:nummul(v1, v2) 1486 | elseif op == "OP_DIV" then 1487 | if v2 == 0 then 1488 | return false 1489 | end; 1490 | r = self:numdiv(v1, v2) 1491 | elseif op == "OP_MOD" then 1492 | if v2 == 0 then 1493 | return false 1494 | end; 1495 | r = self:nummod(v1, v2) 1496 | elseif op == "OP_POW" then 1497 | r = self:numpow(v1, v2) 1498 | elseif op == "OP_UNM" then 1499 | r = self:numunm(v1) 1500 | elseif op == "OP_LEN" then 1501 | return false 1502 | else 1503 | lua_assert(0) 1504 | r = 0 1505 | end; 1506 | if self:numisnan(r) then 1507 | return false 1508 | end; 1509 | e1.nval = r; 1510 | return true 1511 | end; 1512 | function luaK:codearith(fs, op, e1, e2) 1513 | if self:constfolding(op, e1, e2) then 1514 | return 1515 | else 1516 | local o2 = (op ~= "OP_UNM" and op ~= "OP_LEN") and self:exp2RK(fs, e2) or 0; 1517 | local o1 = self:exp2RK(fs, e1) 1518 | if o1 > o2 then 1519 | self:freeexp(fs, e1) 1520 | self:freeexp(fs, e2) 1521 | else 1522 | self:freeexp(fs, e2) 1523 | self:freeexp(fs, e1) 1524 | end; 1525 | e1.info = self:codeABC(fs, op, 0, o1, o2) 1526 | e1.k = "VRELOCABLE" 1527 | end 1528 | end; 1529 | function luaK:codecomp(fs, op, cond, e1, e2) 1530 | local o1 = self:exp2RK(fs, e1) 1531 | local o2 = self:exp2RK(fs, e2) 1532 | self:freeexp(fs, e2) 1533 | self:freeexp(fs, e1) 1534 | if cond == 0 and op ~= "OP_EQ" then 1535 | o1, o2 = o2, o1; 1536 | cond = 1 1537 | end; 1538 | e1.info = self:condjump(fs, op, cond, o1, o2) 1539 | e1.k = "VJMP" 1540 | end; 1541 | function luaK:prefix(fs, op, e) 1542 | local e2 = {} 1543 | e2.t, e2.f = self.NO_JUMP, self.NO_JUMP; 1544 | e2.k = "VKNUM" 1545 | e2.nval = 0; 1546 | if op == "OPR_MINUS" then 1547 | if not self:isnumeral(e) then 1548 | self:exp2anyreg(fs, e) 1549 | end; 1550 | self:codearith(fs, "OP_UNM", e, e2) 1551 | elseif op == "OPR_NOT" then 1552 | self:codenot(fs, e) 1553 | elseif op == "OPR_LEN" then 1554 | self:exp2anyreg(fs, e) 1555 | self:codearith(fs, "OP_LEN", e, e2) 1556 | else 1557 | lua_assert(0) 1558 | end 1559 | end; 1560 | function luaK:infix(fs, op, v) 1561 | if op == "OPR_AND" then 1562 | self:goiftrue(fs, v) 1563 | elseif op == "OPR_OR" then 1564 | self:goiffalse(fs, v) 1565 | elseif op == "OPR_CONCAT" then 1566 | self:exp2nextreg(fs, v) 1567 | elseif op == "OPR_ADD" or op == "OPR_SUB" or op == "OPR_MUL" or op == "OPR_DIV" or op == "OPR_MOD" or op == "OPR_POW" then 1568 | if not self:isnumeral(v) then 1569 | self:exp2RK(fs, v) 1570 | end 1571 | else 1572 | self:exp2RK(fs, v) 1573 | end 1574 | end; 1575 | luaK.arith_op = { 1576 | OPR_ADD = "OP_ADD", 1577 | OPR_SUB = "OP_SUB", 1578 | OPR_MUL = "OP_MUL", 1579 | OPR_DIV = "OP_DIV", 1580 | OPR_MOD = "OP_MOD", 1581 | OPR_POW = "OP_POW" 1582 | } 1583 | luaK.comp_op = { 1584 | OPR_EQ = "OP_EQ", 1585 | OPR_NE = "OP_EQ", 1586 | OPR_LT = "OP_LT", 1587 | OPR_LE = "OP_LE", 1588 | OPR_GT = "OP_LT", 1589 | OPR_GE = "OP_LE" 1590 | } 1591 | luaK.comp_cond = { 1592 | OPR_EQ = 1, 1593 | OPR_NE = 0, 1594 | OPR_LT = 1, 1595 | OPR_LE = 1, 1596 | OPR_GT = 0, 1597 | OPR_GE = 0 1598 | } 1599 | function luaK:posfix(fs, op, e1, e2) 1600 | local function copyexp(e1, e2) 1601 | e1.k = e2.k; 1602 | e1.info = e2.info; 1603 | e1.aux = e2.aux; 1604 | e1.nval = e2.nval; 1605 | e1.t = e2.t; 1606 | e1.f = e2.f 1607 | end; 1608 | if op == "OPR_AND" then 1609 | lua_assert(e1.t == self.NO_JUMP) 1610 | self:dischargevars(fs, e2) 1611 | e2.f = self:concat(fs, e2.f, e1.f) 1612 | copyexp(e1, e2) 1613 | elseif op == "OPR_OR" then 1614 | lua_assert(e1.f == self.NO_JUMP) 1615 | self:dischargevars(fs, e2) 1616 | e2.t = self:concat(fs, e2.t, e1.t) 1617 | copyexp(e1, e2) 1618 | elseif op == "OPR_CONCAT" then 1619 | self:exp2val(fs, e2) 1620 | if e2.k == "VRELOCABLE" and luaP:GET_OPCODE(self:getcode(fs, e2)) == "OP_CONCAT" then 1621 | lua_assert(e1.info == luaP:GETARG_B(self:getcode(fs, e2)) - 1) 1622 | self:freeexp(fs, e1) 1623 | luaP:SETARG_B(self:getcode(fs, e2), e1.info) 1624 | e1.k = "VRELOCABLE" 1625 | e1.info = e2.info 1626 | else 1627 | self:exp2nextreg(fs, e2) 1628 | self:codearith(fs, "OP_CONCAT", e1, e2) 1629 | end 1630 | else 1631 | local arith = self.arith_op[op] 1632 | if arith then 1633 | self:codearith(fs, arith, e1, e2) 1634 | else 1635 | local comp = self.comp_op[op] 1636 | if comp then 1637 | self:codecomp(fs, comp, self.comp_cond[op], e1, e2) 1638 | else 1639 | lua_assert(0) 1640 | end 1641 | end 1642 | end 1643 | end; 1644 | function luaK:fixline(fs, line) 1645 | fs.f.lineinfo[fs.pc - 1] = line 1646 | end; 1647 | function luaK:code(fs, i, line) 1648 | local f = fs.f; 1649 | self:dischargejpc(fs) 1650 | luaY:growvector(fs.L, f.code, fs.pc, f.sizecode, nil, luaY.MAX_INT, "code size overflow") 1651 | f.code[fs.pc] = i; 1652 | luaY:growvector(fs.L, f.lineinfo, fs.pc, f.sizelineinfo, nil, luaY.MAX_INT, "code size overflow") 1653 | f.lineinfo[fs.pc] = line; 1654 | local pc = fs.pc; 1655 | fs.pc = fs.pc + 1; 1656 | return pc 1657 | end; 1658 | function luaK:codeABC(fs, o, a, b, c) 1659 | lua_assert(luaP:getOpMode(o) == luaP.OpMode.iABC) 1660 | lua_assert(luaP:getBMode(o) ~= luaP.OpArgMask.OpArgN or b == 0) 1661 | lua_assert(luaP:getCMode(o) ~= luaP.OpArgMask.OpArgN or c == 0) 1662 | return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.ls.lastline) 1663 | end; 1664 | function luaK:codeABx(fs, o, a, bc) 1665 | lua_assert(luaP:getOpMode(o) == luaP.OpMode.iABx or luaP:getOpMode(o) == luaP.OpMode.iAsBx) 1666 | lua_assert(luaP:getCMode(o) == luaP.OpArgMask.OpArgN) 1667 | return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.ls.lastline) 1668 | end; 1669 | function luaK:setlist(fs, base, nelems, tostore) 1670 | local c = math.floor((nelems - 1) / luaP.LFIELDS_PER_FLUSH) + 1; 1671 | local b = (tostore == luaY.LUA_MULTRET) and 0 or tostore; 1672 | lua_assert(tostore ~= 0) 1673 | if c <= luaP.MAXARG_C then 1674 | self:codeABC(fs, "OP_SETLIST", base, b, c) 1675 | else 1676 | self:codeABC(fs, "OP_SETLIST", base, b, 0) 1677 | self:code(fs, luaP:CREATE_Inst(c), fs.ls.lastline) 1678 | end; 1679 | fs.freereg = base + 1 1680 | end; 1681 | luaY.LUA_QS = luaX.LUA_QS or "'%s'" 1682 | luaY.SHRT_MAX = 32767; 1683 | luaY.LUAI_MAXVARS = 200; 1684 | luaY.LUAI_MAXUPVALUES = 60; 1685 | luaY.MAX_INT = luaX.MAX_INT or 2147483645; 1686 | luaY.LUAI_MAXCCALLS = 200; 1687 | luaY.VARARG_HASARG = 1; 1688 | luaY.HASARG_MASK = 2; 1689 | luaY.VARARG_ISVARARG = 2; 1690 | luaY.VARARG_NEEDSARG = 4; 1691 | luaY.LUA_MULTRET = - 1; 1692 | function luaY:LUA_QL(x) 1693 | return "'" .. x .. "'" 1694 | end; 1695 | function luaY:growvector(L, v, nelems, size, t, limit, e) 1696 | if nelems >= limit then 1697 | error(e) 1698 | end 1699 | end; 1700 | function luaY:newproto(L) 1701 | local f = {} 1702 | f.k = {} 1703 | f.sizek = 0; 1704 | f.p = {} 1705 | f.sizep = 0; 1706 | f.code = {} 1707 | f.sizecode = 0; 1708 | f.sizelineinfo = 0; 1709 | f.sizeupvalues = 0; 1710 | f.nups = 0; 1711 | f.upvalues = {} 1712 | f.numparams = 0; 1713 | f.is_vararg = 0; 1714 | f.maxstacksize = 0; 1715 | f.lineinfo = {} 1716 | f.sizelocvars = 0; 1717 | f.locvars = {} 1718 | f.lineDefined = 0; 1719 | f.lastlinedefined = 0; 1720 | f.source = nil; 1721 | return f 1722 | end; 1723 | function luaY:int2fb(x) 1724 | local e = 0; 1725 | while x >= 16 do 1726 | x = math.floor((x + 1) / 2) 1727 | e = e + 1 1728 | end; 1729 | if x < 8 then 1730 | return x 1731 | else 1732 | return ((e + 1) * 8) + (x - 8) 1733 | end 1734 | end; 1735 | function luaY:hasmultret(k) 1736 | return k == "VCALL" or k == "VVARARG" 1737 | end; 1738 | function luaY:getlocvar(fs, i) 1739 | return fs.f.locvars[fs.actvar[i]] 1740 | end; 1741 | function luaY:checklimit(fs, v, l, m) 1742 | if v > l then 1743 | self:errorlimit(fs, l, m) 1744 | end 1745 | end; 1746 | function luaY:anchor_token(ls) 1747 | if ls.t.token == "TK_NAME" or ls.t.token == "TK_STRING" then 1748 | end 1749 | end; 1750 | function luaY:error_expected(ls, token) 1751 | luaX:syntaxerror(ls, string.format(self.LUA_QS .. " expected", luaX:token2str(ls, token))) 1752 | end; 1753 | function luaY:errorlimit(fs, limit, what) 1754 | local msg = (fs.f.linedefined == 0) and string.format("main function has more than %d %s", limit, what) or string.format("function at line %d has more than %d %s", fs.f.linedefined, limit, what) 1755 | luaX:lexerror(fs.ls, msg, 0) 1756 | end; 1757 | function luaY:testnext(ls, c) 1758 | if ls.t.token == c then 1759 | luaX:next(ls) 1760 | return true 1761 | else 1762 | return false 1763 | end 1764 | end; 1765 | function luaY:check(ls, c) 1766 | if ls.t.token ~= c then 1767 | self:error_expected(ls, c) 1768 | end 1769 | end; 1770 | function luaY:checknext(ls, c) 1771 | self:check(ls, c) 1772 | luaX:next(ls) 1773 | end; 1774 | function luaY:check_condition(ls, c, msg) 1775 | if not c then 1776 | luaX:syntaxerror(ls, msg) 1777 | end 1778 | end; 1779 | function luaY:check_match(ls, what, who, where) 1780 | if not self:testnext(ls, what) then 1781 | if where == ls.linenumber then 1782 | self:error_expected(ls, what) 1783 | else 1784 | luaX:syntaxerror(ls, string.format(self.LUA_QS .. " expected (to close " .. self.LUA_QS .. " at line %d)", luaX:token2str(ls, what), luaX:token2str(ls, who), where)) 1785 | end 1786 | end 1787 | end; 1788 | function luaY:str_checkname(ls) 1789 | self:check(ls, "TK_NAME") 1790 | local ts = ls.t.seminfo; 1791 | luaX:next(ls) 1792 | return ts 1793 | end; 1794 | function luaY:init_exp(e, k, i) 1795 | e.f, e.t = luaK.NO_JUMP, luaK.NO_JUMP; 1796 | e.k = k; 1797 | e.info = i 1798 | end; 1799 | function luaY:codestring(ls, e, s) 1800 | self:init_exp(e, "VK", luaK:stringK(ls.fs, s)) 1801 | end; 1802 | function luaY:checkname(ls, e) 1803 | self:codestring(ls, e, self:str_checkname(ls)) 1804 | end; 1805 | function luaY:registerlocalvar(ls, varname) 1806 | local fs = ls.fs; 1807 | local f = fs.f; 1808 | self:growvector(ls.L, f.locvars, fs.nlocvars, f.sizelocvars, nil, self.SHRT_MAX, "too many local variables") 1809 | f.locvars[fs.nlocvars] = {} 1810 | f.locvars[fs.nlocvars].varname = varname; 1811 | local nlocvars = fs.nlocvars; 1812 | fs.nlocvars = fs.nlocvars + 1; 1813 | return nlocvars 1814 | end; 1815 | function luaY:new_localvarliteral(ls, v, n) 1816 | self:new_localvar(ls, v, n) 1817 | end; 1818 | function luaY:new_localvar(ls, name, n) 1819 | local fs = ls.fs; 1820 | self:checklimit(fs, fs.nactvar + n + 1, self.LUAI_MAXVARS, "local variables") 1821 | fs.actvar[fs.nactvar + n] = self:registerlocalvar(ls, name) 1822 | end; 1823 | function luaY:adjustlocalvars(ls, nvars) 1824 | local fs = ls.fs; 1825 | fs.nactvar = fs.nactvar + nvars; 1826 | for i = nvars, 1, - 1 do 1827 | self:getlocvar(fs, fs.nactvar - i).startpc = fs.pc 1828 | end 1829 | end; 1830 | function luaY:removevars(ls, tolevel) 1831 | local fs = ls.fs; 1832 | while fs.nactvar > tolevel do 1833 | fs.nactvar = fs.nactvar - 1; 1834 | self:getlocvar(fs, fs.nactvar).endpc = fs.pc 1835 | end 1836 | end; 1837 | function luaY:indexupvalue(fs, name, v) 1838 | local f = fs.f; 1839 | for i = 0, f.nups - 1 do 1840 | if fs.upvalues[i].k == v.k and fs.upvalues[i].info == v.info then 1841 | lua_assert(f.upvalues[i] == name) 1842 | return i 1843 | end 1844 | end; 1845 | self:checklimit(fs, f.nups + 1, self.LUAI_MAXUPVALUES, "upvalues") 1846 | self:growvector(fs.L, f.upvalues, f.nups, f.sizeupvalues, nil, self.MAX_INT, "") 1847 | f.upvalues[f.nups] = name; 1848 | lua_assert(v.k == "VLOCAL" or v.k == "VUPVAL") 1849 | fs.upvalues[f.nups] = { 1850 | k = v.k, 1851 | info = v.info 1852 | } 1853 | local nups = f.nups; 1854 | f.nups = f.nups + 1; 1855 | return nups 1856 | end; 1857 | function luaY:searchvar(fs, n) 1858 | for i = fs.nactvar - 1, 0, - 1 do 1859 | if n == self:getlocvar(fs, i).varname then 1860 | return i 1861 | end 1862 | end; 1863 | return - 1 1864 | end; 1865 | function luaY:markupval(fs, level) 1866 | local bl = fs.bl; 1867 | while bl and bl.nactvar > level do 1868 | bl = bl.previous 1869 | end; 1870 | if bl then 1871 | bl.upval = true 1872 | end 1873 | end; 1874 | function luaY:singlevaraux(fs, n, var, base) 1875 | if fs == nil then 1876 | self:init_exp(var, "VGLOBAL", luaP.NO_REG) 1877 | return "VGLOBAL" 1878 | else 1879 | local v = self:searchvar(fs, n) 1880 | if v >= 0 then 1881 | self:init_exp(var, "VLOCAL", v) 1882 | if base == 0 then 1883 | self:markupval(fs, v) 1884 | end; 1885 | return "VLOCAL" 1886 | else 1887 | if self:singlevaraux(fs.prev, n, var, 0) == "VGLOBAL" then 1888 | return "VGLOBAL" 1889 | end; 1890 | var.info = self:indexupvalue(fs, n, var) 1891 | var.k = "VUPVAL" 1892 | return "VUPVAL" 1893 | end 1894 | end 1895 | end; 1896 | function luaY:singlevar(ls, var) 1897 | local varname = self:str_checkname(ls) 1898 | local fs = ls.fs; 1899 | if self:singlevaraux(fs, varname, var, 1) == "VGLOBAL" then 1900 | var.info = luaK:stringK(fs, varname) 1901 | end 1902 | end; 1903 | function luaY:adjust_assign(ls, nvars, nexps, e) 1904 | local fs = ls.fs; 1905 | local extra = nvars - nexps; 1906 | if self:hasmultret(e.k) then 1907 | extra = extra + 1; 1908 | if extra <= 0 then 1909 | extra = 0 1910 | end; 1911 | luaK:setreturns(fs, e, extra) 1912 | if extra > 1 then 1913 | luaK:reserveregs(fs, extra - 1) 1914 | end 1915 | else 1916 | if e.k ~= "VVOID" then 1917 | luaK:exp2nextreg(fs, e) 1918 | end; 1919 | if extra > 0 then 1920 | local reg = fs.freereg; 1921 | luaK:reserveregs(fs, extra) 1922 | luaK:_nil(fs, reg, extra) 1923 | end 1924 | end 1925 | end; 1926 | function luaY:enterlevel(ls) 1927 | ls.L.nCcalls = ls.L.nCcalls + 1; 1928 | if ls.L.nCcalls > self.LUAI_MAXCCALLS then 1929 | luaX:lexerror(ls, "chunk has too many syntax levels", 0) 1930 | end 1931 | end; 1932 | function luaY:leavelevel(ls) 1933 | ls.L.nCcalls = ls.L.nCcalls - 1 1934 | end; 1935 | function luaY:enterblock(fs, bl, isbreakable) 1936 | bl.breaklist = luaK.NO_JUMP; 1937 | bl.isbreakable = isbreakable; 1938 | bl.nactvar = fs.nactvar; 1939 | bl.upval = false; 1940 | bl.previous = fs.bl; 1941 | fs.bl = bl; 1942 | lua_assert(fs.freereg == fs.nactvar) 1943 | end; 1944 | function luaY:leaveblock(fs) 1945 | local bl = fs.bl; 1946 | fs.bl = bl.previous; 1947 | self:removevars(fs.ls, bl.nactvar) 1948 | if bl.upval then 1949 | luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0) 1950 | end; 1951 | lua_assert(not bl.isbreakable or not bl.upval) 1952 | lua_assert(bl.nactvar == fs.nactvar) 1953 | fs.freereg = fs.nactvar; 1954 | luaK:patchtohere(fs, bl.breaklist) 1955 | end; 1956 | function luaY:pushclosure(ls, func, v) 1957 | local fs = ls.fs; 1958 | local f = fs.f; 1959 | self:growvector(ls.L, f.p, fs.np, f.sizep, nil, luaP.MAXARG_Bx, "constant table overflow") 1960 | f.p[fs.np] = func.f; 1961 | fs.np = fs.np + 1; 1962 | self:init_exp(v, "VRELOCABLE", luaK:codeABx(fs, "OP_CLOSURE", 0, fs.np - 1)) 1963 | for i = 0, func.f.nups - 1 do 1964 | local o = (func.upvalues[i].k == "VLOCAL") and "OP_MOVE" or "OP_GETUPVAL" 1965 | luaK:codeABC(fs, o, 0, func.upvalues[i].info, 0) 1966 | end 1967 | end; 1968 | function luaY:open_func(ls, fs) 1969 | local L = ls.L; 1970 | local f = self:newproto(ls.L) 1971 | fs.f = f; 1972 | fs.prev = ls.fs; 1973 | fs.ls = ls; 1974 | fs.L = L; 1975 | ls.fs = fs; 1976 | fs.pc = 0; 1977 | fs.lasttarget = - 1; 1978 | fs.jpc = luaK.NO_JUMP; 1979 | fs.freereg = 0; 1980 | fs.nk = 0; 1981 | fs.np = 0; 1982 | fs.nlocvars = 0; 1983 | fs.nactvar = 0; 1984 | fs.bl = nil; 1985 | f.source = ls.source; 1986 | f.maxstacksize = 2; 1987 | fs.h = {} 1988 | end; 1989 | function luaY:close_func(ls) 1990 | local L = ls.L; 1991 | local fs = ls.fs; 1992 | local f = fs.f; 1993 | self:removevars(ls, 0) 1994 | luaK:ret(fs, 0, 0) 1995 | f.sizecode = fs.pc; 1996 | f.sizelineinfo = fs.pc; 1997 | f.sizek = fs.nk; 1998 | f.sizep = fs.np; 1999 | f.sizelocvars = fs.nlocvars; 2000 | f.sizeupvalues = f.nups; 2001 | lua_assert(fs.bl == nil) 2002 | ls.fs = fs.prev; 2003 | if fs then 2004 | self:anchor_token(ls) 2005 | end 2006 | end; 2007 | function luaY:parser(L, z, buff, name) 2008 | local lexstate = {} 2009 | lexstate.t = {} 2010 | lexstate.lookahead = {} 2011 | local funcstate = {} 2012 | funcstate.upvalues = {} 2013 | funcstate.actvar = {} 2014 | L.nCcalls = 0; 2015 | lexstate.buff = buff; 2016 | luaX:setinput(L, lexstate, z, name) 2017 | self:open_func(lexstate, funcstate) 2018 | funcstate.f.is_vararg = self.VARARG_ISVARARG; 2019 | luaX:next(lexstate) 2020 | self:chunk(lexstate) 2021 | self:check(lexstate, "TK_EOS") 2022 | self:close_func(lexstate) 2023 | lua_assert(funcstate.prev == nil) 2024 | lua_assert(funcstate.f.nups == 0) 2025 | lua_assert(lexstate.fs == nil) 2026 | return funcstate.f 2027 | end; 2028 | function luaY:field(ls, v) 2029 | local fs = ls.fs; 2030 | local key = {} 2031 | luaK:exp2anyreg(fs, v) 2032 | luaX:next(ls) 2033 | self:checkname(ls, key) 2034 | luaK:indexed(fs, v, key) 2035 | end; 2036 | function luaY:yindex(ls, v) 2037 | luaX:next(ls) 2038 | self:expr(ls, v) 2039 | luaK:exp2val(ls.fs, v) 2040 | self:checknext(ls, "]") 2041 | end; 2042 | function luaY:recfield(ls, cc) 2043 | local fs = ls.fs; 2044 | local reg = ls.fs.freereg; 2045 | local key, val = {}, {} 2046 | if ls.t.token == "TK_NAME" then 2047 | self:checklimit(fs, cc.nh, self.MAX_INT, "items in a constructor") 2048 | self:checkname(ls, key) 2049 | else 2050 | self:yindex(ls, key) 2051 | end; 2052 | cc.nh = cc.nh + 1; 2053 | self:checknext(ls, "=") 2054 | local rkkey = luaK:exp2RK(fs, key) 2055 | self:expr(ls, val) 2056 | luaK:codeABC(fs, "OP_SETTABLE", cc.t.info, rkkey, luaK:exp2RK(fs, val)) 2057 | fs.freereg = reg 2058 | end; 2059 | function luaY:closelistfield(fs, cc) 2060 | if cc.v.k == "VVOID" then 2061 | return 2062 | end; 2063 | luaK:exp2nextreg(fs, cc.v) 2064 | cc.v.k = "VVOID" 2065 | if cc.tostore == luaP.LFIELDS_PER_FLUSH then 2066 | luaK:setlist(fs, cc.t.info, cc.na, cc.tostore) 2067 | cc.tostore = 0 2068 | end 2069 | end; 2070 | function luaY:lastlistfield(fs, cc) 2071 | if cc.tostore == 0 then 2072 | return 2073 | end; 2074 | if self:hasmultret(cc.v.k) then 2075 | luaK:setmultret(fs, cc.v) 2076 | luaK:setlist(fs, cc.t.info, cc.na, self.LUA_MULTRET) 2077 | cc.na = cc.na - 1 2078 | else 2079 | if cc.v.k ~= "VVOID" then 2080 | luaK:exp2nextreg(fs, cc.v) 2081 | end; 2082 | luaK:setlist(fs, cc.t.info, cc.na, cc.tostore) 2083 | end 2084 | end; 2085 | function luaY:listfield(ls, cc) 2086 | self:expr(ls, cc.v) 2087 | self:checklimit(ls.fs, cc.na, self.MAX_INT, "items in a constructor") 2088 | cc.na = cc.na + 1; 2089 | cc.tostore = cc.tostore + 1 2090 | end; 2091 | function luaY:constructor(ls, t) 2092 | local fs = ls.fs; 2093 | local line = ls.linenumber; 2094 | local pc = luaK:codeABC(fs, "OP_NEWTABLE", 0, 0, 0) 2095 | local cc = {} 2096 | cc.v = {} 2097 | cc.na, cc.nh, cc.tostore = 0, 0, 0; 2098 | cc.t = t; 2099 | self:init_exp(t, "VRELOCABLE", pc) 2100 | self:init_exp(cc.v, "VVOID", 0) 2101 | luaK:exp2nextreg(ls.fs, t) 2102 | self:checknext(ls, "{") 2103 | repeat 2104 | lua_assert(cc.v.k == "VVOID" or cc.tostore > 0) 2105 | if ls.t.token == "}" then 2106 | break 2107 | end; 2108 | self:closelistfield(fs, cc) 2109 | local c = ls.t.token; 2110 | if c == "TK_NAME" then 2111 | luaX:lookahead(ls) 2112 | if ls.lookahead.token ~= "=" then 2113 | self:listfield(ls, cc) 2114 | else 2115 | self:recfield(ls, cc) 2116 | end 2117 | elseif c == "[" then 2118 | self:recfield(ls, cc) 2119 | else 2120 | self:listfield(ls, cc) 2121 | end 2122 | until not self:testnext(ls, ",") and not self:testnext(ls, ";") 2123 | self:check_match(ls, "}", "{", line) 2124 | self:lastlistfield(fs, cc) 2125 | luaP:SETARG_B(fs.f.code[pc], self:int2fb(cc.na)) 2126 | luaP:SETARG_C(fs.f.code[pc], self:int2fb(cc.nh)) 2127 | end; 2128 | function luaY:parlist(ls) 2129 | local fs = ls.fs; 2130 | local f = fs.f; 2131 | local nparams = 0; 2132 | f.is_vararg = 0; 2133 | if ls.t.token ~= ")" then 2134 | repeat 2135 | local c = ls.t.token; 2136 | if c == "TK_NAME" then 2137 | self:new_localvar(ls, self:str_checkname(ls), nparams) 2138 | nparams = nparams + 1 2139 | elseif c == "TK_DOTS" then 2140 | luaX:next(ls) 2141 | self:new_localvarliteral(ls, "arg", nparams) 2142 | nparams = nparams + 1; 2143 | f.is_vararg = self.VARARG_HASARG + self.VARARG_NEEDSARG; 2144 | f.is_vararg = f.is_vararg + self.VARARG_ISVARARG 2145 | else 2146 | luaX:syntaxerror(ls, " or " .. self:LUA_QL("...") .. " expected") 2147 | end 2148 | until f.is_vararg ~= 0 or not self:testnext(ls, ",") 2149 | end; 2150 | self:adjustlocalvars(ls, nparams) 2151 | f.numparams = fs.nactvar - (f.is_vararg % self.HASARG_MASK) 2152 | luaK:reserveregs(fs, fs.nactvar) 2153 | end; 2154 | function luaY:body(ls, e, needself, line) 2155 | local new_fs = {} 2156 | new_fs.upvalues = {} 2157 | new_fs.actvar = {} 2158 | self:open_func(ls, new_fs) 2159 | new_fs.f.lineDefined = line; 2160 | self:checknext(ls, "(") 2161 | if needself then 2162 | self:new_localvarliteral(ls, "self", 0) 2163 | self:adjustlocalvars(ls, 1) 2164 | end; 2165 | self:parlist(ls) 2166 | self:checknext(ls, ")") 2167 | self:chunk(ls) 2168 | new_fs.f.lastlinedefined = ls.linenumber; 2169 | self:check_match(ls, "TK_END", "TK_FUNCTION", line) 2170 | self:close_func(ls) 2171 | self:pushclosure(ls, new_fs, e) 2172 | end; 2173 | function luaY:explist1(ls, v) 2174 | local n = 1; 2175 | self:expr(ls, v) 2176 | while self:testnext(ls, ",") do 2177 | luaK:exp2nextreg(ls.fs, v) 2178 | self:expr(ls, v) 2179 | n = n + 1 2180 | end; 2181 | return n 2182 | end; 2183 | function luaY:funcargs(ls, f) 2184 | local fs = ls.fs; 2185 | local args = {} 2186 | local nparams; 2187 | local line = ls.linenumber; 2188 | local c = ls.t.token; 2189 | if c == "(" then 2190 | if line ~= ls.lastline then 2191 | luaX:syntaxerror(ls, "ambiguous syntax (function call x new statement)") 2192 | end; 2193 | luaX:next(ls) 2194 | if ls.t.token == ")" then 2195 | args.k = "VVOID" 2196 | else 2197 | self:explist1(ls, args) 2198 | luaK:setmultret(fs, args) 2199 | end; 2200 | self:check_match(ls, ")", "(", line) 2201 | elseif c == "{" then 2202 | self:constructor(ls, args) 2203 | elseif c == "TK_STRING" then 2204 | self:codestring(ls, args, ls.t.seminfo) 2205 | luaX:next(ls) 2206 | else 2207 | luaX:syntaxerror(ls, "function arguments expected") 2208 | return 2209 | end; 2210 | lua_assert(f.k == "VNONRELOC") 2211 | local base = f.info; 2212 | if self:hasmultret(args.k) then 2213 | nparams = self.LUA_MULTRET 2214 | else 2215 | if args.k ~= "VVOID" then 2216 | luaK:exp2nextreg(fs, args) 2217 | end; 2218 | nparams = fs.freereg - (base + 1) 2219 | end; 2220 | self:init_exp(f, "VCALL", luaK:codeABC(fs, "OP_CALL", base, nparams + 1, 2)) 2221 | luaK:fixline(fs, line) 2222 | fs.freereg = base + 1 2223 | end; 2224 | function luaY:prefixexp(ls, v) 2225 | local c = ls.t.token; 2226 | if c == "(" then 2227 | local line = ls.linenumber; 2228 | luaX:next(ls) 2229 | self:expr(ls, v) 2230 | self:check_match(ls, ")", "(", line) 2231 | luaK:dischargevars(ls.fs, v) 2232 | elseif c == "TK_NAME" then 2233 | self:singlevar(ls, v) 2234 | else 2235 | luaX:syntaxerror(ls, "unexpected symbol") 2236 | end; 2237 | return 2238 | end; 2239 | function luaY:primaryexp(ls, v) 2240 | local fs = ls.fs; 2241 | self:prefixexp(ls, v) 2242 | while true do 2243 | local c = ls.t.token; 2244 | if c == "." then 2245 | self:field(ls, v) 2246 | elseif c == "[" then 2247 | local key = {} 2248 | luaK:exp2anyreg(fs, v) 2249 | self:yindex(ls, key) 2250 | luaK:indexed(fs, v, key) 2251 | elseif c == ":" then 2252 | local key = {} 2253 | luaX:next(ls) 2254 | self:checkname(ls, key) 2255 | luaK:_self(fs, v, key) 2256 | self:funcargs(ls, v) 2257 | elseif c == "(" or c == "TK_STRING" or c == "{" then 2258 | luaK:exp2nextreg(fs, v) 2259 | self:funcargs(ls, v) 2260 | else 2261 | return 2262 | end 2263 | end 2264 | end; 2265 | function luaY:simpleexp(ls, v) 2266 | local c = ls.t.token; 2267 | if c == "TK_NUMBER" then 2268 | self:init_exp(v, "VKNUM", 0) 2269 | v.nval = ls.t.seminfo 2270 | elseif c == "TK_STRING" then 2271 | self:codestring(ls, v, ls.t.seminfo) 2272 | elseif c == "TK_NIL" then 2273 | self:init_exp(v, "VNIL", 0) 2274 | elseif c == "TK_TRUE" then 2275 | self:init_exp(v, "VTRUE", 0) 2276 | elseif c == "TK_FALSE" then 2277 | self:init_exp(v, "VFALSE", 0) 2278 | elseif c == "TK_DOTS" then 2279 | local fs = ls.fs; 2280 | self:check_condition(ls, fs.f.is_vararg ~= 0, "cannot use " .. self:LUA_QL("...") .. " outside a vararg function") 2281 | local is_vararg = fs.f.is_vararg; 2282 | if is_vararg >= self.VARARG_NEEDSARG then 2283 | fs.f.is_vararg = is_vararg - self.VARARG_NEEDSARG 2284 | end; 2285 | self:init_exp(v, "VVARARG", luaK:codeABC(fs, "OP_VARARG", 0, 1, 0)) 2286 | elseif c == "{" then 2287 | self:constructor(ls, v) 2288 | return 2289 | elseif c == "TK_FUNCTION" then 2290 | luaX:next(ls) 2291 | self:body(ls, v, false, ls.linenumber) 2292 | return 2293 | else 2294 | self:primaryexp(ls, v) 2295 | return 2296 | end; 2297 | luaX:next(ls) 2298 | end; 2299 | function luaY:getunopr(op) 2300 | if op == "TK_NOT" then 2301 | return "OPR_NOT" 2302 | elseif op == "-" then 2303 | return "OPR_MINUS" 2304 | elseif op == "#" then 2305 | return "OPR_LEN" 2306 | else 2307 | return "OPR_NOUNOPR" 2308 | end 2309 | end; 2310 | luaY.getbinopr_table = { 2311 | ["+"] = "OPR_ADD", 2312 | ["-"] = "OPR_SUB", 2313 | ["*"] = "OPR_MUL", 2314 | ["/"] = "OPR_DIV", 2315 | ["%"] = "OPR_MOD", 2316 | ["^"] = "OPR_POW", 2317 | ["TK_CONCAT"] = "OPR_CONCAT", 2318 | ["TK_NE"] = "OPR_NE", 2319 | ["TK_EQ"] = "OPR_EQ", 2320 | ["<"] = "OPR_LT", 2321 | ["TK_LE"] = "OPR_LE", 2322 | [">"] = "OPR_GT", 2323 | ["TK_GE"] = "OPR_GE", 2324 | ["TK_AND"] = "OPR_AND", 2325 | ["TK_OR"] = "OPR_OR" 2326 | } 2327 | function luaY:getbinopr(op) 2328 | local opr = self.getbinopr_table[op] 2329 | if opr then 2330 | return opr 2331 | else 2332 | return "OPR_NOBINOPR" 2333 | end 2334 | end; 2335 | luaY.priority = { 2336 | { 2337 | 6, 2338 | 6 2339 | }, 2340 | { 2341 | 6, 2342 | 6 2343 | }, 2344 | { 2345 | 7, 2346 | 7 2347 | }, 2348 | { 2349 | 7, 2350 | 7 2351 | }, 2352 | { 2353 | 7, 2354 | 7 2355 | }, 2356 | { 2357 | 10, 2358 | 9 2359 | }, 2360 | { 2361 | 5, 2362 | 4 2363 | }, 2364 | { 2365 | 3, 2366 | 3 2367 | }, 2368 | { 2369 | 3, 2370 | 3 2371 | }, 2372 | { 2373 | 3, 2374 | 3 2375 | }, 2376 | { 2377 | 3, 2378 | 3 2379 | }, 2380 | { 2381 | 3, 2382 | 3 2383 | }, 2384 | { 2385 | 3, 2386 | 3 2387 | }, 2388 | { 2389 | 2, 2390 | 2 2391 | }, 2392 | { 2393 | 1, 2394 | 1 2395 | } 2396 | } 2397 | luaY.UNARY_PRIORITY = 8; 2398 | function luaY:subexpr(ls, v, limit) 2399 | self:enterlevel(ls) 2400 | local uop = self:getunopr(ls.t.token) 2401 | if uop ~= "OPR_NOUNOPR" then 2402 | luaX:next(ls) 2403 | self:subexpr(ls, v, self.UNARY_PRIORITY) 2404 | luaK:prefix(ls.fs, uop, v) 2405 | else 2406 | self:simpleexp(ls, v) 2407 | end; 2408 | local op = self:getbinopr(ls.t.token) 2409 | while op ~= "OPR_NOBINOPR" and self.priority[luaK.BinOpr[op] + 1][1] > limit do 2410 | local v2 = {} 2411 | luaX:next(ls) 2412 | luaK:infix(ls.fs, op, v) 2413 | local nextop = self:subexpr(ls, v2, self.priority[luaK.BinOpr[op] + 1][2]) 2414 | luaK:posfix(ls.fs, op, v, v2) 2415 | op = nextop 2416 | end; 2417 | self:leavelevel(ls) 2418 | return op 2419 | end; 2420 | function luaY:expr(ls, v) 2421 | self:subexpr(ls, v, 0) 2422 | end; 2423 | function luaY:block_follow(token) 2424 | if token == "TK_ELSE" or token == "TK_ELSEIF" or token == "TK_END" or token == "TK_UNTIL" or token == "TK_EOS" then 2425 | return true 2426 | else 2427 | return false 2428 | end 2429 | end; 2430 | function luaY:block(ls) 2431 | local fs = ls.fs; 2432 | local bl = {} 2433 | self:enterblock(fs, bl, false) 2434 | self:chunk(ls) 2435 | lua_assert(bl.breaklist == luaK.NO_JUMP) 2436 | self:leaveblock(fs) 2437 | end; 2438 | function luaY:check_conflict(ls, lh, v) 2439 | local fs = ls.fs; 2440 | local extra = fs.freereg; 2441 | local conflict = false; 2442 | while lh do 2443 | if lh.v.k == "VINDEXED" then 2444 | if lh.v.info == v.info then 2445 | conflict = true; 2446 | lh.v.info = extra 2447 | end; 2448 | if lh.v.aux == v.info then 2449 | conflict = true; 2450 | lh.v.aux = extra 2451 | end 2452 | end; 2453 | lh = lh.prev 2454 | end; 2455 | if conflict then 2456 | luaK:codeABC(fs, "OP_MOVE", fs.freereg, v.info, 0) 2457 | luaK:reserveregs(fs, 1) 2458 | end 2459 | end; 2460 | function luaY:assignment(ls, lh, nvars) 2461 | local e = {} 2462 | local c = lh.v.k; 2463 | self:check_condition(ls, c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL" or c == "VINDEXED", "syntax error") 2464 | if self:testnext(ls, ",") then 2465 | local nv = {} 2466 | nv.v = {} 2467 | nv.prev = lh; 2468 | self:primaryexp(ls, nv.v) 2469 | if nv.v.k == "VLOCAL" then 2470 | self:check_conflict(ls, lh, nv.v) 2471 | end; 2472 | self:checklimit(ls.fs, nvars, self.LUAI_MAXCCALLS - ls.L.nCcalls, "variables in assignment") 2473 | self:assignment(ls, nv, nvars + 1) 2474 | else 2475 | self:checknext(ls, "=") 2476 | local nexps = self:explist1(ls, e) 2477 | if nexps ~= nvars then 2478 | self:adjust_assign(ls, nvars, nexps, e) 2479 | if nexps > nvars then 2480 | ls.fs.freereg = ls.fs.freereg - (nexps - nvars) 2481 | end 2482 | else 2483 | luaK:setoneret(ls.fs, e) 2484 | luaK:storevar(ls.fs, lh.v, e) 2485 | return 2486 | end 2487 | end; 2488 | self:init_exp(e, "VNONRELOC", ls.fs.freereg - 1) 2489 | luaK:storevar(ls.fs, lh.v, e) 2490 | end; 2491 | function luaY:cond(ls) 2492 | local v = {} 2493 | self:expr(ls, v) 2494 | if v.k == "VNIL" then 2495 | v.k = "VFALSE" 2496 | end; 2497 | luaK:goiftrue(ls.fs, v) 2498 | return v.f 2499 | end; 2500 | function luaY:breakstat(ls) 2501 | local fs = ls.fs; 2502 | local bl = fs.bl; 2503 | local upval = false; 2504 | while bl and not bl.isbreakable do 2505 | if bl.upval then 2506 | upval = true 2507 | end; 2508 | bl = bl.previous 2509 | end; 2510 | if not bl then 2511 | luaX:syntaxerror(ls, "no loop to break") 2512 | end; 2513 | if upval then 2514 | luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0) 2515 | end; 2516 | bl.breaklist = luaK:concat(fs, bl.breaklist, luaK:jump(fs)) 2517 | end; 2518 | function luaY:whilestat(ls, line) 2519 | local fs = ls.fs; 2520 | local bl = {} 2521 | luaX:next(ls) 2522 | local whileinit = luaK:getlabel(fs) 2523 | local condexit = self:cond(ls) 2524 | self:enterblock(fs, bl, true) 2525 | self:checknext(ls, "TK_DO") 2526 | self:block(ls) 2527 | luaK:patchlist(fs, luaK:jump(fs), whileinit) 2528 | self:check_match(ls, "TK_END", "TK_WHILE", line) 2529 | self:leaveblock(fs) 2530 | luaK:patchtohere(fs, condexit) 2531 | end; 2532 | function luaY:repeatstat(ls, line) 2533 | local fs = ls.fs; 2534 | local repeat_init = luaK:getlabel(fs) 2535 | local bl1, bl2 = {}, {} 2536 | self:enterblock(fs, bl1, true) 2537 | self:enterblock(fs, bl2, false) 2538 | luaX:next(ls) 2539 | self:chunk(ls) 2540 | self:check_match(ls, "TK_UNTIL", "TK_REPEAT", line) 2541 | local condexit = self:cond(ls) 2542 | if not bl2.upval then 2543 | self:leaveblock(fs) 2544 | luaK:patchlist(ls.fs, condexit, repeat_init) 2545 | else 2546 | self:breakstat(ls) 2547 | luaK:patchtohere(ls.fs, condexit) 2548 | self:leaveblock(fs) 2549 | luaK:patchlist(ls.fs, luaK:jump(fs), repeat_init) 2550 | end; 2551 | self:leaveblock(fs) 2552 | end; 2553 | function luaY:exp1(ls) 2554 | local e = {} 2555 | self:expr(ls, e) 2556 | local k = e.k; 2557 | luaK:exp2nextreg(ls.fs, e) 2558 | return k 2559 | end; 2560 | function luaY:forbody(ls, base, line, nvars, isnum) 2561 | local bl = {} 2562 | local fs = ls.fs; 2563 | self:adjustlocalvars(ls, 3) 2564 | self:checknext(ls, "TK_DO") 2565 | local prep = isnum and luaK:codeAsBx(fs, "OP_FORPREP", base, luaK.NO_JUMP) or luaK:jump(fs) 2566 | self:enterblock(fs, bl, false) 2567 | self:adjustlocalvars(ls, nvars) 2568 | luaK:reserveregs(fs, nvars) 2569 | self:block(ls) 2570 | self:leaveblock(fs) 2571 | luaK:patchtohere(fs, prep) 2572 | local endfor = isnum and luaK:codeAsBx(fs, "OP_FORLOOP", base, luaK.NO_JUMP) or luaK:codeABC(fs, "OP_TFORLOOP", base, 0, nvars) 2573 | luaK:fixline(fs, line) 2574 | luaK:patchlist(fs, isnum and endfor or luaK:jump(fs), prep + 1) 2575 | end; 2576 | function luaY:fornum(ls, varname, line) 2577 | local fs = ls.fs; 2578 | local base = fs.freereg; 2579 | self:new_localvarliteral(ls, "(for index)", 0) 2580 | self:new_localvarliteral(ls, "(for limit)", 1) 2581 | self:new_localvarliteral(ls, "(for step)", 2) 2582 | self:new_localvar(ls, varname, 3) 2583 | self:checknext(ls, '=') 2584 | self:exp1(ls) 2585 | self:checknext(ls, ",") 2586 | self:exp1(ls) 2587 | if self:testnext(ls, ",") then 2588 | self:exp1(ls) 2589 | else 2590 | luaK:codeABx(fs, "OP_LOADK", fs.freereg, luaK:numberK(fs, 1)) 2591 | luaK:reserveregs(fs, 1) 2592 | end; 2593 | self:forbody(ls, base, line, 1, true) 2594 | end; 2595 | function luaY:forlist(ls, indexname) 2596 | local fs = ls.fs; 2597 | local e = {} 2598 | local nvars = 0; 2599 | local base = fs.freereg; 2600 | self:new_localvarliteral(ls, "(for generator)", nvars) 2601 | nvars = nvars + 1; 2602 | self:new_localvarliteral(ls, "(for state)", nvars) 2603 | nvars = nvars + 1; 2604 | self:new_localvarliteral(ls, "(for control)", nvars) 2605 | nvars = nvars + 1; 2606 | self:new_localvar(ls, indexname, nvars) 2607 | nvars = nvars + 1; 2608 | while self:testnext(ls, ",") do 2609 | self:new_localvar(ls, self:str_checkname(ls), nvars) 2610 | nvars = nvars + 1 2611 | end; 2612 | self:checknext(ls, "TK_IN") 2613 | local line = ls.linenumber; 2614 | self:adjust_assign(ls, 3, self:explist1(ls, e), e) 2615 | luaK:checkstack(fs, 3) 2616 | self:forbody(ls, base, line, nvars - 3, false) 2617 | end; 2618 | function luaY:forstat(ls, line) 2619 | local fs = ls.fs; 2620 | local bl = {} 2621 | self:enterblock(fs, bl, true) 2622 | luaX:next(ls) 2623 | local varname = self:str_checkname(ls) 2624 | local c = ls.t.token; 2625 | if c == "=" then 2626 | self:fornum(ls, varname, line) 2627 | elseif c == "," or c == "TK_IN" then 2628 | self:forlist(ls, varname) 2629 | else 2630 | luaX:syntaxerror(ls, self:LUA_QL("=") .. " or " .. self:LUA_QL("in") .. " expected") 2631 | end; 2632 | self:check_match(ls, "TK_END", "TK_FOR", line) 2633 | self:leaveblock(fs) 2634 | end; 2635 | function luaY:test_then_block(ls) 2636 | luaX:next(ls) 2637 | local condexit = self:cond(ls) 2638 | self:checknext(ls, "TK_THEN") 2639 | self:block(ls) 2640 | return condexit 2641 | end; 2642 | function luaY:ifstat(ls, line) 2643 | local fs = ls.fs; 2644 | local escapelist = luaK.NO_JUMP; 2645 | local flist = self:test_then_block(ls) 2646 | while ls.t.token == "TK_ELSEIF" do 2647 | escapelist = luaK:concat(fs, escapelist, luaK:jump(fs)) 2648 | luaK:patchtohere(fs, flist) 2649 | flist = self:test_then_block(ls) 2650 | end; 2651 | if ls.t.token == "TK_ELSE" then 2652 | escapelist = luaK:concat(fs, escapelist, luaK:jump(fs)) 2653 | luaK:patchtohere(fs, flist) 2654 | luaX:next(ls) 2655 | self:block(ls) 2656 | else 2657 | escapelist = luaK:concat(fs, escapelist, flist) 2658 | end; 2659 | luaK:patchtohere(fs, escapelist) 2660 | self:check_match(ls, "TK_END", "TK_IF", line) 2661 | end; 2662 | function luaY:localfunc(ls) 2663 | local v, b = {}, {} 2664 | local fs = ls.fs; 2665 | self:new_localvar(ls, self:str_checkname(ls), 0) 2666 | self:init_exp(v, "VLOCAL", fs.freereg) 2667 | luaK:reserveregs(fs, 1) 2668 | self:adjustlocalvars(ls, 1) 2669 | self:body(ls, b, false, ls.linenumber) 2670 | luaK:storevar(fs, v, b) 2671 | self:getlocvar(fs, fs.nactvar - 1).startpc = fs.pc 2672 | end; 2673 | function luaY:localstat(ls) 2674 | local nvars = 0; 2675 | local nexps; 2676 | local e = {} 2677 | repeat 2678 | self:new_localvar(ls, self:str_checkname(ls), nvars) 2679 | nvars = nvars + 1 2680 | until not self:testnext(ls, ",") 2681 | if self:testnext(ls, "=") then 2682 | nexps = self:explist1(ls, e) 2683 | else 2684 | e.k = "VVOID" 2685 | nexps = 0 2686 | end; 2687 | self:adjust_assign(ls, nvars, nexps, e) 2688 | self:adjustlocalvars(ls, nvars) 2689 | end; 2690 | function luaY:funcname(ls, v) 2691 | local needself = false; 2692 | self:singlevar(ls, v) 2693 | while ls.t.token == "." do 2694 | self:field(ls, v) 2695 | end; 2696 | if ls.t.token == ":" then 2697 | needself = true; 2698 | self:field(ls, v) 2699 | end; 2700 | return needself 2701 | end; 2702 | function luaY:funcstat(ls, line) 2703 | local v, b = {}, {} 2704 | luaX:next(ls) 2705 | local needself = self:funcname(ls, v) 2706 | self:body(ls, b, needself, line) 2707 | luaK:storevar(ls.fs, v, b) 2708 | luaK:fixline(ls.fs, line) 2709 | end; 2710 | function luaY:exprstat(ls) 2711 | local fs = ls.fs; 2712 | local v = {} 2713 | v.v = {} 2714 | self:primaryexp(ls, v.v) 2715 | if v.v.k == "VCALL" then 2716 | luaP:SETARG_C(luaK:getcode(fs, v.v), 1) 2717 | else 2718 | v.prev = nil; 2719 | self:assignment(ls, v, 1) 2720 | end 2721 | end; 2722 | function luaY:retstat(ls) 2723 | local fs = ls.fs; 2724 | local e = {} 2725 | local first, nret; 2726 | luaX:next(ls) 2727 | if self:block_follow(ls.t.token) or ls.t.token == ";" then 2728 | first, nret = 0, 0 2729 | else 2730 | nret = self:explist1(ls, e) 2731 | if self:hasmultret(e.k) then 2732 | luaK:setmultret(fs, e) 2733 | if e.k == "VCALL" and nret == 1 then 2734 | luaP:SET_OPCODE(luaK:getcode(fs, e), "OP_TAILCALL") 2735 | lua_assert(luaP:GETARG_A(luaK:getcode(fs, e)) == fs.nactvar) 2736 | end; 2737 | first = fs.nactvar; 2738 | nret = self.LUA_MULTRET 2739 | else 2740 | if nret == 1 then 2741 | first = luaK:exp2anyreg(fs, e) 2742 | else 2743 | luaK:exp2nextreg(fs, e) 2744 | first = fs.nactvar; 2745 | lua_assert(nret == fs.freereg - first) 2746 | end 2747 | end 2748 | end; 2749 | luaK:ret(fs, first, nret) 2750 | end; 2751 | function luaY:statement(ls) 2752 | local line = ls.linenumber; 2753 | local c = ls.t.token; 2754 | if c == "TK_IF" then 2755 | self:ifstat(ls, line) 2756 | return false 2757 | elseif c == "TK_WHILE" then 2758 | self:whilestat(ls, line) 2759 | return false 2760 | elseif c == "TK_DO" then 2761 | luaX:next(ls) 2762 | self:block(ls) 2763 | self:check_match(ls, "TK_END", "TK_DO", line) 2764 | return false 2765 | elseif c == "TK_FOR" then 2766 | self:forstat(ls, line) 2767 | return false 2768 | elseif c == "TK_REPEAT" then 2769 | self:repeatstat(ls, line) 2770 | return false 2771 | elseif c == "TK_FUNCTION" then 2772 | self:funcstat(ls, line) 2773 | return false 2774 | elseif c == "TK_LOCAL" then 2775 | luaX:next(ls) 2776 | if self:testnext(ls, "TK_FUNCTION") then 2777 | self:localfunc(ls) 2778 | else 2779 | self:localstat(ls) 2780 | end; 2781 | return false 2782 | elseif c == "TK_RETURN" then 2783 | self:retstat(ls) 2784 | return true 2785 | elseif c == "TK_BREAK" then 2786 | luaX:next(ls) 2787 | self:breakstat(ls) 2788 | return true 2789 | else 2790 | self:exprstat(ls) 2791 | return false 2792 | end 2793 | end; 2794 | function luaY:chunk(ls) 2795 | local islast = false; 2796 | self:enterlevel(ls) 2797 | while not islast and not self:block_follow(ls.t.token) do 2798 | islast = self:statement(ls) 2799 | self:testnext(ls, ";") 2800 | lua_assert(ls.fs.f.maxstacksize >= ls.fs.freereg and ls.fs.freereg >= ls.fs.nactvar) 2801 | ls.fs.freereg = ls.fs.nactvar 2802 | end; 2803 | self:leavelevel(ls) 2804 | end; 2805 | luaX:init() 2806 | local LuaState = {} 2807 | function compile(source, name) 2808 | name = name or 'compiled-lua' 2809 | local zio = luaZ:init(luaZ:make_getF(source), nil) 2810 | if not zio then 2811 | return 2812 | end; 2813 | local func = luaY:parser(LuaState, zio, nil, "@" .. name) 2814 | local writer, buff = luaU:make_setS() 2815 | luaU:dump(LuaState, func, writer, buff) 2816 | return Serialize(Deserialize(buff.data)) 2817 | end; 2818 | return compile 2819 | --------------------------------------------------------------------------------