বিষয়বস্তুতে চলুন

মডিউল:nv-conj

উইকিঅভিধান, মুক্ত অভিধান থেকে

এই মডিউলের জন্য মডিউল:nv-conj/নথি-এ নথিপত্র তৈরি করা হয়ে থাকতে পারে

--[[
Based on Kari's paper (1978)
with several personal additions, adaptations and fixes. 

NOTES:
- Lua regex are very expensive, had to scale back my all-regex coding paradigm. 
- In order to facilitate usage of Lua regex (which are very limited), consonants are converted to a one-symbol format (ex: q for k', č for ch...), then rules are applied, then the word is converted back to conventional orthography. 

TODO:
- seriative,  
- "make" verbs in the perfective, 
- get rid of the ":" altogether as a formative boundary. 
]] 

local p = {}

local umatch= mw.ustring.match
local ufind = mw.ustring.find
local subst = mw.ustring.gsub

local UTF8_char = "[\1-\127\194-\244][\128-\191]*"

-- forward declarations
local convert, fut_adjustment_conj


-- ENTRY POINTS
function p.show(frame)
  return p.conj(frame:getParent())  
end

function p.conj(frame) 
  local f = frame.args

  -- retrieve parameters
  get_params(frame)
 
  local data = {} 
  data.form_1sg = f["1sg"] or proc("1sg")
  data.form_2sg = f["2sg"] or proc("2sg") 
  data.form_3sg = f["3sg"] or proc("3sg")
  data.form_4sg = f["4sg"] or proc("4sg")
  data.form_1dl = f["1dl"] or proc("1dl")
  data.form_2dl = f["2dl"] or proc("2dl")
  data.form_1pl = f["1pl"] or proc("1pl")
  data.form_2pl = f["2pl"] or proc("2pl")
  data.form_3pl = f["3pl"] or proc("3pl")
  data.form_4pl = f["4pl"] or proc("4pl")


  if frame.args["test"] then
    return make_string(data) 
  else
    return make_table(data) 
  end
end

function get_params(frame) 

  -- convert 7-args mode to 4-args mode
  if frame.args[7] then
     frame.args["conj"]=frame.args[4]
     frame.args["obj"] =frame.args[3]
     frame.args["disj"]=frame.args[2]
     frame.args[4]     =frame.args[7]
     frame.args[3]     =frame.args[6]
     frame.args[2]     =frame.args[5]
  end

  mode_ = frame.args[1]
  asp_  = frame.args[2]
  cl_   = frame.args[3]
  stem_ = frame.args[4]
  disj_ = frame.args["disj"] or "" 
  conj_ = frame.args["conj"] or "" 
  obj_  = frame.args["obj"]  or ""

  neuter_= frame.args["neuter"] -- ni / ∅
  nodevoice_= frame.args["nodevoice"]
  d_effect_= frame.args["d-effect"]
  nospread_= frame.args["nospread"]
  dashift_= frame.args["dashift"]
  hop_    = frame.args["hop"] or ""

  -- underlying representations 
  -- TODO: improve below code 
  --       manage multiple disj/conj prefs

  if disj_ == "a" then disj_ = "ʼi" 
  elseif disj_ == "á" then disj_ = "ʼí"
  --elseif disj_ == "á" then disj_ = "ʼá"
  end

  disj_ = subst(disj_, "kó", "kwí") 

  if obj_ == "a" then obj_ = "ʼi"
  elseif obj_ == "y" then obj_ = "yi"
  elseif obj_ == "ho" then obj_="hwi"
  end
  
  fut_=""
  if mode_=="fut" then
     fut_adjustment_conj() 
  end

  disj_ = convert(disj_) 
  obj_  = convert(obj_) 
  conj_ = convert(conj_) 
  stem_ = convert(stem_) 

  has_hiss = ufind(stem_, "[szcʒ]")
  has_hush = ufind(stem_, "[šžčćj]")
end

-- PARADIGMS
local paradigms={} 

paradigms["impf"] = {} 
P = paradigms["impf"]
P["∅"]  ={  "š","ni",  "", "iid", "oh"}
P["ni"] ={"niš","ní","ni","niid","noh"}
P["yii"]={"iiš","ii","ii", "iid","ooh"}
--P["í"]  ={"ísh","íní","í", "íid", "óh"}

paradigms["perf"] = {} 
P = paradigms["perf"]
P["yi"] ={"ğí", "ğíní","ğí","iid","oo"}
P["yid"]={"ğiš","ğíní","ği","iid","ooh"}

P["ni"] ={"ní","ğíní","ní","niid","noo"}
P["nid"]={"niš","ğíní","ni","niid","nooh"}

P["si"] ={"sé", "síní","z","siid","soo"}
P["sid"]={"sis","síní","s","siid","sooh"}
P["si2"] ={"é", "íní","ğez","eed","soo"}
P["si2d"]={"és","íní","ğes","eed","sooh"}

P["yii"]={"ii","ini","ii", "iid","oo"}
P["yiid"]={"iiš","ini","ii", "iid","ooh"}

paradigms["fut"] = {} 
P = paradigms["fut"]
P["∅"] ={"ğeš", "ğí","ğo","ğiid","ğoh"}
--P["∅"] ={"eeš", "íí","oo","iid","ooh"}

-- REGEXP
local vowels = "aąáą́eęéę́iįíį́oǫóǫ́"
local V = "[".. vowels.."]"
local L = "[aąeęiįoǫ]"
local H = "[áą́éę́íį́óǫ́]"
local C = "[^:=#" .. vowels .."]"
local C0= "[^=#" .. vowels .."]*="
local K = "[^:=#yʼ" .. vowels .."]"
local I = "[ií]"
local O = "[oó]" 
local S = "[sš]" 

local high_tone = {
    ["a"] = "á", ["e"] = "é", 
    ["i"] = "í", ["o"] = "ó"
} 
local low_tone = {
    ["á"] = "a", ["é"] = "e", 
    ["í"] = "i", ["ó"] = "o"
} 

local d_effect_map = {
    ["z"] = "ʒ",   ["ž"] = "j",
    ["ğ"] = "g",   ["y"] = "ʼy", 
    ["w"] = "ʼw",  ["l"] = "dl",
    ["ʼ"] = "tʼ",  ["m"] = "ʼm",
    ["n"] = "ʼn"
}
--Note: stem must be provided with etymological y or gh, so as to elicit proper d-effect.

local devoicing = {
	["z"] = "s", ["ğ"] = "h",
    ["ž"] = "š", ["l"] = "ł", 
    ["w"] = "h", ["y"] = "h",
} 

local surds  = "([sšhł])"
local voiced = "([zžğwyl])"

local function at(str, i)
	if i == 0 then
		return ""
	elseif i < 0 then
		local n = 0
		local characters = {}
		for character in string.gmatch(str, UTF8_char) do
			n = n + 1
			characters[n] = character
		end
		return characters[n + i + 1]
	else
		local n = 0
		for character in string.gmatch(str, UTF8_char) do
			n = n + 1
			if n == i then
				return character
			end
		end
	end

	return ""
end

local function assimilate(i, v)
   v = at(v, 1) -- first vowel if long
   if i == "í" then
      return high_tone[v] or v
   end

   v = low_tone[v] or v
   return subst(i, "i", v) 
end

local function split_pref(pref) 
  cv,f = umatch(pref, "^(.-)([sšhd]*)$") 
  return cv, f
end

local function append(pref) 
   if not pref or pref == "" then
     return 
   end

   if form_ ~= "" then
     last = at(form_, -1)
     if last == "#" or last == "=" then
      form_ = form_.. pref
     else 
      form_ = form_.. ":".. pref
     end
   else
     form_ = pref
   end
end

local abbrs = {
	V = V, H = H, L = L, C0 = C0, C = C, I = I, O = O, K = K,
}
local function expand_regex(str)
   return string.gsub(str, "[VHLCIOK]0?", abbrs)

--[[ expanding manually instead to speed up? Not faster actually... 
 
   ret=""
   d=""
   for c in mw.ustring.gmatch(str,".") do 
     if c == "V" then ret=ret..V
     elseif c == "H" then ret=ret..H
     elseif c == "L" then ret=ret..L
     elseif d == "C" and c== "0" then 
         ret=ret..C0
     elseif d == "C" and c ~= "0" then 
         ret=ret..C..c
     elseif c == "I" then ret=ret..I
     elseif c == "O" then ret=ret..O
     elseif c == "K" then ret=ret..K
     elseif c ~= "C" then ret=ret..c
     end

     d = c
   end
   return ret
]] 
end

local function replace(str1, str2) 
   str1  = expand_regex(str1) 
   form_ = subst(form_, str1, str2) 
end

-- basic replace without wildcard
local function replace2(str1, str2) 
   form_ = subst(form_, str1, str2) 
end

local function match(str2) 
   str2 = expand_regex(str2)  
   return umatch(form_, str2) 
end

-- basic replace without wildcard
local function match2(str2) 
   return umatch(form_, str2) 
end

di2mono = {
  ["kw"] = "q", 
  ["hw"] = "f", 
  ["kʼ"] = "ç", 
  ["čʼ"] = "ć",   -- trick
  ["tʼ"] = "ť", 
  ["ts"] = "c", 
  ["sh"] = "š", 
  ["zh"] = "ž", 
  ["gh"] = "ğ",
  ["ch"] = "č",
  ["dz"] = "ʒ"
}
mono2di = {
  ["q"] = "kw", 
  ["f"] = "hw", 
  ["ç"] = "kʼ", 
  ["ć"] = "chʼ", 
  ["ť"] = "tʼ", 
  ["c"] = "ts", 
  ["š"] = "sh", 
  ["ž"] = "zh", 
  ["ğ"] = "gh",
  ["č"] = "ch",
  ["ʒ"] = "dz",
  ["ñ"] = "n"
}

-- declared as local above
function convert(str) 
   -- using regex only is too expensive
   -- doing it manually
  
   ret = ""
   d = ""
   for c in mw.ustring.gmatch(str,".") do
     if d == "" then
         d=c
     else
        m = di2mono[d..c] 
        if m and m == "č" then
           d = "č" 
        elseif d == "č" and not m then
           ret = ret.."č"
           d  = c
        elseif m then
          ret  = ret.. m
          d = "" 
        else
          ret  = ret.. d
          d = c
        end
     end   
   end
   ret = ret.. d
   return ret 
end

local function convert_back() 
   -- using regex only is too expensive
   -- doing it manually

   ret =""
   d = ""
   for c in mw.ustring.gmatch(form_,".") do
      if c ==":" or c=="=" or c=="#" then
      elseif ret == ""  and c == "ʼ" then
      elseif d == "s" and c == "h"  then
         ret = ret.."x"
      elseif d == "s"  and c == "s" then
      elseif d == "sh" and c == "š" then
      elseif d == "z"  and c == "z" then
      elseif d == "zh" and c == "ž" then
      elseif c == "ğ" or c == "f" then
         d = c
      elseif d == "ğ" then
         if umatch(c, "[eęiįéę́íį́]") then
             d="y"
         elseif umatch(c,"[oǫóǫ́]") then
             d="w"
         else
             d="gh" 
         end
         ret=ret.. d..c
      elseif d == "f" then
         if umatch(c, "[oǫóǫ́]") then
             d="h" 
         else  
             d="hw"
         end
         ret=ret..d..c
      else
         d = mono2di[c] or c
         ret = ret .. d
      end 
   end
   form_=ret
end

--#################################
-- RULES

-- declared as local above
function fut_adjustment_conj() 
    fut_="di"
    if asp_=="yii" then 
        fut_="ği:".. fut_
        asp_="∅"
    end
end

local function fut_adjustments() 
  -- di- positioning
  replace2("di:([yh][ií])", "%1:di") 

  -- high-tone future 
  replace2("d[ií]:n[ií]", "dí:ní")

  -- methateses that need early ordering 
  replace ("ji:y(I)", "y%1:ji") 
  replace2("(.[:#])ji:ği", "%1ği:ji") 
  replace2("(.+)#yi:ği", "%1#yi") 
 
end

local function ni_adjustments() 
  
  if neuter_ then

    if neuter_ == "∅" then
       replace2(":?ni=", "=") 
    end

    replace2("(.[#:])łi=",  "%1l=")

  else  -- "active" verb 
    
     -- yini/yíní tentatively managed hee
    replace2("yí:ni=", "ó=") -- yíníshta'
    replace2("ğí:ni=", "ó=") -- 'ííníshta' 
    
    -- yinishyé-wolyé-joolyé-daolyé mess
    replace2("da#ği:ni=", "da#ğo=")
    replace2("^#ği:ni=", "#ğo=") 
    replace2("ği:ni=", "oo=")
  
    -- conj-dominant
    if conj_ ~= ""  then
      replace2(":ni=", ":ğe=") 
    else
      -- ∅- or da- dominant
      replace2("^#ni=", "#yí=")
      replace2("^da#ni=", "da#yí=")

      -- disj-dominant
      replace2("#ni=", "#=")
     end
  end 
end


local function yii_adjustments()
 
  -- yi_doubling 
  replace2("^#yi:ii", "#yi:yi:ii") 

  -- dis: ii > i, but da#ii > dayii or dei
  if mode_ == "impf" then
    replace2("da#ii=", "da#yi:ii=") 
  else
    replace2("da#ii=", "da#yi=") 
  end
  replace("(V)#ii(:?š?)=", "%1#i%2=")

  -- ho adjustments: hwi+ii > hoo
  replace2("fi:ii(:?š?)=", "ho:o%1=")

  -- object-dominant 2sg 
  if obj ~= "" and conj_ == "" and rank == 2 then
     replace2("ini=", "iini=") 
   end
end

local function yi_adjustments() 

   -- yi_doubling 
   replace2("^#yi:ğí=", "#yi:yi:ğí=")

   -- hwi-delab needed before gamma_del
   -- for 1sg: hwi:ğí= > hóó, not hwíí
   replace2("fi:ğí=", "ho:ğí=") 

end

local function yi_d_adjustments() 

   -- conjunct
   if rank == 3 then
      replace2("#(.+)ği=", "#%1ğo=") 
   elseif rank == 1 then
      replace2("#(.+)ği:š=", "#%1ğe:š=") 
   end

   -- a-away + perfective = ee
   replace2("ʼi#ği(:?š?)=", "ʼi#ğe%1=")

end 

local function si_adjustments() 
     -- yini
     replace2("da#ği:([sz])=","da#ğo:%1=")
     replace2("ği:([sz])=","oo:%1=")

     -- yiz + ł = yis
     replace2("z=ł:", "s=ł:") 

     -- #s=gan > sigan
     replace2("^#[sz]=([∅ł])", "#si=%1") 

     -- ni:soo > noo or sinoo
     if rank==5 then 
       replace2("^#ni:soo", "#si:noo")
       replace2("^da#ni:soo", "da#si:noo")
       replace2("ni:soo", "noo") 
     end
      
end


local function seriative_h_deletion()   --13
  replace("(#.+:)hi(C0)","%1ii%2") 
  replace2("(#.+:)hi:","%1yi:") 
end

local function d_effect()
   -- handle 1dl cases first
   replace2( ":d=ł:l",   "=dl")
   replace2( ":d=[łl]:", "=l:")
   replace2( ":d=[d∅]:", "=d:")

   replace2( "=∅:",      "=") 
   
   -- apply d-effect
   -- special cases
   if stem_ == "zǫ́ǫ́z" or stem_=="zǫ́ǫ́s" then
       replace2("=d:z", "=d") 
   elseif stem_ == "ʼeeł" or stem_ == "ʼéél" or stem_ == "ʼoł" then
       replace2("=d:", "=") 
   else
     c = match("=d:(C)")
     if c then 
       dc = d_effect_ or d_effect_map[c] or c
       replace2("=d:"..c, "=".. dc) 
     end
   end
end

local function continuant_devoicing()   --18
  if nodevoice_ then
      return
  end

  exp = surds.."([:=])"..voiced
  s, sep, v = match2(exp) 
  if s and sep and v then 
     f = devoicing[v] 
     replace2(s..sep..v, s..sep..f)
   end  
end

local function barred_l_deletion()      --23
  replace2("=ł:([sšł])", "=%1")
end

local function h_deletion()             --32
  replace2(":h=ł:", "=ł") 
end

local function classifier_deletion()    --30
  replace2("([sš])=ł:", "%1=")
end

local function cons_degemination()      --26
 -- replace(":?s=s", "=s") 
 -- replace(":?š=š", "=š")
end

local function pepet_vowel_insertion()  --46
  replace("#(C0)", "#i%1")
end

local function vowel_deletion()         --12
  replace("(C)i:(V)", "%1%2") 
end

local function tone_assimilation()      --39
  -- acceleration
  if not has_high then return end

  --disjunct
  if not nospread_ and has_disj then
    h,l,c0 =match("(H#C?:?C?:?C?)(L)(C0)")
    if h and l and c0 then
      a = high_tone[l]
      replace2(h..l..c0, h..a..c0)
    end
  end

  --conjunct 
  t,h,l = match("#(.*)(H:?C?:C)(L)") 
  if t and  h and l then 
     a = high_tone[l] 
     replace2(t..h..l,t.. h..a) 
  end
end

local function tone_lowering()          --48 
   --used for   ní:ii --> nii
   --what about ní:oh --> nó ? 

 --[[ moved to paradigm adjustments 

   h, l = match("(H)(:L)") 
   if h and l then
     replace2(h..l, low_tone[h]..l)
   end
 ]] 
end

local function gamma_tone_assim() 
 -- acceleration
  if not has_high or nospread_ or not has_disj then return end 

  h,l,c0 = match("(H#ğ)(L)(C0)")
  if h and l and c0 then
      a = high_tone[l]
      replace2(h..l..c0, h..a..c0)
  end
end

local function gamma_deletion()         --41
   replace2("(#.*)ğ([ieoíéó].*=)", "%1%2")

   -- future mode might need a second run
   replace2("(#.*)ğ([ieoíéó].*=)", "%1%2")
end

local function n_deletion()              --? 
  -- made it a late rule instead
  -- bą́:ná#ʼ:dí:š doesn't work, why? 

  -- chʼínéísííd doesn't contract, 
  -- chʼééínísííd does. 

  -- acceleration
  if not (has_disj and has_high) then return end

  c, v, c0, c1 = match(
    "(C)(V):n[áé][#:][ií]?:?(C.-)V(.*=)") 
  if c and v and c0 and c1 and
     c ~= "ʼ" then
       h = high_tone[v] or v
       if h == "í" then
           h="é"
       end
       replace2(c..v..":n[áé]", c..h..h)
  end
  
end

local function tone_raising()           --49
   -- acceleration
   if not has_high then return end

   l,s,h = match("(L)([#:])([íá])")
   if l and s and h then 
      a = high_tone[l]  
      replace2(l..s..h, a..s..h)
   end 
end

local function vowel_assimilation()     --57

  -- special cases
  if has_disj then 
   c, c0 = match("(C)i#i(C0)") 
   if c  and c0 and
     c ~="n" and c ~= "ʼ" then 
       replace2("i#i", "e#e")
   end
  end

  -- a+o = aa dialects, 2dl/pl only
  if pref  == "oh"  then
    replace2("([aá])#o", "%1#a") 
  end

  -- progressive 
  v, s, i, c0 = match("(V)([#:])(I+)(C0)")
  if v and s and i and c0 and
     not ufind(v..s..i, "[aá]#ii") then
       a = assimilate(i, v) 
       replace2(v..s..i..c0,
                v..s..a..c0)
  end
   
  -- regressive disj
  if has_disj then
  b, i, v, c0 = match(
              "([^kqhtc])(I)#(V+)(C0)")
  if b and i and v and c0 then
     a = assimilate(i, v) 
    replace2(b..i.."#"..v..c0,
             b..a.."#"..v..c0)
  end
  end

  -- regressive conj 
  -- Note:  hwi:o > hwo:o, should > ho:o
  --        to manage in convert_back
  --        along with gho > wo

  c,i,v = match("#(.*)(I):(V)")
  if c and i and v then
     a = assimilate(i,v) 
     replace("#".. c.. i..":".. v, 
             "#".. c.. a..":".. v)
  end
end

local function vowel_absorption()       --62
   -- acceleration
   if not has_disj then return end
   -- acceleration
   if not has_high then return end

   -- in C0 environment only
  
  if match("V#VC0") then
    replace2("([ʼł])í#i","%1í#") 
    replace2("í#i","é#")
    replace2("ó#o","ó#")
    replace2("á#a","á#")
    replace2("é#e","é#")
  end

  --[[ not necessarily faster... 

   c, h, l, c0 = match("(C)(H)#(L)(C0)")
   if c and h and l and c0 then
      
      if h=="í" and l=="i" or 
         h=="á" and l=="a" or
         h=="ó" and l=="o" or
         h=="é" and l=="e" then
       
         v=h
         if h == "í" and
            not(c=="ʼ" or c=="ł")  then
               v="é"
         end

        replace2(h.."#"..l,v.."#")
      end 
   end
]] 
end

--function  optative_tone_lowering() --51

local function y_deletion()             --42
   -- acceleration
   if not has_disj then return end

   -- short i only 
   replace("(V)#y(I)([:=]C)", "%1#%2%3")
end

local function vowel_fronting()         --67
   -- acceleration
   if not has_disj then return end

  replace("([^kqht])a#(I)", "%1e#%2") 
  replace("([^kqht])á#(I)", "%1é#%2")
end

local function vowel_degemination()     --47
  -- TODO: might not be enough
  --       need refactoring
  replace("(I)[#:]ii", "%1i") 
  replace("(O)[#:]oo", "%1o")
end

local function seriative_assimilation()
   -- split from vcv_assimilation
   -- must take place before ni-abs
   -- to prevent náhí- from assimilating

   -- acceleration
   if not has_disj then return end

   v, i, c0 = match("(V)#h(I)(C0)")
   if v and i and c0 then
       replace2(v.."#h"..i, v.."#h"..v)
   end
end

local function vcv_assimilation()       --44
  -- NOTE:  seriative case has been split
  --        only at #-boundary? 
  --        only in zero environment? 

   -- acceleration
   if not has_disj then return end

  -- special case
  replace2("ʼi#ʼi([:=])", "ʼe#ʼe%1")
  
  -- regressive 
  k,i,c,v = match("(C)(I)#([mkghʼ])(V)")
  if k and i and c and v and k~="y" then
     a = assimilate(i, v) 
    replace2(i.."#"..c..v,
             a.."#"..c..v)
  end
end

local function i_to_a()                 --71
   --NOTE: easier to split rule in 2 parts
 
   replace("ʼi=", "ʼa=") 
   -- can't do that here 
   -- because of ná'í- 2sg vs 3sg, unless
   -- i_to_a applies after tone_assim? 
   --replace("ʼí=", "ʼá=")
   
   i,s,c= match("ʼ(I)([#:]=?)(C)") 
   if i and s and c and c ~= "ʼ" then
      a = assimilate(i,"a") 
      replace2( "ʼ"..i..s..c,
                "ʼ"..a..s..c)
   end
end

 
local function delabialization1()         --78
  --TODO: C should exclude "y" here. 

  --NOTE: Getting huge contradictions
  --      with regards to the ordering of
  --      the ho-to-ha, v-deletion, 
  --      gamma-deletion, ni-absorption
  --      and pepet vowel insertion rules
  --  ==> handle some cases directly here
  --  ==> split hwi from kwí
  --      kwí must be done before pepet
  --      hwi must be done after gamma_del
  --
  --  Maybe should replace all this with a
  --  with a late labialization rule
  --  instead, where :
  --     ho + ííní  =  hwííní
  --     ho + eesh  =  hweesh... 
  -- but ho + í_C[  =  hóó by assimilation

  -- acceleration
  if not has_high then return end

  replace("qí([#:=]*C)", "kó%1")
  replace("qí#(O)", "kó#")

end

local function delabialization2() 
  replace("fi(C0)", "ha%1")
  replace("fi:(C)", "ho:%1")

  -- below managed as in convert_back
  --replace("f(O)", "h%1") 

end


local function ni_absorption()           --11
   --
  v = match2("([io]):ni=")
  if v then 
     a = high_tone[v] 
     replace2(v..":ni=", a.."=" ) 
  end
end

local function pg_strident_assimilation() --83
   -- might be other cases? 
   replace2("ji:ʒi", "ji:ji") 

   -- might combine directly w/ j_el
   -- ji:dzi > ji:ji > i:ji
   
end

local function j_deletion()              --94
   replace2("ji:ji", "i:ji") 
end

local function vowel_elision()           --86
  -- K = C - {y, ʼ} 

  -- "ji" doesn't elide in front of 
  -- another j (ex. dajijooba) 
  if match2("ji:j") then
     return
  end

  replace("(.[:#]ʼ)i(:KV)", "%1%2")
  replace("(.[:#][jʒ])i(:KV)", "%1%2")
end

local function deaffrication()           --89
   replace("j:(C)", "ž:%1")
   replace("ʒ:(C)", "z:%1")
end

local function glottal_zh_metathesis()   --91
  replace2("ʼ:ž:", "ž:ʼ:")
end

local function glottal_cv_metathesis() 
  -- "far" hop allows glottal stop to 
  -- to hop "inside" 2sg prefix 
  -- ex:  bighá#ʼdííní > bighá#dííʼní
  -- but    bą́ą́#ʼdííní >   bą́ą́#ʼdííní

  if hop_ == "far" then
     replace("(ž?:?ʼ):(d:?V+:?V?):?(K:?V+)", "%2:%1:%3") 
  else
     replace("(ž?:?ʼ):(d:?V+):?(K:?V+)", "%2:%1:%3") 
  end
end

local function zh_cv_metathesis() 
   -- doesn't apply to jidinii, 
   -- is that a more generic rule?
   if  match2("ji:di:n:ii") then
      return
   end

   replace("ji:(C:?V+):(C:?V+)", "%1:ž:%2") 
end

local function strident_assimilation()   --81
  if has_hiss then
    replace2("š", "s") 
  elseif has_hush then
    replace2("s", "š") 
    replace2("z", "ž") 
  end
end

local function syllabic_n()              --100
   -- split b/c of Lua regex limitations
   replace2("n[ia]([#:]ʼ?:?[dtjʒ])","n%1")
   replace2("n[íá]([#:]ʼ?:?[dtjʒ])","ń%1")
 
   replace("na#(ʼ?:?[sš]V)", "ni#%1") 
   replace("ná#(ʼ?:?[sš]V)", "ní#%1")

   replace2("na#(ž:ʼ?:?d)", "ni#%1")
   replace2("ná#(ž:ʼ?:?d)", "ní#%1")
end

local function gamma_insertion()         --6
    -- acceleration
   if has_disj then return end

   replace("^#(V)", "#ğ%1")
end

local function gamma_gliding()           --7
   replace("ğ(I)", "y%1") 
   replace("ğ(O)", "w%1") 
end


--#################################
-- MAIN FUNCTION

function proc(person)

  -- PERSON
  pers, numb = umatch(person,"([0-9])(..)")
  pers = tonumber(pers)

  da   = (numb == "pl") and "da" or "" 
  subj = (pers ==  4)   and "ji" or ""
  obj  = (obj_ == "yi"  and pers ~= 3 ) and "" or obj_

  rank = (pers >= 3) and 3 or (numb == "sg") and pers or (pers + 3)
 
  if dashift_ and numb=="pl" and
    (dashift_ ~= "3" or rank==3)  then
        asp_="si"
  end

  -- Determination of paradigm to use
  asp2_ = asp_
  if mode_ == "perf" then 
    if asp_=="si" and
       umatch(conj_, "[dnh]i$") then
         asp2_ = asp_.."2"
    end

    if cl_=="d" or cl_=="l" then
         asp2_ = asp2_ .. "d"
     end
  end


  pref  = paradigms[mode_][asp2_][rank]
  p, pf = split_pref(pref)

  -- UNDERLYING FORM
   form_ = disj_
   append(da);  form_ = form_.."#"
   append(obj)
   append(subj)
   append(fut_)
   append(conj_) 
   append(p)
   append(pf);  form_ = form_.."="
   append(cl_)
   append(stem_) 
  
  --attempt at accelerating regex
  has_disj= (disj_..da ~= "")
  has_high= match("H") 

  if pers == 3 then
     replace2("P", "y") 
  else 
     replace2("P", "b") 
  end

  --form_=convert(form_) 
 --if true then return form_ end
  
  -- IRREGULAR STEMS
  if stem_ == "ááh" then
     if person == "2sg" then
        replace("=∅:ááh", "=nááh") 
     elseif pers == 2 then 
       replace("=∅:ááh", "=∅:hááh")  
     elseif rank == 3 then 
        replace("=∅:ááh", "=∅:ğááh") 
     end 
  elseif stem_=="yą́" or stem_=="yį́į́ł" then 
     if pers == 1 then
        replace("=∅:y", "=")   
     elseif pers == 2 then
        replace("h=∅:y", "h=s") 
     end
   end

  -- MODE READJUSTMENT RULES

  if mode_ == "fut" then
     fut_adjustments() 

  elseif asp_ == "∅" then
     -- make this a more general rule? 
     -- or amend the tone-lowering rule? 
     -- or make "ní" its own paradigm?

     -- how do manage both:
     --  á#ní:iid > ániildííl,   and
     --    ní:iid >  níilʼį́    ?? 

     replace2("ní:ii", "ni:ii")  
     replace2("ní:o:h","nó:h") 

     -- prevent ni-absorption if ni6
     if rank == 3 then 
         replace2("ni=", "ñi=") 
     end

  elseif asp_ == "ni"  then
     ni_adjustments() 

  elseif asp_ == "yii" then
     yii_adjustments() 

  elseif asp2_ == "yi" then
     yi_adjustments() 

  elseif asp2_ == "yid" then
     yi_d_adjustments() 

  elseif asp_ == "si"  then
     si_adjustments() 

  end

  -- PHONOLOGICAL RULES

  seriative_h_deletion()   --13

  d_effect()        -- 24,35,25

  continuant_devoicing()   --18
  barred_l_deletion()      --23
  h_deletion()             --32
  classifier_deletion()    --30

  -- below ordering is tricky 
  delabialization1()        --78
  --delab2 could go here w/ a labial rule
  --delabialization2()  

  pepet_vowel_insertion()  --46
  vowel_deletion()         --12
  --tone_assimilation()      --39
  --tone_lowering()          --48 
  gamma_tone_assim()       --hack
  gamma_deletion()         --41

  -- trying this here 
  -- must be before ni-abs so that
  -- 2sg náhí- doesn't assimilate to náhá-
  seriative_assimilation() 

  -- trying  hwi-delab here
  -- must be before ni-abs 
  -- hwi:ni-> ho:ni -> hó-
   
  delabialization2()    
  ni_absorption()          --11

  -- moved tone_assim to later rule
  -- so as to allow proper hwi delab
  -- before tone assimilation kicks in
  -- ná#haso -> ná#háso and not ná#hwíso
  -- Might have to move it even after 
  -- v-elision and deaffrication for
  -- words like łí#ji:di -> łí#zh:dí
  -- issue: but tone_assim must be before 
  -- gamma_del for words like :
  -- ná#ghi > ná#ghí > ná#í
  -- ==> wrote a gamma_tone_assim rule
  --tone_assimilation() 

  -- made it a late rule instead b/c
  -- y_deletion hasn't applied yet
  -- cf. chʼínéísííd (no contraction). 
  -- Actually, chʼínéísííd doesn't 
  -- contract b/c éí is considered one 
  -- vowel, so conditions are not met. 
  -- chʼééínísííd on the other side does
  -- contract thanks to intervening ní. 
  --n_deletion()             --? 

  tone_raising()           --49
  vowel_assimilation()     --57
  vowel_absorption()       --62
--optative_tone_lowering() --51
  y_deletion()             --42
  vowel_fronting()         --67
  vowel_degemination()     --47

  pg_strident_assimilation() --83
  j_deletion()              --94
  vowel_elision()           --86
  deaffrication()           --89
  glottal_zh_metathesis()   --91

  glottal_cv_metathesis() 
  zh_cv_metathesis() 
  strident_assimilation()   --81

  -- i_to_a must be before 
  -- tone-assim but after ni-abs:
  --   2sg: ná#'i:ni > ná#'í
  --   3sg: ná#'i > ná#'a > ná#'á
  -- if tone_assim before, 
  -- can't distinguish 2sg from 3sg
  --   3sg: ná#'i > ná#'í > ná#'á ?? 

  i_to_a()
  tone_assimilation() 
  vcv_assimilation()        --44

  -- LATE RULES    

  n_deletion() 
  --cons_degemination()       --26
  --i_to_a()                --72
  syllabic_n()              --100

  -- done in convert_back() 
  gamma_insertion()         --III.6
  --gamma_gliding()           --III.7

  -- FORMAT
  convert_back() 
 
  return form_
end

--##################################

local nv = require("Module:languages").getByCode("nv")
local full_link = require("Module:links").full_link
function link(term)
	return full_link{ term = term, lang = nv }
end

function make_table(data)

  mode = "IMPERFECTIVE" 
  if mode_ == "perf" then 
     mode = "PERFECTIVE" 
  elseif mode_ == "fut" then
     mode = "FUTURE" 
  end

  local function get(code)
    local form_data = data[code]
    return form_data and link(form_data) or error('No content for the code ' .. code .. '.')
  end

  return mw.getCurrentFrame():expandTemplate{
  	title = 'nv-verbtable',
  	args = {
  	  mode,
  	  get('form_1sg'),
  	  get('form_1dl'),
  	  get('form_1pl'),
  	  get('form_2sg'),
  	  get('form_2dl'),
  	  get('form_2pl'),
  	  get('form_3sg'),
  	  get('form_3pl'),
  	  get('form_4sg'),
  	  get('form_4pl')
  	}
  }
end

function make_string(data)
  return data.form_1sg.. " ".. data.form_1dl.. " "..data.form_1pl .. " "..data.form_2sg.. " ".. data.form_2dl.." "..data.form_2pl.. " ".. data.form_3sg.. " ".. data.form_3pl.. " "..data.form_4sg.. " "..data.form_4pl
end

return p