-- This Script is Part of the Prometheus Obfuscator by levno-710 -- -- visitast.lua -- -- This Script provides a utility function for visiting each node of an AST. local Ast = require("prometheus.ast"); local util = require("prometheus.util"); local AstKind = Ast.AstKind; local lookupify = util.lookupify; local visitAst, visitBlock, visitStatement, visitExpression; function visitAst(ast, previsit, postvisit, data) ast.isAst = true; data = data or {}; data.scopeStack = {}; data.functionData = { depth = 0; scope = ast.body.scope; node = ast; }; data.scope = ast.globalScope; data.globalScope = ast.globalScope; if(type(previsit) == "function") then local node, skip = previsit(ast, data); ast = node or ast; if skip then return ast; end end -- Is Function Block because global scope is treated like a Function visitBlock(ast.body, previsit, postvisit, data, true); if(type(postvisit) == "function") then ast = postvisit(ast, data) or ast; end return ast; end local compundStats = lookupify{ AstKind.CompoundAddStatement, AstKind.CompoundSubStatement, AstKind.CompoundMulStatement, AstKind.CompoundDivStatement, AstKind.CompoundModStatement, AstKind.CompoundPowStatement, AstKind.CompoundConcatStatement, } function visitBlock(block, previsit, postvisit, data, isFunctionBlock) block.isBlock = true; block.isFunctionBlock = isFunctionBlock or false; data.scope = block.scope; local parentBlockData = data.blockData; data.blockData = {}; table.insert(data.scopeStack, block.scope); if(type(previsit) == "function") then local node, skip = previsit(block, data); block = node or block; if skip then data.scope = table.remove(data.scopeStack); return block end end local i = 1; while i <= #block.statements do local statement = table.remove(block.statements, i); i = i - 1; local returnedStatements = {visitStatement(statement, previsit, postvisit, data)}; for j, statement in ipairs(returnedStatements) do i = i + 1; table.insert(block.statements, i, statement); end i = i + 1; end if(type(postvisit) == "function") then block = postvisit(block, data) or block; end data.scope = table.remove(data.scopeStack); data.blockData = parentBlockData; return block; end function visitStatement(statement, previsit, postvisit, data) statement.isStatement = true; if(type(previsit) == "function") then local node, skip = previsit(statement, data); statement = node or statement; if skip then return statement; end end -- Visit Child Nodes of Statement if(statement.kind == AstKind.ReturnStatement) then for i, expression in ipairs(statement.args) do statement.args[i] = visitExpression(expression, previsit, postvisit, data); end elseif(statement.kind == AstKind.PassSelfFunctionCallStatement or statement.kind == AstKind.FunctionCallStatement) then statement.base = visitExpression(statement.base, previsit, postvisit, data); for i, expression in ipairs(statement.args) do statement.args[i] = visitExpression(expression, previsit, postvisit, data); end elseif(statement.kind == AstKind.AssignmentStatement) then for i, primaryExpr in ipairs(statement.lhs) do statement.lhs[i] = visitExpression(primaryExpr, previsit, postvisit, data); end for i, expression in ipairs(statement.rhs) do statement.rhs[i] = visitExpression(expression, previsit, postvisit, data); end elseif(statement.kind == AstKind.FunctionDeclaration or statement.kind == AstKind.LocalFunctionDeclaration) then local parentFunctionData = data.functionData; data.functionData = { depth = parentFunctionData.depth + 1; scope = statement.body.scope; node = statement; }; statement.body = visitBlock(statement.body, previsit, postvisit, data, true); data.functionData = parentFunctionData; elseif(statement.kind == AstKind.DoStatement) then statement.body = visitBlock(statement.body, previsit, postvisit, data, false); elseif(statement.kind == AstKind.WhileStatement) then statement.condition = visitExpression(statement.condition, previsit, postvisit, data); statement.body = visitBlock(statement.body, previsit, postvisit, data, false); elseif(statement.kind == AstKind.RepeatStatement) then statement.body = visitBlock(statement.body, previsit, postvisit, data); statement.condition = visitExpression(statement.condition, previsit, postvisit, data); elseif(statement.kind == AstKind.ForStatement) then statement.initialValue = visitExpression(statement.initialValue, previsit, postvisit, data); statement.finalValue = visitExpression(statement.finalValue, previsit, postvisit, data); statement.incrementBy = visitExpression(statement.incrementBy, previsit, postvisit, data); statement.body = visitBlock(statement.body, previsit, postvisit, data, false); elseif(statement.kind == AstKind.ForInStatement) then for i, expression in ipairs(statement.expressions) do statement.expressions[i] = visitExpression(expression, previsit, postvisit, data); end visitBlock(statement.body, previsit, postvisit, data, false); elseif(statement.kind == AstKind.IfStatement) then statement.condition = visitExpression(statement.condition, previsit, postvisit, data); statement.body = visitBlock(statement.body, previsit, postvisit, data, false); for i, eif in ipairs(statement.elseifs) do eif.condition = visitExpression(eif.condition, previsit, postvisit, data); eif.body = visitBlock(eif.body, previsit, postvisit, data, false); end if(statement.elsebody) then statement.elsebody = visitBlock(statement.elsebody, previsit, postvisit, data, false); end elseif(statement.kind == AstKind.LocalVariableDeclaration) then for i, expression in ipairs(statement.expressions) do statement.expressions[i] = visitExpression(expression, previsit, postvisit, data); end elseif compundStats[statement.kind] then statement.lhs = visitExpression(statement.lhs, previsit, postvisit, data); statement.rhs = visitExpression(statement.rhs, previsit, postvisit, data); end if(type(postvisit) == "function") then local statements = {postvisit(statement, data)}; if #statements > 0 then return unpack(statements); end end return statement; end local binaryExpressions = lookupify{ AstKind.OrExpression, AstKind.AndExpression, AstKind.LessThanExpression, AstKind.GreaterThanExpression, AstKind.LessThanOrEqualsExpression, AstKind.GreaterThanOrEqualsExpression, AstKind.NotEqualsExpression, AstKind.EqualsExpression, AstKind.StrCatExpression, AstKind.AddExpression, AstKind.SubExpression, AstKind.MulExpression, AstKind.DivExpression, AstKind.ModExpression, AstKind.PowExpression, } function visitExpression(expression, previsit, postvisit, data) expression.isExpression = true; if(type(previsit) == "function") then local node, skip = previsit(expression, data); expression = node or expression; if skip then return expression; end end if(binaryExpressions[expression.kind]) then expression.lhs = visitExpression(expression.lhs, previsit, postvisit, data); expression.rhs = visitExpression(expression.rhs, previsit, postvisit, data); end if(expression.kind == AstKind.NotExpression or expression.kind == AstKind.NegateExpression or expression.kind == AstKind.LenExpression) then expression.rhs = visitExpression(expression.rhs, previsit, postvisit, data); end if(expression.kind == AstKind.PassSelfFunctionCallExpression or expression.kind == AstKind.FunctionCallExpression) then expression.base = visitExpression(expression.base, previsit, postvisit, data); for i, arg in ipairs(expression.args) do expression.args[i] = visitExpression(arg, previsit, postvisit, data); end end if(expression.kind == AstKind.FunctionLiteralExpression) then local parentFunctionData = data.functionData; data.functionData = { depth = parentFunctionData.depth + 1; scope = expression.body.scope; node = expression; }; expression.body = visitBlock(expression.body, previsit, postvisit, data, true); data.functionData = parentFunctionData; end if(expression.kind == AstKind.TableConstructorExpression) then for i, entry in ipairs(expression.entries) do if entry.kind == AstKind.KeyedTableEntry then entry.key = visitExpression(entry.key, previsit, postvisit, data); end entry.value = visitExpression(entry.value, previsit, postvisit, data); end end if(expression.kind == AstKind.IndexExpression or expression.kind == AstKind.AssignmentIndexing) then expression.base = visitExpression(expression.base, previsit, postvisit, data); expression.index = visitExpression(expression.index, previsit, postvisit, data); end if(expression.kind == AstKind.IfElseExpression) then expression.condition = visitExpression(expression.condition, previsit, postvisit, data); expression.true_value = visitExpression(expression.true_value, previsit, postvisit, data); for i, elif in pairs(expression.elseifs) do elif.condition = visitExpression(elif.condition, previsit, postvisit, data); elif.value = visitExpression(elif.value, previsit, postvisit, data); end expression.false_value = visitExpression(expression.false_value, previsit, postvisit, data); end if(type(postvisit) == "function") then expression = postvisit(expression, data) or expression; end return expression; end return visitAst;