Module:User:Benwing2/object usage
Appearance
- This module sandbox lacks a documentation subpage. Please create it.
- Useful links: root page • root page’s subpages • links • transclusions • testcases • sandbox
local export = {}
local dump = mw.dumpObject
local m_links = require("Module:links")
local form_of_module = "Module:form of"
local labels_module = "Module:labels"
local parse_utilities_module = "Module:parse utilities"
local pron_qualifier_module = "Module:pron qualifier"
local references_module = "Module:references"
local rsubn = mw.ustring.gsub
local rfind = mw.ustring.find
-- version of rsubn() that discards all but the first return value
local function rsub(term, foo, bar)
local retval = rsubn(term, foo, bar)
return retval
end
-- version of rsubn() that returns a 2nd argument boolean indicating whether
-- a substitution was made.
local function rsubb(term, foo, bar)
local retval, nsubs = rsubn(term, foo, bar)
return retval, nsubs > 0
end
-- if not empty
local function ine(val)
if val == "" then
return nil
end
return val
end
-- Convert a value that is not a string or number to a string using mw.dumpObject(), for debugging purposes.
local function dump_if_unusual(val)
return (type(val) == "string" or type(val) == "number") and val or dump(val)
end
local function parse_form(args, i, default)
local m_form_data = mw.loadData('Module:form of/data')
local output = {}
while args[i] do
local tag = args[i]
if m_form_data.shortcuts[tag] then
tag = m_form_data.shortcuts[tag]
end
table.insert(output, tag)
i = i + 1
end
return (#output > 0) and table.concat(output, " ") or default
end
function export.show_bare(frame)
local pargs = frame:getParent().args
local lang = pargs[1]
local means = pargs["means"]
if mw.title.getCurrentTitle().nsText == "Template" then
lang = "und"
means = "meaning"
end
lang = lang and require("Module:languages").getByCode(lang) or require("Module:languages").err(lang, 1)
return "[+" .. parse_form(pargs, 2, "object") .. (means and (" = " .. means) or "") .. "]"
end
function export.show_prep(frame)
local pargs = frame:getParent().args
local lang = pargs[1]
local means = pargs["means"]
local term = ine(pargs[2])
local alt = ine(pargs["alt"])
local senseid = ine(pargs["senseid"])
if mw.title.getCurrentTitle().nsText == "Template" then
lang = "und"
means = "meaning"
term = "preposition"
end
lang = lang and require('Module:languages').getByCode(lang) or require('Module:languages').err(lang, 1)
return "[+ <span>" ..
require('Module:links').full_link({lang = lang, term = term, alt = alt, id = senseid, tr = "-"}, "term") ..
" <span>(" .. parse_form(pargs, 3, "object") .. ")</span></span>" .. (means and (" = " .. means) or "") .. "]"
end
function export.show_postp(frame)
local pargs = frame:getParent().args
local lang = pargs[1]
local means = pargs["means"] or nil
local term = ine(pargs[2])
local alt = ine(pargs["alt"])
local senseid = ine(pargs["senseid"])
if mw.title.getCurrentTitle().nsText == "Template" then
lang = "und"
means = "meaning"
term = "postposition"
end
lang = lang and require('Module:languages').getByCode(lang) or require('Module:languages').err(lang, 1)
return "[+ <span><span>(" .. parse_form(pargs, 3, "object") .. ")</span> " ..
require('Module:links').full_link({lang = lang, term = term, alt = alt, id = senseid, tr = "-"}, "term") ..
"</span>" .. (means and (" = " .. means) or "") .. "]"
end
function export.show_obj(frame)
local pargs = frame:getParent().args
local params = {
[1] = {required = true, type = "language", default = "und"},
[2] = {list = true},
}
local args = require("Module:parameters").process(frame:getParent().args, params)
local lang = args[1]
local m_parse_utilities = require(parse_utilities_module)
local qualifier_label_mod = {"q", "qq", "l", "ll"}
local qualifier_label_mod_with_starred_set = {}
for _, mod in ipairs(qualifier_label_mod) do
qualifier_label_mod_with_starred_set[mod] = true
qualifier_label_mod_with_starred_set[mod .. "*"] = true
end
local function parse_object(object, paramno)
local function parse_one_form(run)
local function parse_err(msg)
error(msg .. ": '" .. table.concat(run) .. "'")
end
if #run == 1 and run[1] == "" then
error("Blank form not allowed")
end
local retval = {}
retval.form = run[1]
retval.form, retval.is_postposition = rsubb(retval.form, "^::", "")
if retval.is_postposition then
retval.is_term = true
else
retval.form, retval.is_term = rsubb(retval.form, "^:", "")
end
for i = 2, #run - 1, 2 do
if run[i + 1] ~= "" then
parse_err("Extraneous text '" .. run[i + 1] .. "' after modifier")
end
if run[i]:find("^%(") then
if not retval.is_term then
parse_err("Can't attach case '" .. run[i] .. "' to non-term")
end
local raw_case = run[i]:gsub("^%((.*)%)$", "%1")
if raw_case:find("[+/&<>()%[%]]") then
retval.case = parse_object(raw_case, ("%s:%s(...)"):format(retval.form, paramno))
else
retval.case = raw_case
end
else
local modtext = run[i]:match("^<(.*)>$")
if not modtext then
parse_err("Internal error: Modifier '" .. modtext .. "' isn't surrounded by angle brackets")
end
local prefix, arg = modtext:match("^([a-z]+%*?):(.*)$")
if prefix then
if qualifier_label_mod_with_starred_set[prefix] or prefix == "t" or prefix == "id" or
prefix == "tr" or prefix == "ts" or prefix == "alt" or prefix == "ref" then
if not retval.is_term and not qualifier_label_mod_with_starred_set[prefix] and
prefix ~= "ref" and prefix ~= "t" then
parse_err("Can't attach prefix '" .. prefix .. "' to non-term")
end
local item_dest = prefix == "ref" and "refs" or prefix
if retval[item_dest] then
parse_err("Can't set two values for prefix '" .. prefix .. "'")
end
if prefix == "l" or prefix == "ll" or prefix == "l*" or prefix == "ll*" then
arg = require(labels_module).split_labels_on_comma(arg)
elseif prefix == "ref" then
arg = require(references_module).parse_references(arg, parse_err)
end
retval[item_dest] = arg
else
parse_err("Unrecognized prefix '" .. prefix .. "' in modifier " .. run[i])
end
else
retval.t = modtext
end
end
end
return retval
end
local parsed_object = {arguments = {}}
local orig_segments =
m_parse_utilities.parse_multi_delimiter_balanced_segment_run(object, {{"[", "]"}, {"(", ")"}, {"<", ">"}})
-- rejoin bracketed segments with nearby ones; we only parse them to ensure that we leave alone parens and
-- angle brackets inside of square brackets.
local joined_segments = {}
local i = 1
while i <= #orig_segments do
local segment = orig_segments[i]
if i % 2 == 0 and segment:find("^%[") then
joined_segments[#joined_segments] = joined_segments[#joined_segments] .. segment .. orig_segments[i + 1]
i = i + 2
else
table.insert(joined_segments, segment)
i = i + 1
end
end
local split_runs =
m_parse_utilities.split_alternating_runs(joined_segments, "%s*[+/&]%s*", "preserve splitchar")
-- Now parse the forms.
i = 1
while i <= #split_runs do
if i == 1 and #split_runs[1] == 1 and split_runs[1][1] == "" and #split_runs > 1 and
rfind(split_runs[2][1], "^%s*&%s*$") then
-- Blank argument at beginning followed by & to suppress the +. Ignore it.
else
local form = parse_one_form(split_runs[i])
local prev_joiner = i > 1 and rsub(split_runs[i - 1][1], "^%s*(.-)%s*$", "%1")
if prev_joiner == "/" then
-- Join to the previous alternant.
table.insert(parsed_object.arguments[#parsed_object.arguments].alternants, form)
else
local suppress_with = prev_joiner == "&"
-- Create a new argument.
table.insert(parsed_object.arguments, {alternants = {form}, suppress_with = suppress_with})
end
end
i = i + 2
end
-- Now move qualifiers up as necessary.
local function parse_err(msg)
error(("%s: %s=%s"):format(msg, paramno, object))
end
for _, argument in ipairs(parsed_object.arguments) do
for i, alternant in ipairs(argument.alternants) do
if #argument.alternants == 1 then
-- If there's only one alternant, convert regular qualifiers to starred versions if there's not
-- already a starred version.
for _, mod in ipairs(qualifier_label_mod) do
if alternant[mod] and not alternant[mod .. "*"] then
alternant[mod .. "*"] = alternant[mod]
alternant[mod] = nil
end
end
end
if i < #argument.alternants then
-- Starred versions cannot be attached to non-final alternants.
for _, mod in ipairs(qualifier_label_mod) do
if alternant[mod .. "*"] then
parse_err(("Starred version '%s' of label or qualifier must be attached to last alternant"):
format(mod .. "*"))
end
end
else
-- Starred versions attached to final alternants should be moved up to argument level.
for _, mod in ipairs(qualifier_label_mod) do
if alternant[mod .. "*"] then
argument[mod] = alternant[mod .. "*"]
alternant[mod .. "*"] = nil
end
end
end
end
end
return parsed_object
end
local parsed_objects = {}
for argno, object in ipairs(args[2]) do
if object == ";" then
-- bare semicolon separator, to create a higher-level separation between parameters than
-- the normal "; or ..." separator.
if not parsed_objects[1] then
error("Can't have bare semicolon separator parameter as first parameter")
end
else
-- argno + 1 because object arguments begin at 2=
local parsed_object = parse_object(object, argno + 1)
if argno > 1 and args[2][argno - 1] == ";" then
parsed_object.separator = ";"
end
table.insert(parsed_objects, parsed_object)
end
end
local function format_parsed_object(parsed_object, recursive_suppress_with)
local argument_parts = {}
local multiple_alternants = false
for _, argument in ipairs(parsed_object.arguments) do
if #argument.alternants > 1 then
multiple_alternants = true
break
end
end
local used_with_in_prefix = false
for i, argument in ipairs(parsed_object.arguments) do
local alternant_parts = {}
local prefix, separator
local suppress_with = argument.suppress_with or i == 1 and recursive_suppress_with
if not suppress_with then
if not used_with_in_prefix then
separator = i > 1 and " " or ""
prefix = "''with'' "
used_with_in_prefix = true
elseif multiple_alternants then
separator = ", "
prefix = "''along with'' "
else
separator = " "
prefix = "''and'' "
end
else
separator = i > 1 and " " or ""
prefix = ""
end
for j, alternant in ipairs(argument.alternants) do
local case_text
if alternant.case then
if type(alternant.case) == "string" then
case_text = require(form_of_module).tagged_inflections {
lang = lang, tags = {alternant.case}, text_classes = text_classes
}
else
case_text = format_parsed_object(alternant.case, "suppress with")
end
if alternant.is_postposition then
case_text = "(" .. case_text .. " +)"
else
case_text = "+ " .. case_text
end
end
local form
--local text_classes = "object-usage-form-of-tag"
local text_classes = "object-usage-tag"
if alternant.is_term then
local term = alternant.form
if term == "" then
term = nil
end
form = m_links.full_link({lang = lang, term = term, alt = alternant.alt, id = alternant.id,
tr = alternant.tr, ts = alternant.ts, pos = not alternant.is_postposition and case_text or nil},
"bold")
if alternant.is_postposition and case_text then
form = case_text .. " " .. form
end
else
form = require(form_of_module).tagged_inflections {
lang = lang, tags = {alternant.form}, text_classes = text_classes
}
if case_text then
if alternant.is_postposition then
form = case_text .. " " .. form
else
form = form .. " (" .. case_text .. ")"
end
end
end
local meaning_text = ""
if alternant.t then
meaning_text = " <small>‘" .. alternant.t .. "’</small>"
end
local part = form .. meaning_text
if j > 1 and not used_with_in_prefix and not recursive_suppress_with then
-- If we used e.g. {{+obj|ca|&transitve/:en}} to suppress the initial ''with'', we want it
-- to appear after the ''or'' so we get ''transitive or with [[en]]'' rather than just
-- ''transitive or [[en]]''.
part = "''with'' " .. part
used_with_in_prefix = true
end
if alternant.q or alternant.qq or alternant.l or alternant.ll or alternant.refs then
part = require(pron_qualifier_module).format_qualifiers {
text = part,
lang = lang,
q = alternant.q and {alternant.q} or nil,
qq = alternant.qq and {alternant.qq} or nil,
l = alternant.l,
ll = alternant.ll,
refs = alternant.refs,
}
end
table.insert(alternant_parts, part)
end
local part = prefix .. table.concat(alternant_parts, " ''or'' ")
if argument.q or argument.qq or argument.l or argument.ll then
part = require(pron_qualifier_module).format_qualifiers {
text = part,
lang = lang,
q = argument.q and {argument.q} or nil,
qq = argument.qq and {argument.qq} or nil,
l = argument.l,
ll = argument.ll,
}
end
table.insert(argument_parts, separator .. part)
end
return table.concat(argument_parts)
end
-- Now generate the text.
local object_parts = {}
local function ins(txt)
table.insert(object_parts, txt)
end
ins(require("Module:TemplateStyles")("Module:User:Benwing2/object usage/style.css"))
ins("[")
for i, parsed_object in ipairs(parsed_objects) do
if i > 1 then
if parsed_object.separator == ";" then
ins("; ''in addition,'' ")
else
ins("; ''or'' ")
end
end
ins(format_parsed_object(parsed_object, false))
end
ins("]")
return table.concat(object_parts)
end
function export.show_aux(frame)
local pargs = frame:getParent().args
local params = {
[1] = {required = true, default = "und"},
[2] = {list = true, allow_holes = true},
["alt"] = {list = true, allow_holes = true},
["q"] = {list = true, allow_holes = true},
["id"] = {list = true, allow_holes = true},
["senseid"] = {list = true, allow_holes = true, alias_of = "id"},
["means"] = {list = true, allow_holes = true},
}
local args = require("Module:parameters").process(frame:getParent().args, params)
local lang = require("Module:languages").getByCode(args[1], 1)
-- Find the maximum index among any of the list parameters.
local maxmaxindex = 0
for k, v in pairs(args) do
if type(v) == "table" and v.maxindex and v.maxindex > maxmaxindex then
maxmaxindex = v.maxindex
end
end
if mw.title.getCurrentTitle().nsText == "Template" and mw.title.getCurrentTitle().text == "+aux" then
return "[auxiliary " .. m_links.full_link({lang = lang, term = "auxiliary"}, "term") .. " = meaning]"
end
local parts = {}
for i = 1, maxmaxindex do
local term = m_links.full_link({lang = lang, term = args[2][i], alt = args.alt[i], id = args.id[i]}, "term")
if args.means[i] then
term = term .. " = " .. args.means[i]
end
if args.q[i] then
term = require("Module:qualifier").format_qualifier(args.q[i]) .. " " .. term
end
table.insert(parts, term)
end
return "[auxiliary " .. require("Module:table").serialCommaJoin(parts, {conj = "or"}) .. "]"
end
return export