pashto-inflector/src/lib/verb-conjugation.ts

721 lines
29 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright (c) 2021 lingdocs.com
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { getVerbInfo } from "./verb-info";
import {
presentEndings,
pastEndings,
imperativeEndings,
baParticle,
equativeEndings,
emptyVerbBlock,
passiveStativeBridge,
} from "./grammar-units";
import {
addToForm,
mapVerbBlock,
concatPsString,
allOnePersonVerbForm,
complementInflects,
concatInflections,
unisexInfToObjectMatrix,
inflectYey,
allOnePersonInflection,
psStringEquals,
makePsString,
} from "./p-text-helpers";
import {
accentOnNFromEnd,
} from "./accent-helpers";
import { pashtoConsonants } from "./pashto-consonants";
import {
checkForIrregularConjugation,
stativeAux,
} from "./irregular-conjugations";
import {
chooseParticipleInflection,
spaceInForm,
noPersInfs,
} from "./misc-helpers";
import * as T from "../types";
const dummyEntry: T.DictionaryEntry = { i: 0, p: "", f: "", g: "", e: "", c: "", ts: 0 };
const aayTail = [{p: "ای", f: "aay" }, { p: "ی", f: "ey" }];
export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.DictionaryEntry, verbInfo?: T.NonComboVerbInfo): T.VerbOutput {
if (!(entry.c && entry.c.slice(0, 2) === "v.")) {
throw new Error("not a verb");
};
const irregularConj = checkForIrregularConjugation(entry);
if (irregularConj) {
return irregularConj;
}
const info = verbInfo ? verbInfo : getVerbInfo(entry, complement);
if (info.type === "transitive or grammatically transitive simple") {
return {
info,
transitive: conjugateVerb({ ...entry, c: entry.c ? entry.c.replace("/gramm. trans.", "") : "" }, dummyEntry, info.transitive) as T.VerbConjugation,
grammaticallyTransitive: conjugateVerb({ ...entry, c: entry.c ? entry.c?.replace("trans./", "") : "" }, dummyEntry, info.grammaticallyTransitive) as T.VerbConjugation,
};
}
if (info.type === "dynamic or stative compound" || info.type === "dynamic or generative stative compound") {
return {
info,
stative: conjugateVerb({ ...entry, c: entry.c ? entry.c.replace("dyn./", "") : "" }, dummyEntry, info.stative) as T.VerbConjugation,
dynamic: conjugateVerb({ ...entry, c: entry.c ? entry.c.replace("/stat.", "") : "" }, dummyEntry, info.dynamic) as T.VerbConjugation,
};
}
if (info.type === "dynamic compound") {
return conjugateDynamicCompound(info);
}
const nonComboInfo = info as T.NonComboVerbInfo;
const conjugation: T.VerbConjugation = {
info: nonComboInfo,
imperfective: makeAspectContent(nonComboInfo, "imperfective"),
perfective: makeAspectContent(nonComboInfo, "perfective"),
hypothetical: makeHypotheticalContent(nonComboInfo),
participle: makeParticipleContent(nonComboInfo),
perfect: makePerfectContent(nonComboInfo),
..."singularForm" in info ? {
singularForm: conjugateVerb(entry, complement, info.singularForm) as T.VerbConjugation,
} : {},
// if transitive include passive voice
...info.transitivity !== "intransitive" ? {
// TODO: STATIVE COMPOUND VERSION OF THIS
passive: makePassiveContent(nonComboInfo),
} : {},
};
return nonComboInfo.transitivity === "grammatically transitive"
? enforceObject(conjugation, 10)
: nonComboInfo.type === "generative stative compound"
? enforceObject(conjugation, nonComboInfo.objComplement.person)
: conjugation;
}
function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjugation {
const willUseImperative = !(
info.type === "dynamic compound"
&& info.transitivity === "intransitive"
&& info.auxVerb.p === "کېدل"
);
const auxConj = enforceObject(
conjugateVerb(info.auxVerb, info.auxVerbComplement) as T.VerbConjugation,
info.objComplement.person,
);
const complement = info.objComplement.plural
? info.objComplement.plural
: makePsString(info.objComplement.entry.p, info.objComplement.entry.f);
const makeAspectContent = (aspect: T.Aspect): T.AspectContent => {
const makeDynamicModalContent = (): T.ModalContent => {
const nonImperative = addToForm([complement, " "], auxConj[aspect].modal.nonImperative);
const future = addToForm([baParticle, " "], nonImperative);
const past = addToForm([complement, " "], auxConj[aspect].modal.past);
const habitualPast = addToForm([baParticle, " "], past);
const hypotheticalPast = addToForm([complement, " "], auxConj[aspect].modal.hypotheticalPast);
return {
nonImperative,
future,
past,
habitualPast,
hypotheticalPast,
};
};
const ac = auxConj[aspect];
const nonImperative = addToForm([complement, " "], ac.nonImperative);
const future = addToForm([baParticle, " "], nonImperative);
const imperative = (ac.imperative && willUseImperative)
? addToForm([complement, " "], ac.imperative)
: null;
const past = addToForm([complement, " "], auxConj[aspect].past);
const habitualPast = addToForm([baParticle, " "], past);
const modal = makeDynamicModalContent();
return {
nonImperative,
future,
...imperative ? {
imperative,
} : {},
past,
habitualPast,
modal,
};
}
const hypothetical = addToForm([complement, " "], auxConj.hypothetical);
const auxPPart = auxConj.participle.past;
const participle = {
present: concatInflections(complement, auxConj.participle.present),
past: (
(("long" in auxPPart) && ("masc" in auxPPart.long)) ||
("masc" in auxPPart)
)
// @ts-ignore
? concatInflections(complement, auxPPart)
// @ts-ignore
: concatPsString(complement, " ", auxPPart)
}
const makePerfect = (pset: T.PerfectContent): T.PerfectContent => ({
halfPerfect: addToForm([complement, " "], pset.halfPerfect),
past: addToForm([complement, " "], pset.past),
present: addToForm([complement, " "], pset.present),
habitual: addToForm([complement, " "], pset.habitual),
subjunctive: addToForm([complement, " "], pset.subjunctive),
future: addToForm([complement, " "], pset.future),
affirmational: addToForm([complement, " "], pset.affirmational),
pastSubjunctiveHypothetical: addToForm([complement, " "], pset.pastSubjunctiveHypothetical),
});
const makePassiveAspectContent = (aspect: T.Aspect, passive: T.PassiveContent): T.AspectContentPassive => {
const nonImperative = addToForm([complement, " "], passive[aspect].nonImperative);
const future = addToForm([baParticle, " "], nonImperative);
const past = addToForm([complement, " "], passive[aspect].past);
const habitualPast = addToForm([baParticle, " "], past);
const modal = makePassiveModalSection([complement, " "], stativeAux.intransitive.imperfective.modal);
return {
nonImperative,
future,
past,
habitualPast,
modal,
}
}
return {
info,
imperfective: makeAspectContent("imperfective"),
perfective: makeAspectContent("perfective"),
hypothetical,
participle,
perfect: makePerfect(auxConj.perfect),
...auxConj.passive ? {
passive: {
imperfective: makePassiveAspectContent("imperfective", auxConj.passive),
perfective: makePassiveAspectContent("perfective", auxConj.passive),
perfect: makePerfect(auxConj.passive.perfect),
},
} : {},
...info.singularForm ? {
singularForm: conjugateDynamicCompound(info.singularForm)
} : {},
...info.intransitiveForm ? {
intransitiveForm: conjugateDynamicCompound(info.intransitiveForm)
} : {},
};
}
function makeAspectContent(info: T.NonComboVerbInfo, aspect: T.Aspect): T.AspectContent {
if ((info.type === "stative compound") && spaceInForm(info.root[aspect])) {
return makeStativeCompoundSeperatedAspectContent(info, aspect);
}
const stem = noPersInfs(info.stem[aspect]);
const root = noPersInfs(info.root[aspect]);
const nonImperative = addToForm([stem], presentEndings);
const future = addToForm([baParticle, " "], nonImperative);
const imperative = addToForm([stem], imperativeEndings);
const roughPast = addToForm([root], pastEndings) as T.LengthOptions<T.VerbBlock>;
// add accents and idiosyncratic third person sing masc forms
const past = finishSimpleVerbPast(info, aspect, roughPast);
const habitualPast = addToForm([baParticle, " "], past);
return {
nonImperative, // stem + present endings
future, // به - ba + nonImperative
imperative, // stem + imperative endings
past, // root + past endings
habitualPast, // ba + past
modal: makeJoinedModalContent(info, aspect),
};
}
function makeJoinedModalContent(info: T.NonComboVerbInfo, aspectIn: T.Aspect): T.ModalContent {
const aspect: T.Aspect = noPerfectiveModal(info) ? "imperfective" : aspectIn;
const aux = stativeAux.intransitive.perfective;
const rAndT = info.yulEnding
? [concatPsString(noPersInfs(info.root[aspect]).long, aayTail[1]), concatPsString(noPersInfs(info.root[aspect]).long, aayTail[0])]
: [concatPsString(noPersInfs(info.root[aspect]), aayTail[1]), concatPsString(noPersInfs(info.root[aspect]), aayTail[0])]
const rootAndTail = aspect === "imperfective"
? rAndT.map((x: T.PsString | T.LengthOptions<T.PsString>) => accentImperfectiveModalRootAndTail(info, x))
: rAndT;
const nonImperative = addToForm([rootAndTail, " "], aux.nonImperative);
const future = addToForm([baParticle, " "], nonImperative);
const past = addToForm(
[rootAndTail, " "],
// @ts-ignore
aux.past.short,
);
const habitualPast = addToForm([baParticle, " "], past);
function mhp(rt: T.PsString[]): T.VerbBlock {
const form = [
concatPsString(rt[0], " ", { p: "سو", f: "shw" }, aayTail[0]),
concatPsString(rt[0], " ", { p: "سو", f: "shw" }, aayTail[1]),
concatPsString(rt[1], " ", { p: "سو", f: "shw" }, aayTail[0]),
] as T.ArrayOneOrMore<T.PsString>;
return [
[form, form],
[form, form],
[form, form],
[form, form],
[form, form],
[form, form],
];
}
const hypotheticalPast = "short" in rootAndTail[0]
? {
short: mhp(rootAndTail.map((rt) => "short" in rt ? rt.short : rt)),
long: mhp(rootAndTail.map((rt) => "short" in rt ? rt.long : rt)),
} : mhp(rootAndTail.map((rt) => "short" in rt ? rt.long : rt));
// const hypotheticalPast = [
// [concatPsString(rootAndTail[0], " ", { p: "سو", f: "shw" }, aayTail[0])]
// ]
// const hypotheticalPast = addToForm([rootAndTail, " ", { p: "شو", f: "shw" }, aayTail[0]], emptyVerbBlock);
return {
nonImperative, // ROOT + aayTail + kedulStat subjunctive
future, // به - ba + modal nonImperative
past, // ROOT + aayTail + kedulStat simple past
habitualPast, // ba + past
hypotheticalPast, // ROOT + aayTail + sh + aayTail
};
}
function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbInfo, aspect: T.Aspect): T.AspectContent {
const transitivity = getTransitivity(info);
const presentComplement = (transitivity === "transitive" && complementInflects(info.complement))
? unisexInfToObjectMatrix(info.complement) // transitive verb requires an object matrix for the complex
: info.complement; // intransitive verb doesn't require that because the complement matches the subject
function makeTransitiveStativeModalContent() {
const aux = stativeAux[transitivity][aspect].modal;
const nonImperative = addToForm([presentComplement, " "], aux.nonImperative);
const future = addToForm([baParticle, " "], nonImperative);
const past = addToForm([info.complement, " "], aux.past);
const habitualPast = addToForm([baParticle, " "], past);
const hypotheticalPast = addToForm([info.complement, " "], aux.hypotheticalPast);
return {
nonImperative,
future,
past,
habitualPast,
hypotheticalPast,
};
}
const aux = stativeAux[transitivity][aspect];
// CHECK, does this work with transitive and intransitive??
const nonImperative = addToForm(
[presentComplement, " "],
stativeAux[transitivity][aspect].nonImperative,
);
const future = addToForm([baParticle, " "], nonImperative);
const imperative = aux.imperative
? addToForm([presentComplement, " "], aux.imperative)
: null;
const past = addToForm([info.complement, " "], aux.past);
const habitualPast = addToForm([baParticle, " "], past);
return {
nonImperative,
future,
past,
habitualPast,
...imperative ? {
imperative,
} : {},
modal: info.transitivity === "transitive"
? makeTransitiveStativeModalContent()
: makeJoinedModalContent(info, "imperfective"),
};
}
function makeHypotheticalContent(info: T.NonComboVerbInfo): T.VerbForm {
function makeStativeCompoundSepHypotheticalContent(info: T.StativeCompoundVerbInfo): T.VerbForm {
const transitivity = getTransitivity(info);
const aux = stativeAux[transitivity].hypothetical;
return addToForm([
(transitivity === "transitive" && complementInflects(info.complement))
? unisexInfToObjectMatrix(info.complement)
: info.complement,
" ",
], aux);
}
if (("complement" in info) && spaceInForm(info.root.imperfective)) {
return makeStativeCompoundSepHypotheticalContent(info as T.StativeCompoundVerbInfo);
}
const makeHypothetical = (root: T.OptionalPersonInflections<T.LengthOptions<T.PsString>>, length: "short" | "long"): T.PsString[] => {
if ("mascSing" in root) {
// BIG TODO: SHOULD THERE BE PERS INFS HERE?? IGNORING THEM NOW IF THEY EXIST
return makeHypothetical(root.mascSing, length) as T.PsString[];
}
return [
accentOnNFromEnd(
concatPsString(root[length], aayTail[0]),
(length === "long" ? 1 : 0) + (info.yulEnding ? 1 : 0),
),
accentOnNFromEnd(
concatPsString(root[length], aayTail[1]),
(length === "long" ? 1 : 0) + (info.yulEnding ? 1 : 0),
),
];
};
const short = makeHypothetical(info.root.imperfective, "short") as T.ArrayOneOrMore<T.PsString>;
const long = makeHypothetical(info.root.imperfective, "long") as T.ArrayOneOrMore<T.PsString>;
return {
short: [
[short, short],
[short, short],
[short, short],
[short, short],
[short, short],
[short, short],
],
long: [
[long, long],
[long, long],
[long, long],
[long, long],
[long, long],
[long, long],
],
};
}
function makeParticipleContent(info: T.NonComboVerbInfo): T.ParticipleContent {
const transitivity = getTransitivity(info);
const past = ("complement" in info)
? concatInflections(info.complement, stativeAux[transitivity].participle.past as T.UnisexInflections)
: ("objComplement" in info)
? concatInflections(info.objComplement.plural ? info.objComplement.plural : info.objComplement.entry, stativeAux[transitivity].participle.past as T.UnisexInflections)
: inflectYey(noPersInfs(info.participle.past));
const present = ("complement" in info && spaceInForm(info.root.imperfective))
? concatInflections(info.complement, stativeAux[transitivity].participle.present as T.UnisexInflections)
: inflectYey(noPersInfs(info.participle.present));
return {
present, // PRESENT PARTICIPLE inflected
past, // PAST PARTICIPLE inflected
};
}
function makePerfectContent(info: T.NonComboVerbInfo): T.PerfectContent {
const transitivity = getTransitivity(info);
const pastPart: (" " | T.SingleOrLengthOpts<T.UnisexInflections> | T.SingleOrLengthOpts<T.PsString>)[] =
(info.type === "stative compound")
// for stative compounds
? [info.complement, " ", stativeAux[transitivity].participle.past]
// for regular compounds
: [inflectYey(noPersInfs(info.participle.past))]
const halfPerfect = addToForm([...pastPart], emptyVerbBlock);
const past = addToForm([...pastPart, " "], equativeEndings.past.short);
const present = addToForm([...pastPart, " "], equativeEndings.present);
const habitual = addToForm([...pastPart, " "], equativeEndings.habitual);
const subjunctive = addToForm([...pastPart, " "], equativeEndings.subjunctive);
const future = addToForm([baParticle, " ", ...pastPart, " "], equativeEndings.habitual);
const affirmational = addToForm([baParticle, " ", ...pastPart, " "], equativeEndings.past.short);
const pastSubjunctiveHypothetical = addToForm([...pastPart, " "], equativeEndings.pastSubjunctive);
return {
halfPerfect, // Past Participle
past, // Past Participle + Past Equative
present, // Past Participle + Present Equative
habitual, // Past Participle + Habitual Equative
subjunctive, // Past Participle + Subjunctive Equative
future, // به - ba + Past Participle + Future/Subj Equative
affirmational, // به - ba + Past Participle + Past Equative
pastSubjunctiveHypothetical, // Past Participle + وای - waay
};
}
function makePassiveContent(info: T.NonComboVerbInfo): {
imperfective: T.AspectContentPassive // --╖ ASPECT = "imperfective"
perfective: T.AspectContentPassive // --╜ ASPECT = "perfective"
perfect: T.PerfectContent;
} {
function makePassiveAspectContent(aspect: T.Aspect): T.AspectContentPassive {
if ("complement" in info && spaceInForm(info.root[aspect])) {
// seperated stative compound verb
const bridge = aspect === "imperfective"
? noPersInfs(stativeAux.transitive.info.root.imperfective).long
: passiveStativeBridge;
const nonImperative = addToForm(
[info.complement, " ", bridge, " "],
stativeAux.intransitive[aspect].nonImperative,
);
const future = addToForm([baParticle, " "], nonImperative);
const past = addToForm(
[info.complement, " ", bridge, " "],
stativeAux.intransitive[aspect].past,
);
const habitualPast = addToForm([baParticle, " "], past);
const modal = makePassiveModalSection([
noPersInfs(info.root.imperfective).long, " ",
], stativeAux.intransitive.imperfective.modal);
return {
nonImperative,
future,
past,
habitualPast,
modal,
};
}
const root = noPersInfs(info.root[aspect]).long;
const aux = stativeAux.intransitive[aspect];
const nonImperative = addToForm([root, " "], aux.nonImperative);
const future = addToForm([baParticle, " "], nonImperative);
const past = addToForm([root, " "], aux.past);
const habitualPast = addToForm([baParticle, " "], past);
const auxModal = aux.modal;
const modal = makePassiveModalSection([noPersInfs(info.root.imperfective).long, " "], auxModal);
return {
nonImperative, // ROOT LONG + kedulStat[aspect].nonImperative
future, // به ba + ROOT LONG + this.nonImperative
past, // ROOT LONG + kedulStat[aspect].past
habitualPast,
modal,
};
}
const simpleVerbParticiple = {
past: concatPsString(
noPersInfs(info.root.imperfective).long,
" ",
stativeAux.intransitive.info.participle.past as T.PsString,
),
present: { p: ا", f: "n / a" },
};
const perfect = (info.type === "stative compound")
? makePassivePerfectContent(info)
: makePerfectContent({ ...info, participle: simpleVerbParticiple });
return {
imperfective: makePassiveAspectContent("imperfective"),
perfective: makePassiveAspectContent("perfective"),
perfect: perfect,
};
}
function makePassiveModalSection(base: Array<" " | T.SingleOrLengthOpts<T.PsString> | T.SingleOrLengthOpts<T.UnisexInflections> | T.SingleOrLengthOpts<T.PsString>[] | T.SingleOrLengthOpts<T.PsString[]> | T.OptionalPersonInflections<T.PsString> | T.VerbBlock>, auxModal: T.ModalContent): T.ModalContent {
return {
nonImperative: addToForm(base, auxModal.nonImperative),
future: addToForm(base, auxModal.future),
past: addToForm(base, auxModal.past),
habitualPast: addToForm(base, auxModal.habitualPast),
hypotheticalPast: addToForm(base, auxModal.hypotheticalPast),
};
}
function makePassivePerfectContent(info: T.StativeCompoundVerbInfo): T.PerfectContent {
const pPart = stativeAux.intransitive.participle.past;
// will always be transitive
const halfPerfect = addToForm(
[info.complement, " ", passiveStativeBridge, " ", pPart],
emptyVerbBlock,
);
const past = addToForm(
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
equativeEndings.past.short,
);
const present = addToForm(
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
equativeEndings.present,
);
const habitual = addToForm(
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
equativeEndings.habitual,
);
const subjunctive = addToForm(
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
equativeEndings.subjunctive,
);
const future = addToForm(
[baParticle, " ", info.complement, " ", passiveStativeBridge, " ", pPart, " "],
equativeEndings.habitual,
);
const affirmational = addToForm(
[baParticle, " ", info.complement, " ", passiveStativeBridge, " ", pPart, " "],
equativeEndings.past.short,
);
const pastSubjunctiveHypothetical = addToForm(
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
equativeEndings.pastSubjunctive,
);
return {
halfPerfect,
past,
present,
habitual,
subjunctive,
future,
affirmational,
pastSubjunctiveHypothetical,
};
}
function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjugation {
const modifyPastInAspect = (as: T.AspectContent): T.AspectContent => ({
nonImperative: allOnePersonInflection(as.nonImperative, person),
future: allOnePersonInflection(as.future, person),
...as.imperative ? {
imperative: allOnePersonInflection(as.imperative, person),
} : {},
past: allOnePersonVerbForm(as.past, person),
habitualPast: allOnePersonInflection(as.habitualPast, person),
modal: {
...as.modal,
past: allOnePersonVerbForm(as.modal.past, person),
},
});
const modifyParticiple = (part: T.ParticipleContent): T.ParticipleContent => ({
// TODO: What to do with this!
present: allOnePersonInflection(part.present, person),
past: chooseParticipleInflection(part.past, person),
});
const modifyPerfect = (perf: T.PerfectContent): T.PerfectContent => ({
halfPerfect: allOnePersonVerbForm(perf.halfPerfect, person),
past: allOnePersonVerbForm(perf.past, person),
present: allOnePersonVerbForm(perf.present, person),
habitual: allOnePersonInflection(perf.habitual, person),
subjunctive: allOnePersonInflection(perf.subjunctive, person),
future: allOnePersonVerbForm(perf.future, person),
affirmational: allOnePersonVerbForm(perf.affirmational, person),
pastSubjunctiveHypothetical: allOnePersonVerbForm(perf.pastSubjunctiveHypothetical, person),
});
const modifyPassiveAspect = (as: T.AspectContentPassive): T.AspectContentPassive => ({
nonImperative: allOnePersonVerbForm(as.nonImperative, person),
future: allOnePersonVerbForm(as.future, person),
past: allOnePersonVerbForm(as.past, person),
habitualPast: allOnePersonInflection(as.past, person),
// TODO: check if this is ok
modal: as.modal,
});
return {
...conj,
imperfective: modifyPastInAspect(conj.imperfective),
perfective: modifyPastInAspect(conj.perfective),
participle: modifyParticiple(conj.participle),
perfect: modifyPerfect(conj.perfect),
...conj.passive ? {
passive: {
imperfective: modifyPassiveAspect(conj.passive.imperfective),
perfective: modifyPassiveAspect(conj.passive.perfective),
perfect: modifyPerfect(conj.passive.perfect),
}
} : {},
};
}
// 2ND LEVER HELPERS
function finishSimpleVerbPast(
info: T.NonComboVerbInfo,
aspect: T.Aspect,
roughPast: T.LengthOptions<T.VerbBlock>,
): T.VerbForm {
const applyAccent = (block: T.VerbBlock, form: "short" | "long"): T.VerbBlock => (
mapVerbBlock((item: T.PsString, rowNum: number | undefined, colNum: number | undefined) => {
const nonRedundantLEnding = (
(rowNum === 4 && colNum === 1) &&
item.p.slice(-1) === "ل" &&
["ul", "úl"].includes(item.f.slice(-2))
)
const n = (((form === "short") || nonRedundantLEnding) ? 0 : 1) + (info.yulEnding ? 1 : 0);
return accentOnNFromEnd(item, n);
}, block)
);
const short = ensureShort3rdPersMascSing(info, aspect, roughPast.short);
if (aspect === "imperfective") {
return {
short: applyAccent(short, "short"),
long: applyAccent(roughPast.long, "long"),
};
}
// don't apply the accent on the perfective because the accent will
// already have been included in the perfective root
return { ...roughPast, short };
}
function ensureShort3rdPersMascSing(
info: T.NonComboVerbInfo,
aspect: T.Aspect,
block: T.VerbBlock,
): T.VerbBlock {
const replace3rdPersMascSing = (
replacement: T.ArrayOneOrMore<T.PsString>,
block: T.VerbBlock,
): T.VerbBlock => ([
...block.slice(0, 4),
[replacement, block[4][1]],
block[5],
] as T.VerbBlock);
const makeAawuForm = (root: T.PsString): T.PsString => {
const base = {
p: root.p.slice(0, -1),
f: root.f.slice(0, -2),
};
return concatPsString(base, { p: "اوه", f: "aawu" });
}
const infinitive = noPersInfs(info.root.imperfective).long;
const endsInAwul = (
(["awul", "awúl"].includes(infinitive.f.slice(-4)))
&&
(infinitive.p.slice(-2) === "ول")
);
if (endsInAwul) {
const root = noPersInfs(info.root[aspect]).short;
return replace3rdPersMascSing([makeAawuForm(root)], block);
}
if (info.idiosyncraticThirdMascSing) {
const form = info.idiosyncraticThirdMascSing[aspect];
// if it ends in a consonant, the special form will also have another
// variation ending with a ه - u
const endsInAConsonant = (pashtoConsonants.includes(form.p.slice(-1)) || form.f.slice(-1) === "w");
const replacement: T.ArrayOneOrMore<T.PsString> = endsInAConsonant
? [form, concatPsString(form, { p: "ه", f: "u" })]
: [form];
return replace3rdPersMascSing(replacement, block);
}
// No need for any special third person masculine singular forms
return block;
}
function accentImperfectiveModalRootAndTail(
info: T.NonComboVerbInfo,
rt: T.SingleOrLengthOpts<T.PsString>,
length?: "long" | "short",
): T.SingleOrLengthOpts<T.PsString> {
if ("long" in rt) {
return {
short: accentImperfectiveModalRootAndTail(info, rt.short, "short") as T.PsString,
long: accentImperfectiveModalRootAndTail(info, rt.long, "long") as T.PsString,
}
}
const n = info.yulEnding
? 2
: length === "short"
? 0
: 1;
return accentOnNFromEnd(rt, n);
}
function getTransitivity(info: T.VerbInfo): "transitive" | "intransitive" {
return ("transitivity" in info && info.transitivity === "intransitive")
? "intransitive"
: "transitive";
}
function noPerfectiveModal(info: T.NonComboVerbInfo): boolean {
if (!("mascSing" in info.root.imperfective)) {
const inf = info.root.imperfective.long;
return (
inf.p === "راتلل" ||
psStringEquals({ p: "تلل", f: "tlul" }, inf) ||
inf.p === "درتلل" ||
inf.p === "ورتلل"
);
}
return false;
}