more
This commit is contained in:
parent
1dbe0a42f4
commit
305fb545b9
|
@ -153,7 +153,7 @@ function VPBuilderDemo({ opts }: {
|
|||
person: testPerson.person,
|
||||
voice: testVoice,
|
||||
}) : 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">
|
||||
<div className="d-block mx-auto card" style={{ maxWidth: "700px", background: "var(--closer)"}}>
|
||||
<div className="card-body">
|
||||
|
@ -252,9 +252,12 @@ function VPBuilderDemo({ opts }: {
|
|||
role="subject"
|
||||
opts={opts}
|
||||
/>
|
||||
{/* <details>
|
||||
<summary>Roots and Stems</summary>
|
||||
<pre>
|
||||
{JSON.stringify(rs, null, " ")}
|
||||
</pre>
|
||||
</details> */}
|
||||
<pre>
|
||||
{JSON.stringify(rv, null, " ")}
|
||||
</pre>
|
||||
|
|
|
@ -104,7 +104,7 @@ const accentReplacer = [
|
|||
{ vowel: "U", accented: "Ú" },
|
||||
];
|
||||
|
||||
function accentSyllable(s: string): string {
|
||||
export function accentSyllable(s: string): string {
|
||||
return s.replace(/a|e|i|o|u|U/, (match) => {
|
||||
const r = accentReplacer.find((x) => x.vowel === match);
|
||||
/* 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[]> {
|
||||
if ("long" in s) {
|
||||
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 {
|
||||
functionOnOptLengths,
|
||||
getPersonInflectionsKey,
|
||||
getVerbBlockPosFromPerson,
|
||||
personGender,
|
||||
personIsPlural,
|
||||
personNumber,
|
||||
} from "../misc-helpers";
|
||||
import {
|
||||
yulEndingInfinitive,
|
||||
trimOffPs,
|
||||
} from "../p-text-helpers";
|
||||
import {
|
||||
concatPsString,
|
||||
|
@ -21,19 +18,14 @@ import {
|
|||
} from "../grammar-units";
|
||||
import { isKawulVerb, isAbilityTense, isPerfectTense, isTlulVerb } from "../type-predicates";
|
||||
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 { makePsString, removeFVarients } from "../accent-and-ps-utils";
|
||||
import { pashtoConsonants } from "../pashto-consonants";
|
||||
import { accentOnNFromEnd, removeAccents } from "../accent-helpers";
|
||||
import { getRootStem as newGetRootStem } from "./roots-and-stems";
|
||||
import { accentPsSyllable } from "../accent-helpers";
|
||||
import { getRootStem } from "./roots-and-stems";
|
||||
|
||||
const kedulStatVerb: T.VerbEntry = {
|
||||
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,
|
||||
};
|
||||
// For the chart display of the results: base the length thing on the VBE at the end, if there are other
|
||||
// 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
|
||||
// works perfectly with stative compounds as well!
|
||||
|
@ -56,302 +48,126 @@ export function renderVerb({ verb, tense, person, voice }: {
|
|||
voice: T.Voice,
|
||||
}): {
|
||||
hasBa: boolean,
|
||||
verbBlocks: T.VB[],
|
||||
vbs: T.VerbRenderedOutput,
|
||||
} {
|
||||
// TODO: check for transitivity with passive voice ??
|
||||
if (isPerfectTense(tense)) {
|
||||
return getPerfectVBs({ verb, tense, person, voice });
|
||||
}
|
||||
|
||||
const hasBa = tenseHasBa(tense);
|
||||
if (isPerfectTense(tense)) {
|
||||
throw new Error("not implemented yet");
|
||||
}
|
||||
|
||||
const isPast = isPastTense(tense);
|
||||
const aspect = getAspect(tense);
|
||||
const isAbility = isAbilityTense(tense);
|
||||
const noPerfective = isAbility && (voice === "passive" || isTlulVerb(verb) || isKedul(verb));
|
||||
// console.log(newGetRootStem({
|
||||
// verb,
|
||||
// part: {
|
||||
// rs: isPast ? "root" : "stem",
|
||||
// aspect,
|
||||
// },
|
||||
// type: "basic",
|
||||
// person: undefined,
|
||||
// }));
|
||||
const { perfectiveHead, rootStem } = getRootStem({
|
||||
verb, aspect, isPast, isAbility, person, voice, noPerfective,
|
||||
});
|
||||
const verbBlocks: T.VB[] = isAbility
|
||||
? getAbilityVerbBlocks({ isPast, person, root: rootStem, aspect, voice, noPerfective })
|
||||
: voice === "passive"
|
||||
? getPassiveVerbBlocks({ root: rootStem, tense, person })
|
||||
: getBasicVerbBlock({
|
||||
rootStem, person, isPast, verb, aspect,
|
||||
const genderNumber = {
|
||||
gender: personGender(person),
|
||||
number: personNumber(person),
|
||||
};
|
||||
// #1 get the appropriate root / stem
|
||||
console.log({ isAbility });
|
||||
const [vHead, rest] = getRootStem({
|
||||
verb,
|
||||
part: {
|
||||
rs: isPast ? "root" : "stem",
|
||||
aspect,
|
||||
},
|
||||
type: isAbility ? "ability" : "basic",
|
||||
genderNumber,
|
||||
});
|
||||
// #2 add the verb ending to it
|
||||
const ending = getEnding(person, isPast);
|
||||
return {
|
||||
hasBa,
|
||||
verbBlocks: [
|
||||
...(!noPerfective && perfectiveHead)
|
||||
? [perfectiveHead] : [],
|
||||
...verbBlocks,
|
||||
vbs: [
|
||||
vHead,
|
||||
addEnding({
|
||||
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 }: {
|
||||
rootStem: T.SingleOrLengthOpts<T.PsString>,
|
||||
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>,
|
||||
function addEnding({ verb, rs, ending, person, pastThird, aspect }: {
|
||||
rs: [T.VB, T.VBA] | [T.VBA],
|
||||
ending: T.SingleOrLengthOpts<T.PsString[]>,
|
||||
person: T.Person,
|
||||
isPast: boolean,
|
||||
verb: T.VerbEntry,
|
||||
pastThird: boolean,
|
||||
aspect: T.Aspect,
|
||||
}): T.SingleOrLengthOpts<T.PsString[]> {
|
||||
// TODO: no need for useless abbreviation now
|
||||
const rs = rootStem;
|
||||
const end = ending;
|
||||
const idiosyncratic3rdPast = isPast && person === T.Person.ThirdSingMale;
|
||||
const safeEndAdd = (rs: T.PsString) => (ending: T.PsString): T.PsString => (
|
||||
(ending.p === "ل" && rs.p.slice(-1) === "ل")
|
||||
? rs
|
||||
: concatPsString(rs, ending)
|
||||
);
|
||||
if ("long" in rs) {
|
||||
}): [T.VB, T.VBE] | [T.VBE] {
|
||||
return rs.length === 2
|
||||
? [rs[0], addEnd(rs[1], ending)]
|
||||
: [addEnd(rs[0], ending)];
|
||||
function addEnd(vba: T.VBA, ending: T.SingleOrLengthOpts<T.PsString[]>): T.VBE {
|
||||
if (vba.type === "welded") {
|
||||
return {
|
||||
...vba,
|
||||
right: addToVBBasicEnd(vba.right, ending),
|
||||
person,
|
||||
};
|
||||
}
|
||||
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 endShort = getLength(end, "short");
|
||||
const shortForm = idiosyncratic3rdPast
|
||||
? ensure3rdPast(endShort, rs.short, verb, aspect)
|
||||
: endShort.map(e => concatPsString(rs.short, e));
|
||||
// TODO: this is a bit hacky
|
||||
const rsLong = rs.long.f === "tlul"
|
||||
? { p: "تلل", f: "tlúl" }
|
||||
: rs.long;
|
||||
// TODO: this is hacky
|
||||
const rsLong: T.PsString[] = vb.ps.long[0].f === "tlul"
|
||||
? [{ p: "تلل", f: "tlúl" }]
|
||||
: vb.ps.long;
|
||||
return {
|
||||
long: endLong.map(safeEndAdd(rsLong)),
|
||||
short: aspect === "imperfective"
|
||||
? applyImperfectiveShortAccent(shortForm, yulEndingInfinitive(removeFVarients(verb.entry)))
|
||||
: shortForm,
|
||||
...vb,
|
||||
ps: {
|
||||
long: verbEndingConcat(rsLong, endLong),
|
||||
short: pastThird
|
||||
? ensure3rdPast(endShort, vb.ps.short, verb, aspect)
|
||||
: verbEndingConcat(vb.ps.short, endShort),
|
||||
},
|
||||
};
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
if ("long" in end) {
|
||||
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) {
|
||||
|
@ -362,53 +178,12 @@ function getEnding(person: T.Person, isPast: boolean) {
|
|||
} : presentEndings[row][col];
|
||||
}
|
||||
|
||||
function chooseParticipleInflection(pinf: T.SingleOrLengthOpts<T.UnisexInflections>, p: T.Person): T.SingleOrLengthOpts<T.PsString[]> {
|
||||
if ("long" in pinf) {
|
||||
return {
|
||||
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 === "شو") {
|
||||
// TODO: THIS IS PROBABLY SKEEEETCH
|
||||
function ensure3rdPast(ending: T.PsString[], rs: T.PsString[], verb: T.VerbEntry, aspect: T.Aspect): T.PsString[] {
|
||||
if (isKedul(verb) && rs[0].p === "شو") {
|
||||
return [{ p: "شو", f: "sho" }];
|
||||
}
|
||||
if (isKawulVerb(verb) && rs.p === "کړ") {
|
||||
if (isKawulVerb(verb) && rs[0].p === "کړ") {
|
||||
return [
|
||||
{ p: "کړ", f: "kuR" },
|
||||
{ p: "کړه", f: "kRu" },
|
||||
|
@ -420,12 +195,12 @@ function ensure3rdPast(ending: T.PsString[], rs: T.PsString, verb: T.VerbEntry,
|
|||
return [{ p: "غی", f: "ghey" }];
|
||||
}
|
||||
const specialTuShort: T.PsString = {
|
||||
p: rs.p.slice(0, -1) + "ه",
|
||||
f: rs.f.slice(0, -1) + (rs.f === "tl" ? "u" : "ú"),
|
||||
p: rs[0].p.slice(0, -1) + "ه",
|
||||
f: rs[0].f.slice(0, -1) + (rs[0].f === "tl" ? "u" : "ú"),
|
||||
};
|
||||
return [
|
||||
specialTuShort,
|
||||
concatPsString(rs, { p: "و", f: "o" }),
|
||||
concatPsString(rs[0], { p: "و", f: "o" }),
|
||||
];
|
||||
}
|
||||
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)
|
||||
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" })];
|
||||
}
|
||||
const endsInDental = ["د", "ت"].includes(rs.p.slice(-1));
|
||||
const endsInDental = ["د", "ت"].includes(rs[0].p.slice(-1));
|
||||
// short endings like ورسېد
|
||||
return (endsInDental ? [
|
||||
"",
|
||||
...ending,
|
||||
] : ending).map(e => concatPsString(rs, e));
|
||||
] : ending).map(e => concatPsString(rs[0], e));
|
||||
}
|
||||
|
||||
function getAspect(tense: T.VerbTense | T.AbilityTense): T.Aspect {
|
||||
|
@ -472,34 +247,6 @@ function isKedul(v: T.VerbEntry): boolean {
|
|||
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 {
|
||||
return t === "presentPerfect"
|
||||
? "present"
|
||||
|
|
|
@ -29,7 +29,7 @@ const ooPh: T.PH = {
|
|||
ps: { p: "و", f: "óo" },
|
||||
};
|
||||
|
||||
type TestGroup = {
|
||||
type RootsAndStemsTestGroup = {
|
||||
verb: T.VerbEntry,
|
||||
result: Record<"stem" | "root", {
|
||||
imperfective: T.RootStemOutput,
|
||||
|
@ -37,9 +37,9 @@ type TestGroup = {
|
|||
}>
|
||||
}[];
|
||||
|
||||
const tests: {
|
||||
const rootsAndStemsTests: {
|
||||
title: string,
|
||||
testGroup: TestGroup,
|
||||
testGroup: RootsAndStemsTestGroup,
|
||||
}[] =
|
||||
[
|
||||
{
|
||||
|
@ -901,14 +901,20 @@ const tests: {
|
|||
verb: kawulStat,
|
||||
result: {
|
||||
"stem": {
|
||||
"perfective": [
|
||||
[
|
||||
"perfective": [{
|
||||
long: [
|
||||
{
|
||||
"p": "کړ",
|
||||
"f": "kR"
|
||||
}
|
||||
]
|
||||
],
|
||||
short: [
|
||||
{
|
||||
p: "ک",
|
||||
f: "k",
|
||||
},
|
||||
],
|
||||
}],
|
||||
"imperfective": [
|
||||
[
|
||||
{
|
||||
|
@ -932,7 +938,13 @@ const tests: {
|
|||
"p": "کړ",
|
||||
"f": "kR"
|
||||
}
|
||||
]
|
||||
],
|
||||
"mini": [
|
||||
{
|
||||
"p": "ک",
|
||||
"f": "k",
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
"imperfective": [
|
||||
|
@ -966,12 +978,17 @@ const tests: {
|
|||
"f": "óo",
|
||||
}
|
||||
},
|
||||
[
|
||||
{
|
||||
long: [
|
||||
{
|
||||
"p": "کړ",
|
||||
"f": "kR"
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
short: [
|
||||
{ p: "ک", f: "k" },
|
||||
],
|
||||
},
|
||||
],
|
||||
"imperfective": [
|
||||
[
|
||||
|
@ -1003,8 +1020,11 @@ const tests: {
|
|||
"p": "کړ",
|
||||
"f": "kR"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mini": [
|
||||
{ p: "ک", f: "k" },
|
||||
],
|
||||
},
|
||||
],
|
||||
"imperfective": [
|
||||
{
|
||||
|
@ -1029,7 +1049,7 @@ const tests: {
|
|||
}
|
||||
];
|
||||
|
||||
tests.forEach(({ title, testGroup }) => {
|
||||
rootsAndStemsTests.forEach(({ title, testGroup }) => {
|
||||
test(title, () => {
|
||||
testGroup.forEach(({ verb, result }) => {
|
||||
expect(getAllRs(verb)).toEqual(result);
|
||||
|
|
|
@ -7,47 +7,83 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
concatPsString,
|
||||
concatPsString, trimOffPs,
|
||||
} from "../p-text-helpers";
|
||||
import * as T from "../../../types";
|
||||
import { makePsString, removeFVarientsFromVerb } from "../accent-and-ps-utils";
|
||||
import { accentOnNFromEnd, removeAccents } from "../accent-helpers";
|
||||
import { assertNever } from "../assert-never";
|
||||
import { accentOnNFromEnd, accentSyllable, removeAccents } from "../accent-helpers";
|
||||
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,
|
||||
part: {
|
||||
rs: "root" | "stem",
|
||||
aspect: T.Aspect,
|
||||
} | {
|
||||
participle: "present" | "past",
|
||||
},
|
||||
} | "pastPart",
|
||||
type: "basic" | "ability" | "passive",
|
||||
person: {
|
||||
genderNumber: {
|
||||
gender: T.Gender,
|
||||
number: T.NounNumber,
|
||||
} | undefined,
|
||||
}): T.RootStemOutput {
|
||||
},
|
||||
}): T.RootsStemsOutput {
|
||||
console.log({ type });
|
||||
const v = removeFVarientsFromVerb(verb);
|
||||
if ("participle" in part) {
|
||||
return [];
|
||||
if (part === "pastPart") {
|
||||
throw new Error("not implemented yet");
|
||||
}
|
||||
console.log({ part });
|
||||
return part.rs === "stem"
|
||||
? getStem(v, part.aspect)
|
||||
: getRoot(v, part.aspect);
|
||||
? part.aspect === "imperfective"
|
||||
? getImperfectiveStem(v)
|
||||
: getPerfectiveStem(v, genderNumber)
|
||||
: part.aspect === "imperfective"
|
||||
? getImperfectiveRoot(v, type)
|
||||
: getPerfectiveRoot(v);
|
||||
}
|
||||
|
||||
function getRoot(verb: T.VerbEntryNoFVars, aspect: T.Aspect): T.RootStemOutput {
|
||||
if (aspect === "imperfective") {
|
||||
function getImperfectiveRoot(verb: T.VerbEntryNoFVars, type: "basic" | "ability" | "passive"): T.RootsStemsOutput {
|
||||
// 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);
|
||||
return [
|
||||
[],
|
||||
[
|
||||
{
|
||||
type: "VB",
|
||||
ps: {
|
||||
long: [infinitive],
|
||||
short: [addTrailingAccent(removeL(infinitive))],
|
||||
},
|
||||
},
|
||||
],
|
||||
];
|
||||
}
|
||||
// aspect === "perfective"
|
||||
|
||||
function getPerfectiveRoot(verb: T.VerbEntryNoFVars): T.RootsStemsOutput {
|
||||
const base = removeAccents(
|
||||
(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);
|
||||
return [
|
||||
...perfectiveHead ? [perfectiveHead] : [],
|
||||
perfectiveHead ? [perfectiveHead] : [],
|
||||
[
|
||||
{
|
||||
type: "VB",
|
||||
ps: {
|
||||
long: [rest],
|
||||
short: [removeL(rest)],
|
||||
...isKawulVerb(verb) ? {
|
||||
mini: [{ p: "ک", f: "k" }],
|
||||
} : {},
|
||||
},
|
||||
},
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
function getStem(verb: T.VerbEntryNoFVars, aspect: T.Aspect): T.RootStemOutput {
|
||||
if (aspect === "imperfective") {
|
||||
function getImperfectiveStem(verb: T.VerbEntryNoFVars): T.RootsStemsOutput {
|
||||
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));
|
||||
if (verb.entry.c?.includes("intrans.") && rawBase.p.endsWith("ېد")) {
|
||||
const long: T.PsString[] = [{
|
||||
p: rawBase.p.slice(0, -1) + "ږ",
|
||||
f: rawBase.f.slice(0, -2) + "éG",
|
||||
}];
|
||||
const shortBase = trimOffPs(rawBase, 1, 2);
|
||||
const long: T.PsString[] = [concatPsString(
|
||||
shortBase,
|
||||
{ p: "ږ", f: "éG" },
|
||||
)];
|
||||
const short: T.PsString[] | undefined = (verb.entry.shortIntrans)
|
||||
? [{
|
||||
p: rawBase.p.slice(0, -2),
|
||||
f: rawBase.f.slice(0, -2),
|
||||
}]
|
||||
? [shortBase]
|
||||
: undefined;
|
||||
return short ? [{ long, short }] : [long]
|
||||
}
|
||||
const vb: T.VB = {
|
||||
type: "VB",
|
||||
ps: short ? { long, short } : long,
|
||||
};
|
||||
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)
|
||||
// with irregular perfective stem
|
||||
? 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));
|
||||
const [perfectiveHead, rest] = getPerfectiveHead(base, verb);
|
||||
return [
|
||||
...perfectiveHead ? [perfectiveHead] : [],
|
||||
[rest],
|
||||
perfectiveHead ? [perfectiveHead] : [],
|
||||
[
|
||||
{
|
||||
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) {
|
||||
// // handle split
|
||||
// }
|
||||
if (entry.separationAtP && entry.separationAtF) {
|
||||
const ph: T.PH = {
|
||||
type: "PH",
|
||||
ps: accentOnNFromEnd({
|
||||
ps: {
|
||||
p: base.p.slice(0, entry.separationAtP),
|
||||
f: base.f.slice(0, entry.separationAtF),
|
||||
}, 0),
|
||||
f: accentSyllable(base.f.slice(0, entry.separationAtF)),
|
||||
},
|
||||
};
|
||||
const rest = {
|
||||
p: base.p.slice(entry.separationAtP),
|
||||
|
@ -195,8 +273,22 @@ function addUl(b: T.PsString): T.PsString {
|
|||
// TODO: could do removeEndingL (slower but safer)
|
||||
|
||||
function removeL(ps: T.PsString): T.PsString {
|
||||
return {
|
||||
p: ps.p.slice(0, -1),
|
||||
f: ps.f.slice(0, -2),
|
||||
};
|
||||
return trimOffPs(ps, 1, 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): {
|
||||
stem: {
|
||||
perfective: T.RootStemOutput,
|
||||
imperfective: T.RootStemOutput,
|
||||
perfective: T.RootsStemsOutput,
|
||||
imperfective: T.RootsStemsOutput,
|
||||
},
|
||||
root: {
|
||||
perfective: T.RootStemOutput,
|
||||
imperfective: T.RootStemOutput,
|
||||
perfective: T.RootsStemsOutput,
|
||||
imperfective: T.RootsStemsOutput,
|
||||
},
|
||||
} {
|
||||
return {
|
||||
stem: {
|
||||
perfective: getRootStem({ verb, type: "basic", part: { rs: "stem", aspect: "perfective" }, person: undefined }),
|
||||
imperfective: getRootStem({ verb, type: "basic", part: { rs: "stem", aspect: "imperfective" }, 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" }, genderNumber: { gender: "masc", number: "singular" } }),
|
||||
},
|
||||
root: {
|
||||
perfective: getRootStem({ verb, type: "basic", part: { rs: "root", aspect: "perfective" }, person: undefined }),
|
||||
imperfective: getRootStem({ verb, type: "basic", part: { rs: "root", aspect: "imperfective" }, 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" }, genderNumber: { gender: "masc", number: "singular" } }),
|
||||
},
|
||||
};
|
||||
}
|
|
@ -24,6 +24,7 @@ import {
|
|||
endsInShwa,
|
||||
splitPsByVarients,
|
||||
endsWith,
|
||||
trimOffPs,
|
||||
} from "./p-text-helpers";
|
||||
import * as T from "../../types";
|
||||
import {
|
||||
|
@ -704,6 +705,15 @@ test(`splitDoubleWord should work`, () => {
|
|||
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`, () => {
|
||||
// expect(
|
||||
// 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
|
||||
*
|
||||
|
|
74
src/types.ts
74
src/types.ts
|
@ -1074,45 +1074,47 @@ export type MiniPronoun = {
|
|||
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 */
|
||||
export type PH = {
|
||||
type: "PH",
|
||||
ps: PsString,
|
||||
} | {
|
||||
type: "PHComp",
|
||||
};
|
||||
|
||||
export type NComp = {
|
||||
type: "NComp",
|
||||
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
|
||||
// - adjective
|
||||
// - locative adv
|
||||
|
@ -1131,13 +1133,3 @@ export type Comp = {
|
|||
type: "NounComp",
|
||||
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