local export = {}
--[[ This module provides two main utilities: tools for parsing other modules,
and, to be added, a linter using those tools. The linter is meant to be
used on documentation pages and the tools are invocable from modules. ]]
local find = string.find
local gmatch = string.gmatch
local gsub = string.gsub
local match = string.match
local setmetatable = setmetatable
local sub = string.sub
----------------------
-- Keys --
----------------------
-- Prototype for keys.
local Key = {
declaration = "", -- This contains the raw declaration, like "local foo = 'bar'" for example.
global = false, -- Whether the variable is global or local.
declared_at = 0, -- The line # the key is declared at.
name = "", -- Name of the key.
--scope = {}, -- A `scope` object in which the variable applies. TODO!
--type = "", -- The type of the variable at the point it's declared. TODO!
uses = 0, -- The number of times it is used throughout the module.
value = "", -- Its value.
}
-- For internal use only.
function Key:new(data)
return setmetatable(data, Key)
end
--[[ Keys are anything defined within the module: local/global variables,
functions, etc. This takes the full text of the module. ]]
function export.grab_keys(text)
local keys = {}
local n = 1
-- Remove comments.
text = gsub(text, "%-%-+", "")
text = gsub(text, "%--%%] ?%--", "")
for declaration in gmatch(text, "%s-(- ?= ?)") do
repeat -- So that keys which can't be assigned values can be skipped.
-- Filter out rubbish: conditionals, returns, etc.
if find(text, sub(declaration, 1, -2) .. "=", declaration_index, true)
or find(declaration, "return")
or find(declaration, "~ -=") then
break
end
local data = {}
local declaration_index = find(text, declaration, nil, true)
if not find(sub(text, declaration_index - 7, declaration_index + #declaration), "local " .. declaration, nil, true) then
data.global = true
end
--[[ Expand the declaration until the full value is found. This can
be somewhat difficult to find. This looks for:
- Matched brackets, as in a table declaration
- End of function
- Comma-separated declarations of multiple variables ]]
-- Simplest case first - regular, single-line declarations, not in tables.
data.value = match(text, declaration .. "(+)", declaration_index)
-- Table declarations.
if not data.value then
data.value = match(text, declaration .. "(%b{}.-)", declaration_index)
-- End of function.
if not data.value then
data.value = match(text, "(" .. declaration .. ".-) end")
-- Comma-separated. TODO!
--if not data.value then
--
--end
if not data.value then
break -- skip
end
end
end
data.name = match(declaration, "local (-) ?= ?") or match(declaration, "(-) ?= ?")
data.declaration = ((not data.global) and "local " or "") .. data.name .. " = " .. data.value
_, data.uses = gsub(text, "" .. data.name .. "", "") -- dummy gsub to get count
-- Find the number of times it's declared and subtract that from uses.
local _, declarations = gsub(text, data.name .. " ?= ?(+)", "")
data.uses = data.uses - declarations
_, data.declared_at = gsub("\n" .. sub(text, 1, declaration_index), "\n", "")
keys = Key:new(data)
n = n + 1
until true
end
keys.amount = #keys
return keys
end
function export.test(frame)
return frame:preprocess('<syntaxhighlight lang="Lua">\n' .. mw.dumpObject(export.grab_keys(frame.args)) .. '\n</syntaxhighlight>')
end
return export