local v={a="\097\110\099\104\111\114\101\100";i="\099\097\115\101\108\101\115\115";m="\109\117\108\116\105\108\105\110\101",s="\100\111\116\097\108\108",u="\117\110\105\099\111\100\101";U="\117\110\103\114\101\101\100\121";x="\101\120\116\101\110\100\101\100"}local N={alnum=true;alpha=true,ascii=true,blank=true;cntrl=true;digit=true;graph=true,lower=true,print=true;punct=true;space=true,upper=true;word=true,xdigit=true}local u={[68]={"\099\108\097\115\115","\100\105\103\105\116";true},[83]={"\099\108\097\115\115";"\115\112\097\099\101",true};[87]={"\099\108\097\115\115","\119\111\114\100";true};[100]={"\099\108\097\115\115";"\100\105\103\105\116";false},[115]={"\099\108\097\115\115","\115\112\097\099\101",false},[119]={"\099\108\097\115\115";"\119\111\114\100",false},[72]={"\099\108\097\115\115";"\098\108\097\110\107",true},[86]={"\099\108\097\115\115";"\118\101\114\116\105\099\097\108\095\116\097\098";true},[104]={"\099\108\097\115\115";"\098\108\097\110\107",false},[118]={"\099\108\097\115\115";"\118\101\114\116\105\099\097\108\095\116\097\098";false},[78]={78},[82]={82};[66]=8,[110]=10,[114]=13;[116]=9}local j={[98]={98;{"\099\108\097\115\115","\119\111\114\100";false}},[66]={66;{"\099\108\097\115\115","\119\111\114\100",false}},[75]={75};[71]={71};[74]={74};[90]={90},[122]={122}}local a={C=true,Cc=true;Cf=true,Cn=true,Co=true,Cs=true;L=true;Ll=true,Lm=true,Lo=true;Lt=true,Lu=true;M=true;Mc=true;Me=true,Mn=true;N=true;Nd=true,Nl=true;No=true;P=true,Pc=true,Pd=true;Pe=true;Pf=true,Pi=true,Po=true,Ps=true,S=true,Sc=true;Sk=true,Sm=true;So=true;Z=true;Zl=true,Zp=true,Zs=true,Xan=true;Xps=true,Xsp=true,Xuc=true;Xwd=true}local l={[33]=true,[34]=true;[35]=true,[36]=true,[37]=true,[38]=true;[39]=true,[40]=true;[41]=true;[42]=true;[43]=true,[44]=true,[45]=true,[46]=true;[47]=true;[58]=true;[59]=true,[60]=true,[61]=true;[62]=true,[63]=true;[64]=true,[91]=true,[92]=true,[93]=true,[94]=true,[95]=true,[96]=true;[123]=true;[124]=true;[125]=true;[126]=true}local J={36}local q={46}local h={94}local T={124}local function K(v,N,u)if v=="\077\097\116\099\104"then return function(...)local v=select("\035",...)if v<1 then error("\109\105\115\115\105\110\103 \097\114\103\117\109\101\110\116 \035\049 \040\077\097\116\099\104 \101\120\112\101\099\116\101\100\041",2)end local j,a=...if not(proxy[j]and proxy[j].name=="\077\097\116\099\104")then error(string.format("\105\110\118\097\108\105\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \037\113 \040\077\097\116\099\104 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",N,typeof(j)),2)else j=proxy[j]end if N=="\103\114\111\117\112"or N=="\115\112\097\110"then if a==nil then a=0 end end return u(j,a)end end return function(...)local v=select("\035",...)if v<1 then error("\109\105\115\115\105\110\103 \097\114\103\117\109\101\110\116 \035\049 \040\082\101\103\069\120 \101\120\112\101\099\116\101\100\041",2)elseif v<2 then error("\109\105\115\115\105\110\103 \097\114\103\117\109\101\110\116 \035\050 \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\041",2)end local j,a,l,J,q,h=...if not(proxy[j]and proxy[j].name=="\082\101\103\069\120")then if type(j)~="\115\116\114\105\110\103"and type(j)~="\110\117\109\098\101\114"then error(string.format("\105\110\118\097\108\105\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \037\113 \040\082\101\103\069\120 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",N,typeof(j)),2)end j=re.fromstring(j)elseif N=="\115\117\098"then if type(l)=="\110\117\109\098\101\114"then l..=""elseif type(l)~="\115\116\114\105\110\103"then error(string.format("\105\110\118\097\108\105\100 \097\114\103\117\109\101\110\116 \035\051 \116\111 \'\115\117\098\' \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",typeof(l)),2)end elseif type(a)=="\110\117\109\098\101\114"then a..=""elseif type(a)~="\115\116\114\105\110\103"then error(string.format("\105\110\118\097\108\105\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \037\113 \040\115\116\114\105\110\103 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",N,typeof(a)),2)end if N~="\115\117\098"and N~="\115\112\108\105\116"then local v=typeof(l)if v~="\110\105\108"then l=tonumber(l)if not l then error(string.format("\105\110\118\097\108\105\100 \097\114\103\117\109\101\110\116 \035\051 \116\111 \037\113 \040\110\117\109\098\101\114 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041",N,v),2)elseif l<0 then l=(#a+math.floor(l+.5))+1 else l=math.max(math.floor(l+.5),1)end end end j=proxy[j]if N=="\109\097\116\099\104"or N=="\109\097\116\099\104\105\116\101\114"then J=...elseif N=="\115\117\098"then h=...end return u(j,a,l,J,q,h)end end
--
local flag_map = {
	a = "anchored",
	i = "caseless",
	m = "multiline",
	s = "dotall",
	u = "unicode",
	U = "ungreedy",
	x = "extended",
}

local posix_class_names = {
	alnum = true,
	alpha = true,
	ascii = true,
	blank = true,
	cntrl = true,
	digit = true,
	graph = true,
	lower = true,
	print = true,
	punct = true,
	space = true,
	upper = true,
	word = true,
	xdigit = true,
}

local escape_chars = {
	-- grouped
	-- digit, spaces and words
	[0x44] = { "class", "digit", true },
	[0x53] = { "class", "space", true },
	[0x57] = { "class", "word", true },
	[0x64] = { "class", "digit", false },
	[0x73] = { "class", "space", false },
	[0x77] = { "class", "word", false },
	-- horizontal/vertical whitespace and newline
	[0x48] = { "class", "blank", true },
	[0x56] = { "class", "vertical_tab", true },
	[0x68] = { "class", "blank", false },
	[0x76] = { "class", "vertical_tab", false },
	[0x4E] = { 0x4E },
	[0x52] = { 0x52 },

	-- not grouped
	[0x42] = 0x08,
	[0x6E] = 0x0A,
	[0x72] = 0x0D,
	[0x74] = 0x09,
}

local b_escape_chars = {
	-- word boundary and not word boundary
	[0x62] = { 0x62, { "class", "word", false } },
	[0x42] = { 0x42, { "class", "word", false } },

	-- keep match out
	[0x4B] = { 0x4B },

	-- start & end of string
	[0x47] = { 0x47 },
	[0x4A] = { 0x4A },
	[0x5A] = { 0x5A },
	[0x7A] = { 0x7A },
}

local valid_categories = {
	C = true,
	Cc = true,
	Cf = true,
	Cn = true,
	Co = true,
	Cs = true,
	L = true,
	Ll = true,
	Lm = true,
	Lo = true,
	Lt = true,
	Lu = true,
	M = true,
	Mc = true,
	Me = true,
	Mn = true,
	N = true,
	Nd = true,
	Nl = true,
	No = true,
	P = true,
	Pc = true,
	Pd = true,
	Pe = true,
	Pf = true,
	Pi = true,
	Po = true,
	Ps = true,
	S = true,
	Sc = true,
	Sk = true,
	Sm = true,
	So = true,
	Z = true,
	Zl = true,
	Zp = true,
	Zs = true,

	Xan = true,
	Xps = true,
	Xsp = true,
	Xuc = true,
	Xwd = true,
}

local class_ascii_punct = {
	[0x21] = true,
	[0x22] = true,
	[0x23] = true,
	[0x24] = true,
	[0x25] = true,
	[0x26] = true,
	[0x27] = true,
	[0x28] = true,
	[0x29] = true,
	[0x2A] = true,
	[0x2B] = true,
	[0x2C] = true,
	[0x2D] = true,
	[0x2E] = true,
	[0x2F] = true,
	[0x3A] = true,
	[0x3B] = true,
	[0x3C] = true,
	[0x3D] = true,
	[0x3E] = true,
	[0x3F] = true,
	[0x40] = true,
	[0x5B] = true,
	[0x5C] = true,
	[0x5D] = true,
	[0x5E] = true,
	[0x5F] = true,
	[0x60] = true,
	[0x7B] = true,
	[0x7C] = true,
	[0x7D] = true,
	[0x7E] = true,
}

local end_str = { 0x24 }
local dot = { 0x2E }
local beginning_str = { 0x5E }
local alternation = { 0x7C }

local function check_re(re_type, name, func)
	if re_type == "Match" then
		return function(...)
			local arg_n = select("#", ...)
			if arg_n < 1 then
				error("missing argument #1 (Match expected)", 2)
			end
			local arg0, arg1 = ...
			if not (proxy[arg0] and proxy[arg0].name == "Match") then
				error(string.format("invalid argument #1 to %q (Match expected, got %s)", name, typeof(arg0)), 2)
			else
				arg0 = proxy[arg0]
			end
			if name == "group" or name == "span" then
				if arg1 == nil then
					arg1 = 0
				end
			end
			return func(arg0, arg1)
		end
	end
	return function(...)
		local arg_n = select("#", ...)
		if arg_n < 1 then
			error("missing argument #1 (RegEx expected)", 2)
		elseif arg_n < 2 then
			error("missing argument #2 (string expected)", 2)
		end
		local arg0, arg1, arg2, arg3, arg4, arg5 = ...
		if not (proxy[arg0] and proxy[arg0].name == "RegEx") then
			if type(arg0) ~= "string" and type(arg0) ~= "number" then
				error(string.format("invalid argument #1 to %q (RegEx expected, got %s)", name, typeof(arg0)), 2)
			end
			arg0 = re.fromstring(arg0)
		elseif name == "sub" then
			if type(arg2) == "number" then
				arg2 ..= ""
			elseif type(arg2) ~= "string" then
				error(string.format("invalid argument #3 to 'sub' (string expected, got %s)", typeof(arg2)), 2)
			end
		elseif type(arg1) == "number" then
			arg1 ..= ""
		elseif type(arg1) ~= "string" then
			error(string.format("invalid argument #2 to %q (string expected, got %s)", name, typeof(arg1)), 2)
		end
		if name ~= "sub" and name ~= "split" then
			local init_type = typeof(arg2)
			if init_type ~= "nil" then
				arg2 = tonumber(arg2)
				if not arg2 then
					error(string.format("invalid argument #3 to %q (number expected, got %s)", name, init_type), 2)
				elseif arg2 < 0 then
					arg2 = #arg1 + math.floor(arg2 + 0.5) + 1
				else
					arg2 = math.max(math.floor(arg2 + 0.5), 1)
				end
			end
		end
		arg0 = proxy[arg0]
		if name == "match" or name == "matchiter" then
			arg3 = ...
		elseif name == "sub" then
			arg5 = ...
		end
		return func(arg0, arg1, arg2, arg3, arg4, arg5)
	end
end
