more
This commit is contained in:
parent
1dbe0a42f4
commit
305fb545b9
|
@ -153,7 +153,7 @@ function VPBuilderDemo({ opts }: {
|
||||||
person: testPerson.person,
|
person: testPerson.person,
|
||||||
voice: testVoice,
|
voice: testVoice,
|
||||||
}) : undefined;
|
}) : undefined;
|
||||||
const rs = v ? getAllRs(v.verb as T.VerbEntry) : undefined
|
// const rs = v ? getAllRs(v.verb as T.VerbEntry) : undefined
|
||||||
return <div className="mt-4">
|
return <div className="mt-4">
|
||||||
<div className="d-block mx-auto card" style={{ maxWidth: "700px", background: "var(--closer)"}}>
|
<div className="d-block mx-auto card" style={{ maxWidth: "700px", background: "var(--closer)"}}>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
|
@ -252,9 +252,12 @@ function VPBuilderDemo({ opts }: {
|
||||||
role="subject"
|
role="subject"
|
||||||
opts={opts}
|
opts={opts}
|
||||||
/>
|
/>
|
||||||
|
{/* <details>
|
||||||
|
<summary>Roots and Stems</summary>
|
||||||
<pre>
|
<pre>
|
||||||
{JSON.stringify(rs, null, " ")}
|
{JSON.stringify(rs, null, " ")}
|
||||||
</pre>
|
</pre>
|
||||||
|
</details> */}
|
||||||
<pre>
|
<pre>
|
||||||
{JSON.stringify(rv, null, " ")}
|
{JSON.stringify(rv, null, " ")}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
@ -104,7 +104,7 @@ const accentReplacer = [
|
||||||
{ vowel: "U", accented: "Ú" },
|
{ vowel: "U", accented: "Ú" },
|
||||||
];
|
];
|
||||||
|
|
||||||
function accentSyllable(s: string): string {
|
export function accentSyllable(s: string): string {
|
||||||
return s.replace(/a|e|i|o|u|U/, (match) => {
|
return s.replace(/a|e|i|o|u|U/, (match) => {
|
||||||
const r = accentReplacer.find((x) => x.vowel === match);
|
const r = accentReplacer.find((x) => x.vowel === match);
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
|
@ -112,6 +112,14 @@ function accentSyllable(s: string): string {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function accentPsSyllable(ps: T.PsString): T.PsString {
|
||||||
|
return {
|
||||||
|
p: ps.p,
|
||||||
|
f: accentSyllable(ps.f),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function removeAccentsWLength(s: T.SingleOrLengthOpts<T.PsString[]>): T.SingleOrLengthOpts<T.PsString[]> {
|
export function removeAccentsWLength(s: T.SingleOrLengthOpts<T.PsString[]>): T.SingleOrLengthOpts<T.PsString[]> {
|
||||||
if ("long" in s) {
|
if ("long" in s) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import * as T from "../../../types";
|
||||||
|
import { accentOnFront } from "../accent-helpers";
|
||||||
|
import { countSyllables } from "../accent-helpers";
|
||||||
|
import { concatPsString, trimOffPs } from "../p-text-helpers";
|
||||||
|
|
||||||
|
export function inflectPattern1(ps: T.PsString, { gender, number }: T.GenderNumber): T.PsString[] {
|
||||||
|
if (gender === "masc") {
|
||||||
|
return [ps];
|
||||||
|
}
|
||||||
|
const inflected = concatPsString(ps, number === "singular" ? { p: "ه", f: "a" } : { p: "ې", f: "e" });
|
||||||
|
if (countSyllables(inflected) === 2) {
|
||||||
|
return [accentOnFront(inflected)];
|
||||||
|
}
|
||||||
|
return [inflected];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function inflectPattern3(ps: T.PsString, { gender, number }: T.GenderNumber): T.PsString[] {
|
||||||
|
if (gender === "masc") {
|
||||||
|
return number === "singular"
|
||||||
|
? [ps]
|
||||||
|
: [concatPsString(trimOffPs(ps, 1, 2), { p: "ي", f: "ee" })];
|
||||||
|
}
|
||||||
|
return [concatPsString(trimOffPs(ps, 1, 2), { p: "ې", f: "e" })];
|
||||||
|
}
|
|
@ -1,14 +1,11 @@
|
||||||
import * as T from "../../../types";
|
import * as T from "../../../types";
|
||||||
import {
|
import {
|
||||||
functionOnOptLengths,
|
|
||||||
getPersonInflectionsKey,
|
|
||||||
getVerbBlockPosFromPerson,
|
getVerbBlockPosFromPerson,
|
||||||
personGender,
|
personGender,
|
||||||
personIsPlural,
|
|
||||||
personNumber,
|
personNumber,
|
||||||
} from "../misc-helpers";
|
} from "../misc-helpers";
|
||||||
import {
|
import {
|
||||||
yulEndingInfinitive,
|
trimOffPs,
|
||||||
} from "../p-text-helpers";
|
} from "../p-text-helpers";
|
||||||
import {
|
import {
|
||||||
concatPsString,
|
concatPsString,
|
||||||
|
@ -21,19 +18,14 @@ import {
|
||||||
} from "../grammar-units";
|
} from "../grammar-units";
|
||||||
import { isKawulVerb, isAbilityTense, isPerfectTense, isTlulVerb } from "../type-predicates";
|
import { isKawulVerb, isAbilityTense, isPerfectTense, isTlulVerb } from "../type-predicates";
|
||||||
import { tenseHasBa } from "../phrase-building/vp-tools";
|
import { tenseHasBa } from "../phrase-building/vp-tools";
|
||||||
import { inflectYey } from "../pashto-inflector";
|
|
||||||
import {
|
|
||||||
getVerbInfo,
|
|
||||||
} from "../verb-info";
|
|
||||||
import { isPastTense } from "../phrase-building/vp-tools";
|
import { isPastTense } from "../phrase-building/vp-tools";
|
||||||
import { makePsString, removeFVarients } from "../accent-and-ps-utils";
|
import { makePsString, removeFVarients } from "../accent-and-ps-utils";
|
||||||
import { pashtoConsonants } from "../pashto-consonants";
|
import { pashtoConsonants } from "../pashto-consonants";
|
||||||
import { accentOnNFromEnd, removeAccents } from "../accent-helpers";
|
import { accentPsSyllable } from "../accent-helpers";
|
||||||
import { getRootStem as newGetRootStem } from "./roots-and-stems";
|
import { getRootStem } from "./roots-and-stems";
|
||||||
|
|
||||||
const kedulStatVerb: T.VerbEntry = {
|
// For the chart display of the results: base the length thing on the VBE at the end, if there are other
|
||||||
entry: {"ts":1581086654898,"i":11100,"p":"کېدل","f":"kedul","g":"kedul","e":"to become _____","r":2,"c":"v. intrans.","ssp":"ش","ssf":"sh","prp":"شول","prf":"shwul","pprtp":"شوی","pprtf":"shúwey","noOo":true,"ec":"become"} as T.VerbDictionaryEntry,
|
// length variations earlier in the blocks, flatten those into the variations
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Amazingly, the basic formula with the roots and stems from the basic verbs
|
// TODO: Amazingly, the basic formula with the roots and stems from the basic verbs
|
||||||
// works perfectly with stative compounds as well!
|
// works perfectly with stative compounds as well!
|
||||||
|
@ -56,302 +48,126 @@ export function renderVerb({ verb, tense, person, voice }: {
|
||||||
voice: T.Voice,
|
voice: T.Voice,
|
||||||
}): {
|
}): {
|
||||||
hasBa: boolean,
|
hasBa: boolean,
|
||||||
verbBlocks: T.VB[],
|
vbs: T.VerbRenderedOutput,
|
||||||
} {
|
} {
|
||||||
// TODO: check for transitivity with passive voice ??
|
// TODO: check for transitivity with passive voice ??
|
||||||
if (isPerfectTense(tense)) {
|
|
||||||
return getPerfectVBs({ verb, tense, person, voice });
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasBa = tenseHasBa(tense);
|
const hasBa = tenseHasBa(tense);
|
||||||
|
if (isPerfectTense(tense)) {
|
||||||
|
throw new Error("not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
const isPast = isPastTense(tense);
|
const isPast = isPastTense(tense);
|
||||||
const aspect = getAspect(tense);
|
const aspect = getAspect(tense);
|
||||||
const isAbility = isAbilityTense(tense);
|
const isAbility = isAbilityTense(tense);
|
||||||
const noPerfective = isAbility && (voice === "passive" || isTlulVerb(verb) || isKedul(verb));
|
const genderNumber = {
|
||||||
// console.log(newGetRootStem({
|
gender: personGender(person),
|
||||||
// verb,
|
number: personNumber(person),
|
||||||
// part: {
|
};
|
||||||
// rs: isPast ? "root" : "stem",
|
// #1 get the appropriate root / stem
|
||||||
// aspect,
|
console.log({ isAbility });
|
||||||
// },
|
const [vHead, rest] = getRootStem({
|
||||||
// type: "basic",
|
verb,
|
||||||
// person: undefined,
|
part: {
|
||||||
// }));
|
rs: isPast ? "root" : "stem",
|
||||||
const { perfectiveHead, rootStem } = getRootStem({
|
aspect,
|
||||||
verb, aspect, isPast, isAbility, person, voice, noPerfective,
|
},
|
||||||
});
|
type: isAbility ? "ability" : "basic",
|
||||||
const verbBlocks: T.VB[] = isAbility
|
genderNumber,
|
||||||
? getAbilityVerbBlocks({ isPast, person, root: rootStem, aspect, voice, noPerfective })
|
|
||||||
: voice === "passive"
|
|
||||||
? getPassiveVerbBlocks({ root: rootStem, tense, person })
|
|
||||||
: getBasicVerbBlock({
|
|
||||||
rootStem, person, isPast, verb, aspect,
|
|
||||||
});
|
});
|
||||||
|
// #2 add the verb ending to it
|
||||||
|
const ending = getEnding(person, isPast);
|
||||||
return {
|
return {
|
||||||
hasBa,
|
hasBa,
|
||||||
verbBlocks: [
|
vbs: [
|
||||||
...(!noPerfective && perfectiveHead)
|
vHead,
|
||||||
? [perfectiveHead] : [],
|
addEnding({
|
||||||
...verbBlocks,
|
rs: rest,
|
||||||
|
ending,
|
||||||
|
verb,
|
||||||
|
person,
|
||||||
|
pastThird: isPast && person === T.Person.ThirdSingMale,
|
||||||
|
aspect,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// const equative = equativeEndings[perfectTenseToEquative(tense)];
|
||||||
|
// const [row, col] = getVerbBlockPosFromPerson(person);
|
||||||
|
// const equativeBlock: T.EQ = {
|
||||||
|
// type: "EQ",
|
||||||
|
// person,
|
||||||
|
// ps: "long" in equative ? {
|
||||||
|
// long: equative.long[row][col],
|
||||||
|
// short: equative.short[row][col],
|
||||||
|
// } : equative[row][col],
|
||||||
|
// }
|
||||||
|
|
||||||
function getBasicVerbBlock({ rootStem, person, isPast, aspect, verb }: {
|
function addEnding({ verb, rs, ending, person, pastThird, aspect }: {
|
||||||
rootStem: T.SingleOrLengthOpts<T.PsString>,
|
rs: [T.VB, T.VBA] | [T.VBA],
|
||||||
person: T.Person,
|
|
||||||
isPast: boolean,
|
|
||||||
aspect: T.Aspect,
|
|
||||||
verb: T.VerbEntry,
|
|
||||||
}): [T.VA] {
|
|
||||||
const ending = getEnding(person, isPast);
|
|
||||||
return [{
|
|
||||||
type: "VA",
|
|
||||||
ps: addEnding({
|
|
||||||
rootStem, ending, person, isPast, verb, aspect,
|
|
||||||
}),
|
|
||||||
person,
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPassiveVerbBlocks({ root, tense, person }: {
|
|
||||||
root: T.SingleOrLengthOpts<T.PsString>,
|
|
||||||
tense: T.VerbTense,
|
|
||||||
person: T.Person,
|
|
||||||
}): T.VB[] {
|
|
||||||
/* istanbul ignore next */
|
|
||||||
if (!("long" in root)) {
|
|
||||||
throw new Error("should have length versions in roots for passive");
|
|
||||||
}
|
|
||||||
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 adjustedAspect = noPerfective ? "imperfective" : aspect;
|
|
||||||
if (voice === "passive") {
|
|
||||||
return [
|
|
||||||
weld(
|
|
||||||
{
|
|
||||||
type: "VI",
|
|
||||||
ps: [root.long],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "VI",
|
|
||||||
ps: addAbilityTailsToRs({
|
|
||||||
long: { p: "کېدل", f: "kedúl" },
|
|
||||||
short: { p: "کېد", f: "ked" },
|
|
||||||
}, adjustedAspect),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
shBlock,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
// TODO: this is redundant, we did it in another part of the program?
|
|
||||||
const verbBlock: T.VI = {
|
|
||||||
type: "VI",
|
|
||||||
ps: addAbilityTailsToRs(root, adjustedAspect),
|
|
||||||
};
|
|
||||||
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 getPerfectVBs({ verb, tense, person, voice }: {
|
|
||||||
verb: T.VerbEntry,
|
|
||||||
tense: T.PerfectTense,
|
|
||||||
person: T.Person,
|
|
||||||
voice: T.Voice,
|
|
||||||
}): { hasBa: boolean, verbBlocks: T.VB[] } {
|
|
||||||
const hasBa = tenseHasBa(tense);
|
|
||||||
const vInfo = getVerbInfo(verb.entry, verb.complement) as T.SimpleVerbInfo;
|
|
||||||
|
|
||||||
if (voice === "passive") {
|
|
||||||
const [pt, eq] = getKedulStatPerfect(person, tense);
|
|
||||||
const passiveRoot: T.VI = {
|
|
||||||
type: "VI",
|
|
||||||
ps: [fromPersInfls(vInfo.root.imperfective, person).long],
|
|
||||||
};
|
|
||||||
const welded: T.Welded = weld(passiveRoot, pt);
|
|
||||||
return {
|
|
||||||
hasBa,
|
|
||||||
verbBlocks: [welded, eq],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const equative = equativeEndings[perfectTenseToEquative(tense)];
|
|
||||||
const [row, col] = getVerbBlockPosFromPerson(person);
|
|
||||||
const equativeBlock: T.EQ = {
|
|
||||||
type: "EQ",
|
|
||||||
person,
|
|
||||||
ps: "long" in equative ? {
|
|
||||||
long: equative.long[row][col],
|
|
||||||
short: equative.short[row][col],
|
|
||||||
} : equative[row][col],
|
|
||||||
}
|
|
||||||
|
|
||||||
const participleBlock: T.PT = {
|
|
||||||
type: "PT",
|
|
||||||
gender: personGender(person),
|
|
||||||
number: personNumber(person),
|
|
||||||
ps: chooseParticipleInflection(inflectYey(fromPersInfls(vInfo.participle.past, person)), person)
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
hasBa,
|
|
||||||
verbBlocks: [participleBlock, equativeBlock],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function weld(left: T.VI, right: T.VA | T.PT | T.VI): T.Welded {
|
|
||||||
return {
|
|
||||||
type: "welded",
|
|
||||||
left: {
|
|
||||||
...left,
|
|
||||||
ps: functionOnOptLengths(left.ps, removeAccents),
|
|
||||||
},
|
|
||||||
right,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRootStem({ verb, aspect, isPast, isAbility, voice, person, noPerfective }: {
|
|
||||||
verb: T.VerbEntry,
|
|
||||||
aspect: T.Aspect,
|
|
||||||
isPast: boolean,
|
|
||||||
isAbility: boolean,
|
|
||||||
person: T.Person,
|
|
||||||
voice: T.Voice,
|
|
||||||
noPerfective: boolean,
|
|
||||||
}): {
|
|
||||||
perfectiveHead: undefined | T.PH,
|
|
||||||
rootStem: T.SingleOrLengthOpts<T.PsString>,
|
|
||||||
} {
|
|
||||||
const vInfo = getVerbInfo(verb.entry, verb.complement) as T.SimpleVerbInfo;
|
|
||||||
const rs = vInfo[(isPast || isAbility || voice === "passive") ? "root" : "stem"];
|
|
||||||
if (noPerfective) {
|
|
||||||
// exception with tlul verbs for ability stems
|
|
||||||
return {
|
|
||||||
perfectiveHead: undefined,
|
|
||||||
rootStem: fromPersInfls(rs.imperfective, person),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (aspect === "perfective" && rs.perfectiveSplit) {
|
|
||||||
return extractPerfectiveSplit(rs.perfectiveSplit);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
perfectiveHead: undefined,
|
|
||||||
// because the persInfs only happen with stative compound verbs,j
|
|
||||||
// which we are handling differently now
|
|
||||||
rootStem: fromPersInfls(rs[aspect], person),
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractPerfectiveSplit(splitInfo: T.SplitInfo): ReturnType<typeof getRootStem> {
|
|
||||||
// this is just for tlul and Daredul ?
|
|
||||||
const si = fromPersInfls(splitInfo, person);
|
|
||||||
if ("long" in si) {
|
|
||||||
return {
|
|
||||||
perfectiveHead: {
|
|
||||||
type: "PH",
|
|
||||||
ps: fromPersInfls(si.long[0], person),
|
|
||||||
},
|
|
||||||
rootStem: {
|
|
||||||
long: si.long[1],
|
|
||||||
short: si.short[1],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
perfectiveHead: {
|
|
||||||
type: "PH",
|
|
||||||
// should only need this for tlul and Daaredul?
|
|
||||||
ps: fromPersInfls(si[0], person),
|
|
||||||
},
|
|
||||||
rootStem: si[1],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addEnding({ rootStem, ending, person, isPast, verb, aspect }:{
|
|
||||||
rootStem: T.SingleOrLengthOpts<T.PsString>,
|
|
||||||
ending: T.SingleOrLengthOpts<T.PsString[]>,
|
ending: T.SingleOrLengthOpts<T.PsString[]>,
|
||||||
person: T.Person,
|
person: T.Person,
|
||||||
isPast: boolean,
|
|
||||||
verb: T.VerbEntry,
|
verb: T.VerbEntry,
|
||||||
|
pastThird: boolean,
|
||||||
aspect: T.Aspect,
|
aspect: T.Aspect,
|
||||||
}): T.SingleOrLengthOpts<T.PsString[]> {
|
}): [T.VB, T.VBE] | [T.VBE] {
|
||||||
// TODO: no need for useless abbreviation now
|
return rs.length === 2
|
||||||
const rs = rootStem;
|
? [rs[0], addEnd(rs[1], ending)]
|
||||||
const end = ending;
|
: [addEnd(rs[0], ending)];
|
||||||
const idiosyncratic3rdPast = isPast && person === T.Person.ThirdSingMale;
|
function addEnd(vba: T.VBA, ending: T.SingleOrLengthOpts<T.PsString[]>): T.VBE {
|
||||||
const safeEndAdd = (rs: T.PsString) => (ending: T.PsString): T.PsString => (
|
if (vba.type === "welded") {
|
||||||
(ending.p === "ل" && rs.p.slice(-1) === "ل")
|
return {
|
||||||
? rs
|
...vba,
|
||||||
: concatPsString(rs, ending)
|
right: addToVBBasicEnd(vba.right, ending),
|
||||||
);
|
person,
|
||||||
if ("long" in rs) {
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...addToVBBasicEnd(vba, ending),
|
||||||
|
person,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function addToVBBasicEnd(vb: T.VBBasic, end: T.SingleOrLengthOpts<T.PsString[]>): T.VBBasic {
|
||||||
|
if ("long" in vb.ps) {
|
||||||
const endLong = getLength(end, "long");
|
const endLong = getLength(end, "long");
|
||||||
const endShort = getLength(end, "short");
|
const endShort = getLength(end, "short");
|
||||||
const shortForm = idiosyncratic3rdPast
|
// TODO: this is hacky
|
||||||
? ensure3rdPast(endShort, rs.short, verb, aspect)
|
const rsLong: T.PsString[] = vb.ps.long[0].f === "tlul"
|
||||||
: endShort.map(e => concatPsString(rs.short, e));
|
? [{ p: "تلل", f: "tlúl" }]
|
||||||
// TODO: this is a bit hacky
|
: vb.ps.long;
|
||||||
const rsLong = rs.long.f === "tlul"
|
|
||||||
? { p: "تلل", f: "tlúl" }
|
|
||||||
: rs.long;
|
|
||||||
return {
|
return {
|
||||||
long: endLong.map(safeEndAdd(rsLong)),
|
...vb,
|
||||||
short: aspect === "imperfective"
|
ps: {
|
||||||
? applyImperfectiveShortAccent(shortForm, yulEndingInfinitive(removeFVarients(verb.entry)))
|
long: verbEndingConcat(rsLong, endLong),
|
||||||
: shortForm,
|
short: pastThird
|
||||||
|
? ensure3rdPast(endShort, vb.ps.short, verb, aspect)
|
||||||
|
: verbEndingConcat(vb.ps.short, endShort),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if ("long" in end) {
|
if ("long" in end) {
|
||||||
throw new Error("should not be using verb stems with long and short endings");
|
throw new Error("should not be using verb stems with long and short endings");
|
||||||
}
|
}
|
||||||
return end.map((e) => concatPsString(rs, e));
|
return {
|
||||||
|
...vb,
|
||||||
|
ps: verbEndingConcat(vb.ps, end),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function verbEndingConcat(ps: T.PsString[], end: T.PsString[]): T.PsString[] {
|
||||||
|
return ps.flatMap(v => (
|
||||||
|
end.map(e => {
|
||||||
|
if (v.f.charAt(v.f.length-1) === "X") {
|
||||||
|
return concatPsString(trimOffPs(v, 0, 1), accentPsSyllable(e))
|
||||||
|
}
|
||||||
|
if (e.p === "ل" && ["ul", "úl"].includes(v.f.slice(-2))) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
return concatPsString(v, e);
|
||||||
|
})
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEnding(person: T.Person, isPast: boolean) {
|
function getEnding(person: T.Person, isPast: boolean) {
|
||||||
|
@ -362,53 +178,12 @@ function getEnding(person: T.Person, isPast: boolean) {
|
||||||
} : presentEndings[row][col];
|
} : presentEndings[row][col];
|
||||||
}
|
}
|
||||||
|
|
||||||
function chooseParticipleInflection(pinf: T.SingleOrLengthOpts<T.UnisexInflections>, p: T.Person): T.SingleOrLengthOpts<T.PsString[]> {
|
// TODO: THIS IS PROBABLY SKEEEETCH
|
||||||
if ("long" in pinf) {
|
function ensure3rdPast(ending: T.PsString[], rs: T.PsString[], verb: T.VerbEntry, aspect: T.Aspect): T.PsString[] {
|
||||||
return {
|
if (isKedul(verb) && rs[0].p === "شو") {
|
||||||
short: chooseParticipleInflection(pinf.short, p) as T.PsString[],
|
|
||||||
long: chooseParticipleInflection(pinf.long, p) as T.PsString[],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const gender = personGender(p);
|
|
||||||
const infNum = personIsPlural(p) ? 1 : 0;
|
|
||||||
return pinf[gender][infNum];
|
|
||||||
}
|
|
||||||
|
|
||||||
function addAbilityTailsToRs(rs: T.LengthOptions<T.PsString>, aspect: T.Aspect): T.SingleOrLengthOpts<T.PsString[]> {
|
|
||||||
const tails: T.PsString[] = [
|
|
||||||
{ p: "ی", f: "ey" },
|
|
||||||
{ p: "ای", f: "aay" },
|
|
||||||
];
|
|
||||||
const accentedTails: T.PsString[] = [
|
|
||||||
{ p: "ی", f: "éy" },
|
|
||||||
{ p: "ای", f: "áay" },
|
|
||||||
];
|
|
||||||
// for single syllable long verb stems like tlul - ensure the accent
|
|
||||||
const psLong = (aspect === "perfective")
|
|
||||||
? removeAccents(rs.long)
|
|
||||||
: ensureAccentLongStem(rs.long);
|
|
||||||
return {
|
|
||||||
long: tails.map(t => concatPsString(psLong, t)),
|
|
||||||
short: (aspect === "perfective" ? tails : accentedTails)
|
|
||||||
.map(t => concatPsString(rs.short, t)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyImperfectiveShortAccent(form: T.PsString[], yulEnding: boolean): T.PsString[] {
|
|
||||||
// TODO: remove this hack - get proper working thing for accentOnNFromEnd not adding accent on 1 syllable words
|
|
||||||
if (form[0].f === "tu") {
|
|
||||||
return form;
|
|
||||||
}
|
|
||||||
return form.map(f => {
|
|
||||||
return accentOnNFromEnd(f, yulEnding ? 1 : 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensure3rdPast(ending: T.PsString[], rs: T.PsString, verb: T.VerbEntry, aspect: T.Aspect): T.PsString[] {
|
|
||||||
if (isKedul(verb) && rs.p === "شو") {
|
|
||||||
return [{ p: "شو", f: "sho" }];
|
return [{ p: "شو", f: "sho" }];
|
||||||
}
|
}
|
||||||
if (isKawulVerb(verb) && rs.p === "کړ") {
|
if (isKawulVerb(verb) && rs[0].p === "کړ") {
|
||||||
return [
|
return [
|
||||||
{ p: "کړ", f: "kuR" },
|
{ p: "کړ", f: "kuR" },
|
||||||
{ p: "کړه", f: "kRu" },
|
{ p: "کړه", f: "kRu" },
|
||||||
|
@ -420,12 +195,12 @@ function ensure3rdPast(ending: T.PsString[], rs: T.PsString, verb: T.VerbEntry,
|
||||||
return [{ p: "غی", f: "ghey" }];
|
return [{ p: "غی", f: "ghey" }];
|
||||||
}
|
}
|
||||||
const specialTuShort: T.PsString = {
|
const specialTuShort: T.PsString = {
|
||||||
p: rs.p.slice(0, -1) + "ه",
|
p: rs[0].p.slice(0, -1) + "ه",
|
||||||
f: rs.f.slice(0, -1) + (rs.f === "tl" ? "u" : "ú"),
|
f: rs[0].f.slice(0, -1) + (rs[0].f === "tl" ? "u" : "ú"),
|
||||||
};
|
};
|
||||||
return [
|
return [
|
||||||
specialTuShort,
|
specialTuShort,
|
||||||
concatPsString(rs, { p: "و", f: "o" }),
|
concatPsString(rs[0], { p: "و", f: "o" }),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if (verb.entry.tppp && verb.entry.tppf) {
|
if (verb.entry.tppp && verb.entry.tppf) {
|
||||||
|
@ -448,15 +223,15 @@ function ensure3rdPast(ending: T.PsString[], rs: T.PsString, verb: T.VerbEntry,
|
||||||
);
|
);
|
||||||
// TODO: check about verbs like tawul (if they exist)
|
// TODO: check about verbs like tawul (if they exist)
|
||||||
if (endsInAwul) {
|
if (endsInAwul) {
|
||||||
const base = { p: rs.p.slice(0, -1), f: rs.f.slice(0, -2) };
|
const base = { p: rs[0].p.slice(0, -1), f: rs[0].f.slice(0, -2) };
|
||||||
return [concatPsString(base, { p: "اوه", f: "aawu" })];
|
return [concatPsString(base, { p: "اوه", f: "aawu" })];
|
||||||
}
|
}
|
||||||
const endsInDental = ["د", "ت"].includes(rs.p.slice(-1));
|
const endsInDental = ["د", "ت"].includes(rs[0].p.slice(-1));
|
||||||
// short endings like ورسېد
|
// short endings like ورسېد
|
||||||
return (endsInDental ? [
|
return (endsInDental ? [
|
||||||
"",
|
"",
|
||||||
...ending,
|
...ending,
|
||||||
] : ending).map(e => concatPsString(rs, e));
|
] : ending).map(e => concatPsString(rs[0], e));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAspect(tense: T.VerbTense | T.AbilityTense): T.Aspect {
|
function getAspect(tense: T.VerbTense | T.AbilityTense): T.Aspect {
|
||||||
|
@ -472,34 +247,6 @@ function isKedul(v: T.VerbEntry): boolean {
|
||||||
return v.entry.p === "کېدل";
|
return v.entry.p === "کېدل";
|
||||||
}
|
}
|
||||||
|
|
||||||
function fromPersInfls<U extends object>(x: T.OptionalPersonInflections<U>, person: T.Person): U {
|
|
||||||
if ("mascSing" in x) {
|
|
||||||
return x[getPersonInflectionsKey(person)];
|
|
||||||
} else {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensureAccentLongStem(ps: T.PsString): T.PsString {
|
|
||||||
if (ps.f.charAt(ps.f.length - 2) === "ú") {
|
|
||||||
return ps;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
p: ps.p,
|
|
||||||
f: ps.f.slice(0, -2) + "úl",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getKedulStatPerfect(person: T.Person, tense: T.PerfectTense): [T.PT, T.EQ] {
|
|
||||||
const { verbBlocks: [pt, eq] } = renderVerb({
|
|
||||||
verb: kedulStatVerb,
|
|
||||||
tense,
|
|
||||||
person,
|
|
||||||
voice: "active",
|
|
||||||
}) as { hasBa: true, verbBlocks: [T.PT, T.EQ] };
|
|
||||||
return [pt, eq];
|
|
||||||
}
|
|
||||||
|
|
||||||
function perfectTenseToEquative(t: T.PerfectTense): keyof typeof equativeEndings {
|
function perfectTenseToEquative(t: T.PerfectTense): keyof typeof equativeEndings {
|
||||||
return t === "presentPerfect"
|
return t === "presentPerfect"
|
||||||
? "present"
|
? "present"
|
||||||
|
|
|
@ -29,7 +29,7 @@ const ooPh: T.PH = {
|
||||||
ps: { p: "و", f: "óo" },
|
ps: { p: "و", f: "óo" },
|
||||||
};
|
};
|
||||||
|
|
||||||
type TestGroup = {
|
type RootsAndStemsTestGroup = {
|
||||||
verb: T.VerbEntry,
|
verb: T.VerbEntry,
|
||||||
result: Record<"stem" | "root", {
|
result: Record<"stem" | "root", {
|
||||||
imperfective: T.RootStemOutput,
|
imperfective: T.RootStemOutput,
|
||||||
|
@ -37,9 +37,9 @@ type TestGroup = {
|
||||||
}>
|
}>
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
const tests: {
|
const rootsAndStemsTests: {
|
||||||
title: string,
|
title: string,
|
||||||
testGroup: TestGroup,
|
testGroup: RootsAndStemsTestGroup,
|
||||||
}[] =
|
}[] =
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -901,14 +901,20 @@ const tests: {
|
||||||
verb: kawulStat,
|
verb: kawulStat,
|
||||||
result: {
|
result: {
|
||||||
"stem": {
|
"stem": {
|
||||||
"perfective": [
|
"perfective": [{
|
||||||
[
|
long: [
|
||||||
{
|
{
|
||||||
"p": "کړ",
|
"p": "کړ",
|
||||||
"f": "kR"
|
"f": "kR"
|
||||||
}
|
}
|
||||||
]
|
|
||||||
],
|
],
|
||||||
|
short: [
|
||||||
|
{
|
||||||
|
p: "ک",
|
||||||
|
f: "k",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
"imperfective": [
|
"imperfective": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -932,7 +938,13 @@ const tests: {
|
||||||
"p": "کړ",
|
"p": "کړ",
|
||||||
"f": "kR"
|
"f": "kR"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"mini": [
|
||||||
|
{
|
||||||
|
"p": "ک",
|
||||||
|
"f": "k",
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"imperfective": [
|
"imperfective": [
|
||||||
|
@ -966,12 +978,17 @@ const tests: {
|
||||||
"f": "óo",
|
"f": "óo",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
{
|
||||||
|
long: [
|
||||||
{
|
{
|
||||||
"p": "کړ",
|
"p": "کړ",
|
||||||
"f": "kR"
|
"f": "kR"
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
|
short: [
|
||||||
|
{ p: "ک", f: "k" },
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
"imperfective": [
|
"imperfective": [
|
||||||
[
|
[
|
||||||
|
@ -1003,8 +1020,11 @@ const tests: {
|
||||||
"p": "کړ",
|
"p": "کړ",
|
||||||
"f": "kR"
|
"f": "kR"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
}
|
"mini": [
|
||||||
|
{ p: "ک", f: "k" },
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
"imperfective": [
|
"imperfective": [
|
||||||
{
|
{
|
||||||
|
@ -1029,7 +1049,7 @@ const tests: {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
tests.forEach(({ title, testGroup }) => {
|
rootsAndStemsTests.forEach(({ title, testGroup }) => {
|
||||||
test(title, () => {
|
test(title, () => {
|
||||||
testGroup.forEach(({ verb, result }) => {
|
testGroup.forEach(({ verb, result }) => {
|
||||||
expect(getAllRs(verb)).toEqual(result);
|
expect(getAllRs(verb)).toEqual(result);
|
||||||
|
|
|
@ -7,47 +7,83 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
concatPsString,
|
concatPsString, trimOffPs,
|
||||||
} from "../p-text-helpers";
|
} from "../p-text-helpers";
|
||||||
import * as T from "../../../types";
|
import * as T from "../../../types";
|
||||||
import { makePsString, removeFVarientsFromVerb } from "../accent-and-ps-utils";
|
import { makePsString, removeFVarientsFromVerb } from "../accent-and-ps-utils";
|
||||||
import { accentOnNFromEnd, removeAccents } from "../accent-helpers";
|
import { accentOnNFromEnd, accentSyllable, removeAccents } from "../accent-helpers";
|
||||||
import { assertNever } from "../assert-never";
|
import { isKawulVerb } from "../type-predicates";
|
||||||
|
import { inflectPattern1 } from "./new-inflectors";
|
||||||
|
|
||||||
export function getRootStem({ verb, part, type, person }: {
|
const shwulVB: T.VBBasic = {
|
||||||
|
type: "VB",
|
||||||
|
ps: {
|
||||||
|
long: [{ p: "شول", f: "shwul" }],
|
||||||
|
short: [{ p: "شو", f: "shw" }],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// start basic inflection functions for pattern 1 and pattern ey things
|
||||||
|
// to be used by inflecting لاړ and participles
|
||||||
|
|
||||||
|
export function getRootStem({ verb, part, type, genderNumber }: {
|
||||||
verb: T.VerbEntry,
|
verb: T.VerbEntry,
|
||||||
part: {
|
part: {
|
||||||
rs: "root" | "stem",
|
rs: "root" | "stem",
|
||||||
aspect: T.Aspect,
|
aspect: T.Aspect,
|
||||||
} | {
|
} | "pastPart",
|
||||||
participle: "present" | "past",
|
|
||||||
},
|
|
||||||
type: "basic" | "ability" | "passive",
|
type: "basic" | "ability" | "passive",
|
||||||
person: {
|
genderNumber: {
|
||||||
gender: T.Gender,
|
gender: T.Gender,
|
||||||
number: T.NounNumber,
|
number: T.NounNumber,
|
||||||
} | undefined,
|
},
|
||||||
}): T.RootStemOutput {
|
}): T.RootsStemsOutput {
|
||||||
|
console.log({ type });
|
||||||
const v = removeFVarientsFromVerb(verb);
|
const v = removeFVarientsFromVerb(verb);
|
||||||
if ("participle" in part) {
|
if (part === "pastPart") {
|
||||||
return [];
|
throw new Error("not implemented yet");
|
||||||
}
|
}
|
||||||
|
console.log({ part });
|
||||||
return part.rs === "stem"
|
return part.rs === "stem"
|
||||||
? getStem(v, part.aspect)
|
? part.aspect === "imperfective"
|
||||||
: getRoot(v, part.aspect);
|
? getImperfectiveStem(v)
|
||||||
|
: getPerfectiveStem(v, genderNumber)
|
||||||
|
: part.aspect === "imperfective"
|
||||||
|
? getImperfectiveRoot(v, type)
|
||||||
|
: getPerfectiveRoot(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRoot(verb: T.VerbEntryNoFVars, aspect: T.Aspect): T.RootStemOutput {
|
function getImperfectiveRoot(verb: T.VerbEntryNoFVars, type: "basic" | "ability" | "passive"): T.RootsStemsOutput {
|
||||||
if (aspect === "imperfective") {
|
// if (type === "ability") {
|
||||||
|
// console.log("in ability");
|
||||||
|
// const basic = getImperfectiveRoot(verb, "basic") as [[T.VHead] | [], [T.VBA]];
|
||||||
|
// return [
|
||||||
|
// basic[0],
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// type: "VB",
|
||||||
|
|
||||||
|
// [1],
|
||||||
|
// shwulVB,
|
||||||
|
// ],
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
const infinitive = accentOnNFromEnd(makePsString(verb.entry.p, verb.entry.f), 0);
|
const infinitive = accentOnNFromEnd(makePsString(verb.entry.p, verb.entry.f), 0);
|
||||||
return [
|
return [
|
||||||
|
[],
|
||||||
|
[
|
||||||
{
|
{
|
||||||
|
type: "VB",
|
||||||
|
ps: {
|
||||||
long: [infinitive],
|
long: [infinitive],
|
||||||
short: [addTrailingAccent(removeL(infinitive))],
|
short: [addTrailingAccent(removeL(infinitive))],
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// aspect === "perfective"
|
|
||||||
|
function getPerfectiveRoot(verb: T.VerbEntryNoFVars): T.RootsStemsOutput {
|
||||||
const base = removeAccents(
|
const base = removeAccents(
|
||||||
(verb.entry.prp && verb.entry.prf)
|
(verb.entry.prp && verb.entry.prf)
|
||||||
? makePsString(verb.entry.prp, verb.entry.prf)
|
? makePsString(verb.entry.prp, verb.entry.prf)
|
||||||
|
@ -55,38 +91,68 @@ function getRoot(verb: T.VerbEntryNoFVars, aspect: T.Aspect): T.RootStemOutput {
|
||||||
);
|
);
|
||||||
const [perfectiveHead, rest] = getPerfectiveHead(base, verb);
|
const [perfectiveHead, rest] = getPerfectiveHead(base, verb);
|
||||||
return [
|
return [
|
||||||
...perfectiveHead ? [perfectiveHead] : [],
|
perfectiveHead ? [perfectiveHead] : [],
|
||||||
|
[
|
||||||
{
|
{
|
||||||
|
type: "VB",
|
||||||
|
ps: {
|
||||||
long: [rest],
|
long: [rest],
|
||||||
short: [removeL(rest)],
|
short: [removeL(rest)],
|
||||||
|
...isKawulVerb(verb) ? {
|
||||||
|
mini: [{ p: "ک", f: "k" }],
|
||||||
|
} : {},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStem(verb: T.VerbEntryNoFVars, aspect: T.Aspect): T.RootStemOutput {
|
function getImperfectiveStem(verb: T.VerbEntryNoFVars): T.RootsStemsOutput {
|
||||||
if (aspect === "imperfective") {
|
|
||||||
if (verb.entry.psp && verb.entry.psf) {
|
if (verb.entry.psp && verb.entry.psf) {
|
||||||
return [[makePsString(verb.entry.psp, verb.entry.psf)]];
|
return [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: "VB",
|
||||||
|
ps: [makePsString(verb.entry.psp, verb.entry.psf)],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
const rawBase = removeL(makePsString(verb.entry.p, verb.entry.f));
|
const rawBase = removeL(makePsString(verb.entry.p, verb.entry.f));
|
||||||
if (verb.entry.c?.includes("intrans.") && rawBase.p.endsWith("ېد")) {
|
if (verb.entry.c?.includes("intrans.") && rawBase.p.endsWith("ېد")) {
|
||||||
const long: T.PsString[] = [{
|
const shortBase = trimOffPs(rawBase, 1, 2);
|
||||||
p: rawBase.p.slice(0, -1) + "ږ",
|
const long: T.PsString[] = [concatPsString(
|
||||||
f: rawBase.f.slice(0, -2) + "éG",
|
shortBase,
|
||||||
}];
|
{ p: "ږ", f: "éG" },
|
||||||
|
)];
|
||||||
const short: T.PsString[] | undefined = (verb.entry.shortIntrans)
|
const short: T.PsString[] | undefined = (verb.entry.shortIntrans)
|
||||||
? [{
|
? [shortBase]
|
||||||
p: rawBase.p.slice(0, -2),
|
|
||||||
f: rawBase.f.slice(0, -2),
|
|
||||||
}]
|
|
||||||
: undefined;
|
: undefined;
|
||||||
return short ? [{ long, short }] : [long]
|
const vb: T.VB = {
|
||||||
}
|
type: "VB",
|
||||||
|
ps: short ? { long, short } : long,
|
||||||
|
};
|
||||||
return [
|
return [
|
||||||
[rawBase],
|
[],
|
||||||
|
[vb],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if (aspect === "perfective") {
|
return [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: "VB",
|
||||||
|
ps: [rawBase],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPerfectiveStem(verb: T.VerbEntryNoFVars, person: { gender: T.Gender, number: T.NounNumber }): T.RootsStemsOutput {
|
||||||
|
if (verb.entry.f === "tlul") {
|
||||||
|
return tlulPerfectiveStem(person);
|
||||||
|
}
|
||||||
const base = (verb.entry.ssp && verb.entry.ssf)
|
const base = (verb.entry.ssp && verb.entry.ssf)
|
||||||
// with irregular perfective stem
|
// with irregular perfective stem
|
||||||
? makePsString(verb.entry.ssp, verb.entry.ssf)
|
? makePsString(verb.entry.ssp, verb.entry.ssf)
|
||||||
|
@ -97,24 +163,36 @@ function getStem(verb: T.VerbEntryNoFVars, aspect: T.Aspect): T.RootStemOutput {
|
||||||
: removeL(makePsString(verb.entry.p, verb.entry.f));
|
: removeL(makePsString(verb.entry.p, verb.entry.f));
|
||||||
const [perfectiveHead, rest] = getPerfectiveHead(base, verb);
|
const [perfectiveHead, rest] = getPerfectiveHead(base, verb);
|
||||||
return [
|
return [
|
||||||
...perfectiveHead ? [perfectiveHead] : [],
|
perfectiveHead ? [perfectiveHead] : [],
|
||||||
[rest],
|
[
|
||||||
|
{
|
||||||
|
type: "VB",
|
||||||
|
ps: isKawulVerb(verb) ? {
|
||||||
|
long: [{ p: "کړ", f: "kR" }],
|
||||||
|
short: [{ p: "ک", f: "k" }],
|
||||||
|
} : [rest],
|
||||||
|
},
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPerfectiveHead(base: T.PsString, { entry }: T.VerbEntry): [T.PH, T.PsString] | [undefined, T.PsString] {
|
// function getPastPart(verb: T.VerbEntryNoFVars, person: { gender: T.Gender, number: T.NounNumber }): T.SingleOrLengthOpts<T.PsString> {
|
||||||
|
// const root = getImperfectiveRoot(verb);
|
||||||
|
// // TODO: with new inflection engine more streamlined
|
||||||
|
// return inflectRoot
|
||||||
|
// }
|
||||||
|
|
||||||
|
function getPerfectiveHead(base: T.PsString, { entry }: T.VerbEntryNoFVars): [T.PH, T.PsString] | [undefined, T.PsString] {
|
||||||
// if ((verb.entry.ssp && verb.entry.ssf) || verb.entry.separationAtP) {
|
// if ((verb.entry.ssp && verb.entry.ssf) || verb.entry.separationAtP) {
|
||||||
// // handle split
|
// // handle split
|
||||||
// }
|
// }
|
||||||
if (entry.separationAtP && entry.separationAtF) {
|
if (entry.separationAtP && entry.separationAtF) {
|
||||||
const ph: T.PH = {
|
const ph: T.PH = {
|
||||||
type: "PH",
|
type: "PH",
|
||||||
ps: accentOnNFromEnd({
|
ps: {
|
||||||
p: base.p.slice(0, entry.separationAtP),
|
p: base.p.slice(0, entry.separationAtP),
|
||||||
f: base.f.slice(0, entry.separationAtF),
|
f: accentSyllable(base.f.slice(0, entry.separationAtF)),
|
||||||
}, 0),
|
},
|
||||||
};
|
};
|
||||||
const rest = {
|
const rest = {
|
||||||
p: base.p.slice(entry.separationAtP),
|
p: base.p.slice(entry.separationAtP),
|
||||||
|
@ -195,8 +273,22 @@ function addUl(b: T.PsString): T.PsString {
|
||||||
// TODO: could do removeEndingL (slower but safer)
|
// TODO: could do removeEndingL (slower but safer)
|
||||||
|
|
||||||
function removeL(ps: T.PsString): T.PsString {
|
function removeL(ps: T.PsString): T.PsString {
|
||||||
return {
|
return trimOffPs(ps, 1, 2);
|
||||||
p: ps.p.slice(0, -1),
|
}
|
||||||
f: ps.f.slice(0, -2),
|
|
||||||
};
|
function tlulPerfectiveStem(person: { gender: T.Gender, number: T.NounNumber }): T.RootsStemsOutput {
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: "PH",
|
||||||
|
ps: inflectPattern1({ p: "لاړ", f: "laaR" }, person).map(x => concatPsString(x, " "))[0],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: "VB",
|
||||||
|
ps: [{ p: "ش", f: "sh" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
}
|
}
|
|
@ -12,22 +12,22 @@ export function vEntry(e: any, c?: any): T.VerbEntry {
|
||||||
|
|
||||||
export function getAllRs(verb: T.VerbEntry): {
|
export function getAllRs(verb: T.VerbEntry): {
|
||||||
stem: {
|
stem: {
|
||||||
perfective: T.RootStemOutput,
|
perfective: T.RootsStemsOutput,
|
||||||
imperfective: T.RootStemOutput,
|
imperfective: T.RootsStemsOutput,
|
||||||
},
|
},
|
||||||
root: {
|
root: {
|
||||||
perfective: T.RootStemOutput,
|
perfective: T.RootsStemsOutput,
|
||||||
imperfective: T.RootStemOutput,
|
imperfective: T.RootsStemsOutput,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
stem: {
|
stem: {
|
||||||
perfective: getRootStem({ verb, type: "basic", part: { rs: "stem", aspect: "perfective" }, person: undefined }),
|
perfective: getRootStem({ verb, type: "basic", part: { rs: "stem", aspect: "perfective" }, genderNumber: { gender: "masc", number: "singular" } }),
|
||||||
imperfective: getRootStem({ verb, type: "basic", part: { rs: "stem", aspect: "imperfective" }, person: undefined }),
|
imperfective: getRootStem({ verb, type: "basic", part: { rs: "stem", aspect: "imperfective" }, genderNumber: { gender: "masc", number: "singular" } }),
|
||||||
},
|
},
|
||||||
root: {
|
root: {
|
||||||
perfective: getRootStem({ verb, type: "basic", part: { rs: "root", aspect: "perfective" }, person: undefined }),
|
perfective: getRootStem({ verb, type: "basic", part: { rs: "root", aspect: "perfective" }, genderNumber: { gender: "masc", number: "singular" } }),
|
||||||
imperfective: getRootStem({ verb, type: "basic", part: { rs: "root", aspect: "imperfective" }, person: undefined }),
|
imperfective: getRootStem({ verb, type: "basic", part: { rs: "root", aspect: "imperfective" }, genderNumber: { gender: "masc", number: "singular" } }),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -24,6 +24,7 @@ import {
|
||||||
endsInShwa,
|
endsInShwa,
|
||||||
splitPsByVarients,
|
splitPsByVarients,
|
||||||
endsWith,
|
endsWith,
|
||||||
|
trimOffPs,
|
||||||
} from "./p-text-helpers";
|
} from "./p-text-helpers";
|
||||||
import * as T from "../../types";
|
import * as T from "../../types";
|
||||||
import {
|
import {
|
||||||
|
@ -704,6 +705,15 @@ test(`splitDoubleWord should work`, () => {
|
||||||
expect(splitDoubleWord(removeFVarients(orig))).toEqual(out);
|
expect(splitDoubleWord(removeFVarients(orig))).toEqual(out);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("trimOffPs should word", () => {
|
||||||
|
expect(trimOffPs({ p: "لیدل", f: "leedúl" }, 1, 2))
|
||||||
|
.toEqual({ p: "لید", f: "leed" });
|
||||||
|
expect(trimOffPs({ p: "کور", f: "kor" }, 2, 2))
|
||||||
|
.toEqual({ p: "ک", f: "k" });
|
||||||
|
expect(trimOffPs({ p: "کور", f: "kor" }, 0, 0))
|
||||||
|
.toEqual({ p: "کور", f: "kor" });
|
||||||
|
});
|
||||||
|
|
||||||
// test(`allThirdPersMascPlur should work`, () => {
|
// test(`allThirdPersMascPlur should work`, () => {
|
||||||
// expect(
|
// expect(
|
||||||
// allThirdPersMascPlur([
|
// allThirdPersMascPlur([
|
||||||
|
|
|
@ -88,6 +88,22 @@ export function concatPsString(...items: Array<T.PsString | T.LengthOptions<T.Ps
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trims off a given amount of characters of p and f in a PsString
|
||||||
|
* (also removes any other fields in the object)
|
||||||
|
*
|
||||||
|
* @param ps
|
||||||
|
* @param pOff - number of characters of pashto script to remove from the end
|
||||||
|
* @param fOff - number of characters of phonetics to remove from the end
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function trimOffPs(ps: T.PsString, pOff: number, fOff: number): T.PsString {
|
||||||
|
return {
|
||||||
|
p: pOff === 0 ? ps.p : ps.p.slice(0, -pOff),
|
||||||
|
f: fOff === 0 ? ps.f : ps.f.slice(0, -fOff),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* breaks a dictionary entry with a double wording (ie. ګډ وډ) into two seperate words
|
* breaks a dictionary entry with a double wording (ie. ګډ وډ) into two seperate words
|
||||||
*
|
*
|
||||||
|
|
74
src/types.ts
74
src/types.ts
|
@ -1074,45 +1074,47 @@ export type MiniPronoun = {
|
||||||
np: NPSelection,
|
np: NPSelection,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type VB = PH | VA | VI | PT | EQ | Welded;
|
export type VerbRenderedOutput = [[VHead] | [], [VB, VBE] | [VBE]];
|
||||||
|
export type RootsStemsOutput = [[VHead] | [], [VB, VBA] | [VBA]]; // or perfect / equative
|
||||||
|
|
||||||
|
export type VB = VBBasic | VBGenNum | Welded;
|
||||||
|
export type VBA = Exclude<VB, VBGenNum>;
|
||||||
|
|
||||||
|
export type VBE = (VBBasic | Welded) & {
|
||||||
|
person: Person,
|
||||||
|
}; // or equative
|
||||||
|
|
||||||
|
export type VBBasic = {
|
||||||
|
type: "VB",
|
||||||
|
ps: SingleOrLengthOpts<PsString[]>,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type VBGenNum = VBBasic & GenderNumber;
|
||||||
|
|
||||||
|
export type GenderNumber = {
|
||||||
|
gender: Gender,
|
||||||
|
number: NounNumber,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Welded = {
|
||||||
|
type: "welded",
|
||||||
|
left: NComp | VBBasic | Welded,
|
||||||
|
right: VBBasic,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type VHead = PH | NComp;
|
||||||
|
|
||||||
/** perfective head block */
|
/** perfective head block */
|
||||||
export type PH = {
|
export type PH = {
|
||||||
type: "PH",
|
type: "PH",
|
||||||
ps: PsString,
|
ps: PsString,
|
||||||
} | {
|
};
|
||||||
type: "PHComp",
|
|
||||||
|
export type NComp = {
|
||||||
|
type: "NComp",
|
||||||
comp: Comp,
|
comp: Comp,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** verb block with person agreement */
|
|
||||||
export type VA = {
|
|
||||||
type: "VA",
|
|
||||||
ps: SingleOrLengthOpts<PsString[]>,
|
|
||||||
person: Person,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** invariable verb block */
|
|
||||||
export type VI = {
|
|
||||||
type: "VI",
|
|
||||||
ps: SingleOrLengthOpts<PsString[]>,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** participle block with inflection */
|
|
||||||
export type PT = {
|
|
||||||
type: "PT",
|
|
||||||
ps: SingleOrLengthOpts<PsString[]>,
|
|
||||||
gender: Gender,
|
|
||||||
number: NounNumber,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** equative block */
|
|
||||||
export type EQ = {
|
|
||||||
type: "EQ",
|
|
||||||
ps: SingleOrLengthOpts<PsString[]>,
|
|
||||||
person: Person,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Complement can be one of
|
// Complement can be one of
|
||||||
// - adjective
|
// - adjective
|
||||||
// - locative adv
|
// - locative adv
|
||||||
|
@ -1131,13 +1133,3 @@ export type Comp = {
|
||||||
type: "NounComp",
|
type: "NounComp",
|
||||||
ps: PsString,
|
ps: PsString,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** a veb block with a welded part having it's accents removed */
|
|
||||||
export type Welded = {
|
|
||||||
type: "welded",
|
|
||||||
/** accents must be removed from the left */
|
|
||||||
left: VI | Comp,
|
|
||||||
right: VA | PT | VI,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type RootStemOutput = (PH | SingleOrLengthOpts<PsString[]>)[];
|
|
||||||
|
|
Loading…
Reference in New Issue