You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
4.9 KiB

local detailsFramework = DetailsFramework
if (not detailsFramework or not DetailsFrameworkCanLoad) then
return
end
local unpack = unpack
local CreateFrame = CreateFrame
local geterrorhandler = geterrorhandler
local wipe = wipe
local parseCodeForNamedLocalFunctions = function(codeBlock, startIndex, listOfFunctionsFound)
local nestedLevel = 0
local endIndex = startIndex
local currentQuote = ""
---@type number for the 'function' keyword, need to ignore the one that started the 'local function' capture
local ignoreFunctionIndex = startIndex + 6
---@type boolean
local bFoundEnd = false
---@type boolean
local bIsInString = false
---@type boolean
local bIsInComment = false
while (endIndex <= #codeBlock) do
local char = string.sub(codeBlock, endIndex, endIndex)
--check if the character is inside a comment
if (char == "-") then
local nextChar = string.sub(codeBlock, endIndex + 1, endIndex + 1)
if nextChar == "-" then
bIsInComment = true
end
elseif (char == "\n") then
bIsInComment = false
end
if (not bIsInComment) then
--check if it is inside a string
if (char == "'" or char == '"') then
if (not bIsInString) then
bIsInString = true
currentQuote = char
elseif (bIsInString and currentQuote == char) then
bIsInString = false
currentQuote = ""
end
end
if (not bIsInString) then
--check if the word starts with "i", "f", "d" or "e"
if (char == "i") then
local nextChars = string.sub(codeBlock, endIndex, endIndex + 1)
if (nextChars == "if") then
nestedLevel = nestedLevel + 1
end
elseif (char == "f") then
local nextChars = string.sub(codeBlock, endIndex, endIndex + 7)
--also check if the index isn't the one that started the 'local function' capture
if (nextChars == "function" and endIndex ~= ignoreFunctionIndex) then
nestedLevel = nestedLevel + 1
end
--for 'do' keyword, used by for and while and also by the 'do' keyword itself creating a block
elseif (char == "d") then
local nextChars = string.sub(codeBlock, endIndex, endIndex + 1)
if (nextChars == "do") then
nestedLevel = nestedLevel + 1
end
elseif (char == "e") then
local nextChars = string.sub(codeBlock, endIndex, endIndex + 2)
if (nextChars == "end") then
if (nestedLevel > 0) then
--reduce the nested level by 1
nestedLevel = nestedLevel - 1
else
--if the nested level is zero then the end of the function got found
bFoundEnd = true
endIndex = endIndex + 2 --adjust endIndex to include the 'end' keyword
break
end
end
end
end
end
endIndex = endIndex + 1
end
if (bFoundEnd) then
---@type string get the function body
local functionBody = string.sub(codeBlock, startIndex, endIndex)
table.insert(listOfFunctionsFound, functionBody)
return endIndex
end
end
---search a code block for named local functions and bring them to the top of the code block
---this is useful for when you want to call a function before it's defined
---same thing as been implemented in Lua 5.2 but not in WoW Lua
---@param codeBlock string
function detailsFramework:BringNamedLocalFunctionToTop(codeBlock)
---@type string[]
local listOfFunctionsFound = {}
---@type number|nil
local startIndex = string.find(codeBlock, "local function")
while startIndex do
startIndex = parseCodeForNamedLocalFunctions(codeBlock, startIndex, listOfFunctionsFound)
if (not startIndex) then
break
end
startIndex = string.find(codeBlock, "local function", startIndex + 1)
end
for i = #listOfFunctionsFound, 1, -1 do
local thisMatch = listOfFunctionsFound[i]
local blockStartIndex = thisMatch[2]
local blockEndIndex = thisMatch[3]
codeBlock = codeBlock:sub(1, blockStartIndex - 1) .. codeBlock:sub(blockEndIndex + 1)
end
for i = #listOfFunctionsFound, 1, -1 do
codeBlock = listOfFunctionsFound[i][1] .. "\n\n" .. codeBlock
end
end