more testing and refactoring
This commit is contained in:
parent
833f5acce6
commit
3eb630a7b7
|
@ -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)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -489,3 +478,19 @@ function getKedulStatPerfect(person: T.Person, tense: T.PerfectTense): [T.PT, T.
|
||||||
}) 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"
|
||||||
|
}
|
Loading…
Reference in New Issue