Jump to content

Module:templateparser

Wiktionary වෙතින්

Comment මෙම මොඩියුලය ඉංග්‍රිසි ව්‍යාපෘතියේ ආකාරයට Module:template parser වෙතට ගෙන ගොස් ඇත.

This module provides functions for parsing and finding template invocations found in wikitext.

parseTemplate(text)
Parses text as a template invocation and returns a pair of values, the template name and the arguments (containing anonymous, numbered and named arguments). If the text could not be parsed as a template invocation, the function returns nil. The parser will try to correctly parse subtemplates and tables when given as template parameters, but will throw an error if it detects invalid markup.
findTemplates(text)
Finds all template invocations in the text. This is designed to be used as an iterator in for statements, and returns six or seven values for each invocation:
  1. The template name.
  2. The template arguments (as in parseTemplate).
  3. The the full template invocation as it appears in the original text.
  4. The index the template appears at within the given text; as with Lua in general, the beginning of the text is index 1.
  5. subst, safesubst or transclude, depending on whether the template has been substituted, safe substituted or trancluded.
  6. template, module or parser function, depending on what the template is.
  7. If a module, the name of the function.

Since the parser is not perfect, it should never be used to audit code.


local export = {}

-- local function strip_whitespace(text)
--	local text, _ = mw.ustring.gsub(text, "%s*(.*)%s*", "%1")
--	return text
-- end
local strip_whitespace = mw.text.trim

local parseTemplateSearchPattern = "(([{|}%[%]=<]).?)"
local parseTemplateSearchPatternNoEq = "(([{|}%[%]<]).?)"

local function invalidSyntax()
	error("Invalid syntax detected!")
end

function export.parseTemplate(text)
	local text, ok = text:gsub("^{{(.+)}}$", "%1")
	if ok == 0 then
		return nil
	end
	
	local prev = 1
	local pos = 1, mend, found, f1
	local in_template = 0
	local in_table = 0
	local in_link = 0
	local search = parseTemplateSearchPattern
	local has_key = false
	local eq_index = 1
	
	local name = nil
	local args = {}
	local next_i = 1
	local function add_param(x, has_key, eq)
		if name == nil then
			name = strip_whitespace(x)
			return
		end

		if has_key then
			local key = strip_whitespace(x:sub(1, eq))
			local value = strip_whitespace(x:sub(eq + 2))
			local num = tonumber(key, 10)
			if num ~= nil and num > 0 then
				key = num
			end
			args[key] = value
		else
			args[next_i] = x
			next_i = next_i + 1
		end
	end

	while true do
		pos, mend, found, f1 = text:find(search, pos)
		if pos == nil then break end

		if found == "{{" then
			-- start of subtemplate
			in_template = in_template + 1
			pos = pos + 2
		elseif found == "{|" then
			-- start of a table
			in_table = in_table + 1
			pos = pos + 2
		elseif found == "[[" then
			-- start of link
			in_link = in_link + 1
			pos = pos + 2
		elseif found == "<n" and text:sub(pos, pos + 7) == "<nowiki>" then
			pos = text:find("</nowiki>", pos)
			if pos == nil then return nil end
			pos = pos + 8
		elseif found == "<-" and text:sub(pos, pos + 3) == "<!--" then
			pos = text:find("-->", pos + 4)
			if pos == nil then return nil end
			pos = pos + 3
		--elseif found == "}}" and in_template == 0 then
		--	invalidSyntax()
		elseif in_template == 0 and in_table == 0 and in_link == 0 then
			if f1 == "|" then
				-- parameter separator
				add_param(text:sub(prev, pos - 1), has_key, eq_index - prev)
				has_key = false
				search = parseTemplateSearchPattern -- allow equals sign again
				prev = pos + 1
			elseif f1 == "=" and not has_key then
				-- parameter key/value separator
				eq_index = pos
				has_key = true
				search = parseTemplateSearchPatternNoEq -- do not allow further equals signs
			end
			pos = pos + 1
		elseif found == "}}" then
			-- end of subtemplate
			if in_template > 0 then in_template = in_template - 1 end
			pos = pos + 2
		elseif found == "|}" then
			-- end of table
			if in_table > 0 then in_table = in_table - 1 end
			pos = pos + 2
		elseif found == "]]" then
			-- end of link
			if in_link > 0 then in_link = in_link - 1 end
			pos = pos + 2
		else
			pos = pos + 1
		end
	end

	if in_template ~= 0 or in_table ~= 0 or in_link ~= 0 then
		invalidSyntax()
	end
	
	add_param(text:sub(prev), has_key, eq_index - prev)

	return name, args
end

function export.findTemplates(text)
	local next = 1

	local function findNextTemplate()
		local pos, mend, found
		local in_template, in_argument = 0, 0
		local temp_start = 1
		pos = next
		while true do
			pos, mend, found = text:find("([{}<][{}n!])", pos)
			if pos == nil then break end
			if found == "{{" then
				if text:sub(pos, pos + 2) == "{{{" then
					pos = pos + 3
					in_argument = in_argument + 1
				else
					if in_template == 0 then
						temp_start = pos
					end
					pos = pos + 2
					in_template = in_template + 1
				end
			elseif found == "}}" then
				if text:sub(pos, pos + 2) == "}}}" and in_argument > 0 then
					in_argument = in_argument - 1
					pos = pos + 3
				else
					if in_template > 0 then
						in_template = in_template - 1
						if in_template == 0 then
							next = pos + 2
							local src = text:sub(temp_start, pos + 1)
							local name, args = export.parseTemplate(src)
							if name ~= nil then
								local modifier, type, func
								for prefix in name:gmatch("%s*(.-):") do
									if prefix == "subst" or prefix == "safesubst" then
										view = prefix
										name = name:gsub(prefix .. ":", "", 1)
									elseif prefix:match("^#") then
										if prefix == "#invoke" then
											type = "module"
											func = args[1]
											for i = 2, #args do
												args[i-1] = args[i]
											end
											args[#args] = nil
										else
											type = "parser function"
										end
										name = name:gsub(prefix .. ":", "", 1)
									end
								end
								name = name:gsub("^%s*(.*)%s*$", "%1")
								view = view or "transclude"
								type = type or "template"
								return name, args, src, temp_start, view, type, func
							end
						end
					end
					pos = pos + 2
				end
			elseif found == "<n" and text:sub(pos, pos + 7) == "<nowiki>" then
				pos = text:find("</nowiki>", pos)
				if pos == nil then break end
				pos = pos + 8
			elseif found == "<!" and text:sub(pos, pos + 3) == "<!--" then
				pos = text:find("-->", pos + 4)
				if pos == nil then break end
				pos = pos + 3
			else
				pos = pos + 1
			end
		end
	end

	return findNextTemplate
end

return export
"https://si.wiktionary.org/w/index.php?title=Module:templateparser&oldid=29076" වෙතින් සම්ප්‍රවේශනය කෙරිණි