local function t(t)local P=proxy[t].spans local W,Y=P[0][1],P[0][2]if Y<=W then return string.format("\077\097\116\099\104 \040\037\100\046\046\037\100\044 \101\109\112\116\121\041",W,Y-1)end return string.format("\077\097\116\099\104 \040\037\100\046\046\037\100\041\058 \037\115",W,Y-1,utf8_sub(P.input,W,Y))end local function P(P,W,Y,b)P.source,P.input=Y,b local i=newproxy(true)local D=getmetatable(i)D.__metatable=lockmsg D.__index=setmetatable(P,match_m)D.__tostring=t proxy[i]={name="\077\097\116\099\104",spans=P,group_id=W}return i end match_m.group=check_re("\077\097\116\099\104","\103\114\111\117\112",function(t,P)local W=t.spans[type(P)=="\110\117\109\098\101\114"and P or t.group_id[P]]if not W then return nil end return utf8_sub(t.spans.input,W[1],W[2])end)match_m.span=check_re("\077\097\116\099\104","\115\112\097\110",function(t,P)local W=t.spans[type(P)=="\110\117\109\098\101\114"and P or t.group_id[P]]if not W then return nil end return W[1],W[2]-1 end)match_m.groups=check_re("\077\097\116\099\104","\103\114\111\117\112\115",function(t)local P=t.spans if P.n>0 then local t=table.create(P.n)for W=0,P.n,1 do local Y=P[W]if Y then t[W]=utf8_sub(P.input,Y[1],Y[2])end end return table.unpack(t,1,P.n)end return utf8_sub(P.input,P[0][1],P[0][2])end)match_m.groupdict=check_re("\077\097\116\099\104","\103\114\111\117\112\100\105\099\116",function(t)local P=t.spans local W={}for t,Y in pairs(t.group_id)do Y=P[Y]if Y then W[t]=utf8_sub(P.input,Y[1],Y[2])end end return W end)match_m.grouparr=check_re("\077\097\116\099\104","\103\114\111\117\112\100\105\099\116",function(t)local P=t.spans local W=table.create(P.n)for t=0,P.n,1 do local Y=P[t]if Y then W[t]=utf8_sub(P.input,Y[1],Y[2])end end W.n=P.n return W end)
--
local function match_tostr(self)
	local spans = proxy[self].spans;
	local s_start, s_end = spans[0][1], spans[0][2];
	if s_end <= s_start then
		return string.format("Match (%d..%d, empty)", s_start, s_end - 1);
	end;
	return string.format("Match (%d..%d): %s", s_start, s_end - 1, utf8_sub(spans.input, s_start, s_end));
end;

local function new_match(span_arr, group_id, re, str)
	span_arr.source, span_arr.input = re, str;
	local object = newproxy(true);
	local object_mt = getmetatable(object);
	object_mt.__metatable = lockmsg;
	object_mt.__index = setmetatable(span_arr, match_m);
	object_mt.__tostring = match_tostr;

	proxy[object] = { name = "Match", spans = span_arr, group_id = group_id };
	return object;
end;

match_m.group = check_re('Match', 'group', function(self, group_id)
	local span = self.spans[type(group_id) == "number" and group_id or self.group_id[group_id]];
	if not span then
		return nil;
	end;
	return utf8_sub(self.spans.input, span[1], span[2]);
end);

match_m.span = check_re('Match', 'span', function(self, group_id)
	local span = self.spans[type(group_id) == "number" and group_id or self.group_id[group_id]];
	if not span then
		return nil;
	end;
	return span[1], span[2] - 1;
end);

match_m.groups = check_re('Match', 'groups', function(self)
	local spans = self.spans;
	if spans.n > 0 then
		local ret = table.create(spans.n);
		for i = 0, spans.n do
			local v = spans[i];
			if v then
				ret[i] = utf8_sub(spans.input, v[1], v[2]);
			end;
		end;
		return table.unpack(ret, 1, spans.n);
	end;
	return utf8_sub(spans.input, spans[0][1], spans[0][2]);
end);

match_m.groupdict = check_re('Match', 'groupdict', function(self)
	local spans = self.spans;
	local ret = { };
	for k, v in pairs(self.group_id) do
		v = spans[v];
		if v then
			ret[k] = utf8_sub(spans.input, v[1], v[2]);
		end;
	end;
	return ret;
end);

match_m.grouparr = check_re('Match', 'groupdict', function(self)
	local spans = self.spans;
	local ret = table.create(spans.n);
	for i = 0, spans.n do
		local v = spans[i];
		if v then
			ret[i] = utf8_sub(spans.input, v[1], v[2]);
		end;
	end;
	ret.n = spans.n;
	return ret;
end);
