local export = {}
local us = mw.ustring
local data = mw.loadData("Module:User:Lunabunn/jje-conj/data")
function block_left(s)
function peek() return us.codepoint(s, 1, 1) end
function pop() return us.sub(s, 1, 1), us.sub(s, 2) end
local cho, jung, jong
-- edge case for lone jong as compat glyph
if (peek() >= 0x3131 and peek() <= 0x314E) then
jong, s = pop()
jong = us.char(data.compat_to_jong)
else
-- cho in Hangul Jamo and Hangul Jamo Extended-A
if (peek() >= 0x1100 and peek() <= 0x115F) or (peek() >= 0xA960 and peek() <= 0xA97C) then
cho, s = pop()
end
-- jung in Hangul Jamo and Hangul Jamo Extended-B
if peek() ~= nil and ((peek() >= 0x1160 and peek() <= 0x11A7) or (peek() >= 0xD7B0 and peek() <= 0xD7C6)) then
jung, s = pop()
end
-- jong in Hangul Jamo and Hangul Jamo Extended-B
if peek() ~= nil and ((peek() >= 0x11A8 and peek() <= 0x11FF) or (peek() >= 0xD7CB and peek() <= 0xD7FB)) then
jong, s = pop()
end
end
return cho, jung, jong, s
end
function block_right(s)
function peek() return us.codepoint(s, -1) end
function pop() return us.sub(s, -1), us.sub(s, 1, -2) end
local cho, jung, jong
-- jong in Hangul Jamo and Hangul Jamo Extended-B
if (peek() >= 0x11A8 and peek() <= 0x11FF) or (peek() >= 0xD7CB and peek() <= 0xD7FB) then
jong, s = pop()
end
-- jung in Hangul Jamo and Hangul Jamo Extended-B
if peek() ~= nil and ((peek() >= 0x1160 and peek() <= 0x11A7) or (peek() >= 0xD7B0 and peek() <= 0xD7C6)) then
jung, s = pop()
end
-- cho in Hangul Jamo and Hangul Jamo Extended-A
if peek() ~= nil and ((peek() >= 0x1100 and peek() <= 0x115F) or (peek() >= 0xA960 and peek() <= 0xA97C)) then
cho, s = pop()
end
return s, cho, jung, jong
end
function is(encoded, compat)
if encoded == nil then return false end
local codepoint = us.codepoint(encoded, 1, 1)
return (encoded == compat)
or (codepoint == data.compat_to_cho)
or (codepoint == data.compat_to_cho_loose_partial)
or (codepoint == data.compat_to_cho_loose)
or (codepoint == data.compat_to_jung)
or (codepoint == data.compat_to_jung_loose)
or (codepoint == data.compat_to_jong)
or (codepoint == data.compat_to_jong_loose_partial)
or (codepoint == data.compat_to_jong_loose)
end
function find(t, target)
for k, v in pairs(t) do
if v == target then
return k
end
end
return nil
end
function loosen(jung)
local code = us.codepoint(jung, 1, 1)
return find(data.compat_to_jung_loose, code) or find(data.compat_to_jung, code)
end
function tighten(loose)
local code = data.compat_to_jung_loose or data.compat_to_jung
if code == nil then return nil end
return us.char(code)
end
function connectability(ajung, bjung)
local aloose, bloose = loosen(ajung), loosen(bjung)
if us.sub(aloose, -1) == us.sub(bloose, 1, 1) then
return 2 -- mergeable
elseif tighten(aloose .. bloose) then
return 1 -- connectable
else
return 0
end
end
function connect(ajung, bjung)
-- assumes that connectability is 1
local aloose, bloose = loosen(ajung), loosen(bjung)
return tighten(aloose .. bloose)
end
function assemble(components)
local result = ""
for _, component in pairs(components) do
if component ~= nil then
result = result .. component
end
end
return result
end
function export.conjugate(frame)
local parent_args = frame:getParent().args
local args = require("Module:parameters").process(parent_args, {
= {},
= {},
= { type = "boolean" },
= {},
})
local stem = us.toNFD(args)
local ending = us.toNFD(args)
local head, acho, ajung, ajong = block_right(stem)
local bcho, bjung, bjong, tail = block_left(ending)
if ajong == nil then
if is(bcho, "ㅇ") and connectability(ajung, bjung) == 2 then
bcho, bjung = nil, nil
end
end
if args == "p" then
if args then
ajong = nil
epenthetic = "우"
elseif is(bcho, "ㅇ") then
ajong = nil
local bloose = loosen(bjung)
if us.sub(bloose, 1, 1) ~= "ㅗ" and us.sub(bloose, 1, 1) ~= "ㅜ" then
bjung = tighten("ㅗ" .. bloose) or tighten("ㅜ" .. bloose)
end
end
elseif ajong == nil and args then
if is(ajong, "ㅅ") or is(ajong, "ㅈ") or is(ajong, "ㅊ") then
epenthetic = "이"
else
epenthetic = "으"
end
end
local components = {head, acho, ajung, ajong, epenthetic, bcho, bjung, bjong, tail}
local result = us.toNFC(assemble(components))
-- second pass for vowel stems with connectability = 1
stem, ending = us.toNFD(args), us.toNFD(args)
head, acho, ajung, ajong = block_right(stem)
bcho, bjung, bjong, tail = block_left(ending)
if ajong == nil and is(bcho, "ㅇ") and connectability(ajung, bjung) == 1 then
ajung = connect(ajung, bjung)
bcho, bjung = nil, nil
components = {head, acho, ajung, ajong, epenthetic, bcho, bjung, bjong, tail}
result = result .. ", " .. us.toNFC(assemble(components))
end
return result
end
return export