local A=require("\098\105\110\046\112\097\114\115\101\084\101\115\116\070\105\108\101")local m=require("\115\114\099\046\082\101\103\069\120\046\095\095\116\101\115\116\115\095\095\046\116\101\115\116\111\117\116\112\117\116\049")local Y=A(m)local x={}local function a(A,...)table.insert(x,"\t"..A:format(...))end local function s(A,m,Y)local x=A:find(m,Y,true)while x~=nil do local Y=false local a=x-1 while A:sub(a,a)=="\092"do Y=not Y a=a-1 if a==0 then break end end if not Y then return x end x=A:find(m,x+1,true)end return nil end local function t(A)local m=1 m=s(A,"\092",m)while m~=nil do if(A:sub(m+1,m+1)):match("\091\097\102\110\114\116\037\100\092\093")then m=s(A,"\092",m+1)else A=A:sub(1,m)..A:sub(m)m=s(A,"\092",m+2)end end return A end local function I(A)return("\"\037\115\""):format((A:gsub("\"","\092\"")):gsub("\n","\092\110"))end local function Q(A)A=((A:gsub("\092\101","\092\048\050\055")):gsub("\092\037\036","\036")):gsub("\092\120\037\120\037\120\063",function(A)local m=tonumber(A:sub(3),16)return("\092\037\048\051\100"):format(m)end)return I(t(A))end local function Z(A)A=((A:gsub("\092\101","\092\048\050\055")):gsub("\092\091\094\116\110\114\102\097\120\092\037\100\093",function(A)return"\092"..A end)):gsub("\092\120\037\120\037\120",function(A)local m=tonumber(A:sub(3),16)return("\092\037\048\051\100"):format(m)end)return I(t(A))end for A,m in ipairs(Y)do local Y=#m.tests if Y>0 then a("\123")a("\t\115\111\117\114\099\101 \061 \091\061\061\091\037\115\093\061\061\093\044",m.source)if m.flags and m.flags~=""then a("\t\102\108\097\103\115 \061 \037\113\044",m.flags)end a("\t\116\101\115\116\115 \061 \123")for A,m in ipairs(m.tests)do if m.matches then a("\t\t\123")a("\t\t\t\105\110\112\117\116 \061 \037\115\044",Q(m.input))if#m.matches==1 then a("\t\t\t\109\097\116\099\104\101\115 \061 \123\123 \105\110\100\101\120 \061 \037\100\044 \109\097\116\099\104 \061 \037\115 \125\125\044",m.matches[1].index,Z(m.matches[1].match))else a("\t\t\t\109\097\116\099\104\101\115 \061 \123")for A,m in ipairs(m.matches)do a("\t\t\t\t\123 \105\110\100\101\120 \061 \037\100\044 \109\097\116\099\104 \061 \037\115 \125\044",m.index,Z(m.match))end a("\t\t\t\125")end a("\t\t\125\044")else a("\t\t\123 \105\110\112\117\116 \061 \037\115 \125\044",Q(m.input))end end a("\t\125\044")a("\125\044")else print(("\110\111 \116\101\115\116 \099\097\115\101 \102\111\117\110\100 \102\111\114 \035\037\100\058 \037\115"):format(A,m.source))end end local W=io.open("\116\101\115\116\111\117\116\112\117\116\049\046\103\101\110\046\108\117\097","\119\043")W:write("\114\101\116\117\114\110 \123\n")W:write(table.concat(x,"\n"))W:write("\n\125\n")W:close()
local parseTestFile = require("bin.parseTestFile")

--[[
	The next require refers to a prce2 test data file wrapped as a lua module
	that returns a string. Tthese test data files can be found on github:
	https://github.com/luvit/pcre2/tree/master/testdata

	Each file that starts with `testoutput` should work, simply take one and
	create a lua file that looks like this:
	```
	return [==========================[
		*** content of the test data file, after the comments (lines starting with #) ***
	]==========================]
	```

	Require the test data file from the project root path. If you put it in the
	root, it is simply the filename without the `.lua` extension.
]]
local testFile = require("src.RegEx.__tests__.testoutput1")

local testCases = parseTestFile(testFile)

local luaOutputLines = {}

local function writeLine(strFormat, ...)
	table.insert(luaOutputLines, "\t" .. strFormat:format(...))
end

local function findNotEscaped(str, char, startIndex)
	local foundIndex = str:find(char, startIndex, true)
	while foundIndex ~= nil do
		local escaped = false
		local currentChar = foundIndex - 1
		while str:sub(currentChar, currentChar) == "\\" do
			escaped = not escaped
			currentChar = currentChar - 1
			if currentChar == 0 then
				break
			end
		end
		if not escaped then
			return foundIndex
		end
		foundIndex = str:find(char, foundIndex + 1, true)
	end
	return nil
end

local function removeUnescapeBackslash(str)
	local index = 1
	index = findNotEscaped(str, "\\", index)
	while index ~= nil do
		if str:sub(index + 1, index + 1):match("[afnrt%d\\]") then
			index = findNotEscaped(str, "\\", index + 1)
		else
			str = str:sub(1, index) .. str:sub(index)
			index = findNotEscaped(str, "\\", index + 2)
		end
	end
	return str
end

local function quote(str)
	return ('"%s"'):format(
		str:gsub('"', '\\"'):gsub("\n", "\\n")
	)
end

local function processInput(str)
	str = str
		:gsub("\\e", "\\027")
		:gsub("\\%$", "$")
		:gsub("\\x%x%x?", function(match)
			local asciiIndex = tonumber(match:sub(3), 16)
			return ("\\%03d"):format(asciiIndex)
		end)

	return quote(removeUnescapeBackslash(str))
end

local function processMatch(str)
	str = str:gsub("\\e", "\\027")
		:gsub("\\[^tnrfax\\%d]", function(match)
			return "\\" .. match
		end)
		:gsub("\\x%x%x", function(match)
			local asciiIndex = tonumber(match:sub(3), 16)
			return ("\\%03d"):format(asciiIndex)
		end)
	return quote(removeUnescapeBackslash(str))
end

for i, case in ipairs(testCases) do
	local totalTestCases = #case.tests
	if totalTestCases > 0 then
		writeLine("{")

		writeLine("\tsource = [==[%s]==],", case.source)
		if case.flags and case.flags ~= "" then
			writeLine("\tflags = %q,", case.flags)
		end

		writeLine("\ttests = {")
		for _, test in ipairs(case.tests) do
			if test.matches then
				writeLine("\t\t{")
				writeLine("\t\t\tinput = %s,", processInput(test.input))
				if #test.matches == 1 then
					writeLine("\t\t\tmatches = {{ index = %d, match = %s }},",
						test.matches[1].index,
						processMatch(test.matches[1].match)
					)
				else
					writeLine("\t\t\tmatches = {")
					for _, match in ipairs(test.matches) do
						writeLine(
							"\t\t\t\t{ index = %d, match = %s },",
							match.index,
							processMatch(match.match)
						)
					end
					writeLine("\t\t\t}")
				end
				writeLine("\t\t},")
			else
				writeLine("\t\t{ input = %s },", processInput(test.input))
			end
		end
		writeLine("\t},")

		writeLine("},")
	else
		print(("no test case found for #%d: %s"):format(i, case.source))
	end
end

local file = io.open("testoutput1.gen.lua", "w+")
file:write("return {\n")

file:write(table.concat(luaOutputLines, "\n"))

file:write("\n}\n")

file:close()
