diff --git a/src/presets.lua b/src/presets.lua index 00ed4699..5a9b9619 100644 --- a/src/presets.lua +++ b/src/presets.lua @@ -1,6 +1,6 @@ -- This Script is Part of the Prometheus Obfuscator by Levno_710 -- --- pipeline.lua +-- presets.lua -- -- This Script Provides some configuration presets diff --git a/src/prometheus/ast.lua b/src/prometheus/ast.lua index 86bb7a97..778f6d8d 100644 --- a/src/prometheus/ast.lua +++ b/src/prometheus/ast.lua @@ -37,7 +37,7 @@ local AstKind = { -- Assignment Index AssignmentIndexing = "AssignmentIndexing"; - AssignmentVariable = "AssignmentVariable"; + AssignmentVariable = "AssignmentVariable"; -- Expression Nodes BooleanExpression = "BooleanExpression"; @@ -769,7 +769,7 @@ end function Ast.VariableExpression(scope, id) scope:addReference(id); return { - kind = AstKind.VariableExpression, + kind = AstKind.VariableExpression, scope = scope, id = id, getName = function(self) @@ -781,7 +781,7 @@ end function Ast.AssignmentVariable(scope, id) scope:addReference(id); return { - kind = AstKind.AssignmentVariable, + kind = AstKind.AssignmentVariable, scope = scope, id = id, getName = function(self) diff --git a/src/prometheus/bit.lua b/src/prometheus/bit.lua deleted file mode 100644 index 7bc926ab..00000000 --- a/src/prometheus/bit.lua +++ /dev/null @@ -1,521 +0,0 @@ --- This Module was NOT written by Levno_710 --- Credit: https://github.com/davidm/lua-bit-numberlua - ---[[ -LUA MODULE - bit.numberlua - Bitwise operations implemented in pure Lua as numbers, - with Lua 5.2 'bit32' and (LuaJIT) LuaBitOp 'bit' compatibility interfaces. -SYNOPSIS - local bit = require 'bit.numberlua' - print(bit.band(0xff00ff00, 0x00ff00ff)) --> 0xffffffff - - -- Interface providing strong Lua 5.2 'bit32' compatibility - local bit32 = require 'bit.numberlua'.bit32 - assert(bit32.band(-1) == 0xffffffff) - - -- Interface providing strong (LuaJIT) LuaBitOp 'bit' compatibility - local bit = require 'bit.numberlua'.bit - assert(bit.tobit(0xffffffff) == -1) - -DESCRIPTION - - This library implements bitwise operations entirely in Lua. - This module is typically intended if for some reasons you don't want - to or cannot install a popular C based bit library like BitOp 'bit' [1] - (which comes pre-installed with LuaJIT) or 'bit32' (which comes - pre-installed with Lua 5.2) but want a similar interface. - - This modules represents bit arrays as non-negative Lua numbers. [1] - It can represent 32-bit bit arrays when Lua is compiled - with lua_Number as double-precision IEEE 754 floating point. - The module is nearly the most efficient it can be but may be a few times - slower than the C based bit libraries and is orders or magnitude - slower than LuaJIT bit operations, which compile to native code. Therefore, - this library is inferior in performane to the other modules. - The `xor` function in this module is based partly on Roberto Ierusalimschy's - post in http://lua-users.org/lists/lua-l/2002-09/msg00134.html . - - The included BIT.bit32 and BIT.bit sublibraries aims to provide 100% - compatibility with the Lua 5.2 "bit32" and (LuaJIT) LuaBitOp "bit" library. - This compatbility is at the cost of some efficiency since inputted - numbers are normalized and more general forms (e.g. multi-argument - bitwise operators) are supported. - -STATUS - WARNING: Not all corner cases have been tested and documented. - Some attempt was made to make these similar to the Lua 5.2 [2] - and LuaJit BitOp [3] libraries, but this is not fully tested and there - are currently some differences. Addressing these differences may - be improved in the future but it is not yet fully determined how to - resolve these differences. - - The BIT.bit32 library passes the Lua 5.2 test suite (bitwise.lua) - http://www.lua.org/tests/5.2/ . The BIT.bit library passes the LuaBitOp - test suite (bittest.lua). However, these have not been tested on - platforms with Lua compiled with 32-bit integer numbers. -API - BIT.tobit(x) --> z - - Similar to function in BitOp. - - BIT.tohex(x, n) - - Similar to function in BitOp. - - BIT.band(x, y) --> z - - Similar to function in Lua 5.2 and BitOp but requires two arguments. - - BIT.bor(x, y) --> z - - Similar to function in Lua 5.2 and BitOp but requires two arguments. - BIT.bxor(x, y) --> z - - Similar to function in Lua 5.2 and BitOp but requires two arguments. - - BIT.bnot(x) --> z - - Similar to function in Lua 5.2 and BitOp. - BIT.lshift(x, disp) --> z - - Similar to function in Lua 5.2 (warning: BitOp uses unsigned lower 5 bits of shift), - - BIT.rshift(x, disp) --> z - - Similar to function in Lua 5.2 (warning: BitOp uses unsigned lower 5 bits of shift), - BIT.extract(x, field [, width]) --> z - - Similar to function in Lua 5.2. - - BIT.replace(x, v, field, width) --> z - - Similar to function in Lua 5.2. - - BIT.bswap(x) --> z - - Similar to function in Lua 5.2. - BIT.rrotate(x, disp) --> z - BIT.ror(x, disp) --> z - - Similar to function in Lua 5.2 and BitOp. - BIT.lrotate(x, disp) --> z - BIT.rol(x, disp) --> z - Similar to function in Lua 5.2 and BitOp. - - BIT.arshift - - Similar to function in Lua 5.2 and BitOp. - - BIT.btest - - Similar to function in Lua 5.2 with requires two arguments. - BIT.bit32 - - This table contains functions that aim to provide 100% compatibility - with the Lua 5.2 "bit32" library. - - bit32.arshift (x, disp) --> z - bit32.band (...) --> z - bit32.bnot (x) --> z - bit32.bor (...) --> z - bit32.btest (...) --> true | false - bit32.bxor (...) --> z - bit32.extract (x, field [, width]) --> z - bit32.replace (x, v, field [, width]) --> z - bit32.lrotate (x, disp) --> z - bit32.lshift (x, disp) --> z - bit32.rrotate (x, disp) --> z - bit32.rshift (x, disp) --> z - BIT.bit - - This table contains functions that aim to provide 100% compatibility - with the LuaBitOp "bit" library (from LuaJIT). - - bit.tobit(x) --> y - bit.tohex(x [,n]) --> y - bit.bnot(x) --> y - bit.bor(x1 [,x2...]) --> y - bit.band(x1 [,x2...]) --> y - bit.bxor(x1 [,x2...]) --> y - bit.lshift(x, n) --> y - bit.rshift(x, n) --> y - bit.arshift(x, n) --> y - bit.rol(x, n) --> y - bit.ror(x, n) --> y - bit.bswap(x) --> y - -DEPENDENCIES - None (other than Lua 5.1 or 5.2). - -DOWNLOAD/INSTALLATION - If using LuaRocks: - luarocks install lua-bit-numberlua - Otherwise, download . - Alternately, if using git: - git clone git://github.com/davidm/lua-bit-numberlua.git - cd lua-bit-numberlua - Optionally unpack: - ./util.mk - or unpack and install in LuaRocks: - ./util.mk install -REFERENCES - [1] http://lua-users.org/wiki/FloatingPoint - [2] http://www.lua.org/manual/5.2/ - [3] http://bitop.luajit.org/ - -LICENSE - (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT). - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - (end license) ---]] - -local M = {_TYPE='module', _NAME='bit.numberlua', _VERSION='0.3.1.20120131'} - -local floor = math.floor - -local MOD = 2^32 -local MODM = MOD-1 - -local function memoize(f) - local mt = {} - local t = setmetatable({}, mt) - function mt:__index(k) - local v = f(k); t[k] = v - return v - end - return t -end - -local function make_bitop_uncached(t, m) - local function bitop(a, b) - local res,p = 0,1 - while a ~= 0 and b ~= 0 do - local am, bm = a%m, b%m - res = res + t[am][bm]*p - a = (a - am) / m - b = (b - bm) / m - p = p*m - end - res = res + (a+b)*p - return res - end - return bitop -end - -local function make_bitop(t) - local op1 = make_bitop_uncached(t,2^1) - local op2 = memoize(function(a) - return memoize(function(b) - return op1(a, b) - end) - end) - return make_bitop_uncached(op2, 2^(t.n or 1)) -end - --- ok? probably not if running on a 32-bit int Lua number type platform -function M.tobit(x) - return x % 2^32 -end - -M.bxor = make_bitop {[0]={[0]=0,[1]=1},[1]={[0]=1,[1]=0}, n=4} -local bxor = M.bxor - -function M.bnot(a) return MODM - a end -local bnot = M.bnot - -function M.band(a,b) return ((a+b) - bxor(a,b))/2 end -local band = M.band - -function M.bor(a,b) return MODM - band(MODM - a, MODM - b) end -local bor = M.bor - -local lshift, rshift -- forward declare - -function M.rshift(a,disp) -- Lua5.2 insipred - if disp < 0 then return lshift(a,-disp) end - return floor(a % 2^32 / 2^disp) -end -rshift = M.rshift - -function M.lshift(a,disp) -- Lua5.2 inspired - if disp < 0 then return rshift(a,-disp) end - return (a * 2^disp) % 2^32 -end -lshift = M.lshift - -function M.tohex(x, n) -- BitOp style - n = n or 8 - local up - if n <= 0 then - if n == 0 then return '' end - up = true - n = - n - end - x = band(x, 16^n-1) - return ('%0'..n..(up and 'X' or 'x')):format(x) -end -local tohex = M.tohex - -function M.extract(n, field, width) -- Lua5.2 inspired - width = width or 1 - return band(rshift(n, field), 2^width-1) -end -local extract = M.extract - -function M.replace(n, v, field, width) -- Lua5.2 inspired - width = width or 1 - local mask1 = 2^width-1 - v = band(v, mask1) -- required by spec? - local mask = bnot(lshift(mask1, field)) - return band(n, mask) + lshift(v, field) -end -local replace = M.replace - -function M.bswap(x) -- BitOp style - local a = band(x, 0xff); x = rshift(x, 8) - local b = band(x, 0xff); x = rshift(x, 8) - local c = band(x, 0xff); x = rshift(x, 8) - local d = band(x, 0xff) - return lshift(lshift(lshift(a, 8) + b, 8) + c, 8) + d -end -local bswap = M.bswap - -function M.rrotate(x, disp) -- Lua5.2 inspired - disp = disp % 32 - local low = band(x, 2^disp-1) - return rshift(x, disp) + lshift(low, 32-disp) -end -local rrotate = M.rrotate - -function M.lrotate(x, disp) -- Lua5.2 inspired - return rrotate(x, -disp) -end -local lrotate = M.lrotate - -M.rol = M.lrotate -- LuaOp inspired -M.ror = M.rrotate -- LuaOp insipred - - -function M.arshift(x, disp) -- Lua5.2 inspired - local z = rshift(x, disp) - if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end - return z -end -local arshift = M.arshift - -function M.btest(x, y) -- Lua5.2 inspired - return band(x, y) ~= 0 -end - --- --- Start Lua 5.2 "bit32" compat section. --- - -M.bit32 = {} -- Lua 5.2 'bit32' compatibility - - -local function bit32_bnot(x) - return (-1 - x) % MOD -end -M.bit32.bnot = bit32_bnot - -local function bit32_bxor(a, b, c, ...) - local z - if b then - a = a % MOD - b = b % MOD - z = bxor(a, b) - if c then - z = bit32_bxor(z, c, ...) - end - return z - elseif a then - return a % MOD - else - return 0 - end -end -M.bit32.bxor = bit32_bxor - -local function bit32_band(a, b, c, ...) - local z - if b then - a = a % MOD - b = b % MOD - z = ((a+b) - bxor(a,b)) / 2 - if c then - z = bit32_band(z, c, ...) - end - return z - elseif a then - return a % MOD - else - return MODM - end -end -M.bit32.band = bit32_band - -local function bit32_bor(a, b, c, ...) - local z - if b then - a = a % MOD - b = b % MOD - z = MODM - band(MODM - a, MODM - b) - if c then - z = bit32_bor(z, c, ...) - end - return z - elseif a then - return a % MOD - else - return 0 - end -end -M.bit32.bor = bit32_bor - -function M.bit32.btest(...) - return bit32_band(...) ~= 0 -end - -function M.bit32.lrotate(x, disp) - return lrotate(x % MOD, disp) -end - -function M.bit32.rrotate(x, disp) - return rrotate(x % MOD, disp) -end - -function M.bit32.lshift(x,disp) - if disp > 31 or disp < -31 then return 0 end - return lshift(x % MOD, disp) -end - -function M.bit32.rshift(x,disp) - if disp > 31 or disp < -31 then return 0 end - return rshift(x % MOD, disp) -end - -function M.bit32.arshift(x,disp) - x = x % MOD - if disp >= 0 then - if disp > 31 then - return (x >= 0x80000000) and MODM or 0 - else - local z = rshift(x, disp) - if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end - return z - end - else - return lshift(x, -disp) - end -end - -function M.bit32.extract(x, field, ...) - local width = ... or 1 - if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end - x = x % MOD - return extract(x, field, ...) -end - -function M.bit32.replace(x, v, field, ...) - local width = ... or 1 - if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end - x = x % MOD - v = v % MOD - return replace(x, v, field, ...) -end - - --- --- Start LuaBitOp "bit" compat section. --- - -M.bit = {} -- LuaBitOp "bit" compatibility - -function M.bit.tobit(x) - x = x % MOD - if x >= 0x80000000 then x = x - MOD end - return x -end -local bit_tobit = M.bit.tobit - -function M.bit.tohex(x, ...) - return tohex(x % MOD, ...) -end - -function M.bit.bnot(x) - return bit_tobit(bnot(x % MOD)) -end - -local function bit_bor(a, b, c, ...) - if c then - return bit_bor(bit_bor(a, b), c, ...) - elseif b then - return bit_tobit(bor(a % MOD, b % MOD)) - else - return bit_tobit(a) - end -end -M.bit.bor = bit_bor - -local function bit_band(a, b, c, ...) - if c then - return bit_band(bit_band(a, b), c, ...) - elseif b then - return bit_tobit(band(a % MOD, b % MOD)) - else - return bit_tobit(a) - end -end -M.bit.band = bit_band - -local function bit_bxor(a, b, c, ...) - if c then - return bit_bxor(bit_bxor(a, b), c, ...) - elseif b then - return bit_tobit(bxor(a % MOD, b % MOD)) - else - return bit_tobit(a) - end -end -M.bit.bxor = bit_bxor - -function M.bit.lshift(x, n) - return bit_tobit(lshift(x % MOD, n % 32)) -end - -function M.bit.rshift(x, n) - return bit_tobit(rshift(x % MOD, n % 32)) -end - -function M.bit.arshift(x, n) - return bit_tobit(arshift(x % MOD, n % 32)) -end - -function M.bit.rol(x, n) - return bit_tobit(lrotate(x % MOD, n % 32)) -end - -function M.bit.ror(x, n) - return bit_tobit(rrotate(x % MOD, n % 32)) -end - -function M.bit.bswap(x) - return bit_tobit(bswap(x % MOD)) -end - -return M \ No newline at end of file diff --git a/src/prometheus/compiler/block.lua b/src/prometheus/compiler/block.lua new file mode 100644 index 00000000..d834114b --- /dev/null +++ b/src/prometheus/compiler/block.lua @@ -0,0 +1,45 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- block.lua +-- Block management for the compiler + +local Scope = require("prometheus.scope"); +local util = require("prometheus.util"); + +local lookupify = util.lookupify; + +return function(Compiler) + function Compiler:createBlock() + local id; + repeat + id = math.random(0, 2^24) + until not self.usedBlockIds[id]; + self.usedBlockIds[id] = true; + + local scope = Scope:new(self.containerFuncScope); + local block = { + id = id; + statements = {}; + scope = scope; + advanceToNextBlock = true; + }; + table.insert(self.blocks, block); + return block; + end + + function Compiler:setActiveBlock(block) + self.activeBlock = block; + end + + function Compiler:addStatement(statement, writes, reads, usesUpvals) + if(self.activeBlock.advanceToNextBlock) then + table.insert(self.activeBlock.statements, { + statement = statement, + writes = lookupify(writes), + reads = lookupify(reads), + usesUpvals = usesUpvals or false, + }); + end + end +end + diff --git a/src/prometheus/compiler/compile_core.lua b/src/prometheus/compiler/compile_core.lua new file mode 100644 index 00000000..fdbd2b9f --- /dev/null +++ b/src/prometheus/compiler/compile_core.lua @@ -0,0 +1,33 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- compile_core.lua +-- This Script contains the core compilation functions: compileTopNode, compileFunction, compileBlock, +-- compileStatement, and compileExpression + +local compileTop = require("prometheus.compiler.compile_top"); +local statementHandlers = require("prometheus.compiler.statements"); +local expressionHandlers = require("prometheus.compiler.expressions"); +local Ast = require("prometheus.ast"); +local logger = require("logger"); +local AstKind = Ast.AstKind; + +return function(Compiler) + compileTop(Compiler); + + function Compiler:compileStatement(statement, funcDepth) + local handler = statementHandlers[statement.kind]; + if handler then + handler(self, statement, funcDepth); + return; + end + logger:error(string.format("%s is not a compileable statement!", statement.kind)); + end + + function Compiler:compileExpression(expression, funcDepth, numReturns) + local handler = expressionHandlers[expression.kind]; + if handler then + return handler(self, expression, funcDepth, numReturns); + end + logger:error(string.format("%s is not an compliable expression!", expression.kind)); + end +end diff --git a/src/prometheus/compiler/compile_top.lua b/src/prometheus/compiler/compile_top.lua new file mode 100644 index 00000000..0ba61d24 --- /dev/null +++ b/src/prometheus/compiler/compile_top.lua @@ -0,0 +1,198 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- compile_top.lua +-- This Script contains the compilation of the top node, function, and block + +local Ast = require("prometheus.ast"); +local util = require("prometheus.util"); +local visitast = require("prometheus.visitast"); + +local lookupify = util.lookupify; +local AstKind = Ast.AstKind; + +return function(Compiler) + function Compiler:compileTopNode(node) + local startBlock = self:createBlock(); + local scope = startBlock.scope; + self.startBlockId = startBlock.id; + self:setActiveBlock(startBlock); + + local varAccessLookup = lookupify{ + AstKind.AssignmentVariable, + AstKind.VariableExpression, + AstKind.FunctionDeclaration, + AstKind.LocalFunctionDeclaration, + } + + local functionLookup = lookupify{ + AstKind.FunctionDeclaration, + AstKind.LocalFunctionDeclaration, + AstKind.FunctionLiteralExpression, + AstKind.TopNode, + } + visitast(node, function(node, data) + if node.kind == AstKind.Block then + node.scope.__depth = data.functionData.depth; + end + + if varAccessLookup[node.kind] then + if not node.scope.isGlobal then + if node.scope.__depth < data.functionData.depth then + if not self:isUpvalue(node.scope, node.id) then + self:makeUpvalue(node.scope, node.id); + end + end + end + end + end, nil, nil) + + self.varargReg = self:allocRegister(true); + scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar); + scope:addReferenceToHigherScope(self.scope, self.selectVar); + scope:addReferenceToHigherScope(self.scope, self.unpackVar); + self:addStatement(self:setRegister(scope, self.varargReg, Ast.VariableExpression(self.containerFuncScope, self.argsVar)), {self.varargReg}, {}, false); + + self:compileBlock(node.body, 0); + if(self.activeBlock.advanceToNextBlock) then + self:addStatement(self:setPos(self.activeBlock.scope, nil), {self.POS_REGISTER}, {}, false); + self:addStatement(self:setReturn(self.activeBlock.scope, Ast.TableConstructorExpression({})), {self.RETURN_REGISTER}, {}, false) + self.activeBlock.advanceToNextBlock = false; + end + + self:resetRegisters(); + end + + function Compiler:compileFunction(node, funcDepth) + funcDepth = funcDepth + 1; + local oldActiveBlock = self.activeBlock; + + local upperVarargReg = self.varargReg; + self.varargReg = nil; + + local upvalueExpressions = {}; + local upvalueIds = {}; + local usedRegs = {}; + + local oldGetUpvalueId = self.getUpvalueId; + self.getUpvalueId = function(self, scope, id) + if(not upvalueIds[scope]) then + upvalueIds[scope] = {}; + end + if(upvalueIds[scope][id]) then + return upvalueIds[scope][id]; + end + local scopeFuncDepth = self.scopeFunctionDepths[scope]; + local expression; + if(scopeFuncDepth == funcDepth) then + oldActiveBlock.scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); + expression = Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {}); + elseif(scopeFuncDepth == funcDepth - 1) then + local varReg = self:getVarRegister(scope, id, scopeFuncDepth, nil); + expression = self:register(oldActiveBlock.scope, varReg); + table.insert(usedRegs, varReg); + else + local higherId = oldGetUpvalueId(self, scope, id); + oldActiveBlock.scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); + expression = Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(higherId)); + end + table.insert(upvalueExpressions, Ast.TableEntry(expression)); + local uid = #upvalueExpressions; + upvalueIds[scope][id] = uid; + return uid; + end + + local block = self:createBlock(); + self:setActiveBlock(block); + local scope = self.activeBlock.scope; + self:pushRegisterUsageInfo(); + for i, arg in ipairs(node.args) do + if(arg.kind == AstKind.VariableExpression) then + if(self:isUpvalue(arg.scope, arg.id)) then + scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); + local argReg = self:getVarRegister(arg.scope, arg.id, funcDepth, nil); + self:addStatement(self:setRegister(scope, argReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {argReg}, {}, false); + self:addStatement(self:setUpvalueMember(scope, self:register(scope, argReg), Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.argsVar), Ast.NumberExpression(i))), {}, {argReg}, true); + else + local argReg = self:getVarRegister(arg.scope, arg.id, funcDepth, nil); + scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar); + self:addStatement(self:setRegister(scope, argReg, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.argsVar), Ast.NumberExpression(i))), {argReg}, {}, false); + end + else + self.varargReg = self:allocRegister(true); + scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar); + scope:addReferenceToHigherScope(self.scope, self.selectVar); + scope:addReferenceToHigherScope(self.scope, self.unpackVar); + self:addStatement(self:setRegister(scope, self.varargReg, Ast.TableConstructorExpression({ + Ast.TableEntry(Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.selectVar), { + Ast.NumberExpression(i); + Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.unpackVar), { + Ast.VariableExpression(self.containerFuncScope, self.argsVar), + }); + })), + })), {self.varargReg}, {}, false); + end + end + + self:compileBlock(node.body, funcDepth); + if(self.activeBlock.advanceToNextBlock) then + self:addStatement(self:setPos(self.activeBlock.scope, nil), {self.POS_REGISTER}, {}, false); + self:addStatement(self:setReturn(self.activeBlock.scope, Ast.TableConstructorExpression({})), {self.RETURN_REGISTER}, {}, false); + self.activeBlock.advanceToNextBlock = false; + end + + if(self.varargReg) then + self:freeRegister(self.varargReg, true); + end + self.varargReg = upperVarargReg; + self.getUpvalueId = oldGetUpvalueId; + + self:popRegisterUsageInfo(); + self:setActiveBlock(oldActiveBlock); + + local scope = self.activeBlock.scope; + + local retReg = self:allocRegister(false); + + local isVarargFunction = #node.args > 0 and node.args[#node.args].kind == AstKind.VarargExpression; + + local retrieveExpression + if isVarargFunction then + scope:addReferenceToHigherScope(self.scope, self.createVarargClosureVar); + retrieveExpression = Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.createVarargClosureVar), { + Ast.NumberExpression(block.id), + Ast.TableConstructorExpression(upvalueExpressions) + }); + else + local varScope, var = self:getCreateClosureVar(#node.args + math.random(0, 5)); + scope:addReferenceToHigherScope(varScope, var); + retrieveExpression = Ast.FunctionCallExpression(Ast.VariableExpression(varScope, var), { + Ast.NumberExpression(block.id), + Ast.TableConstructorExpression(upvalueExpressions) + }); + end + + self:addStatement(self:setRegister(scope, retReg, retrieveExpression), {retReg}, usedRegs, false); + return retReg; + end + + function Compiler:compileBlock(block, funcDepth) + for i, stat in ipairs(block.statements) do + self:compileStatement(stat, funcDepth); + end + + local scope = self.activeBlock.scope; + for id, name in ipairs(block.scope.variables) do + local varReg = self:getVarRegister(block.scope, id, funcDepth, nil); + if self:isUpvalue(block.scope, id) then + scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc); + self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), { + self:register(scope, varReg) + })), {varReg}, {varReg}, false); + else + self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), {varReg}, {}, false); + end + self:freeRegister(varReg, true); + end + end +end + diff --git a/src/prometheus/compiler/compiler.lua b/src/prometheus/compiler/compiler.lua index 7857fd67..65e94c75 100644 --- a/src/prometheus/compiler/compiler.lua +++ b/src/prometheus/compiler/compiler.lua @@ -3,29 +3,27 @@ -- compiler.lua -- This Script contains the new Compiler --- The max Number of variables used as registers -local MAX_REGS = 100; -local MAX_REGS_MUL = 0; - -local Compiler = {}; - local Ast = require("prometheus.ast"); local Scope = require("prometheus.scope"); -local logger = require("logger"); local util = require("prometheus.util"); -local visitast = require("prometheus.visitast") -local randomStrings = require("prometheus.randomStrings") local lookupify = util.lookupify; local AstKind = Ast.AstKind; local unpack = unpack or table.unpack; +local blockModule = require("prometheus.compiler.block"); +local registerModule = require("prometheus.compiler.register"); +local upvalueModule = require("prometheus.compiler.upvalue"); +local emitModule = require("prometheus.compiler.emit"); +local compileCoreModule = require("prometheus.compiler.compile_core"); + +local Compiler = {}; + function Compiler:new() local compiler = { blocks = {}; - registers = { - }; + registers = {}; activeBlock = nil; registersForVar = {}; usedRegisters = 0; @@ -61,39 +59,25 @@ function Compiler:new() return compiler; end -function Compiler:createBlock() - local id; - repeat - id = math.random(0, 2^24) - until not self.usedBlockIds[id]; - self.usedBlockIds[id] = true; - - local scope = Scope:new(self.containerFuncScope); - local block = { - id = id; - statements = { +blockModule(Compiler); +registerModule(Compiler); +upvalueModule(Compiler); +emitModule(Compiler); +compileCoreModule(Compiler); - }; - scope = scope; - advanceToNextBlock = true; - }; - table.insert(self.blocks, block); - return block; -end - -function Compiler:setActiveBlock(block) - self.activeBlock = block; +function Compiler:pushRegisterUsageInfo() + table.insert(self.registerUsageStack, { + usedRegisters = self.usedRegisters; + registers = self.registers; + }); + self.usedRegisters = 0; + self.registers = {}; end -function Compiler:addStatement(statement, writes, reads, usesUpvals) - if(self.activeBlock.advanceToNextBlock) then - table.insert(self.activeBlock.statements, { - statement = statement, - writes = lookupify(writes), - reads = lookupify(reads), - usesUpvals = usesUpvals or false, - }); - end +function Compiler:popRegisterUsageInfo() + local info = table.remove(self.registerUsageStack); + self.usedRegisters = info.usedRegisters; + self.registers = info.registers; end function Compiler:compile(ast) @@ -152,13 +136,11 @@ function Compiler:compile(ast) self.detectGcCollectVar = self.containerFuncScope:addVariable(); self.returnVar = self.containerFuncScope:addVariable(); - -- Upvalues Handling self.upvaluesTable = self.scope:addVariable(); self.upvaluesReferenceCountsTable = self.scope:addVariable(); self.allocUpvalFunction = self.scope:addVariable(); self.currentUpvalId = self.scope:addVariable(); - -- Gc Handling for Upvalues self.upvaluesProxyFunctionVar = self.scope:addVariable(); self.upvaluesGcFunctionVar = self.scope:addVariable(); self.freeUpvalueFunc = self.scope:addVariable(); @@ -174,7 +156,7 @@ function Compiler:compile(ast) local createClosureSubScope = Scope:new(createClosureScope); local upvalEntries = {}; - local upvalueIds = {}; + local upvalueIds = {}; self.getUpvalueId = function(self, scope, id) local expression; local scopeFuncDepth = self.scopeFunctionDepths[scope]; @@ -184,7 +166,7 @@ function Compiler:compile(ast) end expression = Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {}); else - logger:error("Unresolved Upvalue, this error should not occur!"); + require("logger"):error("Unresolved Upvalue, this error should not occur!"); end table.insert(upvalEntries, Ast.TableEntry(expression)); local uid = #upvalEntries; @@ -192,14 +174,12 @@ function Compiler:compile(ast) return uid; end - -- Reference to Higher Scopes createClosureSubScope:addReferenceToHigherScope(self.scope, self.containerFuncVar); createClosureSubScope:addReferenceToHigherScope(createClosureScope, createClosurePosArg) createClosureSubScope:addReferenceToHigherScope(createClosureScope, createClosureUpvalsArg, 1) createClosureScope:addReferenceToHigherScope(self.scope, self.upvaluesProxyFunctionVar) createClosureSubScope:addReferenceToHigherScope(createClosureScope, createClosureProxyObject); - -- Invoke Compiler self:compileTopNode(ast); local functionNodeAssignments = { @@ -234,7 +214,7 @@ function Compiler:compile(ast) Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.containerFuncVar), { Ast.VariableExpression(createClosureScope, createClosurePosArg), Ast.TableConstructorExpression({Ast.TableEntry(Ast.VarargExpression())}), - Ast.VariableExpression(createClosureScope, createClosureUpvalsArg), -- Upvalues + Ast.VariableExpression(createClosureScope, createClosureUpvalsArg), Ast.VariableExpression(createClosureScope, createClosureProxyObject) }) } @@ -291,7 +271,6 @@ function Compiler:compile(ast) assignmentStatRhs[i] = v.val; end - -- Emit Code local functionNode = Ast.FunctionLiteralExpression({ Ast.VariableExpression(self.scope, self.envVar), Ast.VariableExpression(self.scope, self.unpackVar), @@ -368,7 +347,7 @@ function Compiler:getCreateClosureVar(argCount) Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.containerFuncVar), { Ast.VariableExpression(createClosureScope, createClosurePosArg), Ast.TableConstructorExpression(argsTb2), - Ast.VariableExpression(createClosureScope, createClosureUpvalsArg), -- Upvalues + Ast.VariableExpression(createClosureScope, createClosureUpvalsArg), Ast.VariableExpression(createClosureScope, createClosureProxyObject) }) } @@ -389,1988 +368,4 @@ function Compiler:getCreateClosureVar(argCount) return var.scope, var.id; end -function Compiler:pushRegisterUsageInfo() - table.insert(self.registerUsageStack, { - usedRegisters = self.usedRegisters; - registers = self.registers; - }); - self.usedRegisters = 0; - self.registers = {}; -end - -function Compiler:popRegisterUsageInfo() - local info = table.remove(self.registerUsageStack); - self.usedRegisters = info.usedRegisters; - self.registers = info.registers; -end - -function Compiler:createUpvaluesGcFunc() - local scope = Scope:new(self.scope); - local selfVar = scope:addVariable(); - - local iteratorVar = scope:addVariable(); - local valueVar = scope:addVariable(); - - local whileScope = Scope:new(scope); - whileScope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 3); - whileScope:addReferenceToHigherScope(scope, valueVar, 3); - whileScope:addReferenceToHigherScope(scope, iteratorVar, 3); - - local ifScope = Scope:new(whileScope); - ifScope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 1); - ifScope:addReferenceToHigherScope(self.scope, self.upvaluesTable, 1); - - - return Ast.FunctionLiteralExpression({Ast.VariableExpression(scope, selfVar)}, Ast.Block({ - Ast.LocalVariableDeclaration(scope, {iteratorVar, valueVar}, {Ast.NumberExpression(1), Ast.IndexExpression(Ast.VariableExpression(scope, selfVar), Ast.NumberExpression(1))}), - Ast.WhileStatement(Ast.Block({ - Ast.AssignmentStatement({ - Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)), - Ast.AssignmentVariable(scope, iteratorVar), - }, { - Ast.SubExpression(Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)), Ast.NumberExpression(1)), - Ast.AddExpression(unpack(util.shuffle{Ast.VariableExpression(scope, iteratorVar), Ast.NumberExpression(1)})), - }), - Ast.IfStatement(Ast.EqualsExpression(unpack(util.shuffle{Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)), Ast.NumberExpression(0)})), Ast.Block({ - Ast.AssignmentStatement({ - Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)), - Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), Ast.VariableExpression(scope, valueVar)), - }, { - Ast.NilExpression(), - Ast.NilExpression(), - }) - }, ifScope), {}, nil), - Ast.AssignmentStatement({ - Ast.AssignmentVariable(scope, valueVar), - }, { - Ast.IndexExpression(Ast.VariableExpression(scope, selfVar), Ast.VariableExpression(scope, iteratorVar)), - }), - }, whileScope), Ast.VariableExpression(scope, valueVar), scope); - }, scope)); -end - -function Compiler:createFreeUpvalueFunc() - local scope = Scope:new(self.scope); - local argVar = scope:addVariable(); - local ifScope = Scope:new(scope); - ifScope:addReferenceToHigherScope(scope, argVar, 3); - scope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 2); - return Ast.FunctionLiteralExpression({Ast.VariableExpression(scope, argVar)}, Ast.Block({ - Ast.AssignmentStatement({ - Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)) - }, { - Ast.SubExpression(Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)), Ast.NumberExpression(1)); - }), - Ast.IfStatement(Ast.EqualsExpression(unpack(util.shuffle{Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)), Ast.NumberExpression(0)})), Ast.Block({ - Ast.AssignmentStatement({ - Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)), - Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), Ast.VariableExpression(scope, argVar)), - }, { - Ast.NilExpression(), - Ast.NilExpression(), - }) - }, ifScope), {}, nil) - }, scope)) -end - -function Compiler:createUpvaluesProxyFunc() - local scope = Scope:new(self.scope); - scope:addReferenceToHigherScope(self.scope, self.newproxyVar); - - local entriesVar = scope:addVariable(); - - local ifScope = Scope:new(scope); - local proxyVar = ifScope:addVariable(); - local metatableVar = ifScope:addVariable(); - local elseScope = Scope:new(scope); - ifScope:addReferenceToHigherScope(self.scope, self.newproxyVar); - ifScope:addReferenceToHigherScope(self.scope, self.getmetatableVar); - ifScope:addReferenceToHigherScope(self.scope, self.upvaluesGcFunctionVar); - ifScope:addReferenceToHigherScope(scope, entriesVar); - elseScope:addReferenceToHigherScope(self.scope, self.setmetatableVar); - elseScope:addReferenceToHigherScope(scope, entriesVar); - elseScope:addReferenceToHigherScope(self.scope, self.upvaluesGcFunctionVar); - - local forScope = Scope:new(scope); - local forArg = forScope:addVariable(); - forScope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 2); - forScope:addReferenceToHigherScope(scope, entriesVar, 2); - - return Ast.FunctionLiteralExpression({Ast.VariableExpression(scope, entriesVar)}, Ast.Block({ - Ast.ForStatement(forScope, forArg, Ast.NumberExpression(1), Ast.LenExpression(Ast.VariableExpression(scope, entriesVar)), Ast.NumberExpression(1), Ast.Block({ - Ast.AssignmentStatement({ - Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.IndexExpression(Ast.VariableExpression(scope, entriesVar), Ast.VariableExpression(forScope, forArg))) - }, { - Ast.AddExpression(unpack(util.shuffle{ - Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.IndexExpression(Ast.VariableExpression(scope, entriesVar), Ast.VariableExpression(forScope, forArg))), - Ast.NumberExpression(1), - })) - }) - }, forScope), scope); - Ast.IfStatement(Ast.VariableExpression(self.scope, self.newproxyVar), Ast.Block({ - Ast.LocalVariableDeclaration(ifScope, {proxyVar}, { - Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.newproxyVar), { - Ast.BooleanExpression(true) - }); - }); - Ast.LocalVariableDeclaration(ifScope, {metatableVar}, { - Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.getmetatableVar), { - Ast.VariableExpression(ifScope, proxyVar); - }); - }); - Ast.AssignmentStatement({ - Ast.AssignmentIndexing(Ast.VariableExpression(ifScope, metatableVar), Ast.StringExpression("__index")), - Ast.AssignmentIndexing(Ast.VariableExpression(ifScope, metatableVar), Ast.StringExpression("__gc")), - Ast.AssignmentIndexing(Ast.VariableExpression(ifScope, metatableVar), Ast.StringExpression("__len")), - }, { - Ast.VariableExpression(scope, entriesVar), - Ast.VariableExpression(self.scope, self.upvaluesGcFunctionVar), - Ast.FunctionLiteralExpression({}, Ast.Block({ - Ast.ReturnStatement({Ast.NumberExpression(self.upvalsProxyLenReturn)}) - }, Scope:new(ifScope))); - }); - Ast.ReturnStatement({ - Ast.VariableExpression(ifScope, proxyVar) - }) - }, ifScope), {}, Ast.Block({ - Ast.ReturnStatement({Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.setmetatableVar), { - Ast.TableConstructorExpression({}), - Ast.TableConstructorExpression({ - Ast.KeyedTableEntry(Ast.StringExpression("__gc"), Ast.VariableExpression(self.scope, self.upvaluesGcFunctionVar)), - Ast.KeyedTableEntry(Ast.StringExpression("__index"), Ast.VariableExpression(scope, entriesVar)), - Ast.KeyedTableEntry(Ast.StringExpression("__len"), Ast.FunctionLiteralExpression({}, Ast.Block({ - Ast.ReturnStatement({Ast.NumberExpression(self.upvalsProxyLenReturn)}) - }, Scope:new(ifScope)))), - }) - })}) - }, elseScope)); - }, scope)); -end - -function Compiler:createAllocUpvalFunction() - local scope = Scope:new(self.scope); - scope:addReferenceToHigherScope(self.scope, self.currentUpvalId, 4); - scope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 1); - - return Ast.FunctionLiteralExpression({}, Ast.Block({ - Ast.AssignmentStatement({ - Ast.AssignmentVariable(self.scope, self.currentUpvalId), - },{ - Ast.AddExpression(unpack(util.shuffle({ - Ast.VariableExpression(self.scope, self.currentUpvalId), - Ast.NumberExpression(1), - }))), - } - ), - Ast.AssignmentStatement({ - Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(self.scope, self.currentUpvalId)), - }, { - Ast.NumberExpression(1), - }), - Ast.ReturnStatement({ - Ast.VariableExpression(self.scope, self.currentUpvalId), - }) - }, scope)); -end - -function Compiler:emitContainerFuncBody() - local blocks = {}; - - util.shuffle(self.blocks); - - for _, block in ipairs(self.blocks) do - local id = block.id; - local blockstats = block.statements; - - -- Shuffle Blockstats - for i = 2, #blockstats do - local stat = blockstats[i]; - local reads = stat.reads; - local writes = stat.writes; - local maxShift = 0; - local usesUpvals = stat.usesUpvals; - for shift = 1, i - 1 do - local stat2 = blockstats[i - shift]; - - if stat2.usesUpvals and usesUpvals then - break; - end - - local reads2 = stat2.reads; - local writes2 = stat2.writes; - local f = true; - - for r, b in pairs(reads2) do - if(writes[r]) then - f = false; - break; - end - end - - if f then - for r, b in pairs(writes2) do - if(writes[r]) then - f = false; - break; - end - if(reads[r]) then - f = false; - break; - end - end - end - - if not f then - break - end - - maxShift = shift; - end - - local shift = math.random(0, maxShift); - for j = 1, shift do - blockstats[i - j], blockstats[i - j + 1] = blockstats[i - j + 1], blockstats[i - j]; - end - end - - blockstats = {}; - for i, stat in ipairs(block.statements) do - table.insert(blockstats, stat.statement); - end - - table.insert(blocks, { id = id, block = Ast.Block(blockstats, block.scope) }); - end - - table.sort(blocks, function(a, b) - return a.id < b.id; - end); - - local function buildIfBlock(scope, id, lBlock, rBlock) - return Ast.Block({ - Ast.IfStatement(Ast.LessThanExpression(self:pos(scope), Ast.NumberExpression(id)), lBlock, {}, rBlock); - }, scope); - end - - local function buildWhileBody(tb, l, r, pScope, scope) - local len = r - l + 1; - if len == 1 then - tb[r].block.scope:setParent(pScope); - return tb[r].block; - elseif len == 0 then - return nil; - end - - local mid = l + math.ceil(len / 2); - local bound = math.random(tb[mid - 1].id + 1, tb[mid].id); - local ifScope = scope or Scope:new(pScope); - - local lBlock = buildWhileBody(tb, l, mid - 1, ifScope); - local rBlock = buildWhileBody(tb, mid, r, ifScope); - - return buildIfBlock(ifScope, bound, lBlock, rBlock); - end - - local whileBody = buildWhileBody(blocks, 1, #blocks, self.containerFuncScope, self.whileScope); - - self.whileScope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar, 1); - self.whileScope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); - - self.containerFuncScope:addReferenceToHigherScope(self.scope, self.unpackVar); - - local declarations = { - self.returnVar, - } - - for i, var in pairs(self.registerVars) do - if(i ~= MAX_REGS) then - table.insert(declarations, var); - end - end - - local stats = { - Ast.LocalVariableDeclaration(self.containerFuncScope, util.shuffle(declarations), {}); - Ast.WhileStatement(whileBody, Ast.VariableExpression(self.containerFuncScope, self.posVar)); - Ast.AssignmentStatement({ - Ast.AssignmentVariable(self.containerFuncScope, self.posVar) - }, { - Ast.LenExpression(Ast.VariableExpression(self.containerFuncScope, self.detectGcCollectVar)) - }), - Ast.ReturnStatement{ - Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.unpackVar), { - Ast.VariableExpression(self.containerFuncScope, self.returnVar) - }); - } - } - - if self.maxUsedRegister >= MAX_REGS then - table.insert(stats, 1, Ast.LocalVariableDeclaration(self.containerFuncScope, {self.registerVars[MAX_REGS]}, {Ast.TableConstructorExpression({})})); - end - - return Ast.Block(stats, self.containerFuncScope); -end - -function Compiler:freeRegister(id, force) - if force or not (self.registers[id] == self.VAR_REGISTER) then - self.usedRegisters = self.usedRegisters - 1; - self.registers[id] = false - end -end - -function Compiler:isVarRegister(id) - return self.registers[id] == self.VAR_REGISTER; -end - -function Compiler:allocRegister(isVar) - self.usedRegisters = self.usedRegisters + 1; - - if not isVar then - -- POS register can be temporarily used - if not self.registers[self.POS_REGISTER] then - self.registers[self.POS_REGISTER] = true; - return self.POS_REGISTER; - end - - -- RETURN register can be temporarily used - if not self.registers[self.RETURN_REGISTER] then - self.registers[self.RETURN_REGISTER] = true; - return self.RETURN_REGISTER; - end - end - - - local id = 0; - if self.usedRegisters < MAX_REGS * MAX_REGS_MUL then - repeat - id = math.random(1, MAX_REGS - 1); - until not self.registers[id]; - else - repeat - id = id + 1; - until not self.registers[id]; - end - - if id > self.maxUsedRegister then - self.maxUsedRegister = id; - end - - if(isVar) then - self.registers[id] = self.VAR_REGISTER; - else - self.registers[id] = true - end - return id; -end - -function Compiler:isUpvalue(scope, id) - return self.upvalVars[scope] and self.upvalVars[scope][id]; -end - -function Compiler:makeUpvalue(scope, id) - if(not self.upvalVars[scope]) then - self.upvalVars[scope] = {} - end - self.upvalVars[scope][id] = true; -end - -function Compiler:getVarRegister(scope, id, functionDepth, potentialId) - if(not self.registersForVar[scope]) then - self.registersForVar[scope] = {}; - self.scopeFunctionDepths[scope] = functionDepth; - end - - local reg = self.registersForVar[scope][id]; - if not reg then - if potentialId and self.registers[potentialId] ~= self.VAR_REGISTER and potentialId ~= self.POS_REGISTER and potentialId ~= self.RETURN_REGISTER then - self.registers[potentialId] = self.VAR_REGISTER; - reg = potentialId; - else - reg = self:allocRegister(true); - end - self.registersForVar[scope][id] = reg; - end - return reg; -end - -function Compiler:getRegisterVarId(id) - local varId = self.registerVars[id]; - if not varId then - varId = self.containerFuncScope:addVariable(); - self.registerVars[id] = varId; - end - return varId; -end - --- Maybe convert ids to strings -function Compiler:register(scope, id) - if id == self.POS_REGISTER then - return self:pos(scope); - end - - if id == self.RETURN_REGISTER then - return self:getReturn(scope); - end - - if id < MAX_REGS then - local vid = self:getRegisterVarId(id); - scope:addReferenceToHigherScope(self.containerFuncScope, vid); - return Ast.VariableExpression(self.containerFuncScope, vid); - end - - local vid = self:getRegisterVarId(MAX_REGS); - scope:addReferenceToHigherScope(self.containerFuncScope, vid); - return Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, vid), Ast.NumberExpression((id - MAX_REGS) + 1)); -end - -function Compiler:registerList(scope, ids) - local l = {}; - for i, id in ipairs(ids) do - table.insert(l, self:register(scope, id)); - end - return l; -end - -function Compiler:registerAssignment(scope, id) - if id == self.POS_REGISTER then - return self:posAssignment(scope); - end - if id == self.RETURN_REGISTER then - return self:returnAssignment(scope); - end - - if id < MAX_REGS then - local vid = self:getRegisterVarId(id); - scope:addReferenceToHigherScope(self.containerFuncScope, vid); - return Ast.AssignmentVariable(self.containerFuncScope, vid); - end - - local vid = self:getRegisterVarId(MAX_REGS); - scope:addReferenceToHigherScope(self.containerFuncScope, vid); - return Ast.AssignmentIndexing(Ast.VariableExpression(self.containerFuncScope, vid), Ast.NumberExpression((id - MAX_REGS) + 1)); -end - --- Maybe convert ids to strings -function Compiler:setRegister(scope, id, val, compundArg) - if(compundArg) then - return compundArg(self:registerAssignment(scope, id), val); - end - return Ast.AssignmentStatement({ - self:registerAssignment(scope, id) - }, { - val - }); -end - -function Compiler:setRegisters(scope, ids, vals) - local idStats = {}; - for i, id in ipairs(ids) do - table.insert(idStats, self:registerAssignment(scope, id)); - end - - return Ast.AssignmentStatement(idStats, vals); -end - -function Compiler:copyRegisters(scope, to, from) - local idStats = {}; - local vals = {}; - for i, id in ipairs(to) do - local from = from[i]; - if(from ~= id) then - table.insert(idStats, self:registerAssignment(scope, id)); - table.insert(vals, self:register(scope, from)); - end - end - - if(#idStats > 0 and #vals > 0) then - return Ast.AssignmentStatement(idStats, vals); - end -end - -function Compiler:resetRegisters() - self.registers = {}; -end - -function Compiler:pos(scope) - scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); - return Ast.VariableExpression(self.containerFuncScope, self.posVar); -end - -function Compiler:posAssignment(scope) - scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); - return Ast.AssignmentVariable(self.containerFuncScope, self.posVar); -end - -function Compiler:args(scope) - scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar); - return Ast.VariableExpression(self.containerFuncScope, self.argsVar); -end - -function Compiler:unpack(scope) - scope:addReferenceToHigherScope(self.scope, self.unpackVar); - return Ast.VariableExpression(self.scope, self.unpackVar); -end - -function Compiler:env(scope) - scope:addReferenceToHigherScope(self.scope, self.envVar); - return Ast.VariableExpression(self.scope, self.envVar); -end - -function Compiler:jmp(scope, to) - scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); - return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.posVar)},{to}); -end - -function Compiler:setPos(scope, val) - if not val then - - local v = Ast.IndexExpression(self:env(scope), randomStrings.randomStringNode(math.random(12, 14))); --Ast.NilExpression(); - scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); - return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.posVar)}, {v}); - end - scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); - return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.posVar)}, {Ast.NumberExpression(val) or Ast.NilExpression()}); -end - -function Compiler:setReturn(scope, val) - scope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar); - return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.returnVar)}, {val}); -end - -function Compiler:getReturn(scope) - scope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar); - return Ast.VariableExpression(self.containerFuncScope, self.returnVar); -end - -function Compiler:returnAssignment(scope) - scope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar); - return Ast.AssignmentVariable(self.containerFuncScope, self.returnVar); -end - -function Compiler:setUpvalueMember(scope, idExpr, valExpr, compoundConstructor) - scope:addReferenceToHigherScope(self.scope, self.upvaluesTable); - if compoundConstructor then - return compoundConstructor(Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), idExpr), valExpr); - end - return Ast.AssignmentStatement({Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), idExpr)}, {valExpr}); -end - -function Compiler:getUpvalueMember(scope, idExpr) - scope:addReferenceToHigherScope(self.scope, self.upvaluesTable); - return Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesTable), idExpr); -end - -function Compiler:compileTopNode(node) - -- Create Initial Block - local startBlock = self:createBlock(); - local scope = startBlock.scope; - self.startBlockId = startBlock.id; - self:setActiveBlock(startBlock); - - local varAccessLookup = lookupify{ - AstKind.AssignmentVariable, - AstKind.VariableExpression, - AstKind.FunctionDeclaration, - AstKind.LocalFunctionDeclaration, - } - - local functionLookup = lookupify{ - AstKind.FunctionDeclaration, - AstKind.LocalFunctionDeclaration, - AstKind.FunctionLiteralExpression, - AstKind.TopNode, - } - -- Collect Upvalues - visitast(node, function(node, data) - if node.kind == AstKind.Block then - node.scope.__depth = data.functionData.depth; - end - - if varAccessLookup[node.kind] then - if not node.scope.isGlobal then - if node.scope.__depth < data.functionData.depth then - if not self:isUpvalue(node.scope, node.id) then - self:makeUpvalue(node.scope, node.id); - end - end - end - end - end, nil, nil) - - self.varargReg = self:allocRegister(true); - scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar); - scope:addReferenceToHigherScope(self.scope, self.selectVar); - scope:addReferenceToHigherScope(self.scope, self.unpackVar); - self:addStatement(self:setRegister(scope, self.varargReg, Ast.VariableExpression(self.containerFuncScope, self.argsVar)), {self.varargReg}, {}, false); - - -- Compile Block - self:compileBlock(node.body, 0); - if(self.activeBlock.advanceToNextBlock) then - self:addStatement(self:setPos(self.activeBlock.scope, nil), {self.POS_REGISTER}, {}, false); - self:addStatement(self:setReturn(self.activeBlock.scope, Ast.TableConstructorExpression({})), {self.RETURN_REGISTER}, {}, false) - self.activeBlock.advanceToNextBlock = false; - end - - self:resetRegisters(); -end - -function Compiler:compileFunction(node, funcDepth) - funcDepth = funcDepth + 1; - local oldActiveBlock = self.activeBlock; - - local upperVarargReg = self.varargReg; - self.varargReg = nil; - - local upvalueExpressions = {}; - local upvalueIds = {}; - local usedRegs = {}; - - local oldGetUpvalueId = self.getUpvalueId; - self.getUpvalueId = function(self, scope, id) - if(not upvalueIds[scope]) then - upvalueIds[scope] = {}; - end - if(upvalueIds[scope][id]) then - return upvalueIds[scope][id]; - end - local scopeFuncDepth = self.scopeFunctionDepths[scope]; - local expression; - if(scopeFuncDepth == funcDepth) then - oldActiveBlock.scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); - expression = Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {}); - elseif(scopeFuncDepth == funcDepth - 1) then - local varReg = self:getVarRegister(scope, id, scopeFuncDepth, nil); - expression = self:register(oldActiveBlock.scope, varReg); - table.insert(usedRegs, varReg); - else - local higherId = oldGetUpvalueId(self, scope, id); - oldActiveBlock.scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); - expression = Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(higherId)); - end - table.insert(upvalueExpressions, Ast.TableEntry(expression)); - local uid = #upvalueExpressions; - upvalueIds[scope][id] = uid; - return uid; - end - - local block = self:createBlock(); - self:setActiveBlock(block); - local scope = self.activeBlock.scope; - self:pushRegisterUsageInfo(); - for i, arg in ipairs(node.args) do - if(arg.kind == AstKind.VariableExpression) then - if(self:isUpvalue(arg.scope, arg.id)) then - scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); - local argReg = self:getVarRegister(arg.scope, arg.id, funcDepth, nil); - self:addStatement(self:setRegister(scope, argReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {argReg}, {}, false); - self:addStatement(self:setUpvalueMember(scope, self:register(scope, argReg), Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.argsVar), Ast.NumberExpression(i))), {}, {argReg}, true); - else - local argReg = self:getVarRegister(arg.scope, arg.id, funcDepth, nil); - scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar); - self:addStatement(self:setRegister(scope, argReg, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.argsVar), Ast.NumberExpression(i))), {argReg}, {}, false); - end - else - self.varargReg = self:allocRegister(true); - scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar); - scope:addReferenceToHigherScope(self.scope, self.selectVar); - scope:addReferenceToHigherScope(self.scope, self.unpackVar); - self:addStatement(self:setRegister(scope, self.varargReg, Ast.TableConstructorExpression({ - Ast.TableEntry(Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.selectVar), { - Ast.NumberExpression(i); - Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.unpackVar), { - Ast.VariableExpression(self.containerFuncScope, self.argsVar), - }); - })), - })), {self.varargReg}, {}, false); - end - end - - self:compileBlock(node.body, funcDepth); - if(self.activeBlock.advanceToNextBlock) then - self:addStatement(self:setPos(self.activeBlock.scope, nil), {self.POS_REGISTER}, {}, false); - self:addStatement(self:setReturn(self.activeBlock.scope, Ast.TableConstructorExpression({})), {self.RETURN_REGISTER}, {}, false); - self.activeBlock.advanceToNextBlock = false; - end - - if(self.varargReg) then - self:freeRegister(self.varargReg, true); - end - self.varargReg = upperVarargReg; - self.getUpvalueId = oldGetUpvalueId; - - self:popRegisterUsageInfo(); - self:setActiveBlock(oldActiveBlock); - - local scope = self.activeBlock.scope; - - local retReg = self:allocRegister(false); - - local isVarargFunction = #node.args > 0 and node.args[#node.args].kind == AstKind.VarargExpression; - - local retrieveExpression - if isVarargFunction then - scope:addReferenceToHigherScope(self.scope, self.createVarargClosureVar); - retrieveExpression = Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.createVarargClosureVar), { - Ast.NumberExpression(block.id), - Ast.TableConstructorExpression(upvalueExpressions) - }); - else - local varScope, var = self:getCreateClosureVar(#node.args + math.random(0, 5)); - scope:addReferenceToHigherScope(varScope, var); - retrieveExpression = Ast.FunctionCallExpression(Ast.VariableExpression(varScope, var), { - Ast.NumberExpression(block.id), - Ast.TableConstructorExpression(upvalueExpressions) - }); - end - - self:addStatement(self:setRegister(scope, retReg, retrieveExpression), {retReg}, usedRegs, false); - return retReg; -end - -function Compiler:compileBlock(block, funcDepth) - for i, stat in ipairs(block.statements) do - self:compileStatement(stat, funcDepth); - end - - local scope = self.activeBlock.scope; - for id, name in ipairs(block.scope.variables) do - local varReg = self:getVarRegister(block.scope, id, funcDepth, nil); - if self:isUpvalue(block.scope, id) then - scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc); - self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), { - self:register(scope, varReg) - })), {varReg}, {varReg}, false); - else - self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), {varReg}, {}, false); - end - self:freeRegister(varReg, true); - end -end - -function Compiler:compileStatement(statement, funcDepth) - local scope = self.activeBlock.scope; - -- Return Statement - if(statement.kind == AstKind.ReturnStatement) then - local entries = {}; - local regs = {}; - - for i, expr in ipairs(statement.args) do - if i == #statement.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then - local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1]; - table.insert(entries, Ast.TableEntry(Ast.FunctionCallExpression( - self:unpack(scope), - {self:register(scope, reg)}))); - table.insert(regs, reg); - else - local reg = self:compileExpression(expr, funcDepth, 1)[1]; - table.insert(entries, Ast.TableEntry(self:register(scope, reg))); - table.insert(regs, reg); - end - end - - for _, reg in ipairs(regs) do - self:freeRegister(reg, false); - end - - self:addStatement(self:setReturn(scope, Ast.TableConstructorExpression(entries)), {self.RETURN_REGISTER}, regs, false); - self:addStatement(self:setPos(self.activeBlock.scope, nil), {self.POS_REGISTER}, {}, false); - self.activeBlock.advanceToNextBlock = false; - return; - end - - -- Local Variable Declaration - if(statement.kind == AstKind.LocalVariableDeclaration) then - local exprregs = {}; - for i, expr in ipairs(statement.expressions) do - if(i == #statement.expressions and #statement.ids > #statement.expressions) then - local regs = self:compileExpression(expr, funcDepth, #statement.ids - #statement.expressions + 1); - for i, reg in ipairs(regs) do - table.insert(exprregs, reg); - end - else - if statement.ids[i] or expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression then - local reg = self:compileExpression(expr, funcDepth, 1)[1]; - table.insert(exprregs, reg); - end - end - end - - if #exprregs == 0 then - for i=1, #statement.ids do - table.insert(exprregs, self:compileExpression(Ast.NilExpression(), funcDepth, 1)[1]); - end - end - - for i, id in ipairs(statement.ids) do - if(exprregs[i]) then - if(self:isUpvalue(statement.scope, id)) then - local varreg = self:getVarRegister(statement.scope, id, funcDepth); - local varReg = self:getVarRegister(statement.scope, id, funcDepth, nil); - scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); - self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {varReg}, {}, false); - self:addStatement(self:setUpvalueMember(scope, self:register(scope, varReg), self:register(scope, exprregs[i])), {}, {varReg, exprregs[i]}, true); - self:freeRegister(exprregs[i], false); - else - local varreg = self:getVarRegister(statement.scope, id, funcDepth, exprregs[i]); - self:addStatement(self:copyRegisters(scope, {varreg}, {exprregs[i]}), {varreg}, {exprregs[i]}, false); - self:freeRegister(exprregs[i], false); - end - end - end - - if not self.scopeFunctionDepths[statement.scope] then - self.scopeFunctionDepths[statement.scope] = funcDepth; - end - - return; - end - - -- Function Call Statement - if(statement.kind == AstKind.FunctionCallStatement) then - local baseReg = self:compileExpression(statement.base, funcDepth, 1)[1]; - local retReg = self:allocRegister(false); - local regs = {}; - local args = {}; - - for i, expr in ipairs(statement.args) do - if i == #statement.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then - local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1]; - table.insert(args, Ast.FunctionCallExpression( - self:unpack(scope), - {self:register(scope, reg)})); - table.insert(regs, reg); - else - local reg = self:compileExpression(expr, funcDepth, 1)[1]; - table.insert(args, self:register(scope, reg)); - table.insert(regs, reg); - end - end - - self:addStatement(self:setRegister(scope, retReg, Ast.FunctionCallExpression(self:register(scope, baseReg), args)), {retReg}, {baseReg, unpack(regs)}, true); - self:freeRegister(baseReg, false); - self:freeRegister(retReg, false); - for i, reg in ipairs(regs) do - self:freeRegister(reg, false); - end - - return; - end - - -- Pass Self Function Call Statement - if(statement.kind == AstKind.PassSelfFunctionCallStatement) then - local baseReg = self:compileExpression(statement.base, funcDepth, 1)[1]; - local tmpReg = self:allocRegister(false); - local args = { self:register(scope, baseReg) }; - local regs = { baseReg }; - - for i, expr in ipairs(statement.args) do - if i == #statement.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then - local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1]; - table.insert(args, Ast.FunctionCallExpression( - self:unpack(scope), - {self:register(scope, reg)})); - table.insert(regs, reg); - else - local reg = self:compileExpression(expr, funcDepth, 1)[1]; - table.insert(args, self:register(scope, reg)); - table.insert(regs, reg); - end - end - self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(statement.passSelfFunctionName)), {tmpReg}, {}, false); - self:addStatement(self:setRegister(scope, tmpReg, Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, tmpReg))), {tmpReg}, {tmpReg, baseReg}, false); - - self:addStatement(self:setRegister(scope, tmpReg, Ast.FunctionCallExpression(self:register(scope, tmpReg), args)), {tmpReg}, {tmpReg, unpack(regs)}, true); - - self:freeRegister(tmpReg, false); - for i, reg in ipairs(regs) do - self:freeRegister(reg, false); - end - - return; - end - - -- Local Function Declaration - if(statement.kind == AstKind.LocalFunctionDeclaration) then - - if(self:isUpvalue(statement.scope, statement.id)) then - local varReg = self:getVarRegister(statement.scope, statement.id, funcDepth, nil); - scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); - self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {varReg}, {}, false); - local retReg = self:compileFunction(statement, funcDepth); - self:addStatement(self:setUpvalueMember(scope, self:register(scope, varReg), self:register(scope, retReg)), {}, {varReg, retReg}, true); - self:freeRegister(retReg, false); - else - local retReg = self:compileFunction(statement, funcDepth); - local varReg = self:getVarRegister(statement.scope, statement.id, funcDepth, retReg); - self:addStatement(self:copyRegisters(scope, {varReg}, {retReg}), {varReg}, {retReg}, false); - self:freeRegister(retReg, false); - end - return; - end - - -- Function Declaration - if(statement.kind == AstKind.FunctionDeclaration) then - local retReg = self:compileFunction(statement, funcDepth); - if(#statement.indices > 0) then - local tblReg; - if statement.scope.isGlobal then - tblReg = self:allocRegister(false); - self:addStatement(self:setRegister(scope, tblReg, Ast.StringExpression(statement.scope:getVariableName(statement.id))), {tblReg}, {}, false); - self:addStatement(self:setRegister(scope, tblReg, Ast.IndexExpression(self:env(scope), self:register(scope, tblReg))), {tblReg}, {tblReg}, true); - else - if self.scopeFunctionDepths[statement.scope] == funcDepth then - if self:isUpvalue(statement.scope, statement.id) then - tblReg = self:allocRegister(false); - local reg = self:getVarRegister(statement.scope, statement.id, funcDepth); - self:addStatement(self:setRegister(scope, tblReg, self:getUpvalueMember(scope, self:register(scope, reg))), {tblReg}, {reg}, true); - else - tblReg = self:getVarRegister(statement.scope, statement.id, funcDepth, retReg); - end - else - tblReg = self:allocRegister(false); - local upvalId = self:getUpvalueId(statement.scope, statement.id); - scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); - self:addStatement(self:setRegister(scope, tblReg, self:getUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)))), {tblReg}, {}, true); - end - end - - for i = 1, #statement.indices - 1 do - local index = statement.indices[i]; - local indexReg = self:compileExpression(Ast.StringExpression(index), funcDepth, 1)[1]; - local tblRegOld = tblReg; - tblReg = self:allocRegister(false); - self:addStatement(self:setRegister(scope, tblReg, Ast.IndexExpression(self:register(scope, tblRegOld), self:register(scope, indexReg))), {tblReg}, {tblReg, indexReg}, false); - self:freeRegister(tblRegOld, false); - self:freeRegister(indexReg, false); - end - - local index = statement.indices[#statement.indices]; - local indexReg = self:compileExpression(Ast.StringExpression(index), funcDepth, 1)[1]; - self:addStatement(Ast.AssignmentStatement({ - Ast.AssignmentIndexing(self:register(scope, tblReg), self:register(scope, indexReg)), - }, { - self:register(scope, retReg), - }), {}, {tblReg, indexReg, retReg}, true); - self:freeRegister(indexReg, false); - self:freeRegister(tblReg, false); - self:freeRegister(retReg, false); - - return; - end - if statement.scope.isGlobal then - local tmpReg = self:allocRegister(false); - self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(statement.scope:getVariableName(statement.id))), {tmpReg}, {}, false); - self:addStatement(Ast.AssignmentStatement({Ast.AssignmentIndexing(self:env(scope), self:register(scope, tmpReg))}, - {self:register(scope, retReg)}), {}, {tmpReg, retReg}, true); - self:freeRegister(tmpReg, false); - else - if self.scopeFunctionDepths[statement.scope] == funcDepth then - if self:isUpvalue(statement.scope, statement.id) then - local reg = self:getVarRegister(statement.scope, statement.id, funcDepth); - self:addStatement(self:setUpvalueMember(scope, self:register(scope, reg), self:register(scope, retReg)), {}, {reg, retReg}, true); - else - local reg = self:getVarRegister(statement.scope, statement.id, funcDepth, retReg); - if reg ~= retReg then - self:addStatement(self:setRegister(scope, reg, self:register(scope, retReg)), {reg}, {retReg}, false); - end - end - else - local upvalId = self:getUpvalueId(statement.scope, statement.id); - scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); - self:addStatement(self:setUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)), self:register(scope, retReg)), {}, {retReg}, true); - end - end - self:freeRegister(retReg, false); - return; - end - - -- Assignment Statement - if(statement.kind == AstKind.AssignmentStatement) then - local exprregs = {}; - local assignmentIndexingRegs = {}; - for i, primaryExpr in ipairs(statement.lhs) do - if(primaryExpr.kind == AstKind.AssignmentIndexing) then - assignmentIndexingRegs [i] = { - base = self:compileExpression(primaryExpr.base, funcDepth, 1)[1], - index = self:compileExpression(primaryExpr.index, funcDepth, 1)[1], - }; - end - end - - for i, expr in ipairs(statement.rhs) do - if(i == #statement.rhs and #statement.lhs > #statement.rhs) then - local regs = self:compileExpression(expr, funcDepth, #statement.lhs - #statement.rhs + 1); - - for i, reg in ipairs(regs) do - if(self:isVarRegister(reg)) then - local ro = reg; - reg = self:allocRegister(false); - self:addStatement(self:copyRegisters(scope, {reg}, {ro}), {reg}, {ro}, false); - end - table.insert(exprregs, reg); - end - else - if statement.lhs[i] or expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression then - local reg = self:compileExpression(expr, funcDepth, 1)[1]; - if(self:isVarRegister(reg)) then - local ro = reg; - reg = self:allocRegister(false); - self:addStatement(self:copyRegisters(scope, {reg}, {ro}), {reg}, {ro}, false); - end - table.insert(exprregs, reg); - end - end - end - - for i, primaryExpr in ipairs(statement.lhs) do - if primaryExpr.kind == AstKind.AssignmentVariable then - if primaryExpr.scope.isGlobal then - local tmpReg = self:allocRegister(false); - self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(primaryExpr.scope:getVariableName(primaryExpr.id))), {tmpReg}, {}, false); - self:addStatement(Ast.AssignmentStatement({Ast.AssignmentIndexing(self:env(scope), self:register(scope, tmpReg))}, - {self:register(scope, exprregs[i])}), {}, {tmpReg, exprregs[i]}, true); - self:freeRegister(tmpReg, false); - else - if self.scopeFunctionDepths[primaryExpr.scope] == funcDepth then - if self:isUpvalue(primaryExpr.scope, primaryExpr.id) then - local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth); - self:addStatement(self:setUpvalueMember(scope, self:register(scope, reg), self:register(scope, exprregs[i])), {}, {reg, exprregs[i]}, true); - else - local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth, exprregs[i]); - if reg ~= exprregs[i] then - self:addStatement(self:setRegister(scope, reg, self:register(scope, exprregs[i])), {reg}, {exprregs[i]}, false); - end - end - else - local upvalId = self:getUpvalueId(primaryExpr.scope, primaryExpr.id); - scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); - self:addStatement(self:setUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)), self:register(scope, exprregs[i])), {}, {exprregs[i]}, true); - end - end - elseif primaryExpr.kind == AstKind.AssignmentIndexing then - local baseReg = assignmentIndexingRegs[i].base; - local indexReg = assignmentIndexingRegs[i].index; - self:addStatement(Ast.AssignmentStatement({ - Ast.AssignmentIndexing(self:register(scope, baseReg), self:register(scope, indexReg)) - }, { - self:register(scope, exprregs[i]) - }), {}, {exprregs[i], baseReg, indexReg}, true); - self:freeRegister(exprregs[i], false); - self:freeRegister(baseReg, false); - self:freeRegister(indexReg, false); - else - error(string.format("Invalid Assignment lhs: %s", statement.lhs)); - end - end - - return - end - - -- If Statement - if(statement.kind == AstKind.IfStatement) then - local conditionReg = self:compileExpression(statement.condition, funcDepth, 1)[1]; - local finalBlock = self:createBlock(); - - local nextBlock - if statement.elsebody or #statement.elseifs > 0 then - nextBlock = self:createBlock(); - else - nextBlock = finalBlock; - end - local innerBlock = self:createBlock(); - - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(innerBlock.id)), Ast.NumberExpression(nextBlock.id))), {self.POS_REGISTER}, {conditionReg}, false); - - self:freeRegister(conditionReg, false); - - self:setActiveBlock(innerBlock); - scope = innerBlock.scope - self:compileBlock(statement.body, funcDepth); - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(finalBlock.id)), {self.POS_REGISTER}, {}, false); - - for i, eif in ipairs(statement.elseifs) do - self:setActiveBlock(nextBlock); - conditionReg = self:compileExpression(eif.condition, funcDepth, 1)[1]; - local innerBlock = self:createBlock(); - if statement.elsebody or i < #statement.elseifs then - nextBlock = self:createBlock(); - else - nextBlock = finalBlock; - end - local scope = self.activeBlock.scope; - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(innerBlock.id)), Ast.NumberExpression(nextBlock.id))), {self.POS_REGISTER}, {conditionReg}, false); - - self:freeRegister(conditionReg, false); - - self:setActiveBlock(innerBlock); - scope = innerBlock.scope; - self:compileBlock(eif.body, funcDepth); - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(finalBlock.id)), {self.POS_REGISTER}, {}, false); - end - - if statement.elsebody then - self:setActiveBlock(nextBlock); - self:compileBlock(statement.elsebody, funcDepth); - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(finalBlock.id)), {self.POS_REGISTER}, {}, false); - end - - self:setActiveBlock(finalBlock); - - return; - end - - -- Do Statement - if(statement.kind == AstKind.DoStatement) then - self:compileBlock(statement.body, funcDepth); - return; - end - - -- While Statement - if(statement.kind == AstKind.WhileStatement) then - local innerBlock = self:createBlock(); - local finalBlock = self:createBlock(); - local checkBlock = self:createBlock(); - - statement.__start_block = checkBlock; - statement.__final_block = finalBlock; - - self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false); - - self:setActiveBlock(checkBlock); - local scope = self.activeBlock.scope; - local conditionReg = self:compileExpression(statement.condition, funcDepth, 1)[1]; - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(innerBlock.id)), Ast.NumberExpression(finalBlock.id))), {self.POS_REGISTER}, {conditionReg}, false); - self:freeRegister(conditionReg, false); - - self:setActiveBlock(innerBlock); - local scope = self.activeBlock.scope; - self:compileBlock(statement.body, funcDepth); - self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false); - self:setActiveBlock(finalBlock); - return; - end - - -- Repeat Statement - if(statement.kind == AstKind.RepeatStatement) then - local innerBlock = self:createBlock(); - local finalBlock = self:createBlock(); - statement.__start_block = innerBlock; - statement.__final_block = finalBlock; - - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(innerBlock.id)), {self.POS_REGISTER}, {}, false); - self:setActiveBlock(innerBlock); - - -- Compile body statements without automatic variable cleanup - -- self:compileBlock(statement.body, funcDepth); - for i, stat in ipairs(statement.body.statements) do - self:compileStatement(stat, funcDepth); - end; - - local scope = self.activeBlock.scope; - -- Evaluate condition (can access body's local variables) - local conditionReg = (self:compileExpression(statement.condition, funcDepth, 1))[1]; - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(finalBlock.id)), Ast.NumberExpression(innerBlock.id))), { self.POS_REGISTER }, { conditionReg }, false); - self:freeRegister(conditionReg, false); - - -- Clean up body's local variables - for id, name in ipairs(statement.body.scope.variables) do - local varReg = self:getVarRegister(statement.body.scope, id, funcDepth, nil); - if self:isUpvalue(statement.body.scope, id) then - scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc); - self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), { self:register(scope, varReg) })), { varReg }, { varReg }, false); - else - self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), { varReg }, {}, false); - end; - self:freeRegister(varReg, true); - end; - - self:setActiveBlock(finalBlock); - return; - end; - - -- For Statement - if(statement.kind == AstKind.ForStatement) then - local checkBlock = self:createBlock(); - local innerBlock = self:createBlock(); - local finalBlock = self:createBlock(); - - statement.__start_block = checkBlock; - statement.__final_block = finalBlock; - - local posState = self.registers[self.POS_REGISTER]; - self.registers[self.POS_REGISTER] = self.VAR_REGISTER; - - local initialReg = self:compileExpression(statement.initialValue, funcDepth, 1)[1]; - - local finalExprReg = self:compileExpression(statement.finalValue, funcDepth, 1)[1]; - local finalReg = self:allocRegister(false); - self:addStatement(self:copyRegisters(scope, {finalReg}, {finalExprReg}), {finalReg}, {finalExprReg}, false); - self:freeRegister(finalExprReg); - - local incrementExprReg = self:compileExpression(statement.incrementBy, funcDepth, 1)[1]; - local incrementReg = self:allocRegister(false); - self:addStatement(self:copyRegisters(scope, {incrementReg}, {incrementExprReg}), {incrementReg}, {incrementExprReg}, false); - self:freeRegister(incrementExprReg); - - local tmpReg = self:allocRegister(false); - self:addStatement(self:setRegister(scope, tmpReg, Ast.NumberExpression(0)), {tmpReg}, {}, false); - local incrementIsNegReg = self:allocRegister(false); - self:addStatement(self:setRegister(scope, incrementIsNegReg, Ast.LessThanExpression(self:register(scope, incrementReg), self:register(scope, tmpReg))), {incrementIsNegReg}, {incrementReg, tmpReg}, false); - self:freeRegister(tmpReg); - - local currentReg = self:allocRegister(true); - self:addStatement(self:setRegister(scope, currentReg, Ast.SubExpression(self:register(scope, initialReg), self:register(scope, incrementReg))), {currentReg}, {initialReg, incrementReg}, false); - self:freeRegister(initialReg); - - self:addStatement(self:jmp(scope, Ast.NumberExpression(checkBlock.id)), {self.POS_REGISTER}, {}, false); - - self:setActiveBlock(checkBlock); - - scope = checkBlock.scope; - self:addStatement(self:setRegister(scope, currentReg, Ast.AddExpression(self:register(scope, currentReg), self:register(scope, incrementReg))), {currentReg}, {currentReg, incrementReg}, false); - local tmpReg1 = self:allocRegister(false); - local tmpReg2 = self:allocRegister(false); - self:addStatement(self:setRegister(scope, tmpReg2, Ast.NotExpression(self:register(scope, incrementIsNegReg))), {tmpReg2}, {incrementIsNegReg}, false); - self:addStatement(self:setRegister(scope, tmpReg1, Ast.LessThanOrEqualsExpression(self:register(scope, currentReg), self:register(scope, finalReg))), {tmpReg1}, {currentReg, finalReg}, false); - self:addStatement(self:setRegister(scope, tmpReg1, Ast.AndExpression(self:register(scope, tmpReg2), self:register(scope, tmpReg1))), {tmpReg1}, {tmpReg1, tmpReg2}, false); - self:addStatement(self:setRegister(scope, tmpReg2, Ast.GreaterThanOrEqualsExpression(self:register(scope, currentReg), self:register(scope, finalReg))), {tmpReg2}, {currentReg, finalReg}, false); - self:addStatement(self:setRegister(scope, tmpReg2, Ast.AndExpression(self:register(scope, incrementIsNegReg), self:register(scope, tmpReg2))), {tmpReg2}, {tmpReg2, incrementIsNegReg}, false); - self:addStatement(self:setRegister(scope, tmpReg1, Ast.OrExpression(self:register(scope, tmpReg2), self:register(scope, tmpReg1))), {tmpReg1}, {tmpReg1, tmpReg2}, false); - self:freeRegister(tmpReg2); - tmpReg2 = self:compileExpression(Ast.NumberExpression(innerBlock.id), funcDepth, 1)[1]; - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.AndExpression(self:register(scope, tmpReg1), self:register(scope, tmpReg2))), {self.POS_REGISTER}, {tmpReg1, tmpReg2}, false); - self:freeRegister(tmpReg2); - self:freeRegister(tmpReg1); - tmpReg2 = self:compileExpression(Ast.NumberExpression(finalBlock.id), funcDepth, 1)[1]; - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(self:register(scope, self.POS_REGISTER), self:register(scope, tmpReg2))), {self.POS_REGISTER}, {self.POS_REGISTER, tmpReg2}, false); - self:freeRegister(tmpReg2); - - self:setActiveBlock(innerBlock); - scope = innerBlock.scope; - self.registers[self.POS_REGISTER] = posState; - - local varReg = self:getVarRegister(statement.scope, statement.id, funcDepth, nil); - - if(self:isUpvalue(statement.scope, statement.id)) then - scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); - self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {varReg}, {}, false); - self:addStatement(self:setUpvalueMember(scope, self:register(scope, varReg), self:register(scope, currentReg)), {}, {varReg, currentReg}, true); - else - self:addStatement(self:setRegister(scope, varReg, self:register(scope, currentReg)), {varReg}, {currentReg}, false); - end - - - self:compileBlock(statement.body, funcDepth); - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(checkBlock.id)), {self.POS_REGISTER}, {}, false); - - self.registers[self.POS_REGISTER] = self.VAR_REGISTER; - self:freeRegister(finalReg); - self:freeRegister(incrementIsNegReg); - self:freeRegister(incrementReg); - self:freeRegister(currentReg, true); - - self.registers[self.POS_REGISTER] = posState; - self:setActiveBlock(finalBlock); - - return; - end - - -- For In Statement - if(statement.kind == AstKind.ForInStatement) then - local expressionsLength = #statement.expressions; - local exprregs = {}; - for i, expr in ipairs(statement.expressions) do - if(i == expressionsLength and expressionsLength < 3) then - local regs = self:compileExpression(expr, funcDepth, 4 - expressionsLength); - for i = 1, 4 - expressionsLength do - table.insert(exprregs, regs[i]); - end - else - if i <= 3 then - table.insert(exprregs, self:compileExpression(expr, funcDepth, 1)[1]) - else - self:freeRegister(self:compileExpression(expr, funcDepth, 1)[1], false); - end - end - end - - for i, reg in ipairs(exprregs) do - if reg and self.registers[reg] ~= self.VAR_REGISTER and reg ~= self.POS_REGISTER and reg ~= self.RETURN_REGISTER then - self.registers[reg] = self.VAR_REGISTER; - else - exprregs[i] = self:allocRegister(true); - self:addStatement(self:copyRegisters(scope, {exprregs[i]}, {reg}), {exprregs[i]}, {reg}, false); - end - end - - local checkBlock = self:createBlock(); - local bodyBlock = self:createBlock(); - local finalBlock = self:createBlock(); - - statement.__start_block = checkBlock; - statement.__final_block = finalBlock; - - self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false); - - self:setActiveBlock(checkBlock); - local scope = self.activeBlock.scope; - - local varRegs = {}; - for i, id in ipairs(statement.ids) do - varRegs[i] = self:getVarRegister(statement.scope, id, funcDepth) - end - - self:addStatement(Ast.AssignmentStatement({ - self:registerAssignment(scope, exprregs[3]), - varRegs[2] and self:registerAssignment(scope, varRegs[2]), - }, { - Ast.FunctionCallExpression(self:register(scope, exprregs[1]), { - self:register(scope, exprregs[2]), - self:register(scope, exprregs[3]), - }) - }), {exprregs[3], varRegs[2]}, {exprregs[1], exprregs[2], exprregs[3]}, true); - - self:addStatement(Ast.AssignmentStatement({ - self:posAssignment(scope) - }, { - Ast.OrExpression(Ast.AndExpression(self:register(scope, exprregs[3]), Ast.NumberExpression(bodyBlock.id)), Ast.NumberExpression(finalBlock.id)) - }), {self.POS_REGISTER}, {exprregs[3]}, false); - - self:setActiveBlock(bodyBlock); - local scope = self.activeBlock.scope; - self:addStatement(self:copyRegisters(scope, {varRegs[1]}, {exprregs[3]}), {varRegs[1]}, {exprregs[3]}, false); - for i=3, #varRegs do - self:addStatement(self:setRegister(scope, varRegs[i], Ast.NilExpression()), {varRegs[i]}, {}, false); - end - - -- Upvalue fix - for i, id in ipairs(statement.ids) do - if(self:isUpvalue(statement.scope, id)) then - local varreg = varRegs[i]; - local tmpReg = self:allocRegister(false); - scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); - self:addStatement(self:setRegister(scope, tmpReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {tmpReg}, {}, false); - self:addStatement(self:setUpvalueMember(scope, self:register(scope, tmpReg), self:register(scope, varreg)), {}, {tmpReg, varreg}, true); - self:addStatement(self:copyRegisters(scope, {varreg}, {tmpReg}), {varreg}, {tmpReg}, false); - self:freeRegister(tmpReg, false); - end - end - - self:compileBlock(statement.body, funcDepth); - self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false); - self:setActiveBlock(finalBlock); - - for i, reg in ipairs(exprregs) do - self:freeRegister(exprregs[i], true) - end - - return; - end - - -- Do Statement - if(statement.kind == AstKind.DoStatement) then - self:compileBlock(statement.body, funcDepth); - return; - end - - -- Break Statement - if(statement.kind == AstKind.BreakStatement) then - local toFreeVars = {}; - local statScope; - repeat - statScope = statScope and statScope.parentScope or statement.scope; - for id, name in ipairs(statScope.variables) do - table.insert(toFreeVars, { - scope = statScope, - id = id; - }); - end - until statScope == statement.loop.body.scope; - - for i, var in pairs(toFreeVars) do - local varScope, id = var.scope, var.id; - local varReg = self:getVarRegister(varScope, id, nil, nil); - if self:isUpvalue(varScope, id) then - scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc); - self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), { - self:register(scope, varReg) - })), {varReg}, {varReg}, false); - else - self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), {varReg}, {}, false); - end - end - - self:addStatement(self:setPos(scope, statement.loop.__final_block.id), {self.POS_REGISTER}, {}, false); - self.activeBlock.advanceToNextBlock = false; - return; - end - - -- Continue Statement - if(statement.kind == AstKind.ContinueStatement) then - local toFreeVars = {}; - local statScope; - repeat - statScope = statScope and statScope.parentScope or statement.scope; - for id, name in pairs(statScope.variables) do - table.insert(toFreeVars, { - scope = statScope, - id = id; - }); - end - until statScope == statement.loop.body.scope; - - for i, var in ipairs(toFreeVars) do - local varScope, id = var.scope, var.id; - local varReg = self:getVarRegister(varScope, id, nil, nil); - if self:isUpvalue(varScope, id) then - scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc); - self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), { - self:register(scope, varReg) - })), {varReg}, {varReg}, false); - else - self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), {varReg}, {}, false); - end - end - - self:addStatement(self:setPos(scope, statement.loop.__start_block.id), {self.POS_REGISTER}, {}, false); - self.activeBlock.advanceToNextBlock = false; - return; - end - - -- Compound Statements - local compoundConstructors = { - [AstKind.CompoundAddStatement] = Ast.CompoundAddStatement, - [AstKind.CompoundSubStatement] = Ast.CompoundSubStatement, - [AstKind.CompoundMulStatement] = Ast.CompoundMulStatement, - [AstKind.CompoundDivStatement] = Ast.CompoundDivStatement, - [AstKind.CompoundModStatement] = Ast.CompoundModStatement, - [AstKind.CompoundPowStatement] = Ast.CompoundPowStatement, - [AstKind.CompoundConcatStatement] = Ast.CompoundConcatStatement, - } - if compoundConstructors[statement.kind] then - local compoundConstructor = compoundConstructors[statement.kind]; - if statement.lhs.kind == AstKind.AssignmentIndexing then - local indexing = statement.lhs; - local baseReg = self:compileExpression(indexing.base, funcDepth, 1)[1]; - local indexReg = self:compileExpression(indexing.index, funcDepth, 1)[1]; - local valueReg = self:compileExpression(statement.rhs, funcDepth, 1)[1]; - - self:addStatement(compoundConstructor(Ast.AssignmentIndexing(self:register(scope, baseReg), self:register(scope, indexReg)), self:register(scope, valueReg)), {}, {baseReg, indexReg, valueReg}, true); - else - local valueReg = self:compileExpression(statement.rhs, funcDepth, 1)[1]; - local primaryExpr = statement.lhs; - if primaryExpr.scope.isGlobal then - local tmpReg = self:allocRegister(false); - self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(primaryExpr.scope:getVariableName(primaryExpr.id))), {tmpReg}, {}, false); - self:addStatement(Ast.AssignmentStatement({Ast.AssignmentIndexing(self:env(scope), self:register(scope, tmpReg))}, - {self:register(scope, valueReg)}), {}, {tmpReg, valueReg}, true); - self:freeRegister(tmpReg, false); - else - if self.scopeFunctionDepths[primaryExpr.scope] == funcDepth then - if self:isUpvalue(primaryExpr.scope, primaryExpr.id) then - local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth); - self:addStatement(self:setUpvalueMember(scope, self:register(scope, reg), self:register(scope, valueReg), compoundConstructor), {}, {reg, valueReg}, true); - else - local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth, valueReg); - if reg ~= valueReg then - self:addStatement(self:setRegister(scope, reg, self:register(scope, valueReg), compoundConstructor), {reg}, {valueReg}, false); - end - end - else - local upvalId = self:getUpvalueId(primaryExpr.scope, primaryExpr.id); - scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); - self:addStatement(self:setUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)), self:register(scope, valueReg), compoundConstructor), {}, {valueReg}, true); - end - end - end - return; - end - - logger:error(string.format("%s is not a compileable statement!", statement.kind)); -end - -function Compiler:compileExpression(expression, funcDepth, numReturns) - local scope = self.activeBlock.scope; - - -- String Expression - if(expression.kind == AstKind.StringExpression) then - local regs = {}; - for i=1, numReturns, 1 do - regs[i] = self:allocRegister(); - if(i == 1) then - self:addStatement(self:setRegister(scope, regs[i], Ast.StringExpression(expression.value)), {regs[i]}, {}, false); - else - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - -- Number Expression - if(expression.kind == AstKind.NumberExpression) then - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - if(i == 1) then - self:addStatement(self:setRegister(scope, regs[i], Ast.NumberExpression(expression.value)), {regs[i]}, {}, false); - else - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - -- Boolean Expression - if(expression.kind == AstKind.BooleanExpression) then - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - if(i == 1) then - self:addStatement(self:setRegister(scope, regs[i], Ast.BooleanExpression(expression.value)), {regs[i]}, {}, false); - else - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - -- Nil Expression - if(expression.kind == AstKind.NilExpression) then - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - return regs; - end - - -- Variable Expression - if(expression.kind == AstKind.VariableExpression) then - local regs = {}; - for i=1, numReturns do - if(i == 1) then - if(expression.scope.isGlobal) then - -- Global Variable - regs[i] = self:allocRegister(false); - local tmpReg = self:allocRegister(false); - self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(expression.scope:getVariableName(expression.id))), {tmpReg}, {}, false); - self:addStatement(self:setRegister(scope, regs[i], Ast.IndexExpression(self:env(scope), self:register(scope, tmpReg))), {regs[i]}, {tmpReg}, true); - self:freeRegister(tmpReg, false); - else - -- Local Variable - if(self.scopeFunctionDepths[expression.scope] == funcDepth) then - if self:isUpvalue(expression.scope, expression.id) then - local reg = self:allocRegister(false); - local varReg = self:getVarRegister(expression.scope, expression.id, funcDepth, nil); - self:addStatement(self:setRegister(scope, reg, self:getUpvalueMember(scope, self:register(scope, varReg))), {reg}, {varReg}, true); - regs[i] = reg; - else - regs[i] = self:getVarRegister(expression.scope, expression.id, funcDepth, nil); - end - else - local reg = self:allocRegister(false); - local upvalId = self:getUpvalueId(expression.scope, expression.id); - scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); - self:addStatement(self:setRegister(scope, reg, self:getUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)))), {reg}, {}, true); - regs[i] = reg; - end - end - else - regs[i] = self:allocRegister(); - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - -- Function Call Expression - if(expression.kind == AstKind.FunctionCallExpression) then - local baseReg = self:compileExpression(expression.base, funcDepth, 1)[1]; - - local retRegs = {}; - local returnAll = numReturns == self.RETURN_ALL; - if returnAll then - retRegs[1] = self:allocRegister(false); - else - for i = 1, numReturns do - retRegs[i] = self:allocRegister(false); - end - end - - local regs = {}; - local args = {}; - for i, expr in ipairs(expression.args) do - if i == #expression.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then - local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1]; - table.insert(args, Ast.FunctionCallExpression( - self:unpack(scope), - {self:register(scope, reg)})); - table.insert(regs, reg); - else - local reg = self:compileExpression(expr, funcDepth, 1)[1]; - table.insert(args, self:register(scope, reg)); - table.insert(regs, reg); - end - end - - if(returnAll) then - self:addStatement(self:setRegister(scope, retRegs[1], Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, baseReg), args))}), {retRegs[1]}, {baseReg, unpack(regs)}, true); - else - if(numReturns > 1) then - local tmpReg = self:allocRegister(false); - - self:addStatement(self:setRegister(scope, tmpReg, Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, baseReg), args))}), {tmpReg}, {baseReg, unpack(regs)}, true); - - for i, reg in ipairs(retRegs) do - self:addStatement(self:setRegister(scope, reg, Ast.IndexExpression(self:register(scope, tmpReg), Ast.NumberExpression(i))), {reg}, {tmpReg}, false); - end - - self:freeRegister(tmpReg, false); - else - self:addStatement(self:setRegister(scope, retRegs[1], Ast.FunctionCallExpression(self:register(scope, baseReg), args)), {retRegs[1]}, {baseReg, unpack(regs)}, true); - end - end - - self:freeRegister(baseReg, false); - for i, reg in ipairs(regs) do - self:freeRegister(reg, false); - end - - return retRegs; - end - - -- Pass Self Function Call Expression - if(expression.kind == AstKind.PassSelfFunctionCallExpression) then - local baseReg = self:compileExpression(expression.base, funcDepth, 1)[1]; - local retRegs = {}; - local returnAll = numReturns == self.RETURN_ALL; - if returnAll then - retRegs[1] = self:allocRegister(false); - else - for i = 1, numReturns do - retRegs[i] = self:allocRegister(false); - end - end - - local args = { self:register(scope, baseReg) }; - local regs = { baseReg }; - - for i, expr in ipairs(expression.args) do - if i == #expression.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then - local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1]; - table.insert(args, Ast.FunctionCallExpression( - self:unpack(scope), - {self:register(scope, reg)})); - table.insert(regs, reg); - else - local reg = self:compileExpression(expr, funcDepth, 1)[1]; - table.insert(args, self:register(scope, reg)); - table.insert(regs, reg); - end - end - - if(returnAll or numReturns > 1) then - local tmpReg = self:allocRegister(false); - - self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(expression.passSelfFunctionName)), {tmpReg}, {}, false); - self:addStatement(self:setRegister(scope, tmpReg, Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, tmpReg))), {tmpReg}, {baseReg, tmpReg}, false); - - if returnAll then - self:addStatement(self:setRegister(scope, retRegs[1], Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, tmpReg), args))}), {retRegs[1]}, {tmpReg, unpack(regs)}, true); - else - self:addStatement(self:setRegister(scope, tmpReg, Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, tmpReg), args))}), {tmpReg}, {tmpReg, unpack(regs)}, true); - - for i, reg in ipairs(retRegs) do - self:addStatement(self:setRegister(scope, reg, Ast.IndexExpression(self:register(scope, tmpReg), Ast.NumberExpression(i))), {reg}, {tmpReg}, false); - end - end - - self:freeRegister(tmpReg, false); - else - local tmpReg = retRegs[1] or self:allocRegister(false); - - self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(expression.passSelfFunctionName)), {tmpReg}, {}, false); - self:addStatement(self:setRegister(scope, tmpReg, Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, tmpReg))), {tmpReg}, {baseReg, tmpReg}, false); - - self:addStatement(self:setRegister(scope, retRegs[1], Ast.FunctionCallExpression(self:register(scope, tmpReg), args)), {retRegs[1]}, {baseReg, unpack(regs)}, true); - end - - for i, reg in ipairs(regs) do - self:freeRegister(reg, false); - end - - return retRegs; - end - - -- Index Expression - if(expression.kind == AstKind.IndexExpression) then - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - if(i == 1) then - local baseReg = self:compileExpression(expression.base, funcDepth, 1)[1]; - local indexReg = self:compileExpression(expression.index, funcDepth, 1)[1]; - - self:addStatement(self:setRegister(scope, regs[i], Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, indexReg))), {regs[i]}, {baseReg, indexReg}, true); - self:freeRegister(baseReg, false); - self:freeRegister(indexReg, false) - else - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - -- Binary Operations - if(self.BIN_OPS[expression.kind]) then - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - if(i == 1) then - local lhsReg = self:compileExpression(expression.lhs, funcDepth, 1)[1]; - local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; - - self:addStatement(self:setRegister(scope, regs[i], Ast[expression.kind](self:register(scope, lhsReg), self:register(scope, rhsReg))), {regs[i]}, {lhsReg, rhsReg}, true); - self:freeRegister(rhsReg, false); - self:freeRegister(lhsReg, false) - else - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - if(expression.kind == AstKind.NotExpression) then - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - if(i == 1) then - local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; - - self:addStatement(self:setRegister(scope, regs[i], Ast.NotExpression(self:register(scope, rhsReg))), {regs[i]}, {rhsReg}, false); - self:freeRegister(rhsReg, false) - else - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - if(expression.kind == AstKind.NegateExpression) then - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - if(i == 1) then - local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; - - self:addStatement(self:setRegister(scope, regs[i], Ast.NegateExpression(self:register(scope, rhsReg))), {regs[i]}, {rhsReg}, true); - self:freeRegister(rhsReg, false) - else - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - if(expression.kind == AstKind.LenExpression) then - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - if(i == 1) then - local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; - - self:addStatement(self:setRegister(scope, regs[i], Ast.LenExpression(self:register(scope, rhsReg))), {regs[i]}, {rhsReg}, true); - self:freeRegister(rhsReg, false) - else - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - if(expression.kind == AstKind.OrExpression) then - local posState = self.registers[self.POS_REGISTER]; - self.registers[self.POS_REGISTER] = self.VAR_REGISTER; - - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - if(i ~= 1) then - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - - local resReg = regs[1]; - local tmpReg; - - if posState then - tmpReg = self:allocRegister(false); - self:addStatement(self:copyRegisters(scope, {tmpReg}, {self.POS_REGISTER}), {tmpReg}, {self.POS_REGISTER}, false); - end - - local lhsReg = self:compileExpression(expression.lhs, funcDepth, 1)[1]; - if(expression.rhs.isConstant) then - local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; - self:addStatement(self:setRegister(scope, resReg, Ast.OrExpression(self:register(scope, lhsReg), self:register(scope, rhsReg))), {resReg}, {lhsReg, rhsReg}, false); - if tmpReg then - self:freeRegister(tmpReg, false); - end - self:freeRegister(lhsReg, false); - self:freeRegister(rhsReg, false); - return regs; - end - - local block1, block2 = self:createBlock(), self:createBlock(); - self:addStatement(self:copyRegisters(scope, {resReg}, {lhsReg}), {resReg}, {lhsReg}, false); - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, lhsReg), Ast.NumberExpression(block2.id)), Ast.NumberExpression(block1.id))), {self.POS_REGISTER}, {lhsReg}, false); - self:freeRegister(lhsReg, false); - - do - self:setActiveBlock(block1); - local scope = block1.scope; - local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; - self:addStatement(self:copyRegisters(scope, {resReg}, {rhsReg}), {resReg}, {rhsReg}, false); - self:freeRegister(rhsReg, false); - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(block2.id)), {self.POS_REGISTER}, {}, false); - end - - self.registers[self.POS_REGISTER] = posState; - - self:setActiveBlock(block2); - scope = block2.scope; - - if tmpReg then - self:addStatement(self:copyRegisters(scope, {self.POS_REGISTER}, {tmpReg}), {self.POS_REGISTER}, {tmpReg}, false); - self:freeRegister(tmpReg, false); - end - - return regs; - end - - if(expression.kind == AstKind.AndExpression) then - local posState = self.registers[self.POS_REGISTER]; - self.registers[self.POS_REGISTER] = self.VAR_REGISTER; - - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - if(i ~= 1) then - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - - local resReg = regs[1]; - local tmpReg; - - if posState then - tmpReg = self:allocRegister(false); - self:addStatement(self:copyRegisters(scope, {tmpReg}, {self.POS_REGISTER}), {tmpReg}, {self.POS_REGISTER}, false); - end - - - local lhsReg = self:compileExpression(expression.lhs, funcDepth, 1)[1]; - if(expression.rhs.isConstant) then - local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; - self:addStatement(self:setRegister(scope, resReg, Ast.AndExpression(self:register(scope, lhsReg), self:register(scope, rhsReg))), {resReg}, {lhsReg, rhsReg}, false); - if tmpReg then - self:freeRegister(tmpReg, false); - end - self:freeRegister(lhsReg, false); - self:freeRegister(rhsReg, false) - return regs; - end - - - local block1, block2 = self:createBlock(), self:createBlock(); - self:addStatement(self:copyRegisters(scope, {resReg}, {lhsReg}), {resReg}, {lhsReg}, false); - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, lhsReg), Ast.NumberExpression(block1.id)), Ast.NumberExpression(block2.id))), {self.POS_REGISTER}, {lhsReg}, false); - self:freeRegister(lhsReg, false); - do - self:setActiveBlock(block1); - scope = block1.scope; - local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; - self:addStatement(self:copyRegisters(scope, {resReg}, {rhsReg}), {resReg}, {rhsReg}, false); - self:freeRegister(rhsReg, false); - self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(block2.id)), {self.POS_REGISTER}, {}, false); - end - - self.registers[self.POS_REGISTER] = posState; - - self:setActiveBlock(block2); - scope = block2.scope; - - if tmpReg then - self:addStatement(self:copyRegisters(scope, {self.POS_REGISTER}, {tmpReg}), {self.POS_REGISTER}, {tmpReg}, false); - self:freeRegister(tmpReg, false); - end - - return regs; - end - - if(expression.kind == AstKind.TableConstructorExpression) then - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(); - if(i == 1) then - local entries = {}; - local entryRegs = {}; - for i, entry in ipairs(expression.entries) do - if(entry.kind == AstKind.TableEntry) then - local value = entry.value; - if i == #expression.entries and (value.kind == AstKind.FunctionCallExpression or value.kind == AstKind.PassSelfFunctionCallExpression or value.kind == AstKind.VarargExpression) then - local reg = self:compileExpression(entry.value, funcDepth, self.RETURN_ALL)[1]; - table.insert(entries, Ast.TableEntry(Ast.FunctionCallExpression( - self:unpack(scope), - {self:register(scope, reg)}))); - table.insert(entryRegs, reg); - else - local reg = self:compileExpression(entry.value, funcDepth, 1)[1]; - table.insert(entries, Ast.TableEntry(self:register(scope, reg))); - table.insert(entryRegs, reg); - end - else - local keyReg = self:compileExpression(entry.key, funcDepth, 1)[1]; - local valReg = self:compileExpression(entry.value, funcDepth, 1)[1]; - table.insert(entries, Ast.KeyedTableEntry(self:register(scope, keyReg), self:register(scope, valReg))); - table.insert(entryRegs, valReg); - table.insert(entryRegs, keyReg); - end - end - self:addStatement(self:setRegister(scope, regs[i], Ast.TableConstructorExpression(entries)), {regs[i]}, entryRegs, false); - for i, reg in ipairs(entryRegs) do - self:freeRegister(reg, false); - end - else - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - if(expression.kind == AstKind.FunctionLiteralExpression) then - local regs = {}; - for i=1, numReturns do - if(i == 1) then - regs[i] = self:compileFunction(expression, funcDepth); - else - regs[i] = self:allocRegister(); - self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); - end - end - return regs; - end - - if(expression.kind == AstKind.VarargExpression) then - if numReturns == self.RETURN_ALL then - return {self.varargReg}; - end - local regs = {}; - for i=1, numReturns do - regs[i] = self:allocRegister(false); - self:addStatement(self:setRegister(scope, regs[i], Ast.IndexExpression(self:register(scope, self.varargReg), Ast.NumberExpression(i))), {regs[i]}, {self.varargReg}, false); - end - return regs; - end - - logger:error(string.format("%s is not an compliable expression!", expression.kind)); -end - return Compiler; diff --git a/src/prometheus/compiler/constants.lua b/src/prometheus/compiler/constants.lua new file mode 100644 index 00000000..cb1d6c02 --- /dev/null +++ b/src/prometheus/compiler/constants.lua @@ -0,0 +1,10 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- constants.lua +-- This Script contains the compiler constants shared across modules + +return { + MAX_REGS = 100, + MAX_REGS_MUL = 0, +} + diff --git a/src/prometheus/compiler/emit.lua b/src/prometheus/compiler/emit.lua new file mode 100644 index 00000000..2858b8af --- /dev/null +++ b/src/prometheus/compiler/emit.lua @@ -0,0 +1,154 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- emit.lua +-- This Script contains the container function body emission for the compiler + +local Ast = require("prometheus.ast"); +local Scope = require("prometheus.scope"); +local util = require("prometheus.util"); +local constants = require("prometheus.compiler.constants"); + +local MAX_REGS = constants.MAX_REGS; + +return function(Compiler) + function Compiler:emitContainerFuncBody() + local blocks = {}; + + util.shuffle(self.blocks); + + for i, block in ipairs(self.blocks) do + local id = block.id; + local blockstats = block.statements; + + for i = 2, #blockstats do + local stat = blockstats[i]; + local reads = stat.reads; + local writes = stat.writes; + local maxShift = 0; + local usesUpvals = stat.usesUpvals; + for shift = 1, i - 1 do + local stat2 = blockstats[i - shift]; + + if stat2.usesUpvals and usesUpvals then + break; + end + + local reads2 = stat2.reads; + local writes2 = stat2.writes; + local f = true; + + for r, b in pairs(reads2) do + if(writes[r]) then + f = false; + break; + end + end + + if f then + for r, b in pairs(writes2) do + if(writes[r]) then + f = false; + break; + end + if(reads[r]) then + f = false; + break; + end + end + end + + if not f then + break + end + + maxShift = shift; + end + + local shift = math.random(0, maxShift); + for j = 1, shift do + blockstats[i - j], blockstats[i - j + 1] = blockstats[i - j + 1], blockstats[i - j]; + end + end + + blockstats = {}; + for _, stat in ipairs(block.statements) do + table.insert(blockstats, stat.statement); + end + + local block = { id = id, index = i, block = Ast.Block(blockstats, block.scope) } + table.insert(blocks, block); + blocks[id] = block; + end + + table.sort(blocks, function(a, b) + return a.id < b.id; + end); + + local function buildIfBlock(scope, id, lBlock, rBlock) + local condition = Ast.LessThanExpression(self:pos(scope), Ast.NumberExpression(id)); + return Ast.Block({ + Ast.IfStatement(condition, lBlock, {}, rBlock); + }, scope); + end + + local function buildWhileBody(tb, l, r, pScope, scope) + local len = r - l + 1; + if len == 1 then + tb[r].block.scope:setParent(pScope); + return tb[r].block; + elseif len == 0 then + return nil; + end + + local mid = l + math.ceil(len / 2); + local bound = math.random(tb[mid - 1].id + 1, tb[mid].id); + local ifScope = scope or Scope:new(pScope); + + local lBlock = buildWhileBody(tb, l, mid - 1, ifScope); + local rBlock = buildWhileBody(tb, mid, r, ifScope); + + return buildIfBlock(ifScope, bound, lBlock, rBlock); + end + + local whileBody = buildWhileBody(blocks, 1, #blocks, self.containerFuncScope, self.whileScope); + + self.whileScope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar, 1); + self.whileScope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); + + self.containerFuncScope:addReferenceToHigherScope(self.scope, self.unpackVar); + + local declarations = { + self.returnVar, + } + + for i, var in pairs(self.registerVars) do + if(i ~= MAX_REGS) then + table.insert(declarations, var); + end + end + + local stats = {} + + if self.maxUsedRegister >= MAX_REGS then + table.insert(stats, Ast.LocalVariableDeclaration(self.containerFuncScope, {self.registerVars[MAX_REGS]}, {Ast.TableConstructorExpression({})})); + end + + table.insert(stats, Ast.LocalVariableDeclaration(self.containerFuncScope, util.shuffle(declarations), {})); + + table.insert(stats, Ast.WhileStatement(whileBody, Ast.VariableExpression(self.containerFuncScope, self.posVar))); + + table.insert(stats, Ast.AssignmentStatement({ + Ast.AssignmentVariable(self.containerFuncScope, self.posVar) + }, { + Ast.LenExpression(Ast.VariableExpression(self.containerFuncScope, self.detectGcCollectVar)) + })); + + table.insert(stats, Ast.ReturnStatement{ + Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.unpackVar), { + Ast.VariableExpression(self.containerFuncScope, self.returnVar) + }); + }); + + return Ast.Block(stats, self.containerFuncScope); + end +end diff --git a/src/prometheus/compiler/expressions.lua b/src/prometheus/compiler/expressions.lua new file mode 100644 index 00000000..9aaf388d --- /dev/null +++ b/src/prometheus/compiler/expressions.lua @@ -0,0 +1,48 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- expressions.lua +-- This Script contains the expression handlers: exports handler table keyed by AstKind + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +local handlers = {}; +local expressions = "prometheus.compiler.expressions."; +local function requireExpression(name) + return require(expressions .. name); +end +handlers[AstKind.StringExpression] = requireExpression("string"); +handlers[AstKind.NumberExpression] = requireExpression("number"); +handlers[AstKind.BooleanExpression] = requireExpression("boolean"); +handlers[AstKind.NilExpression] = requireExpression("nil"); +handlers[AstKind.VariableExpression] = requireExpression("variable"); +handlers[AstKind.FunctionCallExpression] = requireExpression("function_call"); +handlers[AstKind.PassSelfFunctionCallExpression] = requireExpression("pass_self_function_call"); +handlers[AstKind.IndexExpression] = requireExpression("index"); +handlers[AstKind.NotExpression] = requireExpression("not"); +handlers[AstKind.NegateExpression] = requireExpression("negate"); +handlers[AstKind.LenExpression] = requireExpression("len"); +handlers[AstKind.OrExpression] = requireExpression("or"); +handlers[AstKind.AndExpression] = requireExpression("and"); +handlers[AstKind.TableConstructorExpression] = requireExpression("table_constructor"); +handlers[AstKind.FunctionLiteralExpression] = requireExpression("function_literal"); +handlers[AstKind.VarargExpression] = requireExpression("vararg"); + +-- Binary ops share one handler +local binaryHandler = requireExpression("binary"); +handlers[AstKind.LessThanExpression] = binaryHandler; +handlers[AstKind.GreaterThanExpression] = binaryHandler; +handlers[AstKind.LessThanOrEqualsExpression] = binaryHandler; +handlers[AstKind.GreaterThanOrEqualsExpression] = binaryHandler; +handlers[AstKind.NotEqualsExpression] = binaryHandler; +handlers[AstKind.EqualsExpression] = binaryHandler; +handlers[AstKind.StrCatExpression] = binaryHandler; +handlers[AstKind.AddExpression] = binaryHandler; +handlers[AstKind.SubExpression] = binaryHandler; +handlers[AstKind.MulExpression] = binaryHandler; +handlers[AstKind.DivExpression] = binaryHandler; +handlers[AstKind.ModExpression] = binaryHandler; +handlers[AstKind.PowExpression] = binaryHandler; + +return handlers; + diff --git a/src/prometheus/compiler/expressions/and.lua b/src/prometheus/compiler/expressions/and.lua new file mode 100644 index 00000000..12444a29 --- /dev/null +++ b/src/prometheus/compiler/expressions/and.lua @@ -0,0 +1,66 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- and.lua +-- This Script contains the expression handler for the AndExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local posState = self.registers[self.POS_REGISTER]; + self.registers[self.POS_REGISTER] = self.VAR_REGISTER; + + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + if i ~= 1 then + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + + local resReg = regs[1]; + local tmpReg; + + if posState then + tmpReg = self:allocRegister(false); + self:addStatement(self:copyRegisters(scope, {tmpReg}, {self.POS_REGISTER}), {tmpReg}, {self.POS_REGISTER}, false); + end + + local lhsReg = self:compileExpression(expression.lhs, funcDepth, 1)[1]; + if expression.rhs.isConstant then + local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; + self:addStatement(self:setRegister(scope, resReg, Ast.AndExpression(self:register(scope, lhsReg), self:register(scope, rhsReg))), {resReg}, {lhsReg, rhsReg}, false); + if tmpReg then + self:freeRegister(tmpReg, false); + end + self:freeRegister(lhsReg, false); + self:freeRegister(rhsReg, false); + return regs; + end + + local block1, block2 = self:createBlock(), self:createBlock(); + self:addStatement(self:copyRegisters(scope, {resReg}, {lhsReg}), {resReg}, {lhsReg}, false); + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, lhsReg), Ast.NumberExpression(block1.id)), Ast.NumberExpression(block2.id))), {self.POS_REGISTER}, {lhsReg}, false); + self:freeRegister(lhsReg, false); + do + self:setActiveBlock(block1); + scope = block1.scope; + local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; + self:addStatement(self:copyRegisters(scope, {resReg}, {rhsReg}), {resReg}, {rhsReg}, false); + self:freeRegister(rhsReg, false); + + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(block2.id)), {self.POS_REGISTER}, {}, false); + end + + self.registers[self.POS_REGISTER] = posState; + + self:setActiveBlock(block2); + scope = block2.scope; + + if tmpReg then + self:addStatement(self:copyRegisters(scope, {self.POS_REGISTER}, {tmpReg}), {self.POS_REGISTER}, {tmpReg}, false); + self:freeRegister(tmpReg, false); + end + + return regs; +end; diff --git a/src/prometheus/compiler/expressions/binary.lua b/src/prometheus/compiler/expressions/binary.lua new file mode 100644 index 00000000..3926a12c --- /dev/null +++ b/src/prometheus/compiler/expressions/binary.lua @@ -0,0 +1,26 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- binary.lua +-- This Script contains the expression handler for the Binary operations (Add, Sub, Mul, Div, etc.) + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + if i == 1 then + local lhsReg = self:compileExpression(expression.lhs, funcDepth, 1)[1]; + local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; + + local binaryExpr = Ast[expression.kind](self:register(scope, lhsReg), self:register(scope, rhsReg)); + self:addStatement(self:setRegister(scope, regs[i], binaryExpr), {regs[i]}, {lhsReg, rhsReg}, true); + self:freeRegister(rhsReg, false); + self:freeRegister(lhsReg, false); + else + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; diff --git a/src/prometheus/compiler/expressions/boolean.lua b/src/prometheus/compiler/expressions/boolean.lua new file mode 100644 index 00000000..67de88f2 --- /dev/null +++ b/src/prometheus/compiler/expressions/boolean.lua @@ -0,0 +1,21 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- boolean.lua +-- This Script contains the expression handler for the BooleanExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + if i == 1 then + self:addStatement(self:setRegister(scope, regs[i], Ast.BooleanExpression(expression.value)), {regs[i]}, {}, false); + else + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; + diff --git a/src/prometheus/compiler/expressions/function_call.lua b/src/prometheus/compiler/expressions/function_call.lua new file mode 100644 index 00000000..41e61b11 --- /dev/null +++ b/src/prometheus/compiler/expressions/function_call.lua @@ -0,0 +1,64 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- function_call.lua +-- This Script contains the expression handler for the FunctionCallExpression + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local baseReg = self:compileExpression(expression.base, funcDepth, 1)[1]; + + local retRegs = {}; + local returnAll = numReturns == self.RETURN_ALL; + if returnAll then + retRegs[1] = self:allocRegister(false); + else + for i = 1, numReturns do + retRegs[i] = self:allocRegister(false); + end + end + + local regs = {}; + local args = {}; + for i, expr in ipairs(expression.args) do + if i == #expression.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then + local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1]; + table.insert(args, Ast.FunctionCallExpression( + self:unpack(scope), + {self:register(scope, reg)})); + table.insert(regs, reg); + else + local reg = self:compileExpression(expr, funcDepth, 1)[1]; + table.insert(args, self:register(scope, reg)); + table.insert(regs, reg); + end + end + + if returnAll then + self:addStatement(self:setRegister(scope, retRegs[1], Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, baseReg), args))}), {retRegs[1]}, {baseReg, unpack(regs)}, true); + else + if numReturns > 1 then + local tmpReg = self:allocRegister(false); + + self:addStatement(self:setRegister(scope, tmpReg, Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, baseReg), args))}), {tmpReg}, {baseReg, unpack(regs)}, true); + + + for i, reg in ipairs(retRegs) do + self:addStatement(self:setRegister(scope, reg, Ast.IndexExpression(self:register(scope, tmpReg), Ast.NumberExpression(i))), {reg}, {tmpReg}, false); + end + + self:freeRegister(tmpReg, false); + else + self:addStatement(self:setRegister(scope, retRegs[1], Ast.FunctionCallExpression(self:register(scope, baseReg), args)), {retRegs[1]}, {baseReg, unpack(regs)}, true); + end + end + + self:freeRegister(baseReg, false); + for i, reg in ipairs(regs) do + self:freeRegister(reg, false); + end + + return retRegs; +end; diff --git a/src/prometheus/compiler/expressions/function_literal.lua b/src/prometheus/compiler/expressions/function_literal.lua new file mode 100644 index 00000000..1fc3d9a7 --- /dev/null +++ b/src/prometheus/compiler/expressions/function_literal.lua @@ -0,0 +1,21 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- function_literal.lua +-- This Script contains the expression handler for the FunctionLiteralExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + if i == 1 then + regs[i] = self:compileFunction(expression, funcDepth); + else + regs[i] = self:allocRegister(); + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; + diff --git a/src/prometheus/compiler/expressions/index.lua b/src/prometheus/compiler/expressions/index.lua new file mode 100644 index 00000000..4600b13b --- /dev/null +++ b/src/prometheus/compiler/expressions/index.lua @@ -0,0 +1,28 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- index.lua +-- This Script contains the expression handler for the IndexExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + if i == 1 then + local baseReg = self:compileExpression(expression.base, funcDepth, 1)[1]; + local indexReg = self:compileExpression(expression.index, funcDepth, 1)[1]; + + + + self:addStatement(self:setRegister(scope, regs[i], Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, indexReg))), {regs[i]}, {baseReg, indexReg}, true); + + self:freeRegister(baseReg, false); + self:freeRegister(indexReg, false); + else + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; diff --git a/src/prometheus/compiler/expressions/len.lua b/src/prometheus/compiler/expressions/len.lua new file mode 100644 index 00000000..92c81de5 --- /dev/null +++ b/src/prometheus/compiler/expressions/len.lua @@ -0,0 +1,24 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- len.lua +-- This Script contains the expression handler for the LenExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + if i == 1 then + local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; + + self:addStatement(self:setRegister(scope, regs[i], Ast.LenExpression(self:register(scope, rhsReg))), {regs[i]}, {rhsReg}, true); + self:freeRegister(rhsReg, false); + else + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; + diff --git a/src/prometheus/compiler/expressions/negate.lua b/src/prometheus/compiler/expressions/negate.lua new file mode 100644 index 00000000..41cb9d4a --- /dev/null +++ b/src/prometheus/compiler/expressions/negate.lua @@ -0,0 +1,21 @@ +-- Expression handler: NegateExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + if i == 1 then + local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; + + self:addStatement(self:setRegister(scope, regs[i], Ast.NegateExpression(self:register(scope, rhsReg))), {regs[i]}, {rhsReg}, true); + self:freeRegister(rhsReg, false); + else + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; + diff --git a/src/prometheus/compiler/expressions/nil.lua b/src/prometheus/compiler/expressions/nil.lua new file mode 100644 index 00000000..a314605c --- /dev/null +++ b/src/prometheus/compiler/expressions/nil.lua @@ -0,0 +1,17 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- nil.lua +-- This Script contains the expression handler for the NilExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + return regs; +end; + diff --git a/src/prometheus/compiler/expressions/not.lua b/src/prometheus/compiler/expressions/not.lua new file mode 100644 index 00000000..af847583 --- /dev/null +++ b/src/prometheus/compiler/expressions/not.lua @@ -0,0 +1,24 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- not.lua +-- This Script contains the expression handler for the NotExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + if i == 1 then + local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; + + self:addStatement(self:setRegister(scope, regs[i], Ast.NotExpression(self:register(scope, rhsReg))), {regs[i]}, {rhsReg}, false); + self:freeRegister(rhsReg, false); + else + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; + diff --git a/src/prometheus/compiler/expressions/number.lua b/src/prometheus/compiler/expressions/number.lua new file mode 100644 index 00000000..9f799427 --- /dev/null +++ b/src/prometheus/compiler/expressions/number.lua @@ -0,0 +1,18 @@ +-- Expression handler: NumberExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + if i == 1 then + self:addStatement(self:setRegister(scope, regs[i], Ast.NumberExpression(expression.value)), {regs[i]}, {}, false); + else + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; + diff --git a/src/prometheus/compiler/expressions/or.lua b/src/prometheus/compiler/expressions/or.lua new file mode 100644 index 00000000..c3032f6e --- /dev/null +++ b/src/prometheus/compiler/expressions/or.lua @@ -0,0 +1,65 @@ +-- Expression handler: OrExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local posState = self.registers[self.POS_REGISTER]; + self.registers[self.POS_REGISTER] = self.VAR_REGISTER; + + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + if i ~= 1 then + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + + local resReg = regs[1]; + local tmpReg; + + if posState then + tmpReg = self:allocRegister(false); + self:addStatement(self:copyRegisters(scope, {tmpReg}, {self.POS_REGISTER}), {tmpReg}, {self.POS_REGISTER}, false); + end + + local lhsReg = self:compileExpression(expression.lhs, funcDepth, 1)[1]; + if expression.rhs.isConstant then + local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; + self:addStatement(self:setRegister(scope, resReg, Ast.OrExpression(self:register(scope, lhsReg), self:register(scope, rhsReg))), {resReg}, {lhsReg, rhsReg}, false); + if tmpReg then + self:freeRegister(tmpReg, false); + end + self:freeRegister(lhsReg, false); + self:freeRegister(rhsReg, false); + return regs; + end + + local block1, block2 = self:createBlock(), self:createBlock(); + self:addStatement(self:copyRegisters(scope, {resReg}, {lhsReg}), {resReg}, {lhsReg}, false); + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, lhsReg), Ast.NumberExpression(block2.id)), Ast.NumberExpression(block1.id))), {self.POS_REGISTER}, {lhsReg}, false); + self:freeRegister(lhsReg, false); + + do + self:setActiveBlock(block1); + local scope = block1.scope; + local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1]; + self:addStatement(self:copyRegisters(scope, {resReg}, {rhsReg}), {resReg}, {rhsReg}, false); + self:freeRegister(rhsReg, false); + + + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(block2.id)), {self.POS_REGISTER}, {}, false); + end + + self.registers[self.POS_REGISTER] = posState; + + self:setActiveBlock(block2); + scope = block2.scope; + + if tmpReg then + self:addStatement(self:copyRegisters(scope, {self.POS_REGISTER}, {tmpReg}), {self.POS_REGISTER}, {tmpReg}, false); + self:freeRegister(tmpReg, false); + end + + return regs; +end; diff --git a/src/prometheus/compiler/expressions/pass_self_function_call.lua b/src/prometheus/compiler/expressions/pass_self_function_call.lua new file mode 100644 index 00000000..175f5a8c --- /dev/null +++ b/src/prometheus/compiler/expressions/pass_self_function_call.lua @@ -0,0 +1,69 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- pass_self_function_call.lua +-- This Script contains the expression handler for the PassSelfFunctionCallExpression + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local baseReg = self:compileExpression(expression.base, funcDepth, 1)[1]; + local retRegs = {}; + local returnAll = numReturns == self.RETURN_ALL; + if returnAll then + retRegs[1] = self:allocRegister(false); + else + for i = 1, numReturns do + retRegs[i] = self:allocRegister(false); + end + end + + local args = { self:register(scope, baseReg) }; + local regs = { baseReg }; + + for i, expr in ipairs(expression.args) do + if i == #expression.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then + local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1]; + table.insert(args, Ast.FunctionCallExpression( + self:unpack(scope), + {self:register(scope, reg)})); + table.insert(regs, reg); + else + local reg = self:compileExpression(expr, funcDepth, 1)[1]; + table.insert(args, self:register(scope, reg)); + table.insert(regs, reg); + end + end + + if returnAll or numReturns > 1 then + local tmpReg = self:allocRegister(false); + + self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(expression.passSelfFunctionName)), {tmpReg}, {}, false); + self:addStatement(self:setRegister(scope, tmpReg, Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, tmpReg))), {tmpReg}, {baseReg, tmpReg}, false); + + if returnAll then + self:addStatement(self:setRegister(scope, retRegs[1], Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, tmpReg), args))}), {retRegs[1]}, {tmpReg, unpack(regs)}, true); + else + self:addStatement(self:setRegister(scope, tmpReg, Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, tmpReg), args))}), {tmpReg}, {tmpReg, unpack(regs)}, true); + + for i, reg in ipairs(retRegs) do + self:addStatement(self:setRegister(scope, reg, Ast.IndexExpression(self:register(scope, tmpReg), Ast.NumberExpression(i))), {reg}, {tmpReg}, false); + end + end + + self:freeRegister(tmpReg, false); + else + local tmpReg = retRegs[1] or self:allocRegister(false); + + self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(expression.passSelfFunctionName)), {tmpReg}, {}, false); + self:addStatement(self:setRegister(scope, tmpReg, Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, tmpReg))), {tmpReg}, {baseReg, tmpReg}, false); + self:addStatement(self:setRegister(scope, retRegs[1], Ast.FunctionCallExpression(self:register(scope, tmpReg), args)), {retRegs[1]}, {baseReg, unpack(regs)}, true); + end + + for i, reg in ipairs(regs) do + self:freeRegister(reg, false); + end + + return retRegs; +end; diff --git a/src/prometheus/compiler/expressions/string.lua b/src/prometheus/compiler/expressions/string.lua new file mode 100644 index 00000000..776f0e8d --- /dev/null +++ b/src/prometheus/compiler/expressions/string.lua @@ -0,0 +1,21 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- string.lua +-- This Script contains the expression handler for the StringExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns, 1 do + regs[i] = self:allocRegister(); + if i == 1 then + self:addStatement(self:setRegister(scope, regs[i], Ast.StringExpression(expression.value)), {regs[i]}, {}, false); + else + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; + diff --git a/src/prometheus/compiler/expressions/table_constructor.lua b/src/prometheus/compiler/expressions/table_constructor.lua new file mode 100644 index 00000000..77a400e4 --- /dev/null +++ b/src/prometheus/compiler/expressions/table_constructor.lua @@ -0,0 +1,48 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- table_constructor.lua +-- This Script contains the expression handler for the TableConstructorExpression + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(); + if i == 1 then + local entries = {}; + local entryRegs = {}; + for i, entry in ipairs(expression.entries) do + if entry.kind == AstKind.TableEntry then + local value = entry.value; + if i == #expression.entries and (value.kind == AstKind.FunctionCallExpression or value.kind == AstKind.PassSelfFunctionCallExpression or value.kind == AstKind.VarargExpression) then + local reg = self:compileExpression(entry.value, funcDepth, self.RETURN_ALL)[1]; + table.insert(entries, Ast.TableEntry(Ast.FunctionCallExpression( + self:unpack(scope), + {self:register(scope, reg)}))); + table.insert(entryRegs, reg); + else + local reg = self:compileExpression(entry.value, funcDepth, 1)[1]; + table.insert(entries, Ast.TableEntry(self:register(scope, reg))); + table.insert(entryRegs, reg); + end + else + local keyReg = self:compileExpression(entry.key, funcDepth, 1)[1]; + local valReg = self:compileExpression(entry.value, funcDepth, 1)[1]; + table.insert(entries, Ast.KeyedTableEntry(self:register(scope, keyReg), self:register(scope, valReg))); + table.insert(entryRegs, valReg); + table.insert(entryRegs, keyReg); + end + end + self:addStatement(self:setRegister(scope, regs[i], Ast.TableConstructorExpression(entries)), {regs[i]}, entryRegs, false); + for i, reg in ipairs(entryRegs) do + self:freeRegister(reg, false); + end + else + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; diff --git a/src/prometheus/compiler/expressions/vararg.lua b/src/prometheus/compiler/expressions/vararg.lua new file mode 100644 index 00000000..322430a7 --- /dev/null +++ b/src/prometheus/compiler/expressions/vararg.lua @@ -0,0 +1,20 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- vararg.lua +-- This Script contains the expression handler for the VarargExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + if numReturns == self.RETURN_ALL then + return {self.varargReg}; + end + local regs = {}; + for i = 1, numReturns do + regs[i] = self:allocRegister(false); + self:addStatement(self:setRegister(scope, regs[i], Ast.IndexExpression(self:register(scope, self.varargReg), Ast.NumberExpression(i))), {regs[i]}, {self.varargReg}, false); + end + return regs; +end; + diff --git a/src/prometheus/compiler/expressions/variable.lua b/src/prometheus/compiler/expressions/variable.lua new file mode 100644 index 00000000..c72f0e41 --- /dev/null +++ b/src/prometheus/compiler/expressions/variable.lua @@ -0,0 +1,44 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- variable.lua +-- This Script contains the expression handler for the VariableExpression + +local Ast = require("prometheus.ast"); + +return function(self, expression, funcDepth, numReturns) + local scope = self.activeBlock.scope; + local regs = {}; + for i = 1, numReturns do + if i == 1 then + if expression.scope.isGlobal then + regs[i] = self:allocRegister(false); + local tmpReg = self:allocRegister(false); + self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(expression.scope:getVariableName(expression.id))), {tmpReg}, {}, false); + self:addStatement(self:setRegister(scope, regs[i], Ast.IndexExpression(self:env(scope), self:register(scope, tmpReg))), {regs[i]}, {tmpReg}, true); + self:freeRegister(tmpReg, false); + else + if self.scopeFunctionDepths[expression.scope] == funcDepth then + if self:isUpvalue(expression.scope, expression.id) then + local reg = self:allocRegister(false); + local varReg = self:getVarRegister(expression.scope, expression.id, funcDepth, nil); + self:addStatement(self:setRegister(scope, reg, self:getUpvalueMember(scope, self:register(scope, varReg))), {reg}, {varReg}, true); + regs[i] = reg; + else + regs[i] = self:getVarRegister(expression.scope, expression.id, funcDepth, nil); + end + else + local reg = self:allocRegister(false); + local upvalId = self:getUpvalueId(expression.scope, expression.id); + scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); + self:addStatement(self:setRegister(scope, reg, self:getUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)))), {reg}, {}, true); + regs[i] = reg; + end + end + else + regs[i] = self:allocRegister(); + self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false); + end + end + return regs; +end; + diff --git a/src/prometheus/compiler/register.lua b/src/prometheus/compiler/register.lua new file mode 100644 index 00000000..43789b5a --- /dev/null +++ b/src/prometheus/compiler/register.lua @@ -0,0 +1,256 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- register.lua +-- Register management for the compiler + +local Ast = require("prometheus.ast"); +local constants = require("prometheus.compiler.constants"); +local randomStrings = require("prometheus.randomStrings"); + +local MAX_REGS = constants.MAX_REGS; + +return function(Compiler) + function Compiler:freeRegister(id, force) + if force or not (self.registers[id] == self.VAR_REGISTER) then + self.usedRegisters = self.usedRegisters - 1; + self.registers[id] = false + end + end + + function Compiler:isVarRegister(id) + return self.registers[id] == self.VAR_REGISTER; + end + + function Compiler:allocRegister(isVar) + self.usedRegisters = self.usedRegisters + 1; + + if not isVar then + if not self.registers[self.POS_REGISTER] then + self.registers[self.POS_REGISTER] = true; + return self.POS_REGISTER; + end + + if not self.registers[self.RETURN_REGISTER] then + self.registers[self.RETURN_REGISTER] = true; + return self.RETURN_REGISTER; + end + end + + local id = 0; + if self.usedRegisters < MAX_REGS * constants.MAX_REGS_MUL then + repeat + id = math.random(1, MAX_REGS - 1); + until not self.registers[id]; + else + repeat + id = id + 1; + until not self.registers[id]; + end + + if id > self.maxUsedRegister then + self.maxUsedRegister = id; + end + + if(isVar) then + self.registers[id] = self.VAR_REGISTER; + else + self.registers[id] = true + end + return id; + end + + function Compiler:isUpvalue(scope, id) + return self.upvalVars[scope] and self.upvalVars[scope][id]; + end + + function Compiler:makeUpvalue(scope, id) + if(not self.upvalVars[scope]) then + self.upvalVars[scope] = {} + end + self.upvalVars[scope][id] = true; + end + + function Compiler:getVarRegister(scope, id, functionDepth, potentialId) + if(not self.registersForVar[scope]) then + self.registersForVar[scope] = {}; + self.scopeFunctionDepths[scope] = functionDepth; + end + + local reg = self.registersForVar[scope][id]; + if not reg then + if potentialId and self.registers[potentialId] ~= self.VAR_REGISTER and potentialId ~= self.POS_REGISTER and potentialId ~= self.RETURN_REGISTER then + self.registers[potentialId] = self.VAR_REGISTER; + reg = potentialId; + else + reg = self:allocRegister(true); + end + self.registersForVar[scope][id] = reg; + end + return reg; + end + + function Compiler:getRegisterVarId(id) + local varId = self.registerVars[id]; + if not varId then + varId = self.containerFuncScope:addVariable(); + self.registerVars[id] = varId; + end + return varId; + end + + function Compiler:register(scope, id) + if id == self.POS_REGISTER then + return self:pos(scope); + end + + if id == self.RETURN_REGISTER then + return self:getReturn(scope); + end + + if id < MAX_REGS then + local vid = self:getRegisterVarId(id); + scope:addReferenceToHigherScope(self.containerFuncScope, vid); + return Ast.VariableExpression(self.containerFuncScope, vid); + end + + local vid = self:getRegisterVarId(MAX_REGS); + scope:addReferenceToHigherScope(self.containerFuncScope, vid); + return Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, vid), Ast.NumberExpression((id - MAX_REGS) + 1)); + end + + function Compiler:registerList(scope, ids) + local l = {}; + for i, id in ipairs(ids) do + table.insert(l, self:register(scope, id)); + end + return l; + end + + function Compiler:registerAssignment(scope, id) + if id == self.POS_REGISTER then + return self:posAssignment(scope); + end + if id == self.RETURN_REGISTER then + return self:returnAssignment(scope); + end + + if id < MAX_REGS then + local vid = self:getRegisterVarId(id); + scope:addReferenceToHigherScope(self.containerFuncScope, vid); + return Ast.AssignmentVariable(self.containerFuncScope, vid); + end + + local vid = self:getRegisterVarId(MAX_REGS); + scope:addReferenceToHigherScope(self.containerFuncScope, vid); + return Ast.AssignmentIndexing(Ast.VariableExpression(self.containerFuncScope, vid), Ast.NumberExpression((id - MAX_REGS) + 1)); + end + + function Compiler:setRegister(scope, id, val, compundArg) + if(compundArg) then + return compundArg(self:registerAssignment(scope, id), val); + end + return Ast.AssignmentStatement({ + self:registerAssignment(scope, id) + }, { + val + }); + end + + function Compiler:setRegisters(scope, ids, vals) + local idStats = {}; + for i, id in ipairs(ids) do + table.insert(idStats, self:registerAssignment(scope, id)); + end + + return Ast.AssignmentStatement(idStats, vals); + end + + function Compiler:copyRegisters(scope, to, from) + local idStats = {}; + local vals = {}; + for i, id in ipairs(to) do + local fromId = from[i]; + if(fromId ~= id) then + table.insert(idStats, self:registerAssignment(scope, id)); + table.insert(vals, self:register(scope, fromId)); + end + end + + if(#idStats > 0 and #vals > 0) then + return Ast.AssignmentStatement(idStats, vals); + end + end + + function Compiler:resetRegisters() + self.registers = {}; + end + + function Compiler:pos(scope) + scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); + return Ast.VariableExpression(self.containerFuncScope, self.posVar); + end + + function Compiler:posAssignment(scope) + scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); + return Ast.AssignmentVariable(self.containerFuncScope, self.posVar); + end + + function Compiler:args(scope) + scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar); + return Ast.VariableExpression(self.containerFuncScope, self.argsVar); + end + + function Compiler:unpack(scope) + scope:addReferenceToHigherScope(self.scope, self.unpackVar); + return Ast.VariableExpression(self.scope, self.unpackVar); + end + + function Compiler:env(scope) + scope:addReferenceToHigherScope(self.scope, self.envVar); + return Ast.VariableExpression(self.scope, self.envVar); + end + + function Compiler:jmp(scope, to) + scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); + return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.posVar)},{to}); + end + + function Compiler:setPos(scope, val) + if not val then + local v = Ast.IndexExpression(self:env(scope), randomStrings.randomStringNode(math.random(12, 14))); + scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); + return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.posVar)}, {v}); + end + scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar); + return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.posVar)}, {Ast.NumberExpression(val) or Ast.NilExpression()}); + end + + function Compiler:setReturn(scope, val) + scope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar); + return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.returnVar)}, {val}); + end + + function Compiler:getReturn(scope) + scope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar); + return Ast.VariableExpression(self.containerFuncScope, self.returnVar); + end + + function Compiler:returnAssignment(scope) + scope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar); + return Ast.AssignmentVariable(self.containerFuncScope, self.returnVar); + end + + function Compiler:setUpvalueMember(scope, idExpr, valExpr, compoundConstructor) + scope:addReferenceToHigherScope(self.scope, self.upvaluesTable); + if compoundConstructor then + return compoundConstructor(Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), idExpr), valExpr); + end + return Ast.AssignmentStatement({Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), idExpr)}, {valExpr}); + end + + function Compiler:getUpvalueMember(scope, idExpr) + scope:addReferenceToHigherScope(self.scope, self.upvaluesTable); + return Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesTable), idExpr); + end +end + diff --git a/src/prometheus/compiler/statements.lua b/src/prometheus/compiler/statements.lua new file mode 100644 index 00000000..62264d79 --- /dev/null +++ b/src/prometheus/compiler/statements.lua @@ -0,0 +1,42 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- statements.lua +-- This Script contains the statement handlers: exports handler table keyed by AstKind + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +local handlers = {}; +local statements = "prometheus.compiler.statements."; +local function requireStatement(name) + return require(statements .. name); +end + +handlers[AstKind.ReturnStatement] = requireStatement("return"); +handlers[AstKind.LocalVariableDeclaration] = requireStatement("local_variable_declaration"); +handlers[AstKind.FunctionCallStatement] = requireStatement("function_call"); +handlers[AstKind.PassSelfFunctionCallStatement] = requireStatement("pass_self_function_call"); +handlers[AstKind.LocalFunctionDeclaration] = requireStatement("local_function_declaration"); +handlers[AstKind.FunctionDeclaration] = requireStatement("function_declaration"); +handlers[AstKind.AssignmentStatement] = requireStatement("assignment"); +handlers[AstKind.IfStatement] = requireStatement("if_statement"); +handlers[AstKind.DoStatement] = requireStatement("do_statement"); +handlers[AstKind.WhileStatement] = requireStatement("while_statement"); +handlers[AstKind.RepeatStatement] = requireStatement("repeat_statement"); +handlers[AstKind.ForStatement] = requireStatement("for_statement"); +handlers[AstKind.ForInStatement] = requireStatement("for_in_statement"); +handlers[AstKind.BreakStatement] = requireStatement("break_statement"); +handlers[AstKind.ContinueStatement] = requireStatement("continue_statement"); + +-- Compound statements share one handler +local compoundHandler = requireStatement("compound"); +handlers[AstKind.CompoundAddStatement] = compoundHandler; +handlers[AstKind.CompoundSubStatement] = compoundHandler; +handlers[AstKind.CompoundMulStatement] = compoundHandler; +handlers[AstKind.CompoundDivStatement] = compoundHandler; +handlers[AstKind.CompoundModStatement] = compoundHandler; +handlers[AstKind.CompoundPowStatement] = compoundHandler; +handlers[AstKind.CompoundConcatStatement] = compoundHandler; + +return handlers; + diff --git a/src/prometheus/compiler/statements/assignment.lua b/src/prometheus/compiler/statements/assignment.lua new file mode 100644 index 00000000..305160e9 --- /dev/null +++ b/src/prometheus/compiler/statements/assignment.lua @@ -0,0 +1,87 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- assignment.lua +-- This Script contains the statement handler for the AssignmentStatement + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local exprregs = {}; + local assignmentIndexingRegs = {}; + for i, primaryExpr in ipairs(statement.lhs) do + if(primaryExpr.kind == AstKind.AssignmentIndexing) then + assignmentIndexingRegs [i] = { + base = self:compileExpression(primaryExpr.base, funcDepth, 1)[1], + index = self:compileExpression(primaryExpr.index, funcDepth, 1)[1], + }; + end + end + + for i, expr in ipairs(statement.rhs) do + if(i == #statement.rhs and #statement.lhs > #statement.rhs) then + local regs = self:compileExpression(expr, funcDepth, #statement.lhs - #statement.rhs + 1); + + for i, reg in ipairs(regs) do + if(self:isVarRegister(reg)) then + local ro = reg; + reg = self:allocRegister(false); + self:addStatement(self:copyRegisters(scope, {reg}, {ro}), {reg}, {ro}, false); + end + table.insert(exprregs, reg); + end + else + if statement.lhs[i] or expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression then + local reg = self:compileExpression(expr, funcDepth, 1)[1]; + if(self:isVarRegister(reg)) then + local ro = reg; + reg = self:allocRegister(false); + self:addStatement(self:copyRegisters(scope, {reg}, {ro}), {reg}, {ro}, false); + end + table.insert(exprregs, reg); + end + end + end + + for i, primaryExpr in ipairs(statement.lhs) do + if primaryExpr.kind == AstKind.AssignmentVariable then + if primaryExpr.scope.isGlobal then + local tmpReg = self:allocRegister(false); + self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(primaryExpr.scope:getVariableName(primaryExpr.id))), {tmpReg}, {}, false); + self:addStatement(Ast.AssignmentStatement({Ast.AssignmentIndexing(self:env(scope), self:register(scope, tmpReg))}, + {self:register(scope, exprregs[i])}), {}, {tmpReg, exprregs[i]}, true); + self:freeRegister(tmpReg, false); + else + if self.scopeFunctionDepths[primaryExpr.scope] == funcDepth then + if self:isUpvalue(primaryExpr.scope, primaryExpr.id) then + local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth); + self:addStatement(self:setUpvalueMember(scope, self:register(scope, reg), self:register(scope, exprregs[i])), {}, {reg, exprregs[i]}, true); + else + local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth, exprregs[i]); + if reg ~= exprregs[i] then + self:addStatement(self:setRegister(scope, reg, self:register(scope, exprregs[i])), {reg}, {exprregs[i]}, false); + end + end + else + local upvalId = self:getUpvalueId(primaryExpr.scope, primaryExpr.id); + scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); + self:addStatement(self:setUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)), self:register(scope, exprregs[i])), {}, {exprregs[i]}, true); + end + end + elseif primaryExpr.kind == AstKind.AssignmentIndexing then + local baseReg = assignmentIndexingRegs[i].base; + local indexReg = assignmentIndexingRegs[i].index; + self:addStatement(Ast.AssignmentStatement({ + Ast.AssignmentIndexing(self:register(scope, baseReg), self:register(scope, indexReg)) + }, { + self:register(scope, exprregs[i]) + }), {}, {exprregs[i], baseReg, indexReg}, true); + self:freeRegister(exprregs[i], false); + self:freeRegister(baseReg, false); + self:freeRegister(indexReg, false); + else + error(string.format("Invalid Assignment lhs: %s", statement.lhs)); + end + end +end; diff --git a/src/prometheus/compiler/statements/break_statement.lua b/src/prometheus/compiler/statements/break_statement.lua new file mode 100644 index 00000000..909c0260 --- /dev/null +++ b/src/prometheus/compiler/statements/break_statement.lua @@ -0,0 +1,38 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- break_statement.lua +-- This Script contains the statement handler for the BreakStatement + +local Ast = require("prometheus.ast"); + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local toFreeVars = {}; + local statScope; + repeat + statScope = statScope and statScope.parentScope or statement.scope; + for id, name in ipairs(statScope.variables) do + table.insert(toFreeVars, { + scope = statScope, + id = id; + }); + end + until statScope == statement.loop.body.scope; + + for i, var in pairs(toFreeVars) do + local varScope, id = var.scope, var.id; + local varReg = self:getVarRegister(varScope, id, nil, nil); + if self:isUpvalue(varScope, id) then + scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc); + self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), { + self:register(scope, varReg) + })), {varReg}, {varReg}, false); + else + self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), {varReg}, {}, false); + end + end + + + self:addStatement(self:setPos(scope, statement.loop.__final_block.id), {self.POS_REGISTER}, {}, false); + self.activeBlock.advanceToNextBlock = false; +end; diff --git a/src/prometheus/compiler/statements/compound.lua b/src/prometheus/compiler/statements/compound.lua new file mode 100644 index 00000000..a07eb097 --- /dev/null +++ b/src/prometheus/compiler/statements/compound.lua @@ -0,0 +1,61 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- compound.lua +-- This Script contains the statement handler for the Compound statements (compound add, sub, mul, etc.) + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +local compoundConstructors = { + [AstKind.CompoundAddStatement] = Ast.CompoundAddStatement, + [AstKind.CompoundSubStatement] = Ast.CompoundSubStatement, + [AstKind.CompoundMulStatement] = Ast.CompoundMulStatement, + [AstKind.CompoundDivStatement] = Ast.CompoundDivStatement, + [AstKind.CompoundModStatement] = Ast.CompoundModStatement, + [AstKind.CompoundPowStatement] = Ast.CompoundPowStatement, + [AstKind.CompoundConcatStatement] = Ast.CompoundConcatStatement, +}; + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local compoundConstructor = compoundConstructors[statement.kind]; + if statement.lhs.kind == AstKind.AssignmentIndexing then + local indexing = statement.lhs; + local baseReg = self:compileExpression(indexing.base, funcDepth, 1)[1]; + local indexReg = self:compileExpression(indexing.index, funcDepth, 1)[1]; + local valueReg = self:compileExpression(statement.rhs, funcDepth, 1)[1]; + + self:addStatement(compoundConstructor(Ast.AssignmentIndexing(self:register(scope, baseReg), self:register(scope, indexReg)), self:register(scope, valueReg)), {}, {baseReg, indexReg, valueReg}, true); + self:freeRegister(baseReg, false); + self:freeRegister(indexReg, false); + self:freeRegister(valueReg, false); + else + local valueReg = self:compileExpression(statement.rhs, funcDepth, 1)[1]; + local primaryExpr = statement.lhs; + if primaryExpr.scope.isGlobal then + local tmpReg = self:allocRegister(false); + self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(primaryExpr.scope:getVariableName(primaryExpr.id))), {tmpReg}, {}, false); + self:addStatement(compoundConstructor(Ast.AssignmentIndexing(self:env(scope), self:register(scope, tmpReg)), + self:register(scope, valueReg)), {}, {tmpReg, valueReg}, true); + self:freeRegister(tmpReg, false); + self:freeRegister(valueReg, false); + else + if self.scopeFunctionDepths[primaryExpr.scope] == funcDepth then + if self:isUpvalue(primaryExpr.scope, primaryExpr.id) then + local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth); + self:addStatement(self:setUpvalueMember(scope, self:register(scope, reg), self:register(scope, valueReg), compoundConstructor), {}, {reg, valueReg}, true); + else + local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth, valueReg); + if reg ~= valueReg then + self:addStatement(self:setRegister(scope, reg, self:register(scope, valueReg), compoundConstructor), {reg}, {valueReg}, false); + end + end + else + local upvalId = self:getUpvalueId(primaryExpr.scope, primaryExpr.id); + scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); + self:addStatement(self:setUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)), self:register(scope, valueReg), compoundConstructor), {}, {valueReg}, true); + end + self:freeRegister(valueReg, false); + end + end +end; diff --git a/src/prometheus/compiler/statements/continue_statement.lua b/src/prometheus/compiler/statements/continue_statement.lua new file mode 100644 index 00000000..e2b0984f --- /dev/null +++ b/src/prometheus/compiler/statements/continue_statement.lua @@ -0,0 +1,38 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- continue_statement.lua +-- This Script contains the statement handler for the ContinueStatement + +local Ast = require("prometheus.ast"); + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local toFreeVars = {}; + local statScope; + repeat + statScope = statScope and statScope.parentScope or statement.scope; + for id, name in pairs(statScope.variables) do + table.insert(toFreeVars, { + scope = statScope, + id = id; + }); + end + until statScope == statement.loop.body.scope; + + for i, var in ipairs(toFreeVars) do + local varScope, id = var.scope, var.id; + local varReg = self:getVarRegister(varScope, id, nil, nil); + if self:isUpvalue(varScope, id) then + scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc); + self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), { + self:register(scope, varReg) + })), {varReg}, {varReg}, false); + else + self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), {varReg}, {}, false); + end + end + + + self:addStatement(self:setPos(scope, statement.loop.__start_block.id), {self.POS_REGISTER}, {}, false); + self.activeBlock.advanceToNextBlock = false; +end; diff --git a/src/prometheus/compiler/statements/do_statement.lua b/src/prometheus/compiler/statements/do_statement.lua new file mode 100644 index 00000000..d8b7f025 --- /dev/null +++ b/src/prometheus/compiler/statements/do_statement.lua @@ -0,0 +1,9 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- do_statement.lua +-- This Script contains the statement handler for the DoStatement + +return function(self, statement, funcDepth) + self:compileBlock(statement.body, funcDepth); +end; + diff --git a/src/prometheus/compiler/statements/for_in_statement.lua b/src/prometheus/compiler/statements/for_in_statement.lua new file mode 100644 index 00000000..fd779351 --- /dev/null +++ b/src/prometheus/compiler/statements/for_in_statement.lua @@ -0,0 +1,101 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- for_in_statement.lua +-- This Script contains the statement handler for the ForInStatement + +local Ast = require("prometheus.ast"); + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local expressionsLength = #statement.expressions; + local exprregs = {}; + for i, expr in ipairs(statement.expressions) do + if(i == expressionsLength and expressionsLength < 3) then + local regs = self:compileExpression(expr, funcDepth, 4 - expressionsLength); + for i = 1, 4 - expressionsLength do + table.insert(exprregs, regs[i]); + end + else + if i <= 3 then + table.insert(exprregs, self:compileExpression(expr, funcDepth, 1)[1]) + else + self:freeRegister(self:compileExpression(expr, funcDepth, 1)[1], false); + end + end + end + + for i, reg in ipairs(exprregs) do + if reg and self.registers[reg] ~= self.VAR_REGISTER and reg ~= self.POS_REGISTER and reg ~= self.RETURN_REGISTER then + self.registers[reg] = self.VAR_REGISTER; + else + exprregs[i] = self:allocRegister(true); + self:addStatement(self:copyRegisters(scope, {exprregs[i]}, {reg}), {exprregs[i]}, {reg}, false); + end + end + + local checkBlock = self:createBlock(); + local bodyBlock = self:createBlock(); + local finalBlock = self:createBlock(); + + statement.__start_block = checkBlock; + statement.__final_block = finalBlock; + + self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false); + + self:setActiveBlock(checkBlock); + local scope = self.activeBlock.scope; + + local varRegs = {}; + for i, id in ipairs(statement.ids) do + varRegs[i] = self:getVarRegister(statement.scope, id, funcDepth) + end + + + + self:addStatement(Ast.AssignmentStatement({ + self:registerAssignment(scope, exprregs[3]), + varRegs[2] and self:registerAssignment(scope, varRegs[2]), + }, { + Ast.FunctionCallExpression(self:register(scope, exprregs[1]), { + self:register(scope, exprregs[2]), + self:register(scope, exprregs[3]), + }) + }), {exprregs[3], varRegs[2]}, {exprregs[1], exprregs[2], exprregs[3]}, true); + + + + self:addStatement(Ast.AssignmentStatement({ + self:posAssignment(scope) + }, { + Ast.OrExpression(Ast.AndExpression(self:register(scope, exprregs[3]), Ast.NumberExpression(bodyBlock.id)), Ast.NumberExpression(finalBlock.id)) + }), {self.POS_REGISTER}, {exprregs[3]}, false); + + self:setActiveBlock(bodyBlock); + local scope = self.activeBlock.scope; + + self:addStatement(self:copyRegisters(scope, {varRegs[1]}, {exprregs[3]}), {varRegs[1]}, {exprregs[3]}, false); + + for i=3, #varRegs do + self:addStatement(self:setRegister(scope, varRegs[i], Ast.NilExpression()), {varRegs[i]}, {}, false); + end + + for i, id in ipairs(statement.ids) do + if(self:isUpvalue(statement.scope, id)) then + local varreg = varRegs[i]; + local tmpReg = self:allocRegister(false); + scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); + self:addStatement(self:setRegister(scope, tmpReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {tmpReg}, {}, false); + self:addStatement(self:setUpvalueMember(scope, self:register(scope, tmpReg), self:register(scope, varreg)), {}, {tmpReg, varreg}, true); + self:addStatement(self:copyRegisters(scope, {varreg}, {tmpReg}), {varreg}, {tmpReg}, false); + self:freeRegister(tmpReg, false); + end + end + + self:compileBlock(statement.body, funcDepth); + self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false); + self:setActiveBlock(finalBlock); + + for i, reg in ipairs(exprregs) do + self:freeRegister(exprregs[i], true) + end +end; diff --git a/src/prometheus/compiler/statements/for_statement.lua b/src/prometheus/compiler/statements/for_statement.lua new file mode 100644 index 00000000..38adb3d9 --- /dev/null +++ b/src/prometheus/compiler/statements/for_statement.lua @@ -0,0 +1,92 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- for_statement.lua +-- This Script contains the statement handler for the ForStatement + +local Ast = require("prometheus.ast"); + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local checkBlock = self:createBlock(); + local innerBlock = self:createBlock(); + local finalBlock = self:createBlock(); + + statement.__start_block = checkBlock; + statement.__final_block = finalBlock; + + local posState = self.registers[self.POS_REGISTER]; + self.registers[self.POS_REGISTER] = self.VAR_REGISTER; + + local initialReg = self:compileExpression(statement.initialValue, funcDepth, 1)[1]; + + local finalExprReg = self:compileExpression(statement.finalValue, funcDepth, 1)[1]; + local finalReg = self:allocRegister(false); + self:addStatement(self:copyRegisters(scope, {finalReg}, {finalExprReg}), {finalReg}, {finalExprReg}, false); + self:freeRegister(finalExprReg); + + local incrementExprReg = self:compileExpression(statement.incrementBy, funcDepth, 1)[1]; + local incrementReg = self:allocRegister(false); + self:addStatement(self:copyRegisters(scope, {incrementReg}, {incrementExprReg}), {incrementReg}, {incrementExprReg}, false); + self:freeRegister(incrementExprReg); + + local tmpReg = self:allocRegister(false); + self:addStatement(self:setRegister(scope, tmpReg, Ast.NumberExpression(0)), {tmpReg}, {}, false); + local incrementIsNegReg = self:allocRegister(false); + self:addStatement(self:setRegister(scope, incrementIsNegReg, Ast.LessThanExpression(self:register(scope, incrementReg), self:register(scope, tmpReg))), {incrementIsNegReg}, {incrementReg, tmpReg}, false); + self:freeRegister(tmpReg); + + local currentReg = self:allocRegister(true); + self:addStatement(self:setRegister(scope, currentReg, Ast.SubExpression(self:register(scope, initialReg), self:register(scope, incrementReg))), {currentReg}, {initialReg, incrementReg}, false); + self:freeRegister(initialReg); + + self:addStatement(self:jmp(scope, Ast.NumberExpression(checkBlock.id)), {self.POS_REGISTER}, {}, false); + + self:setActiveBlock(checkBlock); + + scope = checkBlock.scope; + self:addStatement(self:setRegister(scope, currentReg, Ast.AddExpression(self:register(scope, currentReg), self:register(scope, incrementReg))), {currentReg}, {currentReg, incrementReg}, false); + local tmpReg1 = self:allocRegister(false); + local tmpReg2 = self:allocRegister(false); + self:addStatement(self:setRegister(scope, tmpReg2, Ast.NotExpression(self:register(scope, incrementIsNegReg))), {tmpReg2}, {incrementIsNegReg}, false); + self:addStatement(self:setRegister(scope, tmpReg1, Ast.LessThanOrEqualsExpression(self:register(scope, currentReg), self:register(scope, finalReg))), {tmpReg1}, {currentReg, finalReg}, false); + self:addStatement(self:setRegister(scope, tmpReg1, Ast.AndExpression(self:register(scope, tmpReg2), self:register(scope, tmpReg1))), {tmpReg1}, {tmpReg1, tmpReg2}, false); + self:addStatement(self:setRegister(scope, tmpReg2, Ast.GreaterThanOrEqualsExpression(self:register(scope, currentReg), self:register(scope, finalReg))), {tmpReg2}, {currentReg, finalReg}, false); + self:addStatement(self:setRegister(scope, tmpReg2, Ast.AndExpression(self:register(scope, incrementIsNegReg), self:register(scope, tmpReg2))), {tmpReg2}, {tmpReg2, incrementIsNegReg}, false); + self:addStatement(self:setRegister(scope, tmpReg1, Ast.OrExpression(self:register(scope, tmpReg2), self:register(scope, tmpReg1))), {tmpReg1}, {tmpReg1, tmpReg2}, false); + self:freeRegister(tmpReg2); + tmpReg2 = self:compileExpression(Ast.NumberExpression(innerBlock.id), funcDepth, 1)[1]; + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.AndExpression(self:register(scope, tmpReg1), self:register(scope, tmpReg2))), {self.POS_REGISTER}, {tmpReg1, tmpReg2}, false); + self:freeRegister(tmpReg2); + self:freeRegister(tmpReg1); + tmpReg2 = self:compileExpression(Ast.NumberExpression(finalBlock.id), funcDepth, 1)[1]; + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(self:register(scope, self.POS_REGISTER), self:register(scope, tmpReg2))), {self.POS_REGISTER}, {self.POS_REGISTER, tmpReg2}, false); + self:freeRegister(tmpReg2); + + self:setActiveBlock(innerBlock); + scope = innerBlock.scope; + self.registers[self.POS_REGISTER] = posState; + + local varReg = self:getVarRegister(statement.scope, statement.id, funcDepth, nil); + + if(self:isUpvalue(statement.scope, statement.id)) then + scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); + self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {varReg}, {}, false); + self:addStatement(self:setUpvalueMember(scope, self:register(scope, varReg), self:register(scope, currentReg)), {}, {varReg, currentReg}, true); + else + self:addStatement(self:setRegister(scope, varReg, self:register(scope, currentReg)), {varReg}, {currentReg}, false); + end + + + self:compileBlock(statement.body, funcDepth); + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(checkBlock.id)), {self.POS_REGISTER}, {}, false); + + self.registers[self.POS_REGISTER] = self.VAR_REGISTER; + self:freeRegister(finalReg); + self:freeRegister(incrementIsNegReg); + self:freeRegister(incrementReg); + self:freeRegister(currentReg, true); + + self.registers[self.POS_REGISTER] = posState; + self:setActiveBlock(finalBlock); +end; + diff --git a/src/prometheus/compiler/statements/function_call.lua b/src/prometheus/compiler/statements/function_call.lua new file mode 100644 index 00000000..865a5e40 --- /dev/null +++ b/src/prometheus/compiler/statements/function_call.lua @@ -0,0 +1,38 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- function_call.lua +-- This Script contains the statement handler for the FunctionCallStatement + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local baseReg = self:compileExpression(statement.base, funcDepth, 1)[1]; + local retReg = self:allocRegister(false); + local regs = {}; + local args = {}; + + for i, expr in ipairs(statement.args) do + if i == #statement.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then + local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1]; + table.insert(args, Ast.FunctionCallExpression( + self:unpack(scope), + {self:register(scope, reg)})); + table.insert(regs, reg); + else + local reg = self:compileExpression(expr, funcDepth, 1)[1]; + local argExpr = self:register(scope, reg); + table.insert(args, argExpr); + table.insert(regs, reg); + end + end + + self:addStatement(self:setRegister(scope, retReg, Ast.FunctionCallExpression(self:register(scope, baseReg), args)), {retReg}, {baseReg, unpack(regs)}, true); + self:freeRegister(baseReg, false); + self:freeRegister(retReg, false); + for i, reg in ipairs(regs) do + self:freeRegister(reg, false); + end +end; + diff --git a/src/prometheus/compiler/statements/function_declaration.lua b/src/prometheus/compiler/statements/function_declaration.lua new file mode 100644 index 00000000..8142a2fe --- /dev/null +++ b/src/prometheus/compiler/statements/function_declaration.lua @@ -0,0 +1,82 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- function_declaration.lua +-- This Script contains the statement handler for the FunctionDeclaration + +local Ast = require("prometheus.ast"); + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local retReg = self:compileFunction(statement, funcDepth); + if(#statement.indices > 0) then + local tblReg; + if statement.scope.isGlobal then + tblReg = self:allocRegister(false); + self:addStatement(self:setRegister(scope, tblReg, Ast.StringExpression(statement.scope:getVariableName(statement.id))), {tblReg}, {}, false); + self:addStatement(self:setRegister(scope, tblReg, Ast.IndexExpression(self:env(scope), self:register(scope, tblReg))), {tblReg}, {tblReg}, true); + else + if self.scopeFunctionDepths[statement.scope] == funcDepth then + if self:isUpvalue(statement.scope, statement.id) then + tblReg = self:allocRegister(false); + local reg = self:getVarRegister(statement.scope, statement.id, funcDepth); + self:addStatement(self:setRegister(scope, tblReg, self:getUpvalueMember(scope, self:register(scope, reg))), {tblReg}, {reg}, true); + else + tblReg = self:getVarRegister(statement.scope, statement.id, funcDepth, retReg); + end + else + tblReg = self:allocRegister(false); + local upvalId = self:getUpvalueId(statement.scope, statement.id); + scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); + self:addStatement(self:setRegister(scope, tblReg, self:getUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)))), {tblReg}, {}, true); + end + end + + for i = 1, #statement.indices - 1 do + local index = statement.indices[i]; + local indexReg = self:compileExpression(Ast.StringExpression(index), funcDepth, 1)[1]; + local tblRegOld = tblReg; + tblReg = self:allocRegister(false); + self:addStatement(self:setRegister(scope, tblReg, Ast.IndexExpression(self:register(scope, tblRegOld), self:register(scope, indexReg))), {tblReg}, {tblReg, indexReg}, false); + self:freeRegister(tblRegOld, false); + self:freeRegister(indexReg, false); + end + + local index = statement.indices[#statement.indices]; + local indexReg = self:compileExpression(Ast.StringExpression(index), funcDepth, 1)[1]; + self:addStatement(Ast.AssignmentStatement({ + Ast.AssignmentIndexing(self:register(scope, tblReg), self:register(scope, indexReg)), + }, { + self:register(scope, retReg), + }), {}, {tblReg, indexReg, retReg}, true); + self:freeRegister(indexReg, false); + self:freeRegister(tblReg, false); + self:freeRegister(retReg, false); + + return; + end + if statement.scope.isGlobal then + local tmpReg = self:allocRegister(false); + self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(statement.scope:getVariableName(statement.id))), {tmpReg}, {}, false); + self:addStatement(Ast.AssignmentStatement({Ast.AssignmentIndexing(self:env(scope), self:register(scope, tmpReg))}, + {self:register(scope, retReg)}), {}, {tmpReg, retReg}, true); + self:freeRegister(tmpReg, false); + else + if self.scopeFunctionDepths[statement.scope] == funcDepth then + if self:isUpvalue(statement.scope, statement.id) then + local reg = self:getVarRegister(statement.scope, statement.id, funcDepth); + self:addStatement(self:setUpvalueMember(scope, self:register(scope, reg), self:register(scope, retReg)), {}, {reg, retReg}, true); + else + local reg = self:getVarRegister(statement.scope, statement.id, funcDepth, retReg); + if reg ~= retReg then + self:addStatement(self:setRegister(scope, reg, self:register(scope, retReg)), {reg}, {retReg}, false); + end + end + else + local upvalId = self:getUpvalueId(statement.scope, statement.id); + scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar); + self:addStatement(self:setUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)), self:register(scope, retReg)), {}, {retReg}, true); + end + end + self:freeRegister(retReg, false); +end; + diff --git a/src/prometheus/compiler/statements/if_statement.lua b/src/prometheus/compiler/statements/if_statement.lua new file mode 100644 index 00000000..45b2c127 --- /dev/null +++ b/src/prometheus/compiler/statements/if_statement.lua @@ -0,0 +1,60 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- if_statement.lua +-- This Script contains the statement handler for the IfStatement + +local Ast = require("prometheus.ast"); + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local conditionReg = self:compileExpression(statement.condition, funcDepth, 1)[1]; + local finalBlock = self:createBlock(); + + local nextBlock + if statement.elsebody or #statement.elseifs > 0 then + nextBlock = self:createBlock(); + else + nextBlock = finalBlock; + end + local innerBlock = self:createBlock(); + + + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(innerBlock.id)), Ast.NumberExpression(nextBlock.id))), {self.POS_REGISTER}, {conditionReg}, false); + + self:freeRegister(conditionReg, false); + + self:setActiveBlock(innerBlock); + scope = innerBlock.scope + self:compileBlock(statement.body, funcDepth); + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(finalBlock.id)), {self.POS_REGISTER}, {}, false); + + for i, eif in ipairs(statement.elseifs) do + self:setActiveBlock(nextBlock); + conditionReg = self:compileExpression(eif.condition, funcDepth, 1)[1]; + local innerBlock = self:createBlock(); + if statement.elsebody or i < #statement.elseifs then + nextBlock = self:createBlock(); + else + nextBlock = finalBlock; + end + local scope = self.activeBlock.scope; + + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(innerBlock.id)), Ast.NumberExpression(nextBlock.id))), {self.POS_REGISTER}, {conditionReg}, false); + + + self:freeRegister(conditionReg, false); + + self:setActiveBlock(innerBlock); + scope = innerBlock.scope; + self:compileBlock(eif.body, funcDepth); + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(finalBlock.id)), {self.POS_REGISTER}, {}, false); + end + + if statement.elsebody then + self:setActiveBlock(nextBlock); + self:compileBlock(statement.elsebody, funcDepth); + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(finalBlock.id)), {self.POS_REGISTER}, {}, false); + end + + self:setActiveBlock(finalBlock); +end; diff --git a/src/prometheus/compiler/statements/local_function_declaration.lua b/src/prometheus/compiler/statements/local_function_declaration.lua new file mode 100644 index 00000000..22525f1c --- /dev/null +++ b/src/prometheus/compiler/statements/local_function_declaration.lua @@ -0,0 +1,26 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- local_function_declaration.lua +-- This Script contains the statement handler for the LocalFunctionDeclaration + +local Ast = require("prometheus.ast"); + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + + if(self:isUpvalue(statement.scope, statement.id)) then + local varReg = self:getVarRegister(statement.scope, statement.id, funcDepth, nil); + scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); + self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {varReg}, {}, false); + local retReg = self:compileFunction(statement, funcDepth); + self:addStatement(self:setUpvalueMember(scope, self:register(scope, varReg), self:register(scope, retReg)), {}, {varReg, retReg}, true); + self:freeRegister(retReg, false); + else + local retReg = self:compileFunction(statement, funcDepth); + local varReg = self:getVarRegister(statement.scope, statement.id, funcDepth, retReg); + + self:addStatement(self:copyRegisters(scope, {varReg}, {retReg}), {varReg}, {retReg}, false); + self:freeRegister(retReg, false); + end +end; + diff --git a/src/prometheus/compiler/statements/local_variable_declaration.lua b/src/prometheus/compiler/statements/local_variable_declaration.lua new file mode 100644 index 00000000..5189c8e4 --- /dev/null +++ b/src/prometheus/compiler/statements/local_variable_declaration.lua @@ -0,0 +1,53 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- local_variable_declaration.lua +-- This Script contains the statement handler for the LocalVariableDeclaration + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local exprregs = {}; + for i, expr in ipairs(statement.expressions) do + if(i == #statement.expressions and #statement.ids > #statement.expressions) then + local regs = self:compileExpression(expr, funcDepth, #statement.ids - #statement.expressions + 1); + for i, reg in ipairs(regs) do + table.insert(exprregs, reg); + end + else + if statement.ids[i] or expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression then + local reg = self:compileExpression(expr, funcDepth, 1)[1]; + table.insert(exprregs, reg); + end + end + end + + if #exprregs == 0 then + for i=1, #statement.ids do + table.insert(exprregs, self:compileExpression(Ast.NilExpression(), funcDepth, 1)[1]); + end + end + + for i, id in ipairs(statement.ids) do + if(exprregs[i]) then + if(self:isUpvalue(statement.scope, id)) then + local varreg = self:getVarRegister(statement.scope, id, funcDepth); + local varReg = self:getVarRegister(statement.scope, id, funcDepth, nil); + scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction); + self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {varReg}, {}, false); + self:addStatement(self:setUpvalueMember(scope, self:register(scope, varReg), self:register(scope, exprregs[i])), {}, {varReg, exprregs[i]}, true); + self:freeRegister(exprregs[i], false); + else + local varreg = self:getVarRegister(statement.scope, id, funcDepth, exprregs[i]); + self:addStatement(self:copyRegisters(scope, {varreg}, {exprregs[i]}), {varreg}, {exprregs[i]}, false); + self:freeRegister(exprregs[i], false); + end + end + end + + if not self.scopeFunctionDepths[statement.scope] then + self.scopeFunctionDepths[statement.scope] = funcDepth; + end +end; + diff --git a/src/prometheus/compiler/statements/pass_self_function_call.lua b/src/prometheus/compiler/statements/pass_self_function_call.lua new file mode 100644 index 00000000..03e16757 --- /dev/null +++ b/src/prometheus/compiler/statements/pass_self_function_call.lua @@ -0,0 +1,39 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- pass_self_function_call.lua +-- This Script contains the statement handler for the PassSelfFunctionCallStatement + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local baseReg = self:compileExpression(statement.base, funcDepth, 1)[1]; + local tmpReg = self:allocRegister(false); + local args = { self:register(scope, baseReg) }; + local regs = { baseReg }; + + for i, expr in ipairs(statement.args) do + if i == #statement.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then + local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1]; + table.insert(args, Ast.FunctionCallExpression( + self:unpack(scope), + {self:register(scope, reg)})); + table.insert(regs, reg); + else + local reg = self:compileExpression(expr, funcDepth, 1)[1]; + table.insert(args, self:register(scope, reg)); + table.insert(regs, reg); + end + end + self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(statement.passSelfFunctionName)), {tmpReg}, {}, false); + self:addStatement(self:setRegister(scope, tmpReg, Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, tmpReg))), {tmpReg}, {tmpReg, baseReg}, false); + + self:addStatement(self:setRegister(scope, tmpReg, Ast.FunctionCallExpression(self:register(scope, tmpReg), args)), {tmpReg}, {tmpReg, unpack(regs)}, true); + + self:freeRegister(tmpReg, false); + for i, reg in ipairs(regs) do + self:freeRegister(reg, false); + end +end; + diff --git a/src/prometheus/compiler/statements/repeat_statement.lua b/src/prometheus/compiler/statements/repeat_statement.lua new file mode 100644 index 00000000..c3e4be85 --- /dev/null +++ b/src/prometheus/compiler/statements/repeat_statement.lua @@ -0,0 +1,39 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- repeat_statement.lua +-- This Script contains the statement handler for the RepeatStatement + +local Ast = require("prometheus.ast"); + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local innerBlock = self:createBlock(); + local finalBlock = self:createBlock(); + statement.__start_block = innerBlock; + statement.__final_block = finalBlock; + + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(innerBlock.id)), {self.POS_REGISTER}, {}, false); + self:setActiveBlock(innerBlock); + + for i, stat in ipairs(statement.body.statements) do + self:compileStatement(stat, funcDepth); + end; + + local scope = self.activeBlock.scope; + local conditionReg = (self:compileExpression(statement.condition, funcDepth, 1))[1]; + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(finalBlock.id)), Ast.NumberExpression(innerBlock.id))), { self.POS_REGISTER }, { conditionReg }, false); + self:freeRegister(conditionReg, false); + + for id, name in ipairs(statement.body.scope.variables) do + local varReg = self:getVarRegister(statement.body.scope, id, funcDepth, nil); + if self:isUpvalue(statement.body.scope, id) then + scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc); + self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), { self:register(scope, varReg) })), { varReg }, { varReg }, false); + else + self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), { varReg }, {}, false); + end; + self:freeRegister(varReg, true); + end; + + self:setActiveBlock(finalBlock); +end; diff --git a/src/prometheus/compiler/statements/return.lua b/src/prometheus/compiler/statements/return.lua new file mode 100644 index 00000000..cdd59e09 --- /dev/null +++ b/src/prometheus/compiler/statements/return.lua @@ -0,0 +1,35 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- return.lua +-- This Script contains the statement handler for the ReturnStatement + +local Ast = require("prometheus.ast"); +local AstKind = Ast.AstKind; + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local entries = {}; + local regs = {}; + + for i, expr in ipairs(statement.args) do + if i == #statement.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then + local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1]; + table.insert(entries, Ast.TableEntry(Ast.FunctionCallExpression( + self:unpack(scope), + {self:register(scope, reg)}))); + table.insert(regs, reg); + else + local reg = self:compileExpression(expr, funcDepth, 1)[1]; + table.insert(entries, Ast.TableEntry(self:register(scope, reg))); + table.insert(regs, reg); + end + end + + for _, reg in ipairs(regs) do + self:freeRegister(reg, false); + end + + self:addStatement(self:setReturn(scope, Ast.TableConstructorExpression(entries)), {self.RETURN_REGISTER}, regs, false); + self:addStatement(self:setPos(self.activeBlock.scope, nil), {self.POS_REGISTER}, {}, false); + self.activeBlock.advanceToNextBlock = false; +end; diff --git a/src/prometheus/compiler/statements/while_statement.lua b/src/prometheus/compiler/statements/while_statement.lua new file mode 100644 index 00000000..5d58d125 --- /dev/null +++ b/src/prometheus/compiler/statements/while_statement.lua @@ -0,0 +1,30 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- while_statement.lua +-- This Script contains the statement handler for the WhileStatement + +local Ast = require("prometheus.ast"); + +return function(self, statement, funcDepth) + local scope = self.activeBlock.scope; + local innerBlock = self:createBlock(); + local finalBlock = self:createBlock(); + local checkBlock = self:createBlock(); + + statement.__start_block = checkBlock; + statement.__final_block = finalBlock; + + self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false); + + self:setActiveBlock(checkBlock); + local scope = self.activeBlock.scope; + local conditionReg = self:compileExpression(statement.condition, funcDepth, 1)[1]; + self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(innerBlock.id)), Ast.NumberExpression(finalBlock.id))), {self.POS_REGISTER}, {conditionReg}, false); + self:freeRegister(conditionReg, false); + + self:setActiveBlock(innerBlock); + local scope = self.activeBlock.scope; + self:compileBlock(statement.body, funcDepth); + self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false); + self:setActiveBlock(finalBlock); +end; diff --git a/src/prometheus/compiler/upvalue.lua b/src/prometheus/compiler/upvalue.lua new file mode 100644 index 00000000..1db1e5cc --- /dev/null +++ b/src/prometheus/compiler/upvalue.lua @@ -0,0 +1,181 @@ +-- This Script is Part of the Prometheus Obfuscator by Levno_710 +-- +-- upvalue.lua +-- Upvalue and GC management for the compiler + +local Ast = require("prometheus.ast"); +local Scope = require("prometheus.scope"); +local util = require("prometheus.util"); + +local unpack = unpack or table.unpack; + +return function(Compiler) + function Compiler:createUpvaluesGcFunc() + local scope = Scope:new(self.scope); + local selfVar = scope:addVariable(); + + local iteratorVar = scope:addVariable(); + local valueVar = scope:addVariable(); + + local whileScope = Scope:new(scope); + whileScope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 3); + whileScope:addReferenceToHigherScope(scope, valueVar, 3); + whileScope:addReferenceToHigherScope(scope, iteratorVar, 3); + + local ifScope = Scope:new(whileScope); + ifScope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 1); + ifScope:addReferenceToHigherScope(self.scope, self.upvaluesTable, 1); + + return Ast.FunctionLiteralExpression({Ast.VariableExpression(scope, selfVar)}, Ast.Block({ + Ast.LocalVariableDeclaration(scope, {iteratorVar, valueVar}, {Ast.NumberExpression(1), Ast.IndexExpression(Ast.VariableExpression(scope, selfVar), Ast.NumberExpression(1))}), + Ast.WhileStatement(Ast.Block({ + Ast.AssignmentStatement({ + Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)), + Ast.AssignmentVariable(scope, iteratorVar), + }, { + Ast.SubExpression(Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)), Ast.NumberExpression(1)), + Ast.AddExpression(unpack(util.shuffle{Ast.VariableExpression(scope, iteratorVar), Ast.NumberExpression(1)})), + }), + Ast.IfStatement(Ast.EqualsExpression(unpack(util.shuffle{Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)), Ast.NumberExpression(0)})), Ast.Block({ + Ast.AssignmentStatement({ + Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)), + Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), Ast.VariableExpression(scope, valueVar)), + }, { + Ast.NilExpression(), + Ast.NilExpression(), + }) + }, ifScope), {}, nil), + Ast.AssignmentStatement({ + Ast.AssignmentVariable(scope, valueVar), + }, { + Ast.IndexExpression(Ast.VariableExpression(scope, selfVar), Ast.VariableExpression(scope, iteratorVar)), + }), + }, whileScope), Ast.VariableExpression(scope, valueVar), scope); + }, scope)); + end + + function Compiler:createFreeUpvalueFunc() + local scope = Scope:new(self.scope); + local argVar = scope:addVariable(); + local ifScope = Scope:new(scope); + ifScope:addReferenceToHigherScope(scope, argVar, 3); + scope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 2); + return Ast.FunctionLiteralExpression({Ast.VariableExpression(scope, argVar)}, Ast.Block({ + Ast.AssignmentStatement({ + Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)) + }, { + Ast.SubExpression(Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)), Ast.NumberExpression(1)); + }), + Ast.IfStatement(Ast.EqualsExpression(unpack(util.shuffle{Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)), Ast.NumberExpression(0)})), Ast.Block({ + Ast.AssignmentStatement({ + Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)), + Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), Ast.VariableExpression(scope, argVar)), + }, { + Ast.NilExpression(), + Ast.NilExpression(), + }) + }, ifScope), {}, nil) + }, scope)) + end + + function Compiler:createUpvaluesProxyFunc() + local scope = Scope:new(self.scope); + scope:addReferenceToHigherScope(self.scope, self.newproxyVar); + + local entriesVar = scope:addVariable(); + + local ifScope = Scope:new(scope); + local proxyVar = ifScope:addVariable(); + local metatableVar = ifScope:addVariable(); + local elseScope = Scope:new(scope); + ifScope:addReferenceToHigherScope(self.scope, self.newproxyVar); + ifScope:addReferenceToHigherScope(self.scope, self.getmetatableVar); + ifScope:addReferenceToHigherScope(self.scope, self.upvaluesGcFunctionVar); + ifScope:addReferenceToHigherScope(scope, entriesVar); + elseScope:addReferenceToHigherScope(self.scope, self.setmetatableVar); + elseScope:addReferenceToHigherScope(scope, entriesVar); + elseScope:addReferenceToHigherScope(self.scope, self.upvaluesGcFunctionVar); + + local forScope = Scope:new(scope); + local forArg = forScope:addVariable(); + forScope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 2); + forScope:addReferenceToHigherScope(scope, entriesVar, 2); + + return Ast.FunctionLiteralExpression({Ast.VariableExpression(scope, entriesVar)}, Ast.Block({ + Ast.ForStatement(forScope, forArg, Ast.NumberExpression(1), Ast.LenExpression(Ast.VariableExpression(scope, entriesVar)), Ast.NumberExpression(1), Ast.Block({ + Ast.AssignmentStatement({ + Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.IndexExpression(Ast.VariableExpression(scope, entriesVar), Ast.VariableExpression(forScope, forArg))) + }, { + Ast.AddExpression(unpack(util.shuffle{ + Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.IndexExpression(Ast.VariableExpression(scope, entriesVar), Ast.VariableExpression(forScope, forArg))), + Ast.NumberExpression(1), + })) + }) + }, forScope), scope); + Ast.IfStatement(Ast.VariableExpression(self.scope, self.newproxyVar), Ast.Block({ + Ast.LocalVariableDeclaration(ifScope, {proxyVar}, { + Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.newproxyVar), { + Ast.BooleanExpression(true) + }); + }); + Ast.LocalVariableDeclaration(ifScope, {metatableVar}, { + Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.getmetatableVar), { + Ast.VariableExpression(ifScope, proxyVar); + }); + }); + Ast.AssignmentStatement({ + Ast.AssignmentIndexing(Ast.VariableExpression(ifScope, metatableVar), Ast.StringExpression("__index")), + Ast.AssignmentIndexing(Ast.VariableExpression(ifScope, metatableVar), Ast.StringExpression("__gc")), + Ast.AssignmentIndexing(Ast.VariableExpression(ifScope, metatableVar), Ast.StringExpression("__len")), + }, { + Ast.VariableExpression(scope, entriesVar), + Ast.VariableExpression(self.scope, self.upvaluesGcFunctionVar), + Ast.FunctionLiteralExpression({}, Ast.Block({ + Ast.ReturnStatement({Ast.NumberExpression(self.upvalsProxyLenReturn)}) + }, Scope:new(ifScope))); + }); + Ast.ReturnStatement({ + Ast.VariableExpression(ifScope, proxyVar) + }) + }, ifScope), {}, Ast.Block({ + Ast.ReturnStatement({Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.setmetatableVar), { + Ast.TableConstructorExpression({}), + Ast.TableConstructorExpression({ + Ast.KeyedTableEntry(Ast.StringExpression("__gc"), Ast.VariableExpression(self.scope, self.upvaluesGcFunctionVar)), + Ast.KeyedTableEntry(Ast.StringExpression("__index"), Ast.VariableExpression(scope, entriesVar)), + Ast.KeyedTableEntry(Ast.StringExpression("__len"), Ast.FunctionLiteralExpression({}, Ast.Block({ + Ast.ReturnStatement({Ast.NumberExpression(self.upvalsProxyLenReturn)}) + }, Scope:new(ifScope)))), + }) + })}) + }, elseScope)); + }, scope)); + end + + function Compiler:createAllocUpvalFunction() + local scope = Scope:new(self.scope); + scope:addReferenceToHigherScope(self.scope, self.currentUpvalId, 4); + scope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 1); + + return Ast.FunctionLiteralExpression({}, Ast.Block({ + Ast.AssignmentStatement({ + Ast.AssignmentVariable(self.scope, self.currentUpvalId), + },{ + Ast.AddExpression(unpack(util.shuffle({ + Ast.VariableExpression(self.scope, self.currentUpvalId), + Ast.NumberExpression(1), + }))), + } + ), + Ast.AssignmentStatement({ + Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(self.scope, self.currentUpvalId)), + }, { + Ast.NumberExpression(1), + }), + Ast.ReturnStatement({ + Ast.VariableExpression(self.scope, self.currentUpvalId), + }) + }, scope)); + end +end + diff --git a/src/prometheus/enums.lua b/src/prometheus/enums.lua index 5e9b3cba..162bdfac 100644 --- a/src/prometheus/enums.lua +++ b/src/prometheus/enums.lua @@ -15,12 +15,12 @@ Enums.LuaVersion = { Enums.Conventions = { [Enums.LuaVersion.Lua51] = { Keywords = { - "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "if", + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" }, - + SymbolChars = chararray("+-*/%^#=~<>(){}[];:,."), MaxSymbolLength = 3, Symbols = { @@ -38,7 +38,7 @@ Enums.Conventions = { HexadecimalNums = {"x", "X"}, BinaryNums = {"b", "B"}, DecimalSeperators = false, - + EscapeSequences = { ["a"] = "\a"; ["b"] = "\b"; @@ -59,11 +59,11 @@ Enums.Conventions = { [Enums.LuaVersion.LuaU] = { Keywords = { "and", "break", "do", "else", "elseif", "continue", - "end", "false", "for", "function", "if", + "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" }, - + SymbolChars = chararray("+-*/%^#=~<>(){}[];:,."), MaxSymbolLength = 3, Symbols = { @@ -72,7 +72,7 @@ Enums.Conventions = { "+=", "-=", "/=", "%=", "^=", "..=", "*=", "(", ")", "{", "}", "[", "]", ";", ":", ",", ".", "..", "...", - "::", "->", "?", "|", "&", + "::", "->", "?", "|", "&", }, IdentChars = chararray("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"), @@ -83,7 +83,7 @@ Enums.Conventions = { HexadecimalNums = {"x", "X"}, BinaryNums = {"b", "B"}, DecimalSeperators = {"_"}, - + EscapeSequences = { ["a"] = "\a"; ["b"] = "\b"; diff --git a/src/prometheus/parser.lua b/src/prometheus/parser.lua index 10cdd5f8..f027e15f 100644 --- a/src/prometheus/parser.lua +++ b/src/prometheus/parser.lua @@ -4,12 +4,12 @@ -- Overview: -- This Script provides a class for parsing of lua code. -- This Parser is Capable of parsing LuaU and Lua5.1 --- +-- -- Note that when parsing LuaU "continue" is treated as a Keyword, so no variable may be named "continue" even though this would be valid in LuaU -- -- Settings Object: -- luaVersion : The LuaVersion of the Script - Currently Supported : Lua51 and LuaU --- +-- local Tokenizer = require("prometheus.tokenizer"); local Enums = require("prometheus.enums"); @@ -22,10 +22,6 @@ local AstKind = Ast.AstKind; local LuaVersion = Enums.LuaVersion; local lookupify = util.lookupify; -local unlookupify = util.unlookupify; -local escape = util.escape; -local chararray = util.chararray; -local keys = util.keys; local TokenKind = Tokenizer.TokenKind; @@ -54,7 +50,7 @@ local function generateError(self, message) else token = self.tokens[self.index]; end - + return "Parsing Error at Position " .. tostring(token.line) .. ":" .. tostring(token.linePos) .. ", " .. message; end @@ -73,10 +69,10 @@ function Parser:new(settings) length = 0; index = 0; }; - + setmetatable(parser, self); self.__index = self; - + return parser; end @@ -98,13 +94,13 @@ local function get(self) end self.index = self.index + 1; local tk = self.tokens[i]; - + return tk; end local function is(self, kind, sourceOrN, n) local token = peek(self, n); - + local source = nil; if(type(sourceOrN) == "string") then source = sourceOrN; @@ -112,13 +108,13 @@ local function is(self, kind, sourceOrN, n) n = sourceOrN; end n = n or 0; - + if(token.kind == kind) then if(source == nil or token.source == source) then return true; end end - + return false; end @@ -134,7 +130,7 @@ local function expect(self, kind, source) if(is(self, kind, source, 0)) then return get(self); end - + local token = peek(self); if self.disableLog then error() end if(source) then @@ -149,10 +145,10 @@ function Parser:parse(code) self.tokenizer:append(code); self.tokens = self.tokenizer:scanAll(); self.length = #self.tokens; - + -- Create Global Variable Scope local globalScope = Scope:newGlobal(); - + local ast = Ast.TopNode(self:block(globalScope, false), globalScope); -- File Must be Over when Top Node is Fully Parsed expect(self, TokenKind.Eof); @@ -163,9 +159,9 @@ function Parser:parse(code) self.tokens = {}; self.index = 0; self.length = 0; - + logger:debug("Cleanup Done") - + return ast; end @@ -173,15 +169,15 @@ end function Parser:block(parentScope, currentLoop, scope) scope = scope or Scope:new(parentScope); local statements = {}; - + repeat local statement, isTerminatingStatement = self:statement(scope, currentLoop); table.insert(statements, statement); until isTerminatingStatement or not statement - + -- Consume Eventual Semicolon after terminating return, break or continue consume(self, TokenKind.Symbol, ";"); - + return Ast.Block(statements, scope); end @@ -189,9 +185,9 @@ function Parser:statement(scope, currentLoop) -- Skip all semicolons before next real statement -- NOP statements are therefore ignored while(consume(self, TokenKind.Symbol, ";")) do - + end - + -- Break Statement - only valid inside of Loops if(consume(self, TokenKind.Keyword, "break")) then if(not currentLoop) then @@ -201,7 +197,7 @@ function Parser:statement(scope, currentLoop) -- Return true as Second value because break must be the last Statement in a block return Ast.BreakStatement(currentLoop, scope), true; end - + -- Continue Statement - only valid inside of Loops - only valid in LuaU if(self.luaVersion == LuaVersion.LuaU and consume(self, TokenKind.Keyword, "continue")) then if(not currentLoop) then @@ -211,14 +207,14 @@ function Parser:statement(scope, currentLoop) -- Return true as Second value because continue must be the last Statement in a block return Ast.ContinueStatement(currentLoop, scope), true; end - + -- do ... end Statement if(consume(self, TokenKind.Keyword, "do")) then local body = self:block(scope, currentLoop); expect(self, TokenKind.Keyword, "end"); return Ast.DoStatement(body); end - + -- While Statement if(consume(self, TokenKind.Keyword, "while")) then local condition = self:expression(scope); @@ -228,7 +224,7 @@ function Parser:statement(scope, currentLoop) expect(self, TokenKind.Keyword, "end"); return stat; end - + -- Repeat Statement if(consume(self, TokenKind.Keyword, "repeat")) then local repeatScope = Scope:new(scope); @@ -238,7 +234,7 @@ function Parser:statement(scope, currentLoop) stat.condition = self:expression(repeatScope); return stat; end - + -- Return Statement if(consume(self, TokenKind.Keyword, "return")) then local args = {}; @@ -248,37 +244,37 @@ function Parser:statement(scope, currentLoop) -- Return true as Second value because return must be the last Statement in a block return Ast.ReturnStatement(args), true; end - + -- If Statement if(consume(self, TokenKind.Keyword, "if")) then local condition = self:expression(scope); expect(self, TokenKind.Keyword, "then"); local body = self:block(scope, currentLoop); - + local elseifs = {}; -- Elseifs while(consume(self, TokenKind.Keyword, "elseif")) do local condition = self:expression(scope); expect(self, TokenKind.Keyword, "then"); local body = self:block(scope, currentLoop); - + table.insert(elseifs, { condition = condition, body = body, }); end - + local elsebody = nil; -- Else if(consume(self, TokenKind.Keyword, "else")) then elsebody = self:block(scope, currentLoop); end - + expect(self, TokenKind.Keyword, "end"); - + return Ast.IfStatement(condition, body, elseifs, elsebody); end - + -- Function Declaration if(consume(self, TokenKind.Keyword, "function")) then -- TODO: Parse Function Declaration Name @@ -286,13 +282,13 @@ function Parser:statement(scope, currentLoop) local baseScope = obj.scope; local baseId = obj.id; local indices = obj.indices; - + local funcScope = Scope:new(scope); - + expect(self, TokenKind.Symbol, "("); local args = self:functionArgList(funcScope); expect(self, TokenKind.Symbol, ")"); - + if(obj.passSelf) then local id = funcScope:addVariable("self", obj.token); table.insert(args, 1, Ast.VariableExpression(funcScope, id)); @@ -300,20 +296,20 @@ function Parser:statement(scope, currentLoop) local body = self:block(nil, false, funcScope); expect(self, TokenKind.Keyword, "end"); - + return Ast.FunctionDeclaration(baseScope, baseId, indices, args, body); end - + -- Local Function or Variable Declaration if(consume(self, TokenKind.Keyword, "local")) then -- Local Function Declaration if(consume(self, TokenKind.Keyword, "function")) then local ident = expect(self, TokenKind.Ident); local name = ident.value; - + local id = scope:addVariable(name, ident); local funcScope = Scope:new(scope); - + expect(self, TokenKind.Symbol, "("); local args = self:functionArgList(funcScope); expect(self, TokenKind.Symbol, ")"); @@ -323,7 +319,7 @@ function Parser:statement(scope, currentLoop) return Ast.LocalFunctionDeclaration(scope, id, args, body); end - + -- Local Variable Declaration local ids = self:nameList(scope); local expressions = {}; @@ -333,35 +329,35 @@ function Parser:statement(scope, currentLoop) -- Variables can only be reffered to in the next statement, so the id's are enabled after the expressions have been parsed self:enableNameList(scope, ids); - + if(#expressions > #ids) then logger:warn(generateWarning(peek(self, -1), string.format("assigning %d values to %d variable" .. ((#ids > 1 and "s") or ""), #expressions, #ids))); elseif(#ids > #expressions and #expressions > 0 and not ASSIGNMENT_NO_WARN_LOOKUP[expressions[#expressions].kind]) then - logger:warn(generateWarning(peek(self, -1), string.format("assigning %d value" .. ((#expressions > 1 and "s") or "") .. + logger:warn(generateWarning(peek(self, -1), string.format("assigning %d value" .. ((#expressions > 1 and "s") or "") .. " to %d variables initializes extra variables with nil, add a nil value to silence", #expressions, #ids))); - end + end return Ast.LocalVariableDeclaration(scope, ids, expressions); end - + -- For Statement if(consume(self, TokenKind.Keyword, "for")) then -- Normal for Statement if(is(self, TokenKind.Symbol, "=", 1)) then local forScope = Scope:new(scope); - + local ident = expect(self, TokenKind.Ident); local varId = forScope:addDisabledVariable(ident.value, ident); - + expect(self, TokenKind.Symbol, "="); local initialValue = self:expression(scope); - + expect(self, TokenKind.Symbol, ","); local finalValue = self:expression(scope); local incrementBy = Ast.NumberExpression(1); if(consume(self, TokenKind.Symbol, ",")) then incrementBy = self:expression(scope); end - + local stat = Ast.ForStatement(forScope, varId, initialValue, finalValue, incrementBy, nil, scope); forScope:enableVariable(varId); expect(self, TokenKind.Keyword, "do"); @@ -369,10 +365,10 @@ function Parser:statement(scope, currentLoop) expect(self, TokenKind.Keyword, "end"); return stat; end - + -- For ... in ... statement local forScope = Scope:new(scope); - + local ids = self:nameList(forScope); expect(self, TokenKind.Keyword, "in"); local expressions = self:exprList(scope); @@ -386,10 +382,10 @@ function Parser:statement(scope, currentLoop) local stat = Ast.ForInStatement(forScope, ids, expressions, nil, scope); stat.body = self:block(nil, stat, forScope); expect(self, TokenKind.Keyword, "end"); - + return stat; end - + local expr = self:primaryExpression(scope); -- Variable Assignment or Function Call if expr then @@ -397,12 +393,12 @@ function Parser:statement(scope, currentLoop) if(expr.kind == AstKind.FunctionCallExpression) then return Ast.FunctionCallStatement(expr.base, expr.args); end - + -- Function Call Statement passing self if(expr.kind == AstKind.PassSelfFunctionCallExpression) then return Ast.PassSelfFunctionCallStatement(expr.base, expr.passSelfFunctionName, expr.args); end - + -- Variable Assignment if(expr.kind == AstKind.IndexExpression or expr.kind == AstKind.VariableExpression) then if(expr.kind == AstKind.IndexExpression) then @@ -453,15 +449,15 @@ function Parser:statement(scope, currentLoop) local lhs = { expr } - + while consume(self, TokenKind.Symbol, ",") do expr = self:primaryExpression(scope); - + if(not expr) then if self.disableLog then error() end; logger:error(generateError(self, string.format("expected a valid assignment statement lhs part but got nil"))); end - + if(expr.kind == AstKind.IndexExpression or expr.kind == AstKind.VariableExpression) then if(expr.kind == AstKind.IndexExpression) then expr.kind = AstKind.AssignmentIndexing @@ -475,18 +471,18 @@ function Parser:statement(scope, currentLoop) logger:error(generateError(self, string.format("expected a valid assignment statement lhs part but got <%s>", expr.kind))); end end - + expect(self, TokenKind.Symbol, "="); - + local rhs = self:exprList(scope); - + return Ast.AssignmentStatement(lhs, rhs); end - + if self.disableLog then error() end; logger:error(generateError(self, "expressions are not valid statements!")); end - + return nil; end @@ -518,17 +514,17 @@ end -- list of local variable names function Parser:nameList(scope) local ids = {}; - + local ident = expect(self, TokenKind.Ident); local id = scope:addDisabledVariable(ident.value, ident); table.insert(ids, id); - + while(consume(self, TokenKind.Symbol, ",")) do ident = expect(self, TokenKind.Ident); id = scope:addDisabledVariable(ident.value, ident); table.insert(ids, id); end - + return ids; end @@ -543,20 +539,20 @@ end function Parser:funcName(scope) local ident = expect(self, TokenKind.Ident); local baseName = ident.value; - + local baseScope, baseId = scope:resolve(baseName); - + local indices = {}; local passSelf = false; while(consume(self, TokenKind.Symbol, ".")) do table.insert(indices, expect(self, TokenKind.Ident).value); end - + if(consume(self, TokenKind.Symbol, ":")) then table.insert(indices, expect(self, TokenKind.Ident).value); passSelf = true; end - + return { scope = baseScope, id = baseId, @@ -573,12 +569,12 @@ end function Parser:expressionOr(scope) local lhs = self:expressionAnd(scope); - + if(consume(self, TokenKind.Keyword, "or")) then local rhs = self:expressionOr(scope); return Ast.OrExpression(lhs, rhs, true); end - + return lhs; end @@ -602,31 +598,31 @@ function Parser:expressionComparision(scope) curr = Ast.LessThanExpression(curr, rhs, true); found = true; end - + if(consume(self, TokenKind.Symbol, ">")) then local rhs = self:expressionStrCat(scope); curr = Ast.GreaterThanExpression(curr, rhs, true); found = true; end - + if(consume(self, TokenKind.Symbol, "<=")) then local rhs = self:expressionStrCat(scope); curr = Ast.LessThanOrEqualsExpression(curr, rhs, true); found = true; end - + if(consume(self, TokenKind.Symbol, ">=")) then local rhs = self:expressionStrCat(scope); curr = Ast.GreaterThanOrEqualsExpression(curr, rhs, true); found = true; end - + if(consume(self, TokenKind.Symbol, "~=")) then local rhs = self:expressionStrCat(scope); curr = Ast.NotEqualsExpression(curr, rhs, true); found = true; end - + if(consume(self, TokenKind.Symbol, "==")) then local rhs = self:expressionStrCat(scope); curr = Ast.EqualsExpression(curr, rhs, true); @@ -658,14 +654,14 @@ function Parser:expressionAddSub(scope) curr = Ast.AddExpression(curr, rhs, true); found = true; end - + if(consume(self, TokenKind.Symbol, "-")) then local rhs = self:expressionMulDivMod(scope); curr = Ast.SubExpression(curr, rhs, true); found = true; end until not found; - + return curr; end @@ -680,7 +676,7 @@ function Parser:expressionMulDivMod(scope) curr = Ast.MulExpression(curr, rhs, true); found = true; end - + if(consume(self, TokenKind.Symbol, "/")) then local rhs = self:expressionUnary(scope); curr = Ast.DivExpression(curr, rhs, true); @@ -702,12 +698,12 @@ function Parser:expressionUnary(scope) local rhs = self:expressionUnary(scope); return Ast.NotExpression(rhs, true); end - + if(consume(self, TokenKind.Symbol, "#")) then local rhs = self:expressionUnary(scope); return Ast.LenExpression(rhs, true); end - + if(consume(self, TokenKind.Symbol, "-")) then local rhs = self:expressionUnary(scope); return Ast.NegateExpression(rhs, true); @@ -729,30 +725,30 @@ end -- Table Literals and Function Literals cannot directly be called or indexed function Parser:tableOrFunctionLiteral(scope) - + if(is(self, TokenKind.Symbol, "{")) then return self:tableConstructor(scope); end - + if(is(self, TokenKind.Keyword, "function")) then return self:expressionFunctionLiteral(scope); end - + return self:expressionFunctionCall(scope); end function Parser:expressionFunctionLiteral(parentScope) local scope = Scope:new(parentScope); - + expect(self, TokenKind.Keyword, "function"); - + expect(self, TokenKind.Symbol, "("); local args = self:functionArgList(scope); expect(self, TokenKind.Symbol, ")"); - + local body = self:block(nil, false, scope); expect(self, TokenKind.Keyword, "end"); - + return Ast.FunctionLiteralExpression(args, body); end @@ -762,20 +758,20 @@ function Parser:functionArgList(scope) table.insert(args, Ast.VarargExpression()); return args; end - + if(is(self, TokenKind.Ident)) then local ident = get(self); local name = ident.value; - + local id = scope:addVariable(name, ident); table.insert(args, Ast.VariableExpression(scope, id)); - + while(consume(self, TokenKind.Symbol, ",")) do if(consume(self, TokenKind.Symbol, "...")) then table.insert(args, Ast.VarargExpression()); return args; end - + ident = get(self); name = ident.value; @@ -783,7 +779,7 @@ function Parser:functionArgList(scope) table.insert(args, Ast.VariableExpression(scope, id)); end end - + return args; end @@ -793,7 +789,7 @@ function Parser:expressionFunctionCall(scope, base) if(not (base and (CALLABLE_PREFIX_EXPRESSION_LOOKUP[base.kind] or base.isParenthesizedExpression))) then return base; end - + -- Normal Function Call local args = {}; if(is(self, TokenKind.String)) then @@ -812,9 +808,9 @@ function Parser:expressionFunctionCall(scope, base) else return base; end - + local node = Ast.FunctionCallExpression(base, args); - + -- the result of a function call can be indexed if(is(self, TokenKind.Symbol, ".") or is(self, TokenKind.Symbol, "[") or is(self, TokenKind.Symbol, ":")) then return self:expressionIndex(scope, node); @@ -824,25 +820,25 @@ function Parser:expressionFunctionCall(scope, base) if(is(self, TokenKind.Symbol, "(") or is(self, TokenKind.Symbol, "{") or is(self, TokenKind.String)) then return self:expressionFunctionCall(scope, node); end - + return node; end function Parser:expressionIndex(scope, base) base = base or self:expressionLiteral(scope); - + -- Parse Indexing Expressions while(consume(self, TokenKind.Symbol, "[")) do local expr = self:expression(scope); expect(self, TokenKind.Symbol, "]"); base = Ast.IndexExpression(base, expr); end - + -- Parse Indexing Expressions while consume(self, TokenKind.Symbol, ".") do local ident = expect(self, TokenKind.Ident); base = Ast.IndexExpression(base, Ast.StringExpression(ident.value)); - + while(consume(self, TokenKind.Symbol, "[")) do local expr = self:expression(scope); expect(self, TokenKind.Symbol, "]"); @@ -869,7 +865,7 @@ function Parser:expressionIndex(scope, base) end expect(self, TokenKind.Symbol, ")"); end - + local node = Ast.PassSelfFunctionCallExpression(base, passSelfFunctionName, args); -- the result of a function call can be indexed @@ -881,7 +877,7 @@ function Parser:expressionIndex(scope, base) if(is(self, TokenKind.Symbol, "(") or is(self, TokenKind.Symbol, "{") or is(self, TokenKind.String)) then return self:expressionFunctionCall(scope, node); end - + return node end @@ -889,7 +885,7 @@ function Parser:expressionIndex(scope, base) if(is(self, TokenKind.Symbol, "(") or is(self, TokenKind.Symbol, "{") or is(self, TokenKind.String)) then return self:expressionFunctionCall(scope, base); end - + return base; end @@ -903,42 +899,42 @@ function Parser:expressionLiteral(scope) end return expr; end - + -- String Literal if(is(self, TokenKind.String)) then return Ast.StringExpression(get(self).value); end - + -- Number Literal if(is(self, TokenKind.Number)) then return Ast.NumberExpression(get(self).value); end - + -- True Literal if(consume(self, TokenKind.Keyword, "true")) then return Ast.BooleanExpression(true); end - + -- False Literal if(consume(self, TokenKind.Keyword, "false")) then return Ast.BooleanExpression(false); end - + -- Nil Literal if(consume(self, TokenKind.Keyword, "nil")) then return Ast.NilExpression(); end - + -- Vararg Literal if(consume(self, TokenKind.Symbol, "...")) then return Ast.VarargExpression(); end - + -- Variable if(is(self, TokenKind.Ident)) then local ident = get(self); local name = ident.value; - + local scope, id = scope:resolve(name); return Ast.VariableExpression(scope, id); end @@ -955,7 +951,7 @@ function Parser:expressionLiteral(scope) return Ast.IfElseExpression(condition, true_value, false_value); end end - + if(self.disableLog) then error() end logger:error(generateError(self, "Unexpected Token \"" .. peek(self).source .. "\". Expected a Expression!")) end @@ -963,9 +959,9 @@ end function Parser:tableConstructor(scope) -- TODO: Parse Table Literals local entries = {}; - + expect(self, TokenKind.Symbol, "{"); - + while (not consume(self, TokenKind.Symbol, "}")) do if(consume(self, TokenKind.Symbol, "[")) then local key = self:expression(scope); @@ -982,14 +978,14 @@ function Parser:tableConstructor(scope) local value = self:expression(scope); table.insert(entries, Ast.TableEntry(value)); end - - + + if (not consume(self, TokenKind.Symbol, ";") and not consume(self, TokenKind.Symbol, ",") and not is(self, TokenKind.Symbol, "}")) then if self.disableLog then error() end logger:error(generateError(self, "expected a \";\" or a \",\"")); end end - + return Ast.TableConstructorExpression(entries); end diff --git a/src/prometheus/pipeline.lua b/src/prometheus/pipeline.lua index 221ba5db..7e4f0775 100644 --- a/src/prometheus/pipeline.lua +++ b/src/prometheus/pipeline.lua @@ -5,8 +5,6 @@ -- This Script Provides a Configurable Obfuscation Pipeline that can obfuscate code using different Modules -- These Modules can simply be added to the pipeline -local config = require("config"); -local Ast = require("prometheus.ast"); local Enums = require("prometheus.enums"); local util = require("prometheus.util"); local Parser = require("prometheus.parser"); @@ -16,10 +14,7 @@ local logger = require("logger"); local NameGenerators = require("prometheus.namegenerators"); local Steps = require("prometheus.steps"); - -local lookupify = util.lookupify; local LuaVersion = Enums.LuaVersion; -local AstKind = Ast.AstKind; -- On Windows os.clock can be used. On other Systems os.time must be used for benchmarking local isWindows = package and package.config and type(package.config) == "string" and package.config:sub(1,1) == "\\"; @@ -47,14 +42,14 @@ function Pipeline:new(settings) local luaVersion = settings.luaVersion or settings.LuaVersion or Pipeline.DefaultSettings.LuaVersion; local conventions = Enums.Conventions[luaVersion]; if(not conventions) then - logger:error("The Lua Version \"" .. luaVersion + logger:error("The Lua Version \"" .. luaVersion .. "\" is not recognised by the Tokenizer! Please use one of the following: \"" .. table.concat(util.keys(Enums.Conventions), "\",\"") .. "\""); end - + local prettyPrint = settings.PrettyPrint or Pipeline.DefaultSettings.PrettyPrint; local prefix = settings.VarNamePrefix or Pipeline.DefaultSettings.VarNamePrefix; local seed = settings.Seed or 0; - + local pipeline = { LuaVersion = luaVersion; PrettyPrint = prettyPrint; @@ -72,10 +67,10 @@ function Pipeline:new(settings) conventions = conventions; steps = {}; } - + setmetatable(pipeline, self); self.__index = self; - + return pipeline; end @@ -121,7 +116,7 @@ end function Pipeline:setOption(name, value) assert(false, "TODO"); if(Pipeline.DefaultSettings[name] ~= nil) then - + else logger:error(string.format("\"%s\" is not a valid setting")); end @@ -130,10 +125,10 @@ end function Pipeline:setLuaVersion(luaVersion) local conventions = Enums.Conventions[luaVersion]; if(not conventions) then - logger:error("The Lua Version \"" .. luaVersion + logger:error("The Lua Version \"" .. luaVersion .. "\" is not recognised by the Tokenizer! Please use one of the following: \"" .. table.concat(util.keys(Enums.Conventions), "\",\"") .. "\""); end - + self.parser = Parser:new({ luaVersion = luaVersion; }); @@ -151,7 +146,7 @@ function Pipeline:setNameGenerator(nameGenerator) if(type(nameGenerator) == "string") then nameGenerator = Pipeline.NameGenerators[nameGenerator]; end - + if(type(nameGenerator) == "function" or type(nameGenerator) == "table") then self.namegenerator = nameGenerator; return; @@ -170,7 +165,7 @@ function Pipeline:apply(code, filename) else math.randomseed(os.time()) end - + logger:info("Parsing ..."); local parserStartTime = gettime(); @@ -179,7 +174,7 @@ function Pipeline:apply(code, filename) local parserTimeDiff = gettime() - parserStartTime; logger:info(string.format("Parsing Done in %.2f seconds", parserTimeDiff)); - + -- User Defined Steps for i, step in ipairs(self.steps) do local stepStartTime = gettime(); @@ -190,37 +185,37 @@ function Pipeline:apply(code, filename) end logger:info(string.format("Step \"%s\" Done in %.2f seconds", step.Name or "Unnamed", gettime() - stepStartTime)); end - + -- Rename Variables Step self:renameVariables(ast); - + code = self:unparse(ast); - + local timeDiff = gettime() - startTime; logger:info(string.format("Obfuscation Done in %.2f seconds", timeDiff)); - + logger:info(string.format("Generated Code size is %.2f%% of the Source Code size", (string.len(code) / sourceLen)*100)) - + return code; end function Pipeline:unparse(ast) local startTime = gettime(); logger:info("Generating Code ..."); - + local unparsed = self.unparser:unparse(ast); - + local timeDiff = gettime() - startTime; logger:info(string.format("Code Generation Done in %.2f seconds", timeDiff)); - + return unparsed; end function Pipeline:renameVariables(ast) local startTime = gettime(); logger:info("Renaming Variables ..."); - - + + local generatorFunction = self.namegenerator or Pipeline.NameGenerators.mangled; if(type(generatorFunction) == "table") then if (type(generatorFunction.prepare) == "function") then @@ -228,7 +223,7 @@ function Pipeline:renameVariables(ast) end generatorFunction = generatorFunction.generateName; end - + if not self.unparser:isValidIdentifier(self.VarNamePrefix) and #self.VarNamePrefix ~= 0 then logger:error(string.format("The Prefix \"%s\" is not a valid Identifier in %s", self.VarNamePrefix, self.LuaVersion)); end @@ -239,12 +234,9 @@ function Pipeline:renameVariables(ast) generateName = generatorFunction; prefix = self.VarNamePrefix; }); - + local timeDiff = gettime() - startTime; logger:info(string.format("Renaming Done in %.2f seconds", timeDiff)); end - - - return Pipeline; diff --git a/src/prometheus/scope.lua b/src/prometheus/scope.lua index a3911000..fad21f60 100644 --- a/src/prometheus/scope.lua +++ b/src/prometheus/scope.lua @@ -31,7 +31,7 @@ function Scope:new(parentScope, name) children = {}, level = parentScope.level and (parentScope.level + 1) or 1; } - + setmetatable(scope, self); self.__index = self; parentScope:addChild(scope); @@ -51,10 +51,10 @@ function Scope:newGlobal() children = {}, level = 0, }; - + setmetatable(scope, self); self.__index = self; - + return scope; end @@ -77,17 +77,17 @@ function Scope:addVariable(name, token) name = string.format("%s%i", config.IdentPrefix, next_name_i); next_name_i = next_name_i + 1; end - + if self.variablesLookup[name] ~= nil then if(token) then logger:warn(generateWarning(token, "the variable \"" .. name .. "\" is already defined in that scope")); else logger:error(string.format("A variable with the name \"%s\" was already defined, you should have no variables starting with \"%s\"", name, config.IdentPrefix)); end - + --return self.variablesLookup[name]; end - + table.insert(self.variables, name); local id = #self.variables; self.variablesLookup[name] = id; @@ -104,17 +104,17 @@ function Scope:addDisabledVariable(name, token) name = string.format("%s%i", config.IdentPrefix, next_name_i); next_name_i = next_name_i + 1; end - + if self.variablesLookup[name] ~= nil then if(token) then logger:warn(generateWarning(token, "the variable \"" .. name .. "\" is already defined in that scope")); else logger:warn(string.format("a variable with the name \"%s\" was already defined", name)); end - + --return self.variablesLookup[name]; end - + table.insert(self.variables, name); local id = #self.variables; return id; @@ -294,7 +294,7 @@ function Scope:renameVariables(settings) for _, keyword in pairs(settings.Keywords) do forbiddenNamesLookup[keyword] = true; end - + for scope, ids in pairs(self.variablesFromHigherScopes) do for id, count in pairs(ids) do if count and count > 0 then @@ -303,9 +303,9 @@ function Scope:renameVariables(settings) end end end - + self.variablesLookup = {}; - + local i = 0; for id, originalName in pairs(self.variables) do if(not self.skipIdLookup[id] and (self.referenceCounts[id] or 0) >= 0) then @@ -323,7 +323,7 @@ function Scope:renameVariables(settings) end end end - + for _, scope in pairs(self.children) do scope:renameVariables(settings); end diff --git a/src/prometheus/step.lua b/src/prometheus/step.lua index 78aca937..4168f2d6 100644 --- a/src/prometheus/step.lua +++ b/src/prometheus/step.lua @@ -17,11 +17,11 @@ function Step:new(settings) local instance = {}; setmetatable(instance, self); self.__index = self; - + if type(settings) ~= "table" then settings = {}; end - + for key, data in pairs(self.SettingsDescriptor) do if settings[key] == nil then if data.default == nil then @@ -42,17 +42,17 @@ function Step:new(settings) logger:error(string.format("Invalid value for the Setting \"%s\" of the Step \"%s\". It must be at least %d", key, self.Name, data.min)); end end - + if data.max then if settings[key] > data.max then logger:error(string.format("Invalid value for the Setting \"%s\" of the Step \"%s\". The biggest allowed value is %d", key, self.Name, data.min)); end end - + instance[key] = settings[key]; end end - + instance:init(); return instance; diff --git a/src/prometheus/steps.lua b/src/prometheus/steps.lua index 915dd210..dd9638f2 100644 --- a/src/prometheus/steps.lua +++ b/src/prometheus/steps.lua @@ -1,12 +1,12 @@ return { - WrapInFunction = require("prometheus.steps.WrapInFunction"); - SplitStrings = require("prometheus.steps.SplitStrings"); - Vmify = require("prometheus.steps.Vmify"); - ConstantArray = require("prometheus.steps.ConstantArray"); - ProxifyLocals = require("prometheus.steps.ProxifyLocals"); - AntiTamper = require("prometheus.steps.AntiTamper"); - EncryptStrings = require("prometheus.steps.EncryptStrings"); - NumbersToExpressions = require("prometheus.steps.NumbersToExpressions"); - AddVararg = require("prometheus.steps.AddVararg"); - WatermarkCheck = require("prometheus.steps.WatermarkCheck"); -} \ No newline at end of file + WrapInFunction = require("prometheus.steps.WrapInFunction"), + SplitStrings = require("prometheus.steps.SplitStrings"), + Vmify = require("prometheus.steps.Vmify"), + ConstantArray = require("prometheus.steps.ConstantArray"), + ProxifyLocals = require("prometheus.steps.ProxifyLocals"), + AntiTamper = require("prometheus.steps.AntiTamper"), + EncryptStrings = require("prometheus.steps.EncryptStrings"), + NumbersToExpressions = require("prometheus.steps.NumbersToExpressions"), + AddVararg = require("prometheus.steps.AddVararg"), + WatermarkCheck = require("prometheus.steps.WatermarkCheck"), +} diff --git a/src/prometheus/tokenizer.lua b/src/prometheus/tokenizer.lua index 209e9df9..865bc95d 100644 --- a/src/prometheus/tokenizer.lua +++ b/src/prometheus/tokenizer.lua @@ -73,7 +73,7 @@ function Tokenizer:getPosition(i) local column = self.columnMap[i] if not column then --// `i` is bigger than self.length, this shouldnt happen, but it did. (Theres probably some error in the tokenizer, cant find it.) - column = self.columnMap[#self.columnMap] + column = self.columnMap[#self.columnMap] end return column.id, column.charMap[i] @@ -101,21 +101,21 @@ function Tokenizer:prepareGetPosition() end -- Constructor for Tokenizer -function Tokenizer:new(settings) +function Tokenizer:new(settings) local luaVersion = (settings and (settings.luaVersion or settings.LuaVersion)) or LuaVersion.LuaU; local conventions = Tokenizer.Conventions[luaVersion]; - + if(conventions == nil) then logger:error("The Lua Version \"" .. luaVersion .. "\" is not recognised by the Tokenizer! Please use one of the following: \"" .. table.concat(keys(Tokenizer.Conventions), "\",\"") .. "\""); end - + local tokenizer = { index = 0, -- Index where the current char is read length = 0, source = "", -- Source to Tokenize luaVersion = luaVersion, -- LuaVersion to be used while Tokenizing conventions = conventions; - + NumberChars = conventions.NumberChars, NumberCharsLookup = lookupify(conventions.NumberChars), Keywords = conventions.Keywords, @@ -130,26 +130,26 @@ function Tokenizer:new(settings) DecimalSeperators = conventions.DecimalSeperators, IdentChars = conventions.IdentChars, IdentCharsLookup = lookupify(conventions.IdentChars), - + EscapeSequences = conventions.EscapeSequences, NumericalEscapes = conventions.NumericalEscapes, EscapeZIgnoreNextWhitespace = conventions.EscapeZIgnoreNextWhitespace, HexEscapes = conventions.HexEscapes, UnicodeEscapes = conventions.UnicodeEscapes, - + SymbolChars = conventions.SymbolChars, SymbolCharsLookup = lookupify(conventions.SymbolChars), MaxSymbolLength = conventions.MaxSymbolLength, Symbols = conventions.Symbols, SymbolsLookup = lookupify(conventions.Symbols), - + StringStartLookup = lookupify({"\"", "\'"}), annotations = {}, }; - + setmetatable(tokenizer, self); self.__index = self; - + return tokenizer; end @@ -194,7 +194,7 @@ local function expect(self, charOrLookup) if(type(charOrLookup) == "string") then charOrLookup = {[charOrLookup] = true}; end - + local char = peek(self); if charOrLookup[char] ~= true then local etb = unlookupify(charOrLookup); @@ -204,7 +204,7 @@ local function expect(self, charOrLookup) local errorMessage = "Unexpected char \"" .. escape(char) .. "\"! Expected one of \"" .. table.concat(etb, "\",\"") .. "\""; logger:error(generateError(self, errorMessage)); end - + self.index = self.index + 1; return char; end @@ -300,7 +300,7 @@ end function Tokenizer:number() local startPos = self.index; local source = expect(self, setmetatable({["."] = true}, {__index = self.NumberCharsLookup})); - + if source == "0" then if self.BinaryNums and is(self, lookupify(self.BinaryNums)) then self.index = self.index + 1; @@ -308,7 +308,7 @@ function Tokenizer:number() local value = tonumber(source, 2); return token(self, startPos, Tokenizer.TokenKind.Number, value); end - + if self.HexadecimalNums and is(self, lookupify(self.HexadecimalNums)) then self.index = self.index + 1; source = int(self, self.HexNumberCharsLookup, lookupify(self.DecimalSeperators or {})); @@ -316,7 +316,7 @@ function Tokenizer:number() return token(self, startPos, Tokenizer.TokenKind.Number, value); end end - + if source == "." then source = source .. int(self, self.NumberCharsLookup, lookupify(self.DecimalSeperators or {})); else @@ -325,7 +325,7 @@ function Tokenizer:number() source = source .. get(self) .. int(self, self.NumberCharsLookup, lookupify(self.DecimalSeperators or {})); end end - + if(self.DecimalExponent and is(self, lookupify(self.DecimalExponent))) then source = source .. get(self); if(is(self, lookupify({"+","-"}))) then @@ -337,7 +337,7 @@ function Tokenizer:number() end source = source .. v; end - + local value = tonumber(source); return token(self, startPos, Tokenizer.TokenKind.Number, value); end @@ -355,13 +355,13 @@ function Tokenizer:ident() if(self.KeywordsLookup[source]) then return token(self, startPos, Tokenizer.TokenKind.Keyword, source); end - + local tk = token(self, startPos, Tokenizer.TokenKind.Ident, source); - + if(string.sub(source, 1, string.len(config.IdentPrefix)) == config.IdentPrefix) then logger:warn(generateWarning(tk, string.format("identifiers should not start with \"%s\" as this may break the program", config.IdentPrefix))); end - + return tk; end @@ -372,36 +372,36 @@ function Tokenizer:singleLineString() while (not is(self, startChar)) do local char = get(self); - + -- Single Line String may not contain Linebreaks except when they are escaped by \ if(char == '\n') then self.index = self.index - 1; logger:error(generateError(self, "Unterminated String")); end - - + + if(char == "\\") then char = get(self); - + local escape = self.EscapeSequences[char]; if(type(escape) == "string") then char = escape; - + elseif(self.NumericalEscapes and self.NumberCharsLookup[char]) then local numstr = char; - + if(is(self, self.NumberCharsLookup)) then char = get(self); numstr = numstr .. char; end - + if(is(self, self.NumberCharsLookup)) then char = get(self); numstr = numstr .. char; end - + char = string.char(tonumber(numstr)); - + elseif(self.UnicodeEscapes and char == "u") then expect(self, "{"); local num = ""; @@ -420,13 +420,13 @@ function Tokenizer:singleLineString() end end end - + --// since table.insert is slower in lua51 buffer[#buffer + 1] = char end - + expect(self, startChar); - + return token(self, startPos, Tokenizer.TokenKind.String, table.concat(buffer)) end @@ -442,13 +442,13 @@ function Tokenizer:multiLineString() if(is(self, "[")) then -- Multiline String -- Parse String to Closing bracket but also consider that the count of equal signs must be the same - + -- Skip Leading newline if existing self.index = self.index + 1; if(is(self, "\n")) then self.index = self.index + 1; end - + local value = ""; while true do local char = get(self); @@ -490,27 +490,27 @@ end function Tokenizer:next() -- Skip All Whitespace before the token self:skipWhitespaceAndComments(); - + local startPos = self.index; if startPos >= self.length then return token(self, startPos, Tokenizer.TokenKind.Eof); end - + -- Numbers if(is(self, self.NumberCharsLookup)) then return self:number(); end - + -- Identifiers and Keywords if(is(self, self.IdentCharsLookup)) then return self:ident(); end - + -- Singleline String Literals if(is(self, self.StringStartLookup)) then return self:singleLineString(); end - + -- Multiline String Literals if(is(self, "[", 0)) then -- The isString variable is due to the fact that "[" could also be a symbol for indexing @@ -524,12 +524,12 @@ function Tokenizer:next() if(is(self, ".") and is(self, self.NumberCharsLookup, 1)) then return self:number(); end - + -- Symbols if(is(self, self.SymbolCharsLookup)) then return self:symbol(); end - + logger:error(generateError(self, "Unexpected char \"" .. escape(peek(self)) .. "\"!")); end diff --git a/src/prometheus/unparser.lua b/src/prometheus/unparser.lua index b32e98fb..315cd66c 100644 --- a/src/prometheus/unparser.lua +++ b/src/prometheus/unparser.lua @@ -4,7 +4,7 @@ -- Overview: -- This Script provides a class for lua code generation from an ast -- This UnParser is Capable of generating LuaU and Lua5.1 --- +-- -- Note that a LuaU ast can only be unparsed as LuaU if it contains any continue statements -- -- Settings Object: @@ -45,10 +45,10 @@ function Unparser:new(settings) highlight = settings and settings.Highlight or false; keywordsLookup = lookupify(conventions.Keywords); } - + setmetatable(unparser, self); self.__index = self; - + return unparser; end @@ -107,17 +107,17 @@ function Unparser:unparse(ast) if(ast.kind ~= AstKind.TopNode) then logger:error("Unparser:unparse expects a TopNode as first argument") end - + return self:unparseBlock(ast.body); end function Unparser:unparseBlock(block, tabbing) local code = ""; - + if(#block.statements < 1) then return self:whitespace(); end - + for i, statement in ipairs(block.statements) do if(statement.kind ~= AstKind.NopStatement) then local statementCode = self:unparseStatement(statement, tabbing); @@ -136,41 +136,41 @@ function Unparser:unparseBlock(block, tabbing) code = code .. statementCode; end end - + return code; end function Unparser:unparseStatement(statement, tabbing) tabbing = tabbing and tabbing + 1 or 0; local code = ""; - + if(statement.kind == AstKind.ContinueStatement) then code = "continue"; - + -- Break Statement elseif(statement.kind == AstKind.BreakStatement) then code = "break"; - - + + -- Do Statement elseif(statement.kind == AstKind.DoStatement) then local bodyCode = self:unparseBlock(statement.body, tabbing); code = "do" .. self:whitespaceIfNeeded(bodyCode, self:newline(true)) .. bodyCode .. self:newline(false) .. self:whitespaceIfNeeded2(bodyCode, self:tabs(tabbing, true)) .. "end"; - + -- While Statement elseif(statement.kind == AstKind.WhileStatement) then local expressionCode = self:unparseExpression(statement.condition, tabbing); - + local bodyCode = self:unparseBlock(statement.body, tabbing); - - - code = "while" .. self:whitespaceIfNeeded(expressionCode) .. expressionCode .. self:whitespaceIfNeeded2(expressionCode) + + + code = "while" .. self:whitespaceIfNeeded(expressionCode) .. expressionCode .. self:whitespaceIfNeeded2(expressionCode) .. "do" .. self:whitespaceIfNeeded(bodyCode, self:newline(true)) .. bodyCode .. self:newline(false) .. self:whitespaceIfNeeded2(bodyCode, self:tabs(tabbing, true)) .. "end"; - + -- Repeat Until Statement elseif(statement.kind == AstKind.RepeatStatement) then local expressionCode = self:unparseExpression(statement.condition, tabbing); @@ -185,78 +185,78 @@ function Unparser:unparseStatement(statement, tabbing) -- For Statement elseif(statement.kind == AstKind.ForStatement) then local bodyCode = self:unparseBlock(statement.body, tabbing); - + code = "for" .. self:whitespace() .. statement.scope:getVariableName(statement.id) .. self:optionalWhitespace() .. "="; code = code .. self:optionalWhitespace() .. self:unparseExpression(statement.initialValue, tabbing) .. ","; code = code .. self:optionalWhitespace() .. self:unparseExpression(statement.finalValue, tabbing) .. ","; - + local incrementByCode = statement.incrementBy and self:unparseExpression(statement.incrementBy, tabbing) or "1"; code = code .. self:optionalWhitespace() .. incrementByCode .. self:whitespaceIfNeeded2(incrementByCode) .. "do" .. self:whitespaceIfNeeded(bodyCode, self:newline(true)) .. bodyCode .. self:newline(false) .. self:whitespaceIfNeeded2(bodyCode, self:tabs(tabbing, true)) .. "end"; - - + + -- For In Statement elseif(statement.kind == AstKind.ForInStatement) then code = "for" .. self:whitespace(); - + for i, id in ipairs(statement.ids) do if(i ~= 1) then code = code .. "," .. self:optionalWhitespace(); end - + code = code .. statement.scope:getVariableName(id); end - + code = code .. self:whitespace() .. "in"; - + local exprcode = self:unparseExpression(statement.expressions[1], tabbing); code = code .. self:whitespaceIfNeeded(exprcode) .. exprcode; for i = 2, #statement.expressions, 1 do exprcode = self:unparseExpression(statement.expressions[i], tabbing); code = code .. "," .. self:optionalWhitespace() .. exprcode; end - + local bodyCode = self:unparseBlock(statement.body, tabbing); code = code .. self:whitespaceIfNeeded2(code) .. "do" .. self:whitespaceIfNeeded(bodyCode, self:newline(true)) .. bodyCode .. self:newline(false) .. self:whitespaceIfNeeded2(bodyCode, self:tabs(tabbing, true)) .. "end"; - - + + -- If Statement elseif(statement.kind == AstKind.IfStatement) then local exprcode = self:unparseExpression(statement.condition, tabbing); - + local bodyCode = self:unparseBlock(statement.body, tabbing); code = "if" .. self:whitespaceIfNeeded(exprcode) .. exprcode .. self:whitespaceIfNeeded2(exprcode) .. "then" .. self:whitespaceIfNeeded(bodyCode, self:newline(true)) .. bodyCode; - + for i, eif in ipairs(statement.elseifs) do exprcode = self:unparseExpression(eif.condition, tabbing); bodyCode = self:unparseBlock(eif.body, tabbing); - code = code .. self:newline(false) .. self:whitespaceIfNeeded2(code, self:tabs(tabbing, true)) .. "elseif" .. self:whitespaceIfNeeded(exprcode) .. exprcode .. self:whitespaceIfNeeded2(exprcode) + code = code .. self:newline(false) .. self:whitespaceIfNeeded2(code, self:tabs(tabbing, true)) .. "elseif" .. self:whitespaceIfNeeded(exprcode) .. exprcode .. self:whitespaceIfNeeded2(exprcode) .. "then" .. self:whitespaceIfNeeded(bodyCode, self:newline(true)) .. bodyCode; end - + if(statement.elsebody) then bodyCode = self:unparseBlock(statement.elsebody, tabbing); code = code .. self:newline(false) .. self:whitespaceIfNeeded2(code, self:tabs(tabbing, true)) .. "else" .. self:whitespaceIfNeeded(bodyCode, self:newline(true)) .. bodyCode; end - + code = code .. self:newline(false) .. self:whitespaceIfNeeded2(bodyCode, self:tabs(tabbing, true)) .. "end"; - - + + -- Function Declaration elseif(statement.kind == AstKind.FunctionDeclaration) then local funcname = statement.scope:getVariableName(statement.id); for _, index in ipairs(statement.indices) do funcname = funcname .. "." .. index; end - + code = "function" .. self:whitespace() .. funcname .. "("; - + for i, arg in ipairs(statement.args) do if i > 1 then code = code .. "," .. self:optionalWhitespace(); @@ -268,16 +268,16 @@ function Unparser:unparseStatement(statement, tabbing) end end code = code .. ")"; - + local bodyCode = self:unparseBlock(statement.body, tabbing); code = code .. self:newline(false) .. bodyCode .. self:newline(false) .. self:whitespaceIfNeeded2(bodyCode, self:tabs(tabbing, true)) .. "end"; - - + + -- Local Function Declaration elseif(statement.kind == AstKind.LocalFunctionDeclaration) then local funcname = statement.scope:getVariableName(statement.id); code = "local" .. self:whitespace() .. "function" .. self:whitespace() .. funcname .. "("; - + for i, arg in ipairs(statement.args) do if i > 1 then code = code .. "," .. self:optionalWhitespace(); @@ -292,11 +292,11 @@ function Unparser:unparseStatement(statement, tabbing) local bodyCode = self:unparseBlock(statement.body, tabbing); code = code .. self:newline(false) .. bodyCode .. self:newline(false) .. self:whitespaceIfNeeded2(bodyCode, self:tabs(tabbing, true)) .. "end"; - + -- Local Variable Declaration elseif(statement.kind == AstKind.LocalVariableDeclaration) then code = "local" .. self:whitespace(); - + for i, id in ipairs(statement.ids) do if i > 1 then code = code .. "," .. self:optionalWhitespace(); @@ -320,18 +320,18 @@ function Unparser:unparseStatement(statement, tabbing) else code = self:unparseExpression(statement.base, tabbing); end - + code = code .. "("; - + for i, arg in ipairs(statement.args) do if i > 1 then code = code .. "," .. self:optionalWhitespace(); end code = code .. self:unparseExpression(arg, tabbing); end - + code = code .. ")"; - + -- Pass Self Function Call Statement elseif(statement.kind == AstKind.PassSelfFunctionCallStatement) then if not (statement.base.kind == AstKind.IndexExpression or statement.base.kind == AstKind.VariableExpression) then @@ -352,8 +352,8 @@ function Unparser:unparseStatement(statement, tabbing) end code = code .. ")"; - - + + elseif(statement.kind == AstKind.AssignmentStatement) then for i, primary_expr in ipairs(statement.lhs) do if i > 1 then @@ -361,16 +361,16 @@ function Unparser:unparseStatement(statement, tabbing) end code = code .. self:unparseExpression(primary_expr, tabbing); end - + code = code .. self:optionalWhitespace() .. "=" .. self:optionalWhitespace(); - + for i, expr in ipairs(statement.rhs) do if i > 1 then code = code .. "," .. self:optionalWhitespace(); end code = code .. self:unparseExpression(expr, tabbing + 1); end - + -- Return Statement elseif(statement.kind == AstKind.ReturnStatement) then code = "return"; @@ -392,7 +392,7 @@ function Unparser:unparseStatement(statement, tabbing) [AstKind.CompoundPowStatement] = "^=", [AstKind.CompoundConcatStatement] = "..=", } - + local operator = compoundOperators[statement.kind] if operator then code = code .. self:unparseExpression(statement.lhs, tabbing) .. self:optionalWhitespace() .. operator .. self:optionalWhitespace() .. self:unparseExpression(statement.rhs, tabbing) @@ -400,7 +400,7 @@ function Unparser:unparseStatement(statement, tabbing) logger:error(string.format("\"%s\" is not a valid unparseable statement in %s!", statement.kind, self.luaVersion)) end end - + return self:tabs(tabbing, false) .. code; end @@ -436,7 +436,7 @@ end function Unparser:unparseExpression(expression, tabbing) local code = ""; - + if(expression.kind == AstKind.BooleanExpression) then if(expression.value) then return "true"; @@ -444,7 +444,7 @@ function Unparser:unparseExpression(expression, tabbing) return "false"; end end - + if(expression.kind == AstKind.NumberExpression) then local str = tostring(expression.value); if(str == "inf") then @@ -458,45 +458,45 @@ function Unparser:unparseExpression(expression, tabbing) end return str; end - + if(expression.kind == AstKind.VariableExpression or expression.kind == AstKind.AssignmentVariable) then return expression.scope:getVariableName(expression.id); end - + if(expression.kind == AstKind.StringExpression) then return "\"" .. escapeString(expression.value) .. "\""; end - + if(expression.kind == AstKind.NilExpression) then return "nil"; end - + if(expression.kind == AstKind.VarargExpression) then return "..."; end - + local k = AstKind.OrExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); local rhs = self:unparseExpression(expression.rhs, tabbing); return lhs .. self:whitespaceIfNeeded2(lhs) .. "or" .. self:whitespaceIfNeeded(rhs) .. rhs; end - + k = AstKind.AndExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); if(Ast.astKindExpressionToNumber(expression.lhs.kind) >= Ast.astKindExpressionToNumber(k)) then lhs = "(" .. lhs .. ")"; end - + local rhs = self:unparseExpression(expression.rhs, tabbing); if(Ast.astKindExpressionToNumber(expression.rhs.kind) >= Ast.astKindExpressionToNumber(k)) then rhs = "(" .. rhs .. ")"; end - + return lhs .. self:whitespaceIfNeeded2(lhs) .. "and" .. self:whitespaceIfNeeded(rhs) .. rhs; end - + k = AstKind.LessThanExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -511,7 +511,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. "<" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.GreaterThanExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -526,7 +526,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. ">" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.LessThanOrEqualsExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -541,7 +541,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. "<=" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.GreaterThanOrEqualsExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -556,7 +556,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. ">=" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.NotEqualsExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -571,7 +571,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. "~=" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.EqualsExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -586,7 +586,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. "==" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.StrCatExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -605,7 +605,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. ".." .. self:optionalWhitespace() .. rhs; end - + k = AstKind.AddExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -620,7 +620,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. "+" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.SubExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -635,11 +635,11 @@ function Unparser:unparseExpression(expression, tabbing) if string.sub(rhs, 1, 1) == "-" then rhs = "(" .. rhs .. ")"; - end + end return lhs .. self:optionalWhitespace() .. "-" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.MulExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -654,7 +654,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. "*" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.DivExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -669,7 +669,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. "/" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.ModExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -684,7 +684,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. "%" .. self:optionalWhitespace() .. rhs; end - + k = AstKind.PowExpression; if(expression.kind == k) then local lhs = self:unparseExpression(expression.lhs, tabbing); @@ -699,7 +699,7 @@ function Unparser:unparseExpression(expression, tabbing) return lhs .. self:optionalWhitespace() .. "^" .. self:optionalWhitespace() .. rhs; end - + -- Unary Expressions k = AstKind.NotExpression; if(expression.kind == k) then @@ -710,7 +710,7 @@ function Unparser:unparseExpression(expression, tabbing) return "not" .. self:whitespaceIfNeeded(rhs) .. rhs; end - + k = AstKind.NegateExpression; if(expression.kind == k) then local rhs = self:unparseExpression(expression.rhs, tabbing); @@ -720,11 +720,11 @@ function Unparser:unparseExpression(expression, tabbing) if string.sub(rhs, 1, 1) == "-" then rhs = "(" .. rhs .. ")"; - end + end return "-" .. rhs; end - + k = AstKind.LenExpression; if(expression.kind == k) then local rhs = self:unparseExpression(expression.rhs, tabbing); @@ -734,24 +734,24 @@ function Unparser:unparseExpression(expression, tabbing) return "#" .. rhs; end - + k = AstKind.IndexExpression; if(expression.kind == k or expression.kind == AstKind.AssignmentIndexing) then local base = self:unparseExpression(expression.base, tabbing); if(expression.base.kind == AstKind.VarargExpression or Ast.astKindExpressionToNumber(expression.base.kind) > Ast.astKindExpressionToNumber(k)) then base = "(" .. base .. ")"; end - + -- Identifier Indexing e.g: x.y instead of x["y"]; if(expression.index.kind == AstKind.StringExpression and self:isValidIdentifier(expression.index.value)) then return base .. "." .. expression.index.value; end - + -- Index never needs parens local index = self:unparseExpression(expression.index, tabbing); return base .. "[" .. index .. "]"; end - + k = AstKind.FunctionCallExpression; if(expression.kind == k) then if not (expression.base.kind == AstKind.IndexExpression or expression.base.kind == AstKind.VariableExpression) then @@ -772,8 +772,8 @@ function Unparser:unparseExpression(expression, tabbing) code = code .. ")"; return code; end - - + + k = AstKind.PassSelfFunctionCallExpression; if(expression.kind == k) then if not (expression.base.kind == AstKind.IndexExpression or expression.base.kind == AstKind.VariableExpression) then @@ -796,7 +796,7 @@ function Unparser:unparseExpression(expression, tabbing) code = code .. ")"; return code; end - + k = AstKind.FunctionLiteralExpression; if(expression.kind == k) then code = "function" .. "("; @@ -817,21 +817,21 @@ function Unparser:unparseExpression(expression, tabbing) code = code .. self:newline(false) .. bodyCode .. self:newline(false) .. self:whitespaceIfNeeded2(bodyCode, self:tabs(tabbing, true)) .. "end"; return code; end - + k = AstKind.TableConstructorExpression; if(expression.kind == k) then if(#expression.entries == 0) then return "{}" end; local inlineTable = #expression.entries <= 3; local tableTabbing = tabbing + 1; - + code = "{"; if inlineTable then code = code .. self:optionalWhitespace(); else code = code .. self:optionalWhitespace(self:newline() .. self:tabs(tableTabbing)); end - + local p = false; for i, entry in ipairs(expression.entries) do p = true; @@ -856,7 +856,7 @@ function Unparser:unparseExpression(expression, tabbing) if inlineTable then return code .. self:optionalWhitespace() .. "}"; end - + return code .. self:optionalWhitespace((p and "," or "") .. self:newline() .. self:tabs(tabbing)) .. "}"; end diff --git a/src/prometheus/util.lua b/src/prometheus/util.lua index 8d33421e..704bab28 100644 --- a/src/prometheus/util.lua +++ b/src/prometheus/util.lua @@ -3,11 +3,6 @@ -- util.lua -- This file Provides some utility functions -local logger = require("logger"); -local bit32 = require("prometheus.bit").bit32; - -local MAX_UNPACK_COUNT = 195; - local function lookupify(tb) local tb2 = {}; for _, v in ipairs(tb) do @@ -58,11 +53,11 @@ local function chararray(str) end local function keys(tb) - local keyset={} + local keyset = {} local n=0 - for k,v in pairs(tb) do - n=n+1 - keyset[n]=k + for k, _ in pairs(tb) do + n = n + 1 + keyset[n] = k end return keyset end @@ -99,160 +94,6 @@ local function shuffle(tb) end return tb end -local function shuffle_string(str) - local len = #str - local t = {} - for i = 1, len do - t[i] = string.sub(str, i, i) - end - for i = 1, len do - local j = math.random(i, len) - t[i], t[j] = t[j], t[i] - end - return table.concat(t) -end - -local function readDouble(bytes) - local sign = 1 - local mantissa = bytes[2] % 2^4 - for i = 3, 8 do - mantissa = mantissa * 256 + bytes[i] - end - if bytes[1] > 127 then sign = -1 end - local exponent = (bytes[1] % 128) * 2^4 + math.floor(bytes[2] / 2^4) - - if exponent == 0 then - return 0 - end - mantissa = (math.ldexp(mantissa, -52) + 1) * sign - return math.ldexp(mantissa, exponent - 1023) -end - -local function writeDouble(num) - local bytes = {0,0,0,0, 0,0,0,0} - if num == 0 then - return bytes - end - local anum = math.abs(num) - - local mantissa, exponent = math.frexp(anum) - exponent = exponent - 1 - mantissa = mantissa * 2 - 1 - local sign = num ~= anum and 128 or 0 - exponent = exponent + 1023 - - bytes[1] = sign + math.floor(exponent / 2^4) - mantissa = mantissa * 2^4 - local currentmantissa = math.floor(mantissa) - mantissa = mantissa - currentmantissa - bytes[2] = (exponent % 2^4) * 2^4 + currentmantissa - for i= 3, 8 do - mantissa = mantissa * 2^8 - currentmantissa = math.floor(mantissa) - mantissa = mantissa - currentmantissa - bytes[i] = currentmantissa - end - return bytes -end - -local function writeU16(u16) - if (u16 < 0 or u16 > 65535) then - logger:error(string.format("u16 out of bounds: %d", u16)); - end - local lower = bit32.band(u16, 255); - local upper = bit32.rshift(u16, 8); - return {lower, upper} -end - -local function readU16(arr) - return bit32.bor(arr[1], bit32.lshift(arr[2], 8)); -end - -local function writeU24(u24) - if(u24 < 0 or u24 > 16777215) then - logger:error(string.format("u24 out of bounds: %d", u24)); - end - - local arr = {}; - for i = 0, 2 do - arr[i + 1] = bit32.band(bit32.rshift(u24, 8 * i), 255); - end - return arr; -end - -local function readU24(arr) - local val = 0; - - for i = 0, 2 do - val = bit32.bor(val, bit32.lshift(arr[i + 1], 8 * i)); - end - - return val; -end - -local function writeU32(u32) - if(u32 < 0 or u32 > 4294967295) then - logger:error(string.format("u32 out of bounds: %d", u32)); - end - - local arr = {}; - for i = 0, 3 do - arr[i + 1] = bit32.band(bit32.rshift(u32, 8 * i), 255); - end - return arr; -end - -local function readU32(arr) - local val = 0; - - for i = 0, 3 do - val = bit32.bor(val, bit32.lshift(arr[i + 1], 8 * i)); - end - - return val; -end - -local function bytesToString(arr) - local length = arr.n or #arr; - - if length < MAX_UNPACK_COUNT then - return string.char(table.unpack(arr)) - end - - local str = ""; - local overflow = length % MAX_UNPACK_COUNT; - - for i = 1, (#arr - overflow) / MAX_UNPACK_COUNT do - str = str .. string.char(table.unpack(arr, (i - 1) * MAX_UNPACK_COUNT + 1, i * MAX_UNPACK_COUNT)); - end - - return str..(overflow > 0 and string.char(table.unpack(arr, length - overflow + 1, length)) or ""); -end - -local function isNaN(n) - return type(n) == "number" and n ~= n; -end - -local function isInt(n) - return math.floor(n) == n; -end - -local function isU32(n) - return n >= 0 and n <= 4294967295 and isInt(n); -end - -local function toBits(num) - -- returns a table of bits, least significant first. - local t={} -- will contain the bits - local rest; - while num>0 do - rest=math.fmod(num,2) - t[#t+1]=rest - num=(num-rest)/2 - end - return t -end - local function readonly(obj) local r = newproxy(true); @@ -267,20 +108,6 @@ return { chararray = chararray, keys = keys, shuffle = shuffle, - shuffle_string = shuffle_string, - readDouble = readDouble, - writeDouble = writeDouble, - readU16 = readU16, - writeU16 = writeU16, - readU32 = readU32, - writeU32 = writeU32, - readU24 = readU24, - writeU24 = writeU24, - isNaN = isNaN, - isU32 = isU32, - isInt = isInt, utf8char = utf8char, - toBits = toBits, - bytesToString = bytesToString, - readonly = readonly, + readonly = readonly } diff --git a/tests.lua b/tests.lua index 566ee243..ffa16a4b 100644 --- a/tests.lua +++ b/tests.lua @@ -10,7 +10,7 @@ local Prometheus = require("src.prometheus") -- logger.logLevel = logger.LogLevel.Debug; -- Config Variables - Later passed as Parameters -local noColors = false; -- Wether Colors in the Console output should be enabled +local noColors = false; -- Wether Colors in the Console output should be enabled local isWindows = true; -- Wether the Test are Performed on a Windows or Linux System local ciMode = false; -- Wether the Test error are ignored or not local iterationCount = 20; -- How often each test should be executed @@ -91,7 +91,7 @@ local function validate(a, b) outa = outa .. tostring(v); end end - + envb.print = function(...) for i, v in ipairs({...}) do outb = outb .. tostring(v); @@ -138,7 +138,7 @@ for i, filename in ipairs(scandir(testdir)) do fc = fc + 1; else local validated, outa, outb = validate(funca, funcb); - + if not validated then print(Prometheus.colors("[FAILED] ", "red") .. "(" .. filename .. "): " .. name); print("[OUTA] ", outa);