taipa
Version:
Taiwanese morphological parsing library
660 lines • 31.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TonalSoundUnchangingMorphemeMaker = exports.TonalSoundUnchangingMorpheme = exports.TonalStandaloneMorphemeMaker = exports.TonalStandaloneMorpheme = exports.syllabifyTonal = void 0;
const unit_1 = require("../unit");
const maker_1 = require("../maker");
const tonalres_1 = require("../tonal/tonalres");
const unit_2 = require("../unit");
const soundgen_1 = require("../tonal/soundgen");
const syllablelists_1 = require("../tonal/syllablelists");
const matcher_1 = require("./matcher");
const collections_1 = require("../tonal/collections");
const metaplasm_1 = require("./metaplasm");
const metaplasm_2 = require("../metaplasm");
const unit_3 = require("./unit");
function syllabifyTonal(letters, beginOfSyllable) {
// get the longest matched syllable pattern
let literal = '';
let matched = '';
let begin = 0;
let ltrs = new Array();
let matchedLtrs = new Array();
let literalLexicalRoot4th8th = ''; // could be an 4th or 8th root
let literalLexicalRootEighth = ''; // specific an 8th root
for (let i = beginOfSyllable; i < letters.length; i++) {
literal = literal + letters[i].literal;
ltrs.push(letters[i].literal);
// console.log(`begining of the loop: ${literal}. ${ltrs}`);
const had = collections_1.fourthToEighthFinalConsonants.has(letters[i].literal);
if (i + 1 < letters.length &&
had &&
(tonalres_1.TonalLetterTags.w === letters[i + 1].literal ||
tonalres_1.TonalLetterTags.x === letters[i + 1].literal)) {
const got = collections_1.fourthToEighthFinalConsonants.get(letters[i].literal);
// restore the lexical roots for 4th final consonants, which is 8th finals
// in case of absent 8th roots, 4th roots should also be restored
// e.g. koehwlaih, jiwpowcitwlaw, khihwlih
// in case of absent 4th roots for an triplet
// e.g. juahxjuahwjuahh. there is no juah present in syllable table
// 4th and 8th roots for 3rd checked tones
if (got) {
// since it is 4th finals, length of 4th final is one, just slice one character
literalLexicalRootEighth =
literalLexicalRoot4th8th.slice(0, literalLexicalRoot4th8th.length) +
got;
// console.log(`literalRoot4thFinal: ${literalRoot4thChecked}, 8th: ${literalRoot8thChecked}`);
// the below fourth should go after the above eighth
literalLexicalRoot4th8th =
literalLexicalRoot4th8th + letters[i].literal;
}
}
else {
literalLexicalRoot4th8th = literalLexicalRoot4th8th + letters[i].literal;
}
if ((0, syllablelists_1.isInSyllableTable)(literal) &&
tonalres_1.freeToneLettersTonal.includes(letters[i].literal)) {
// console.log(`i: ${i}, literal: ${literal}, tone: ${letters[i].literal}, letters[i+1]: ${letters[i + 1].literal}`)
if (begin === beginOfSyllable) {
matched = literal;
Object.assign(matchedLtrs, ltrs);
}
break;
}
else if (((0, syllablelists_1.isInSyllableTable)(literalLexicalRoot4th8th) ||
(0, syllablelists_1.isInSyllableTable)(literalLexicalRootEighth)) &&
tonalres_1.finalConsonantsPtkhppttkkhhTonal.includes(letters[i].literal)) {
// console.log(`i: ${i}, literal: ${literal}, root4th8th: ${literalLexicalRoot4th8th}, root8th: ${literalLexicalRootEighth}, stopFinalConsonant: ${letters[i].literal}`);
// console.log(`begin: ${begin}, beginOfSyllable: ${beginOfSyllable}`);
if (begin === beginOfSyllable) {
matched = literal; // assign literal instead of literalRoot4thFinal
Object.assign(matchedLtrs, ltrs);
}
break;
}
else if (tonalres_1.freeToneLettersTonal.includes(letters[i].literal)) {
// check tonals is the subset of free tonals
// console.log(`i: ${i}, literal: ${literal}, letters[i].literal, ${letters[i].literal}`);
// when there are tonals
if (literal.length > 1 &&
letters[i] &&
letters[i - 1] &&
((0, matcher_1.smBgkpF)(letters[i - 1].literal, letters[i].literal) ||
(0, matcher_1.smBgkpWx)(letters[i - 1].literal, letters[i].literal) ||
(0, matcher_1.smJlsF)(letters[i - 1].literal, letters[i].literal) ||
(0, matcher_1.smJsW)(letters[i - 1].literal, letters[i].literal) ||
(0, matcher_1.smLWx)(letters[i - 1].literal, letters[i].literal))) {
// b, g, bb, gg, l, j, s, ll, ss need to be handled in TonalCombiningMorpheme.assignAllomorph
// this combining form is not present in the pool.
matched = literal;
Object.assign(matchedLtrs, ltrs);
break;
}
else if (literal.length > 2 &&
letters[i] &&
letters[i - 1] &&
letters[i - 2] &&
((0, matcher_1.smMnngHWx)(letters[i - 2].literal, letters[i - 1].literal, letters[i].literal) ||
(0, matcher_1.smMnngHF)(letters[i - 2].literal, letters[i - 1].literal, letters[i].literal))) {
// in case of -mhw.
matched = literal;
Object.assign(matchedLtrs, ltrs);
break;
}
else if (literal.length > 1 &&
letters[i] &&
letters[i - 1] &&
(0, matcher_1.smMngFywxz)(letters[i - 1].literal, letters[i].literal)) {
// in case of -iengz, -uamz.
// matched = literal;
// Object.assign(matchedLtrs, ltrs);
// break;
}
// tone change of free allomorphs
const rulesFa = tonalres_1.freeAllomorphStandaloneRules.get(letters[i].literal);
const tnlsFa = !rulesFa ? [] : rulesFa.map((x) => x.toString());
// tone sandhi of ay
const rulesAy = tonalres_1.standaloneRulesAy.get(letters[i].literal);
const tnlsAy = !rulesAy ? [] : rulesAy.map((x) => x.toString());
// merge the above twoo arrays
const tnls = tnlsFa.concat(tnlsAy.filter((item) => tnlsFa.indexOf(item) < 0));
// console.log(`literal: ${literal}`);
if (tnls.length > 0) {
for (let t of tnls) {
// console.log(literal, t.toString(), tnls.length, tnls);
if ((0, syllablelists_1.isInSyllableTable)(letters
.slice(beginOfSyllable, i)
.map((x) => x.literal)
.join('') + t)) {
// this combining form is not present in the pool,
// but its standalone forms are. e.g. aw.
matched = literal;
Object.assign(matchedLtrs, ltrs);
break;
}
}
if (matched.length > 0 && matchedLtrs.length > 0)
break;
}
else {
// no standalone forms for this combining form. e.g. ax.
matched = '';
matchedLtrs = [];
}
}
else if ((0, syllablelists_1.isInSyllableTable)(literal)) {
matched = literal;
Object.assign(matchedLtrs, ltrs);
begin = beginOfSyllable;
// console.log(matched);
}
else {
// console.log('no matched for syllabifyTonal:' + ltrs);
// when there are no tone letters
if (collections_1.finalConsonantsBgjlsbbggjjllss.includes(letters[i].literal)) {
// for the syllables with sandhi final consonants that are not present in syllable tables
const literalWithoutFinal = letters
.map((val, ind, arr) => ind < i && ind >= beginOfSyllable ? arr[ind].literal : '')
.join('');
const gotFinalConsonants = collections_1.finalConsonantsForBgjlsbbggjjllss.get(letters[i].literal);
if (gotFinalConsonants) {
// check if at least one uncombinging form present
const isUncombingFormPresent = gotFinalConsonants
.map((it) => (0, syllablelists_1.isInSyllableTable)(literalWithoutFinal + it))
.reduce((prev, curr, ind, arr) => prev || curr);
// console.log(literal,gotFinalConsonants,isUncombingFormPresent,literalWithoutFinal,`i: ${i}`);
if (isUncombingFormPresent) {
// at least one standalone form is present
matched = literal;
Object.assign(matchedLtrs, ltrs);
}
}
}
else if ((0, matcher_1.smEk)(ltrs[ltrs.length - 2], ltrs[ltrs.length - 1]) || (0, matcher_1.smIk)(ltrs[ltrs.length - 2], ltrs[ltrs.length - 1])) {
// match for -ek or -ik
matched = literal;
Object.assign(matchedLtrs, ltrs);
}
else if ((0, matcher_1.smVowelMng)(ltrs[ltrs.length - 2], ltrs[ltrs.length - 1])) {
// match for -ieng, -uam
// matched = literal;
// Object.assign(matchedLtrs, ltrs);
}
else if (!tonalres_1.freeToneLettersTonal.includes(letters[i].literal)) {
// free first tone without a free tonal
const rules = tonalres_1.freeAllomorphStandaloneRules.get(tonalres_1.TonalLetterTags.zero);
const tnls = !rules ? [] : rules;
for (let t of tnls) {
// append second tonal letter
// check the standalone forms
if ((0, syllablelists_1.isInSyllableTable)(literal + t.toString())) {
// if the free first tone's lemma is included
matched = literal;
Object.assign(matchedLtrs, ltrs);
//break;
}
}
}
// when there is no matched lexcial roots for this syllable, we still assign begin
begin = beginOfSyllable;
}
}
// console.log(`literal: ${literal}. matched: ${matched}`);
// console.log(matchedLtrs);
if (matched.length > 0 && literal.length > matched.length) {
// when ~ay is longer than ~a by one letter y
// for those first tone lexcial roots that are present
matched = '';
matchedLtrs = [];
}
// console.log('matched: ' + matched);
const tsg = new soundgen_1.TonalSoundGenerator();
//console.log('matched: ' + matched)
let list = new Array();
if (matched.length > 0) {
list = tsg.generate(matchedLtrs);
}
else {
if (ltrs.length == 3 && ltrs[1] === 'a' && ltrs[2] === 'y') {
const rea = new metaplasm_2.RemovingEpenthesisOfAy();
const done = rea.applyToString(literal);
//console.log(done.toString())
if (collections_1.epentheticLetters.includes(ltrs[0]) && (0, syllablelists_1.isInSyllableTable)(done)) {
list = tsg.generate(ltrs);
}
}
}
// console.log(list);
let matchedLen = 0;
let mp = new unit_1.MatchedPattern();
for (let m in list) {
const min = Math.min(letters.length - beginOfSyllable, list[m].length);
if (list[m].length == min) {
for (let n = 0; n < min; n++) {
if (list[m][n] != undefined) {
if (letters[beginOfSyllable + n].literal === list[m][n].toString()) {
//console.log(syllabary[m])
if (n + 1 == min && min > matchedLen) {
// to make sure it is longer than previous patterns
// last letter matched for the pattern
matchedLen = min;
// copy the matched letters
for (let q = 0; q < matchedLen; q++) {
mp.letters[q] = letters[beginOfSyllable + q];
}
// copy the pattern of sounds
mp.pattern = list[m];
//console.log(syllabary.list[m])
//console.log(mp.letters)
}
}
else {
break;
}
}
}
}
}
return mp;
}
exports.syllabifyTonal = syllabifyTonal;
/** A syllable and its standalone forms. */
class TonalStandaloneMorpheme extends unit_1.Morpheme {
syllable;
allomorph;
metaplasm;
forms;
sounds;
constructor(syllable, sounds, metaplasm) {
super();
this.syllable = syllable;
this.metaplasm = metaplasm;
// assign allomorph for each syllable
this.sounds = sounds;
this.allomorph = this.assignAllomorph(this.sounds);
this.forms = this.metaplasm.apply(this.sounds, this.allomorph);
}
getForms() {
return this.forms;
}
addForms(syllables) {
if (syllables && syllables.length == 1) {
this.forms.push(syllables[0]);
}
}
assignAllomorph(letters) {
let allomorph = new tonalres_1.ZeroAllomorph();
// assign the matched allomorph for this syllable
let las = []; // list of allomorphs
const s = new unit_3.TonalSyllable(letters.map((it) => new unit_2.AlphabeticLetter(it.characters)));
const keys = Array.from(tonalres_1.checkedAllomorphs.keys());
for (let k = 0; k < keys.length; k++) {
const am = tonalres_1.checkedAllomorphs.get(keys[k]);
if (am && am instanceof tonalres_1.CheckedAllomorph) {
if (am.tonal) {
if (am.tonal.toString() === s.lastLetter.literal &&
am.final.toString() === s.lastSecondLetter.literal) {
las.push(am);
break;
}
else {
if (am.final.toString() === s.lastLetter.literal) {
las.push(am);
break;
}
}
}
}
}
if (las.length > 0) {
// there is only one match after processing, we just assign it
const ret = las.shift();
if (ret)
return ret;
}
// after matching with checked allomorphs, we go on matching free allomorphs
las = [];
if (tonalres_1.freeAllomorphs.has(s.lastLetter.literal)) {
const am = tonalres_1.freeAllomorphs.get(s.lastLetter.literal);
const stpFnls = letters.filter((it) => it.name === tonalres_1.TonalSpellingTags.stopFinalConsonant);
const chkttnls = letters.filter((it) => it.name === tonalres_1.TonalSpellingTags.checkedTone);
if (am &&
!(stpFnls.length == 1 &&
stpFnls[0].toString().length == 2 &&
chkttnls.length == 1)) {
// when 8th finals *not* followed by a tonal
las.push(am);
}
else
las.push(new tonalres_1.Allomorph());
}
if (las.length == 0) {
// tone 1 has no allomorph
allomorph = new tonalres_1.ZeroAllomorph();
}
else if (las.length == 1) {
// are there multiple allomorphs? there should be only one.
for (let i = 0; i < las.length; i++) {
if (las[i].tonal.toString() === new tonalres_1.AllomorphX().tonal.toString()) {
// this syllable is already in base form
// in order to display this inflectional ending, we have to assign
allomorph = las[i];
}
else {
allomorph = las[i];
}
}
}
return allomorph;
}
}
exports.TonalStandaloneMorpheme = TonalStandaloneMorpheme;
class TonalStandaloneMorphemeMaker extends maker_1.MorphemeMaker {
sandhiFinals = new Array();
sandhiFinalTonals = new Array();
metaplasm;
constructor(metaplasm) {
super();
this.metaplasm = metaplasm;
}
createArray() {
return new Array();
}
createMorpheme(matched, metaplasm) {
const tum = new TonalStandaloneMorpheme(new unit_3.TonalSyllable(matched.letters), matched.pattern, metaplasm);
return tum;
}
isCombiningAy(syllables) {
const keysAy = Array.from(tonalres_1.standaloneRulesAy.keys());
if (syllables.length >= 2) {
const nslFnlLast2nd = syllables[syllables.length - 2].pattern.filter((it) => it.name === tonalres_1.TonalSpellingTags.nasalFinalConsonant);
const stpFnlH = syllables[syllables.length - 2].pattern.filter((it) => it.name === tonalres_1.TonalSpellingTags.stopFinalConsonant &&
it.toString() === tonalres_1.TonalLetterTags.h);
const tnl = syllables[syllables.length - 2].pattern.filter((it) => (it.name === tonalres_1.TonalSpellingTags.nasalFinalConsonant ||
it.name === tonalres_1.TonalSpellingTags.checkedTone) &&
keysAy.includes(it.toString()));
const nslInitLast = syllables[syllables.length - 1].pattern.filter((it) => it.name === tonalres_1.TonalSpellingTags.initialConsonant &&
collections_1.nasalInitialConsonants.includes(it.toString()));
// ending ay
const endingAy = syllables[syllables.length - 1].lastSecondLetter.literal ===
tonalres_1.TonalLetterTags.a &&
syllables[syllables.length - 1].lastLetter.literal ===
tonalres_1.TonalLetterTags.y;
// ending a is the proceeding form of ay
const endingA = syllables[syllables.length - 1].lastLetter.literal ===
tonalres_1.TonalLetterTags.a;
if (!(nslFnlLast2nd.length == 1 &&
stpFnlH.length == 1 &&
tnl.length == 1) &&
(endingAy || endingA)) {
// bypass sandhi t. e.g. vunghf~.
if (nslInitLast.length == 1 && nslFnlLast2nd.length == 0) {
// in case of words like vutfngay
return false;
}
const initLast = syllables[syllables.length - 1].pattern.filter((it) => it.name === tonalres_1.TonalSpellingTags.initialConsonant &&
tonalres_1.initialConsonantsTonal.includes(it.toString()));
const mdlLast = syllables[syllables.length - 1].pattern.filter((it) => it.name === tonalres_1.TonalSpellingTags.vowel);
if (stpFnlH.length == 0 &&
nslFnlLast2nd.length == 1 &&
initLast.length == 1 &&
nslFnlLast2nd[0].toString() != initLast[0].toString()) {
// in case of words like angzchuay, ngzchuay
return false;
}
else if (initLast.length == 1 && mdlLast.length > 1) {
// in case of suafluay, suafsuay
return false;
}
return true;
}
}
return false;
}
isCombiningEx(syllables) {
// ending ex
const endingEx = syllables[syllables.length - 1].lastSecondLetter.literal ===
tonalres_1.TonalLetterTags.e &&
syllables[syllables.length - 1].lastLetter.literal === tonalres_1.TonalLetterTags.x;
if (endingEx) {
return true;
}
return false;
}
isTransfixInflection(syllables) {
// TODO: there are not many of them. make a tiny dictionary to cover the ocurrences
const thirds = syllables
.map((it) => it.pattern.filter((ltr) => ltr.toString() === tonalres_1.TonalLetterTags.w))
.map((seq) => seq.map((ltr) => ltr.toString()))
.filter((arr) => arr.length > 0);
const endingAw = syllables[syllables.length - 1].lastSecondLetter.literal ===
tonalres_1.TonalLetterTags.a;
if (syllables.length > 1 && thirds.length == syllables.length && endingAw)
return true;
return false;
}
isDoublet(syllables) {
if (syllables.length == 2) {
const stems = syllables
.map((it) => it.pattern.filter((s) => s.name !== tonalres_1.TonalSpellingTags.freeTone))
.map((seq) => seq.map((s) => s.toString()).join(''));
// TODO: add checks for tone group
const tnls = syllables
.map((it) => it.pattern.filter((s) => s.name === tonalres_1.TonalSpellingTags.freeTone))
.map((seq) => seq.map((ltr) => ltr.toString()).join(''));
// compare 2 strings/lexical stems
if (stems[0] === stems[1])
return true; // identical
}
return false;
}
isTriplet(syllables) {
if (syllables.length == 3) {
const stems = syllables
.map((it) => it.pattern.filter((ltr) => ltr.name !== tonalres_1.TonalSpellingTags.freeTone &&
ltr.name !== tonalres_1.TonalSpellingTags.checkedTone))
.map((seq) => seq.map((ltr) => ltr.toString()).join(''));
const fnls = syllables
.map((it) => it.pattern.filter((s) => s.name === tonalres_1.TonalSpellingTags.stopFinalConsonant))
.map((seq) => seq.map((s) => s.toString()).join(''));
// TODO: add checks for tone group
const tnls = syllables
.map((it) => it.pattern.filter((s) => s.name === tonalres_1.TonalSpellingTags.freeTone))
.map((seq) => seq.map((s) => s.toString()).join(''));
// compare 3 strings/lexical stems
if (fnls && fnls.length > 0) {
// stems of checked tones
if (stems[0] === stems[1] && stems[0] + fnls[0] === stems[2])
return true;
}
else {
// stems of free tones
if (stems.every((v, i, a) => v === a[a.length - 1]))
return true; // identical
}
}
return false;
}
/** Check if ~ek or ~ekk available for the ~iet syllable. */
isEkEkkAvailableForRimeIet(syllables) {
if (syllables.length >= 2) {
const vs = syllables[syllables.length - 2].pattern.filter((i) => i.name === tonalres_1.TonalSpellingTags.vowel);
const fcs = syllables[syllables.length - 2].pattern.filter((i) => i.name === tonalres_1.TonalSpellingTags.stopFinalConsonant);
const ts = syllables[syllables.length - 2].pattern.filter((i) => i.name === tonalres_1.TonalSpellingTags.checkedTone);
if (vs.length == 2 &&
fcs.length == 1 &&
ts.length == 1 &&
vs[0].toString() === tonalres_1.TonalLetterTags.i &&
vs[1].toString() === tonalres_1.TonalLetterTags.e &&
fcs[0].toString() === tonalres_1.TonalLetterTags.t &&
(ts[0].toString() === tonalres_1.TonalLetterTags.f ||
ts[0].toString() === tonalres_1.TonalLetterTags.w)) {
// TODO: check if the standalone forms present in syllable table.
return true;
}
}
else if (syllables.length == 1) {
// standalone syllables ietw and ietf should be handled in this block
}
return false;
}
preprocess(graphemes) {
let ltrs = new Array();
ltrs = graphemes.map((it) => it.letter);
return ltrs;
}
postprocess(matched) {
const morphemes = this.createArray();
for (let i = 0; i < matched.length; i++) {
const ptn = matched[i];
if (this.isCombiningAy(matched) && matched.length == 2) {
// ~fa, ~xa, fay, or ~xay. only 2 syllables
morphemes.push(this.createMorpheme(ptn, new metaplasm_1.PrecedingAyStandalone()));
}
else if (this.isCombiningAy(matched) &&
(matched.length == 3 || matched.length == 4)) {
// ~fa, ~xa, fay, or ~xay. more than 2 syllables
if (i == matched.length - 2 || i == matched.length - 1)
// the last 2 syllables
morphemes.push(this.createMorpheme(ptn, new metaplasm_1.PrecedingAyStandalone()));
else if (i == matched.length - 3)
// the first syllable of a 3-syllable word or the 2nd syllable of a 4-syllable word
morphemes.push(this.createMorpheme(ptn, new metaplasm_1.TonalStandaloneForms(matched[i + 1].pattern)));
else if (matched.length == 4 && i == matched.length - 4)
// the first syllable of a 4-syllable word
morphemes.push(this.createMorpheme(ptn, new metaplasm_1.TonalStandaloneForms(matched[i + 1].pattern)));
}
else if (this.isCombiningEx(matched) && matched.length == 2) {
// ~ex
morphemes.push(this.createMorpheme(ptn, new metaplasm_1.PrecedingExStandalone()));
}
else if (this.isTriplet(matched)) {
// triplet construction. pass the last syllable as an argument
morphemes.push(this.createMorpheme(ptn, new metaplasm_1.LastSyllableForms(matched[2].pattern)));
}
else if (this.isDoublet(matched)) {
// doublet construction. pass the last syllable as an argument
morphemes.push(this.createMorpheme(ptn, new metaplasm_1.LastSyllableForms(matched[1].pattern)));
}
else if (this.isTransfixInflection(matched)) {
morphemes.push(this.createMorpheme(ptn, new metaplasm_1.TransfixStandalone()));
}
else {
if (i < matched.length - 1) {
// when the target syllable is not the last one in a word.
// pass the letters of the following syllable to unchange letters accordingly
morphemes.push(this.createMorpheme(ptn, new metaplasm_1.TonalStandaloneForms(matched[i + 1].pattern)));
}
else {
// no sandhi letters to unchange, just pass an empty array
// the metaplasm argument would be either TonalStandaloneForms or PhrasalVerbParticleStandalone
morphemes.push(this.createMorpheme(ptn, this.metaplasm));
}
if (this.isEkEkkAvailableForRimeIet(matched) && i < matched.length - 1) {
const forms = this.createMorpheme(ptn, new metaplasm_1.StandaloneFormsIetfIetwToEkEkk()).getForms();
if (forms && forms.length == 1) {
morphemes[i].addForms(forms);
}
}
}
}
return morphemes;
}
makeMorphemes(graphemes) {
const ltrs = this.preprocess(graphemes);
const ptns = this.make(ltrs, syllabifyTonal);
const ms = this.postprocess(ptns);
// TODO: to further check if the syllable is valid, given the following syllable
return ms;
}
}
exports.TonalStandaloneMorphemeMaker = TonalStandaloneMorphemeMaker;
/** A syllable and its sound changing forms. */
class TonalSoundUnchangingMorpheme extends unit_1.Morpheme {
syllable;
sounds;
constructor(syllable, sounds) {
super();
this.syllable = syllable;
this.sounds = sounds;
}
get lastSecondLetter() {
return this.sounds[this.sounds.length - 2].toString();
}
uninsertNasal() {
const ltrs = this.sounds;
ltrs.shift();
return [
new unit_3.TonalSyllable(ltrs.map((it) => new unit_2.AlphabeticLetter(it.characters))),
];
}
toVoicelessFinal() {
// unvoiced
if (collections_1.voicedVoicelessFinalConsonants.has(this.sounds[this.sounds.length - 2].toString())) {
const fnl = collections_1.voicedVoicelessFinalConsonants.get(this.sounds[this.sounds.length - 2].toString());
if (fnl) {
const s = new unit_3.TonalSyllable(this.sounds.map((it) => new unit_2.AlphabeticLetter(it.characters)));
s.replaceLetter(s.letters.length - 2, tonalres_1.lowerLettersTonal.get(fnl));
return [s];
}
}
return [];
}
unmutateInitialConsonant(initial) {
if (initial.name === tonalres_1.TonalSpellingTags.initialConsonant &&
initial.toString() === tonalres_1.TonalLetterTags.t) {
// l- -> t-
const s = new unit_3.TonalSyllable(this.sounds.map((it) => new unit_2.AlphabeticLetter(it.characters)));
s.replaceLetter(0, tonalres_1.lowerLettersTonal.get(tonalres_1.TonalLetterTags.t));
return [s];
}
return [];
}
unmutateFinalConsonant(initial) {
if (initial.name === tonalres_1.TonalSpellingTags.initialConsonant &&
initial.toString() === tonalres_1.TonalLetterTags.g) {
// gg -> tt
const syl = new unit_3.TonalSyllable(this.sounds.map((it) => new unit_2.AlphabeticLetter(it.characters)));
const idx = this.sounds.findIndex((i) => i.name === tonalres_1.TonalSpellingTags.stopFinalConsonant);
syl.replaceLetter(idx, tonalres_1.lowerLettersTonal.get(tonalres_1.TonalLetterTags.tt));
return [syl];
}
return [];
}
uninfect() {
const n = this.sounds.filter((i) => i.name === tonalres_1.TonalSpellingTags.nasalization);
if (n.length == 1) {
let ltrs = this.sounds.filter((i) => i.name !== tonalres_1.TonalSpellingTags.nasalization);
const s = new unit_3.TonalSyllable(ltrs.map((it) => new unit_2.AlphabeticLetter(it.characters)));
return [s];
}
return [];
}
}
exports.TonalSoundUnchangingMorpheme = TonalSoundUnchangingMorpheme;
class TonalSoundUnchangingMorphemeMaker extends maker_1.MorphemeMaker {
constructor() {
super();
}
createArray() {
return new Array();
}
createMorpheme(match) {
const tcm = new TonalSoundUnchangingMorpheme(new unit_3.TonalSyllable(match.letters), match.pattern);
return tcm;
}
postprocess(matches) {
let morphemes = this.createArray();
for (let i in matches) {
morphemes.push(this.createMorpheme(matches[i]));
}
return morphemes;
}
makeMorphemes(graphemes) {
const ltrs = graphemes.map((it) => it.letter);
const ptrns = this.make(ltrs, syllabifyTonal);
const ms = this.postprocess(ptrns);
return ms;
}
}
exports.TonalSoundUnchangingMorphemeMaker = TonalSoundUnchangingMorphemeMaker;
//# sourceMappingURL=morpheme.js.map