Module:User:Benwing2/object usage

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 "[+ " .. require('Module:links').full_link({lang = lang, term = term, alt = alt, id = senseid, tr = "-"}, "term") .. " (" .. parse_form(pargs, 3, "object") .. ") " .. (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 "[+ (" .. parse_form(pargs, 3, "object") .. ") " .. require('Module:links').full_link({lang = lang, term = term, alt = alt, id = senseid, tr = "-"}, "term") .. " " .. (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 = " ‘" .. alternant.t .. "’ "				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. 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,&ensp;") else ins("; or&ensp;") 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