more testing and refactoring

This commit is contained in:
adueck 2023-04-01 22:19:16 +04:00
parent 833f5acce6
commit 3eb630a7b7
2 changed files with 125 additions and 120 deletions

View File

@ -1372,7 +1372,7 @@ test("ability simple verb forms", () => {
] ]
}, },
}, },
// exception with tlul verbs losing aspect // exception with tlul verbs losing aspect
{ {
tense: "subjunctiveVerbModal", tense: "subjunctiveVerbModal",
person: 10, person: 10,

View File

@ -49,99 +49,91 @@ export function renderVerb({ verb, tense, person, voice }: {
verbBlocks: T.VB[], verbBlocks: T.VB[],
} { } {
// TODO: check for transitivity with passive voice ?? // TODO: check for transitivity with passive voice ??
// WARNING: this only works with simple verbs
const hasBa = tenseHasBa(tense);
if (isPerfectTense(tense)) { if (isPerfectTense(tense)) {
return { return getPerfectVBs({ verb, tense, person, voice });
hasBa,
verbBlocks: getPerfectBlocks({ verb, tense, person, voice }),
};
} }
const hasBa = tenseHasBa(tense);
const isPast = isPastTense(tense); const isPast = isPastTense(tense);
const aspect = getAspect(tense); const aspect = getAspect(tense);
const isAbility = isModalTense(tense); const isAbility = isModalTense(tense);
const noPerfective = isAbility && (voice === "passive" || isTlulVerb(verb) || isKedul(verb));
const { perfectiveHead, rootStem } = getRootStem({ const { perfectiveHead, rootStem } = getRootStem({
verb, aspect, isPast, isAbility, person, voice verb, aspect, isPast, isAbility, person, voice, noPerfective,
}); });
const perfectiveHeadBlock: T.PH | undefined = perfectiveHead ? { const verbBlocks: T.VB[] = isAbility
type: "PH", ? getAbilityVerbBlocks({ isPast, person, root: rootStem, aspect, voice, noPerfective })
// should only need this for tlul and Daaredul? : voice === "passive"
ps: fromPersInfls(perfectiveHead, person), ? getPassiveVerbBlocks({ root: rootStem, tense, person })
} : undefined; : getBasicVerbBlock({
rootStem, person, isPast, verb, aspect,
});
return {
hasBa,
verbBlocks: [
...!noPerfective && perfectiveHead ? [perfectiveHead] : [],
...verbBlocks,
],
};
}
function getBasicVerbBlock({ rootStem, person, isPast, aspect, verb }: {
rootStem: T.SingleOrLengthOpts<T.PsString>,
person: T.Person,
isPast: boolean,
aspect: T.Aspect,
verb: T.VerbEntry,
}): [T.VA] {
const ending = getEnding(person, isPast); const ending = getEnding(person, isPast);
if (isAbility) { return [{
const [vb, shPart] = getAbilityVerbBlocks({ verb, isPast, person, root: rootStem, aspect, voice });
return {
hasBa,
verbBlocks: (perfectiveHeadBlock && voice === "active")
? [perfectiveHeadBlock, vb, shPart]
: [vb, shPart],
};
}
if (voice === "passive") {
const vbs = getPassiveVerbBlocks({ root: rootStem, tense, person });
return {
hasBa,
verbBlocks: [
...perfectiveHeadBlock ? [perfectiveHeadBlock] : [],
vbs,
],
};
}
const verbBlock: T.VA = {
type: "VA", type: "VA",
ps: addEnding({ ps: addEnding({
rootStem, ending, person, isPast, verb, aspect, rootStem, ending, person, isPast, verb, aspect,
}), }),
person, person,
}; }];
return {
hasBa,
verbBlocks: perfectiveHeadBlock ? [
perfectiveHeadBlock, verbBlock,
] : [verbBlock],
}
} }
function getPassiveVerbBlocks({ root, tense, person }: { function getPassiveVerbBlocks({ root, tense, person }: {
root: T.SingleOrLengthOpts<T.PsString>, root: T.SingleOrLengthOpts<T.PsString>,
tense: T.VerbTense, tense: T.VerbTense,
person: T.Person, person: T.Person,
}): T.Welded {
/* istanbul ignore next */
if (!("long" in root)) {
throw new Error("should have length versions in roots for passive");
}
const { verbBlocks: [auxVerb] } = renderVerb({
verb: kedulStatVerb,
tense,
person,
voice: "active",
}) as { hasBa: boolean, verbBlocks: [T.VA] };
return weld(
{
type: "VI",
ps: [root.long],
},
auxVerb,
);
}
function getAbilityVerbBlocks({ verb, isPast, person, root, aspect, voice }: {
verb: T.VerbEntry,
isPast: boolean,
person: T.Person,
root: T.SingleOrLengthOpts<T.PsString>,
aspect: T.Aspect,
voice: T.Voice,
}): T.VB[] { }): T.VB[] {
/* istanbul ignore next */ /* istanbul ignore next */
if (!("long" in root)) { if (!("long" in root)) {
throw new Error("should have length versions in roots for passive"); throw new Error("should have length versions in roots for passive");
} }
const noPerfective = isTlulVerb(verb) || isKedul(verb); const { verbBlocks: [auxVerb] } = renderVerb({
// TODO: "kedulStat" verb argument with overload that removes the "as" usage
verb: kedulStatVerb,
tense,
person,
voice: "active",
}) as { hasBa: boolean, verbBlocks: [T.VA] };
return [
weld(
{
type: "VI",
ps: [root.long],
},
auxVerb,
),
];
}
function getAbilityVerbBlocks({ isPast, person, root, aspect, voice, noPerfective }: {
isPast: boolean,
person: T.Person,
root: T.SingleOrLengthOpts<T.PsString>,
aspect: T.Aspect,
voice: T.Voice,
noPerfective: boolean,
}): T.VB[] {
/* istanbul ignore next */
if (!("long" in root)) {
throw new Error("should have length versions in roots for passive");
}
const shBlock = getAbilityShPart(isPast, person); const shBlock = getAbilityShPart(isPast, person);
const adjustedAspect = noPerfective ? "imperfective" : aspect;
if (voice === "passive") { if (voice === "passive") {
return [ return [
weld( weld(
@ -154,7 +146,7 @@ function getAbilityVerbBlocks({ verb, isPast, person, root, aspect, voice }: {
ps: addAbilityTailsToRs({ ps: addAbilityTailsToRs({
long: { p: "کېدل", f: "kedúl" }, long: { p: "کېدل", f: "kedúl" },
short: { p: "کېد", f: "ked" }, short: { p: "کېد", f: "ked" },
}, aspect, true), }, adjustedAspect),
}, },
), ),
shBlock, shBlock,
@ -163,38 +155,38 @@ function getAbilityVerbBlocks({ verb, isPast, person, root, aspect, voice }: {
// TODO: this is redundant, we did it in another part of the program? // TODO: this is redundant, we did it in another part of the program?
const verbBlock: T.VI = { const verbBlock: T.VI = {
type: "VI", type: "VI",
ps: addAbilityTailsToRs(root, aspect, noPerfective), ps: addAbilityTailsToRs(root, adjustedAspect),
}; };
return [verbBlock, shBlock]; return [verbBlock, shBlock];
function getAbilityShPart(isPast: boolean, person: T.Person): T.VA {
// TODO: optimized shortcut version of this
const { verbBlocks: [shBlock] } = renderVerb({
verb: kedulStatVerb,
tense: isPast ? "perfectivePast" : "subjunctiveVerb",
person,
voice: "active",
}) as {
hasBa: boolean,
verbBlocks: [T.VA],
};
return {
type: "VA",
ps: shBlock.ps,
person,
};
}
} }
function getPerfectBlocks({ verb, tense, person, voice }: { function getAbilityShPart(isPast: boolean, person: T.Person): T.VA {
// TODO: optimized shortcut version of this
const { verbBlocks: [shBlock] } = renderVerb({
verb: kedulStatVerb,
tense: isPast ? "perfectivePast" : "subjunctiveVerb",
person,
voice: "active",
}) as {
hasBa: boolean,
verbBlocks: [T.VA],
};
return {
type: "VA",
ps: shBlock.ps,
person,
};
}
function getPerfectVBs({ verb, tense, person, voice }: {
verb: T.VerbEntry, verb: T.VerbEntry,
tense: T.PerfectTense, tense: T.PerfectTense,
person: T.Person, person: T.Person,
voice: T.Voice, voice: T.Voice,
}): T.VB[] { }): { hasBa: boolean, verbBlocks: T.VB[] } {
const hasBa = tenseHasBa(tense);
const vInfo = getVerbInfo(verb.entry) as T.SimpleVerbInfo; const vInfo = getVerbInfo(verb.entry) as T.SimpleVerbInfo;
// TODO: put this in a seperate function?
if (voice === "passive") { if (voice === "passive") {
const [pt, eq] = getKedulStatPerfect(person, tense); const [pt, eq] = getKedulStatPerfect(person, tense);
const passiveRoot: T.VI = { const passiveRoot: T.VI = {
@ -202,7 +194,10 @@ function getPerfectBlocks({ verb, tense, person, voice }: {
ps: [noPersInfs(vInfo.root.imperfective).long], ps: [noPersInfs(vInfo.root.imperfective).long],
}; };
const welded: T.Welded = weld(passiveRoot, pt); const welded: T.Welded = weld(passiveRoot, pt);
return [welded, eq]; return {
hasBa,
verbBlocks: [welded, eq],
}
} }
const equative = equativeEndings[perfectTenseToEquative(tense)]; const equative = equativeEndings[perfectTenseToEquative(tense)];
@ -222,7 +217,10 @@ function getPerfectBlocks({ verb, tense, person, voice }: {
number: personNumber(person), number: personNumber(person),
ps: chooseParticipleInflection(inflectYey(noPersInfs(vInfo.participle.past)), person) ps: chooseParticipleInflection(inflectYey(noPersInfs(vInfo.participle.past)), person)
} }
return [participleBlock, equativeBlock]; return {
hasBa,
verbBlocks: [participleBlock, equativeBlock],
};
} }
function weld(left: T.VI, right: T.VA | T.PT | T.VI): T.Welded { function weld(left: T.VI, right: T.VA | T.PT | T.VI): T.Welded {
@ -236,21 +234,21 @@ function weld(left: T.VI, right: T.VA | T.PT | T.VI): T.Welded {
}; };
} }
function getRootStem({ verb, aspect, isPast, isAbility, voice, person }: { function getRootStem({ verb, aspect, isPast, isAbility, voice, person, noPerfective }: {
verb: T.VerbEntry, verb: T.VerbEntry,
aspect: T.Aspect, aspect: T.Aspect,
isPast: boolean, isPast: boolean,
isAbility: boolean, isAbility: boolean,
person: T.Person, person: T.Person,
voice: T.Voice, voice: T.Voice,
noPerfective: boolean,
}): { }): {
perfectiveHead: undefined | T.OptionalPersonInflections<T.PsString>, perfectiveHead: undefined | T.PH,
rootStem: T.SingleOrLengthOpts<T.PsString>, rootStem: T.SingleOrLengthOpts<T.PsString>,
} { } {
const vInfo = getVerbInfo(verb.entry) as T.SimpleVerbInfo; const vInfo = getVerbInfo(verb.entry) as T.SimpleVerbInfo;
const noPerfective = isTlulVerb(verb) || isKedul(verb);
const rs = vInfo[(isPast || isAbility || voice === "passive") ? "root" : "stem"]; const rs = vInfo[(isPast || isAbility || voice === "passive") ? "root" : "stem"];
if (noPerfective && isAbility) { if (noPerfective) {
// exception with tlul verbs for ability stems // exception with tlul verbs for ability stems
return { return {
perfectiveHead: undefined, perfectiveHead: undefined,
@ -272,7 +270,10 @@ function getRootStem({ verb, aspect, isPast, isAbility, voice, person }: {
const si = fromPersInfls(splitInfo, person); const si = fromPersInfls(splitInfo, person);
if ("long" in si) { if ("long" in si) {
return { return {
perfectiveHead: si.long[0], perfectiveHead: {
type: "PH",
ps: fromPersInfls(si.long[0], person),
},
rootStem: { rootStem: {
long: si.long[1], long: si.long[1],
short: si.short[1], short: si.short[1],
@ -280,9 +281,13 @@ function getRootStem({ verb, aspect, isPast, isAbility, voice, person }: {
} }
} else { } else {
return { return {
perfectiveHead: si[0], perfectiveHead: {
type: "PH",
// should only need this for tlul and Daaredul?
ps: fromPersInfls(si[0], person),
},
rootStem: si[1], rootStem: si[1],
} };
} }
} }
} }
@ -336,22 +341,6 @@ function getEnding(person: T.Person, isPast: boolean) {
} : presentEndings[row][col]; } : presentEndings[row][col];
} }
function perfectTenseToEquative(t: T.PerfectTense): keyof typeof equativeEndings {
return t === "presentPerfect"
? "present"
: t === "futurePerfect"
? "habitual"
: t === "habitualPerfect"
? "habitual"
: t === "pastPerfect"
? "past"
: t === "pastSubjunctivePerfect"
? "pastSubjunctive"
: t === "wouldBePerfect"
? "past"
: "subjunctive"
}
function chooseParticipleInflection(pinf: T.SingleOrLengthOpts<T.UnisexInflections>, p: T.Person): T.SingleOrLengthOpts<T.PsString[]> { function chooseParticipleInflection(pinf: T.SingleOrLengthOpts<T.UnisexInflections>, p: T.Person): T.SingleOrLengthOpts<T.PsString[]> {
if ("long" in pinf) { if ("long" in pinf) {
return { return {
@ -364,7 +353,7 @@ function chooseParticipleInflection(pinf: T.SingleOrLengthOpts<T.UnisexInflectio
return pinf[gender][infNum]; return pinf[gender][infNum];
} }
function addAbilityTailsToRs(rs: T.LengthOptions<T.PsString>, aspect: T.Aspect, noPerfective: boolean): T.SingleOrLengthOpts<T.PsString[]> { function addAbilityTailsToRs(rs: T.LengthOptions<T.PsString>, aspect: T.Aspect): T.SingleOrLengthOpts<T.PsString[]> {
const tails: T.PsString[] = [ const tails: T.PsString[] = [
{ p: "ی", f: "ey" }, { p: "ی", f: "ey" },
{ p: "ای", f: "aay" }, { p: "ای", f: "aay" },
@ -374,12 +363,12 @@ function addAbilityTailsToRs(rs: T.LengthOptions<T.PsString>, aspect: T.Aspect,
{ p: "ای", f: "áay" }, { p: "ای", f: "áay" },
]; ];
// for single syllable long verb stems like tlul - ensure the accent // for single syllable long verb stems like tlul - ensure the accent
const psLong = (aspect === "perfective" && !noPerfective) const psLong = (aspect === "perfective")
? removeAccents(rs.long) ? removeAccents(rs.long)
: ensureAccentLongStem(rs.long); : ensureAccentLongStem(rs.long);
return { return {
long: tails.map(t => concatPsString(psLong, t)), long: tails.map(t => concatPsString(psLong, t)),
short: (aspect === "perfective" && !noPerfective ? tails : accentedTails) short: (aspect === "perfective" ? tails : accentedTails)
.map(t => concatPsString(rs.short, t)), .map(t => concatPsString(rs.short, t)),
}; };
} }
@ -488,4 +477,20 @@ function getKedulStatPerfect(person: T.Person, tense: T.PerfectTense): [T.PT, T.
voice: "active", voice: "active",
}) as { hasBa: true, verbBlocks: [T.PT, T.EQ] }; }) as { hasBa: true, verbBlocks: [T.PT, T.EQ] };
return [pt, eq]; return [pt, eq];
}
function perfectTenseToEquative(t: T.PerfectTense): keyof typeof equativeEndings {
return t === "presentPerfect"
? "present"
: t === "futurePerfect"
? "habitual"
: t === "habitualPerfect"
? "habitual"
: t === "pastPerfect"
? "past"
: t === "pastSubjunctivePerfect"
? "pastSubjunctive"
: t === "wouldBePerfect"
? "past"
: "subjunctive"
} }