模組:TryError

local p={}
local lib_arg={}
local yesno = {}
function p._message(err_obj)
	local err_array = err_obj
	local body = ''
	if type(err_obj.message) == type("string") then err_array={err_obj} end
	for i=1,#err_array do body = body .. err_array[i].message or ''end
	return body
end
function p._throw(err_obj)
	local err_array = err_obj
	local body = ''
	if type(err_obj.message) == type("string") then err_array={err_obj} end
	for i=1,#err_array do
		local message = err_array[i].message or ''
	    if mw.text.trim(message) == '' then message = error('没有指定的錯誤-{zh-cn:信息; zh-tw:資訊}-', 2) end
	    message = tostring(message)
	    local tag = 'strong'

	    -- Generate the html.
	    local root = mw.html.create(tag)
	    for j=1,#err_array[i].types do
	    	root:addClass(err_array[i].types[j])
	    end
	    root
	        :addClass('error')
	        :wikitext(message)
		body = body .. tostring(root)
	end
	return body
end
function p._constructErrorFromArg(str)
	local error_array = {}
	mw.ustring.gsub(str,"([^%(]+)%(([^%)]*)%)",function(name,para)
		error_array[#error_array + 1] = {['message']=para,['types']=mw.text.split(name,',')or {name} }
		return name..para 
	end)
	return error_array
end
function p._constructError(str)
	local result={['message']='',['types']={}}
	if mw.text.trim(str or '') == "" then return {['message']='',['types']={'unknown'}} end
	local error_tags = {'strong', 'span', 'p', 'div'}
    for i=1,#error_tags do
    	local check_tag = error_tags[i]:gsub('^(.-)$','<%1[^>]*>(.-)</%1>')
    	local find_msg = '<'
    	mw.ustring.gsub(str,check_tag,function(check_msg)find_msg=check_msg end)
    	find_msg = mw.text.trim(find_msg)
    	if mw.ustring.sub(find_msg,1,1) ~= '<' then
    		result.message = find_msg
    		break
    	end
    end
    local error_attritube = {'class', 'id'}
    local typemap={['error']=1}
    for i=1,#error_attritube do
    	local check_tag_dstr = error_attritube[i]:gsub('^(.-)$','%1="([^"]+)"')
    	local check_tag_sstr = error_attritube[i]:gsub('^(.-)$',"%1='([^']+)'")
    	local check_tag_pstr = error_attritube[i]:gsub('^(.-)$',"%1=([^%%s]+)")
    	local dstr,sstr,pstr = '','',''
    	mw.ustring.gsub(str,check_tag_dstr,function(check_msg)dstr=mw.text.trim(check_msg)end)
    	mw.ustring.gsub(str,check_tag_sstr,function(check_msg)sstr=mw.text.trim(check_msg)end)
    	mw.ustring.gsub(str,check_tag_pstr,function(check_msg)pstr=mw.text.trim(check_msg)end)
    	local pstr_ch = mw.ustring.sub(pstr,1,1)
    	if pstr_ch ~= '"' and pstr_ch ~= "'" then 
    		if mw.text.trim(pstr) ~= "" then
    			typemap[pstr] = 1
    		end
    	end
    	local sdstr = mw.ustring.gsub(dstr .. ' ' .. sstr, '%s+', ' ')
    	local sdarr = mw.text.split(sdstr,' ')
    	for _,class_name in ipairs(sdarr) do
    		if mw.text.trim(class_name) ~= "" then
    			typemap[class_name] = 1
    		end
    	end
    end
    for class_name,_ in pairs(typemap) do
    	if type(result.types) ~= type{"table"} then result.types={} end
    	result.types[#result.types + 1]=class_name
    end
    local getFrommsg = mw.text.split(result.message,"[::︓﹕。%s]")
    result.types[#result.types + 1]=mw.ustring.gsub(getFrommsg[1],"<[^>]+>","")
    result.types[#result.types]=mw.ustring.gsub(result.types[#result.types],'[“"「][^”"」]-[”"」]','')
    
	return result
end
function p.try(frame)
	local args, working_frame
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame, {
        	parentFirst=true,
        	trim = false,
			removeBlanks = false
        })
        working_frame = frame
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
        if type(args) ~= type({}) then args = {frame} end
    end
    local input_try = args[1] or args['1']
    local multi_catch = false
    if (args.multi or '') ~= '' then
		if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
		multi_catch = yesno(args.multi or 'no')
	end
	local preprocess = false
    if (args.preprocess or '') ~= '' then
		if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
		preprocess = yesno(args.preprocess or 'no')
	end
    local if_errorcall = tonumber(mw.getCurrentFrame().args.if_errorcall or '0') or 0
    local catch_list = {}
    local default_catch = {["value"]="{{{throw|error(未處理的例外狀況:)}}}{{{throw}}}", ["exception"]={} }
    for key,value in pairs(args) do
    	local argname = mw.ustring.lower(tostring(key))
    	local exception_data ,checker = mw.ustring.gsub(argname,'^%s*catch%s*%((.-)%)%s*$','%1')
    	if checker > 0 then
    		catch_list[#catch_list+1] = {["value"]=value, ["exception"]=(mw.text.split(exception_data,',') or {exception_data})}
    	elseif mw.text.trim(argname) == 'catch' then
    		default_catch.value=value
    	end
    end
    catch_list[#catch_list+1]=default_catch
    
    local find_error = ' ' .. (input_try or '') .. ' '--/^...$/
    local error_tags = {'strong', 'span', 'p', 'div'}
    local exceptions = {}

    for i=1,#error_tags do
    	local check_tag = error_tags[i]:gsub('^(.-)$','<%1[^>]+error.-</%1>')
    	find_error = mw.ustring.gsub(find_error,check_tag,function(exception)
    		exceptions[#exceptions + 1] = p._constructError(exception)
    	return''end)
    end
	find_error = mw.text.trim(find_error)
	if #exceptions<=0 and if_errorcall > 0 then
		exceptions[#exceptions + 1] = {['message']='其他錯誤',['types']={'error'}}
	end
	if #exceptions<=0 and if_errorcall <= 0 then
		if preprocess == true then return working_frame:preprocess(input_try) end
		return input_try
	end
	local body = ''
	local catched = false
	for i=1,#catch_list do
		local current_catch = catch_list[i]
		local found = false
		local exception_obj = nil
		for j=1,#current_catch.exception do
			for k=1,#exceptions do
				for ke=1,#exceptions[k].types do
					local to_check_ex = mw.ustring.lower(exceptions[k].types[ke])
					local to_check_pattern = mw.text.trim(mw.ustring.lower(current_catch.exception[j]))
					local check_eq = to_check_ex == to_check_pattern
					local check_isregexp = false
					if mw.ustring.sub(to_check_pattern,1,1) == '/' and mw.ustring.sub(to_check_pattern,-1,-1) == '/' then
						to_check_pattern = mw.ustring.sub(to_check_pattern,2,-2)
						if check_eq ~= true then
							xpcall( function() 
								local check_req = mw.ustring.find(to_check_ex, to_check_pattern)
								if check_req then check_eq = true end
							end , function() end )
						end
					end
					if check_eq == true then
						found = true
						exception_obj = exceptions[k]
						break
					end
				end
				if found == true then break end
			end
			if found == true then break end
		end
		if #exceptions > 0 and i==#catch_list then 
			exception_obj=exceptions[1]
			found = true
		end
		if i==#catch_list then 
			if catched==true then
				catch_list[#catch_list].value = "{{{throw}}}"
			end
		end
		if found == true and exception_obj then
			local catch_data = catch_list[i].value
			catch_data = mw.ustring.gsub(catch_data, '%{%{%{%s*throw%s*(|?[^%}]*)%}%}%}',function(str)
				local use_old_error = false
				local input_throw = mw.text.trim(str)
				if input_throw == '' then use_old_error = true end
				if mw.ustring.sub(input_throw,1,1) == '|' then
					input_throw=mw.text.trim(mw.ustring.sub(input_throw,2,-1))
					if input_throw == '' then return '' end
					return p._throw(p._constructErrorFromArg(input_throw))
				elseif use_old_error == true then
					if i==#catch_list then return p._throw(exceptions) end
					return p._throw(exception_obj)
				end
				return '{{{throw' .. str .. '}}}'
			end)
			catch_data = mw.ustring.gsub(catch_data, '%{%{%{%s*message%s*(|?[^%}]*)%}%}%}',function(str)
				local use_old_error = false
				local input_throw = mw.text.trim(str)
				if input_throw == '' then use_old_error = true end
				if mw.ustring.sub(input_throw,1,1) == '|' then
					input_throw=mw.text.trim(mw.ustring.sub(input_throw,2,-1))
					if input_throw == '' then return '' end
					return p._message(p._constructErrorFromArg(input_throw))
				elseif use_old_error == true then
					if i==#catch_list then return p._message(exceptions) end
					return p._message(exception_obj)
				end
				return '{{{message' .. str .. '}}}'
			end)
			body = body .. catch_data
			if multi_catch==true then 
				catched = true
			else
				break
			end
		end
	end
	body = mw.ustring.gsub(body, '%{%{%{%s*[Nn][Oo]%s*[Ee][Rr][Rr][Oo][Rr]%s*(|?[^%}]*)%}%}%}',function(str)
		local use_old_error = false
		local input_throw = mw.text.trim(str)
		if input_throw == '' then use_old_error = true end
		if mw.ustring.sub(input_throw,1,1) == '|' then
			input_throw=mw.text.trim(mw.ustring.sub(input_throw,2,-1))
			if mw.ustring.trim(input_throw) == '' then return '' end
			if mw.ustring.trim(find_error) == '' then return input_throw end
			return find_error
		elseif use_old_error == true then return find_error end
		return '{{{no error' .. str .. '}}}'
	end)
	if preprocess == true then return working_frame:preprocess(body) end
    return body
end
return p