Module:User:Theknightwho/parser/preprocessor2

local insert = table.insert local max = math.max

local ParserTag = require("Module:User:Theknightwho/parser/tokens").ParserTag

local ALLOW_MISSING_END = { includeonly = true, noinclude = true, onlyinclude = true }

local SPACES_TABS = { [" "] = true, ["\t"] = true }

local TAG_LETTERS = { A = true, B = true, C = true, D = true, E = true, F = true, G = true, H = true, I = true, J = true, K = true, L = true, M = true, N = true, O = true, P = true, Q = true, R = true, S = true, T = true, U = true, V = true, W = true, X = true, Y = true, Z = true, a = true, b = true, c = true, d = true, e = true, f = true, g = true, h = true, i = true, j = true, k = true, l = true, m = true, n = true, o = true, p = true, q = true, r = true, s = true, t = true, u = true, v = true, w = true, x = true, y = true, z = true }

local WHITESPACE = { ["\t"] = true, ["\n"] = true, ["\v"] = true, ["\f"] = true, ["\r"] = true, [" "] = true }

local TAGS = { categorytree = true, ce = true, charinsert = true, chem = true, dynamicpagelist = true, gallery = true, graph = true, hiero = true, imagemap = true, indicator = true, inputbox = true, langconvert = true, mapframe = true, maplink = true, math = true, nowiki = true, poem = true, pre = true, ref = true, references = true, score = true, section = true, source = true, syntaxhighlight = true, talkpage = true, templatedata = true, templatestyles = true, thread = true, timeline = true }

local MAX_TAG_LENGTH = 0 for tag in pairs(TAGS) do	local tag_len = #tag if tag_len > MAX_TAG_LENGTH then MAX_TAG_LENGTH = tag_len end end

local ignored_element local ignored_tags

local function strspn(str, chars, init) local str_len = #str for i = init or 1, str_len do		if not chars[str:sub(i, i)] then return i - init end end return str_len - init + 1 end

local function strcspn(str, chars, init) local str_len = #str for i = init or 1, str_len do		if chars[str:sub(i, i)] then return i - init end end return str_len - init + 1 end

local function get_tag_name(str, init) local max = init + MAX_TAG_LENGTH + 1 for i = init, max do		local char = str:sub(i, i)		if (			WHITESPACE[char] or			char == ">" or			char == "/" and str:sub(i + 1, i + 1) == ">"		) then local name = str:sub(init, i - 1) local name_lower = name:lower if (				TAGS[name_lower] or				ignored_tags[name_lower] or				name_lower == ignored_element			) then return name, name_lower end elseif not TAG_LETTERS[char] then break end end return nil end

local function find_close_tag(str, name, init) local i = init repeat i = str:find("") and				str:sub(i + 2, j - 1):lower == name			) then repeat if char == ">" then return i, j					elseif not WHITESPACE[char] then break end j = j + 1 char = str:sub(j, j)				until false i = i + 1 break elseif not TAG_LETTERS[char] then i = i + 1 break end end until false end

local function parse(str, transclude) local text, stack = {}, {} local enable_onlyinclude if transclude then ignored_tags = { includeonly = true, ["/includeonly"] = true }		ignored_element = "noinclude" if str:find(" ") and str:find(" ") then enable_onlyinclude = true end else ignored_tags = { noinclude = true, ["/noinclude"] = true, onlyinclude = true, ["/onlyinclude"] = true }		ignored_element = "includeonly" end local str_rev = str:reverse local str_len = #str local find_equals local find_pipe local heading_index = 1 local in_heading local no_more_gt local no_more_closing_tag = {} local find_onlyinclude = enable_onlyinclude local fake_linestart = true local i = 1 repeat repeat if find_onlyinclude then local start_pos = str:find(str, " ", i)				if not start_pos then return text end i = start_pos + 13 find_onlyinclude = false end if fake_linestart then found = "line-start" char = "" else local search = { ["["] = true, ["{"] = true, ["<"] = true, ["\n"] = true, ["-"] = true }				if #stack == 0 then closing = {} else -- ???				end if find_pipe then search["|"] = true end if find_equals then search["="] = true end rule = nil local lit_len = strcspn(str, search, i)				if lit_len > 0 then insert(text, str:sub(i, i + lit_len - 1)) end i = i + lit_len if i > str_len then if closing == "\n" then found = "line-end" char = "" end return text end char = str:sub(i, i)				char_2 = str:sub(i, i + 1) if char == "|" then found = "pipe" elseif char == "=" then found = "equals" elseif char == "<" then found = "angle" elseif char == "\n" then if in_heading then found = "line-end" else found = "line-start" end elseif char_2 == closing then found = "close" char = char_2 elseif char == closing then found = "close" elseif rules[char_2] then char = char_2 found = "open" rule = rules[char] elseif rules[char] then found = "open" rule = rules[char] elseif char == "-" or char == "}" then insert(text, char) i = i + 1 break end end if found == "angle" then if enable_onlyinclude and str:find("^ ", i) == 1 then find_onlyinclude = true break end if str:find("^", i + 4) if not end_pos then return text else end_pos = end_pos + 3 end local ws_start = i - strspn(str_rev, SPACES_TABS, str_len - i + 2) local ws_end = end_pos + strspn(str, SPACES_TABS, end_pos) while str:find("^", ws_end + 4) if not c then return text else c = c + 3 end ws_end = c + strspn(str, SPACES_TABS, c)					end local ws_prev = ws_start - 1 if (						ws_start > 1 and						str:sub(ws_prev, ws_prev) == "\n" and						str:sub(ws_end, ws_end) == "\n"					) then local ws_length = i - ws_start local end_index = #text local end_index_len = #text[end_index] if (							ws_length > 0 and							end_index > 0 and 							strspn(text[end_index], SPACES_TABS, end_index_len - ws_length + 1) == ws_length						) then text[end_index] = text[end_index]:sub(1, end_index_len - ws_length) end fake_linestart = true end i = end_pos break elseif no_more_gt then insert(text, "<") i = i + 1 break else local name, name_lower = get_tag_name(str, i + 1) if not name then insert(text, "<") i = i + 1 break end local attr_start = i + #name + 1 local tag_end_pos = str:find(">", attr_start) if not tag_end_pos then no_more_gt = true insert(text, "<") i = i + 1 break elseif ignored_tags[name_lower] then i = tag_end_pos + 1 break end local tag_start_pos = i					local attr_end = tag_end_pos - 1 if str:sub(attr_end, attr_end) == "/" then inner = nil i = tag_end_pos + 1 close = nil else attr_end = tag_end_pos if not no_more_closing_tag[name_lower] then local close_start, close_end = find_close_tag(str, name_lower, tag_end_pos + 1) if close_start then local inner = str:sub(tag_end_pos + 1, close_start - 1) insert(text, ParserTag:new(name_lower, inner)) i = close_end + 1 break end end if ALLOW_MISSING_END[name_lower] then local inner = str:sub(tag_end_pos + 1) insert(text, ParserTag:new(name_lower, inner)) i = str_len close = nil break end i = tag_end_pos + 1 insert(text, str:sub(tag_start_pos, tag_end_pos)) no_more_closing_tag[name_lower] = true break end end elseif found == "line-start" then if fake_linestart then fake_linestart = false else insert(text, char) i = i + 1 end local count = #str:match("^=+", i)				if (					count > 0 and					not (count == 1 and find_equals)				) then end end until true until false end