working on new roots and stems getter to replace verbInfo
This commit is contained in:
parent
3eb630a7b7
commit
1658f021a0
|
@ -28,8 +28,8 @@ function AllTensesDisplay({ VS, opts }: { VS: T.VerbSelection, opts: T.TextOptio
|
|||
: ("transitive" in rawConjugations)
|
||||
? rawConjugations[VS.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
|
||||
: rawConjugations;
|
||||
function getTense(baseTense: T.VerbTense | T.PerfectTense | T.ImperativeTense): T.VerbTense | T.PerfectTense | T.ImperativeTense | T.ModalTense {
|
||||
return VS.tenseCategory === "modal" ? `${baseTense}Modal` as T.ModalTense : baseTense;
|
||||
function getTense(baseTense: T.VerbTense | T.PerfectTense | T.ImperativeTense): T.VerbTense | T.PerfectTense | T.ImperativeTense | T.AbilityTense {
|
||||
return VS.tenseCategory === "modal" ? `${baseTense}Modal` as T.AbilityTense : baseTense;
|
||||
}
|
||||
return <div>
|
||||
<div className="clickable mb-2 small text-center" onClick={() => setShowFormulas(x => !x)}>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Select from "react-select";
|
||||
import * as T from "../../../types";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
import { isImperativeTense, isModalTense, isPerfectTense, isVerbTense } from "../../../lib/src/type-predicates";
|
||||
import { isImperativeTense, isAbilityTense, isPerfectTense, isVerbTense } from "../../../lib/src/type-predicates";
|
||||
import useStickyState from "../useStickyState";
|
||||
import { customStyles } from "../EntrySelect";
|
||||
import {
|
||||
|
@ -19,15 +19,15 @@ function composeFormula(formula: string, prefix: "passive" | "ability"): string
|
|||
.replace("past participle", `${prefix} past participle`);
|
||||
}
|
||||
|
||||
export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense): T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense {
|
||||
let tns: T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense;
|
||||
export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.AbilityTense | T.ImperativeTense): T.PerfectTense | T.VerbTense | T.AbilityTense | T.ImperativeTense {
|
||||
let tns: T.PerfectTense | T.VerbTense | T.AbilityTense | T.ImperativeTense;
|
||||
const oldTenseCategory = !o
|
||||
? undefined
|
||||
: getTenseCategory(o);
|
||||
const tenseOptions = oldTenseCategory === "perfect"
|
||||
? perfectTenseOptions
|
||||
: oldTenseCategory === "modal"
|
||||
? verbTenseOptions.map(x => ({ ...x, value: `${x.value}Modal` as T.ModalTense }))
|
||||
? verbTenseOptions.map(x => ({ ...x, value: `${x.value}Modal` as T.AbilityTense }))
|
||||
: oldTenseCategory === "imperative"
|
||||
? imperativeTenseOptions
|
||||
: verbTenseOptions;
|
||||
|
@ -238,14 +238,14 @@ function TensePicker(props: ({
|
|||
|
||||
export default TensePicker;
|
||||
|
||||
function getTenseCategory(tense: T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense): "basic" | "perfect" | "modal" | "imperative" {
|
||||
function getTenseCategory(tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense): "basic" | "perfect" | "modal" | "imperative" {
|
||||
if (isPerfectTense(tense)) {
|
||||
return "perfect";
|
||||
}
|
||||
if (isVerbTense(tense)) {
|
||||
return "basic";
|
||||
}
|
||||
if (isModalTense(tense)) {
|
||||
if (isAbilityTense(tense)) {
|
||||
return "modal";
|
||||
}
|
||||
if (isImperativeTense(tense)) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import * as T from "../../../types";
|
|||
|
||||
function ChartDisplay({ conjugations, tense, opts, voice }: {
|
||||
conjugations: T.VerbConjugation,
|
||||
tense: T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense,
|
||||
tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense,
|
||||
opts: T.TextOptions,
|
||||
voice: T.VerbSelection["voice"],
|
||||
}) {
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
randomNumber,
|
||||
} from "../lib/src/misc-helpers";
|
||||
import { entryFeeder } from "./entryFeeder";
|
||||
import { renderVerb } from "../lib/src/render-verb";
|
||||
import { renderVerb } from "../lib/src/new-verb-engine/render-verb";
|
||||
import NPPronounPicker from "../components/src/np-picker/NPPronounPicker";
|
||||
|
||||
|
||||
|
@ -56,7 +56,7 @@ const testPerfectTenses: T.PerfectTense[] = [
|
|||
"pastSubjunctivePerfect",
|
||||
];
|
||||
|
||||
const testAbilityTenses: T.ModalTense[] = testVerbTenses.map<T.ModalTense>(t => `${t}Modal`);
|
||||
const testAbilityTenses: T.AbilityTense[] = testVerbTenses.map<T.AbilityTense>(t => `${t}Modal`);
|
||||
|
||||
const testTenses = [
|
||||
...testVerbTenses,
|
||||
|
@ -76,7 +76,7 @@ function VPBuilderDemo({ opts }: {
|
|||
person: 0,
|
||||
}, "testPronoun");
|
||||
const [testVoice, setTestVoice] = useStickyState<T.Voice>("active", "testVoice");
|
||||
const [testTense, setTestTense] = useStickyState<T.VerbTense | T.PerfectTense | T.ModalTense>("presentVerb", "testTense");
|
||||
const [testTense, setTestTense] = useStickyState<T.VerbTense | T.PerfectTense | T.AbilityTense>("presentVerb", "testTense");
|
||||
// const onlyGrammTrans = (arr: Transitivity[]) => (
|
||||
// arr.length === 1 && arr[0] === "grammatically transitive"
|
||||
// );
|
||||
|
|
|
@ -10,10 +10,21 @@ export function makePsString(p: string, f: string): T.PsString {
|
|||
return { p, f };
|
||||
}
|
||||
|
||||
export function removeFVarientsFromVerb(v: T.VerbEntry): T.VerbEntryNoFVars {
|
||||
const b = removeFVarients(v.entry);
|
||||
return {
|
||||
entry: b,
|
||||
...v.complement ? {
|
||||
complement: removeFVarients(v.complement),
|
||||
} : {},
|
||||
} as T.VerbEntryNoFVars;
|
||||
}
|
||||
|
||||
export function removeFVarients(x: T.VerbDictionaryEntry): T.VerbDictionaryEntryNoFVars;
|
||||
export function removeFVarients(x: T.DictionaryEntry): T.DictionaryEntryNoFVars;
|
||||
export function removeFVarients(x: T.PsString): T.PsStringNoFVars;
|
||||
export function removeFVarients(x: string): T.FStringNoFVars;
|
||||
export function removeFVarients(x: string | T.PsString | T.DictionaryEntry): T.FStringNoFVars | T.PsStringNoFVars | T.DictionaryEntryNoFVars {
|
||||
export function removeFVarients(x: string | T.PsString | T.DictionaryEntry | T.VerbDictionaryEntry): T.FStringNoFVars | T.PsStringNoFVars | T.DictionaryEntryNoFVars | T.VerbDictionaryEntryNoFVars {
|
||||
if (typeof x === "string") {
|
||||
return x.split(",")[0] as T.FStringNoFVars;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as T from "../../types";
|
||||
import {
|
||||
isModalTense,
|
||||
isAbilityTense,
|
||||
isPerfectTense,
|
||||
isImperativeTense,
|
||||
} from "./type-predicates";
|
||||
|
@ -24,7 +24,7 @@ function humanReadableVerbTense(tense: T.VerbTense): string {
|
|||
: "habitual continuous past";
|
||||
}
|
||||
|
||||
function humanReadableModalTense(tense: T.ModalTense): string {
|
||||
function humanReadableModalTense(tense: T.AbilityTense): string {
|
||||
const base = tense.replace("Modal", "") as T.VerbTense;
|
||||
return `${humanReadableVerbTense(base)} ability`;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ function humanReadableImperativeTense(tense: T.ImperativeTense): string {
|
|||
}
|
||||
|
||||
export function humanReadableVerbForm(f: T.VerbFormName): string {
|
||||
return isModalTense(f)
|
||||
return isAbilityTense(f)
|
||||
? humanReadableModalTense(f)
|
||||
: isPerfectTense(f)
|
||||
? humanReadablePerfectTense(f)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as T from "../../types";
|
||||
import * as T from "../../../types";
|
||||
import { renderVerb } from "./render-verb";
|
||||
|
||||
function vEntry(e: any, c?: any): T.VerbEntry {
|
||||
export function vEntry(e: any, c?: any): T.VerbEntry {
|
||||
return {
|
||||
entry: e,
|
||||
...c ? {
|
||||
|
@ -1214,7 +1214,7 @@ test("perfect simple verb forms", () => {
|
|||
});
|
||||
|
||||
test("ability simple verb forms", () => {
|
||||
const tests: { verb: T.VerbEntry, tense: T.ModalTense, person: T.Person, output: ReturnType<typeof renderVerb> }[] = [
|
||||
const tests: { verb: T.VerbEntry, tense: T.AbilityTense, person: T.Person, output: ReturnType<typeof renderVerb> }[] = [
|
||||
{
|
||||
tense: "presentVerbModal",
|
||||
verb: ganul,
|
||||
|
@ -1625,7 +1625,7 @@ test("passive perfect simple verbs", () => {
|
|||
});
|
||||
|
||||
test("passive ability simple verbs", () => {
|
||||
const tests: { verb: T.VerbEntry, tense: T.ModalTense, person: T.Person, output: ReturnType<typeof renderVerb> }[] = [
|
||||
const tests: { verb: T.VerbEntry, tense: T.AbilityTense, person: T.Person, output: ReturnType<typeof renderVerb> }[] = [
|
||||
{
|
||||
verb: ganul,
|
||||
tense: "presentVerbModal",
|
|
@ -1,47 +1,57 @@
|
|||
import * as T from "../../types";
|
||||
import * as T from "../../../types";
|
||||
import {
|
||||
functionOnOptLengths,
|
||||
getPersonInflectionsKey,
|
||||
getVerbBlockPosFromPerson,
|
||||
noPersInfs,
|
||||
personGender,
|
||||
personIsPlural,
|
||||
personNumber,
|
||||
} from "./misc-helpers";
|
||||
} from "../misc-helpers";
|
||||
import {
|
||||
yulEndingInfinitive,
|
||||
} from "./p-text-helpers";
|
||||
} from "../p-text-helpers";
|
||||
import {
|
||||
concatPsString,
|
||||
getLength,
|
||||
} from "./p-text-helpers";
|
||||
} from "../p-text-helpers";
|
||||
import {
|
||||
presentEndings,
|
||||
pastEndings,
|
||||
equativeEndings,
|
||||
} from "./grammar-units";
|
||||
import { isKawulVerb, isModalTense, isPerfectTense, isTlulVerb } from "./type-predicates";
|
||||
import { tenseHasBa } from "./phrase-building/vp-tools";
|
||||
import { inflectYey } from "./pashto-inflector";
|
||||
} 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";
|
||||
} 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";
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
// TODO: Amazingly, the basic formula with the roots and stems from the basic verbs
|
||||
// works perfectly with stative compounds as well!
|
||||
// The only issue is that if we want to include more information (complement noun gender etc) in the blocks
|
||||
// we need to redo the stem building to have those parts
|
||||
// 2 options:
|
||||
// 1. redo the root/stem builder to output primitive blocks
|
||||
// 2. rebuild the roots/stems in the verb engine
|
||||
// Will start with number 2 and then if I go back and rebuild the root/stem builder
|
||||
// We can go back to using a very simple verb building formula
|
||||
|
||||
// TODO: problem with laaR - no perfective split
|
||||
// TODO: are azmóyulum and wáayulo really not just azmoyúlum and waayúlo ?
|
||||
// TODO: automatic 3rd person idiosyncronizing of raTul raaTu, shaRul, shaaRu, rasedul rased etc
|
||||
|
||||
export function renderVerb({ verb, tense, person, voice }: {
|
||||
verb: T.VerbEntry,
|
||||
tense: T.VerbTense | T.PerfectTense | T.ModalTense, // TODO: make T.Tense
|
||||
tense: T.VerbTense | T.PerfectTense | T.AbilityTense, // TODO: make T.Tense
|
||||
person: T.Person,
|
||||
voice: T.Voice,
|
||||
}): {
|
||||
|
@ -52,26 +62,37 @@ export function renderVerb({ verb, tense, person, voice }: {
|
|||
if (isPerfectTense(tense)) {
|
||||
return getPerfectVBs({ verb, tense, person, voice });
|
||||
}
|
||||
|
||||
const hasBa = tenseHasBa(tense);
|
||||
const isPast = isPastTense(tense);
|
||||
const aspect = getAspect(tense);
|
||||
const isAbility = isModalTense(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,
|
||||
});
|
||||
? getPassiveVerbBlocks({ root: rootStem, tense, person })
|
||||
: getBasicVerbBlock({
|
||||
rootStem, person, isPast, verb, aspect,
|
||||
});
|
||||
return {
|
||||
hasBa,
|
||||
verbBlocks: [
|
||||
...!noPerfective && perfectiveHead ? [perfectiveHead] : [],
|
||||
...verbBlocks,
|
||||
...(!noPerfective && perfectiveHead)
|
||||
? [perfectiveHead] : [],
|
||||
...verbBlocks,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
@ -185,19 +206,19 @@ function getPerfectVBs({ verb, tense, person, voice }: {
|
|||
voice: T.Voice,
|
||||
}): { hasBa: boolean, verbBlocks: T.VB[] } {
|
||||
const hasBa = tenseHasBa(tense);
|
||||
const vInfo = getVerbInfo(verb.entry) as T.SimpleVerbInfo;
|
||||
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: [noPersInfs(vInfo.root.imperfective).long],
|
||||
ps: [fromPersInfls(vInfo.root.imperfective, person).long],
|
||||
};
|
||||
const welded: T.Welded = weld(passiveRoot, pt);
|
||||
return {
|
||||
hasBa,
|
||||
verbBlocks: [welded, eq],
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const equative = equativeEndings[perfectTenseToEquative(tense)];
|
||||
|
@ -215,7 +236,7 @@ function getPerfectVBs({ verb, tense, person, voice }: {
|
|||
type: "PT",
|
||||
gender: personGender(person),
|
||||
number: personNumber(person),
|
||||
ps: chooseParticipleInflection(inflectYey(noPersInfs(vInfo.participle.past)), person)
|
||||
ps: chooseParticipleInflection(inflectYey(fromPersInfls(vInfo.participle.past, person)), person)
|
||||
}
|
||||
return {
|
||||
hasBa,
|
||||
|
@ -246,13 +267,13 @@ function getRootStem({ verb, aspect, isPast, isAbility, voice, person, noPerfect
|
|||
perfectiveHead: undefined | T.PH,
|
||||
rootStem: T.SingleOrLengthOpts<T.PsString>,
|
||||
} {
|
||||
const vInfo = getVerbInfo(verb.entry) as T.SimpleVerbInfo;
|
||||
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: noPersInfs(rs.imperfective),
|
||||
rootStem: fromPersInfls(rs.imperfective, person),
|
||||
};
|
||||
}
|
||||
if (aspect === "perfective" && rs.perfectiveSplit) {
|
||||
|
@ -262,7 +283,7 @@ function getRootStem({ verb, aspect, isPast, isAbility, voice, person, noPerfect
|
|||
perfectiveHead: undefined,
|
||||
// because the persInfs only happen with stative compound verbs,j
|
||||
// which we are handling differently now
|
||||
rootStem: noPersInfs(rs[aspect]),
|
||||
rootStem: fromPersInfls(rs[aspect], person),
|
||||
}
|
||||
|
||||
function extractPerfectiveSplit(splitInfo: T.SplitInfo): ReturnType<typeof getRootStem> {
|
||||
|
@ -438,7 +459,7 @@ function ensure3rdPast(ending: T.PsString[], rs: T.PsString, verb: T.VerbEntry,
|
|||
] : ending).map(e => concatPsString(rs, e));
|
||||
}
|
||||
|
||||
function getAspect(tense: T.VerbTense | T.ModalTense): T.Aspect {
|
||||
function getAspect(tense: T.VerbTense | T.AbilityTense): T.Aspect {
|
||||
const t = tense.replace("Modal", "");
|
||||
if (["presentVerb", "imperfectiveFuture", "imperfectivePast", "habitualImperfectivePast"].includes(t)) {
|
||||
return "imperfective";
|
|
@ -0,0 +1,181 @@
|
|||
import * as T from "../../../types";
|
||||
import { getRootStem } from "./roots-and-stems";
|
||||
import { vEntry } from "./render-verb.test";
|
||||
import { ooPrefix } from "./roots-and-stems";
|
||||
|
||||
const wahul = vEntry({"ts":1527815399,"i":15049,"p":"وهل","f":"wahul","g":"wahul","e":"to hit","r":4,"c":"v. trans.","tppp":"واهه","tppf":"waahu","ec":"hit,hits,hitting,hit,hit"});
|
||||
const achawul = vEntry({"ts":1527811872,"i":224,"p":"اچول","f":"achawul","g":"achawul","e":"to put, pour, drop, throw, put on","r":4,"c":"v. trans.","ec":"put,puts,putting,put,put"});
|
||||
const ganul = vEntry({"ts":1527812000,"i":11398,"p":"ګڼل","f":"gaNul, guNul","g":"gaNul,guNul","e":"to count, consider, reckon, suppose, assume","r":4,"c":"v. trans.","tppp":"ګاڼه","tppf":"gaaNu","ec":"deem"});
|
||||
const kawulStat = vEntry({"ts":1579015359582,"i":11030,"p":"کول","f":"kawul","g":"kawul","e":"to make ____ ____ (as in \"He's making me angry.\")","r":4,"c":"v. trans.","ssp":"کړ","ssf":"kR","prp":"کړل","prf":"kRul","pprtp":"کړی","pprtf":"kúRey","noOo":true,"ec":"make,makes,making,made,made"});
|
||||
const kawulDyn = vEntry({"ts":1527812752,"i":11031,"p":"کول","f":"kawul","g":"kawul","e":"to do (an action or activity)","r":4,"c":"v. trans./gramm. trans.","ssp":"وکړ","ssf":"óokR","prp":"وکړل","prf":"óokRul","pprtp":"کړی","pprtf":"kúRey","diacExcept":true,"ec":"do,does,doing,did,done"});
|
||||
const kedulStat = vEntry({"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"});
|
||||
const kedulDyn = vEntry({"ts":1527812754,"i":11101,"p":"کېدل","f":"kedul","g":"kedul","e":"to happen, occur","r":2,"c":"v. intrans.","ssp":"وش","ssf":"óosh","prp":"وشول","prf":"óoshwul","pprtp":"شوی","pprtf":"shúwey","diacExcept":true,"ec":"happen"});
|
||||
const raatlul = vEntry({"ts":1527815216,"i":6875,"p":"راتلل","f":"raatlúl","g":"raatlul","e":"to come","r":4,"c":"v. intrans.","psp":"راځ","psf":"raadz","ssp":"راش","ssf":"ráash","prp":"راغلل","prf":"ráaghlul","pprtp":"راغلی","pprtf":"raaghúley","tppp":"راغی","tppf":"ráaghey","noOo":true,"separationAtP":2,"separationAtF":3,"ec":"come,comes,coming,came,come"});
|
||||
const wartlul = vEntry({"ts":1585228579997,"i":14821,"p":"ورتلل","f":"wărtlul","g":"wartlul","e":"to come / go over to (third person or place)","r":4,"c":"v. intrans.","psp":"ورځ","psf":"wărdz","ssp":"ورش","ssf":"wársh","prp":"ورغلل","prf":"wárghlul","pprtp":"ورغلی","pprtf":"wărghúley","tppp":"ورغی","tppf":"wărghey","noOo":true,"separationAtP":2,"separationAtF":3,"ec":"come,comes,coming,came,come"});
|
||||
const tlul = vEntry({"ts":1527815348,"i":3791,"p":"تلل","f":"tlul","g":"tlul","e":"to go","r":4,"c":"v. intrans.","psp":"ځ","psf":"dz","ssp":"لاړ ش","ssf":"láaR sh","prp":"لاړ","prf":"láaR","ec":"go,goes,going,went,gone"});
|
||||
const awuxtul = vEntry({"ts":1527814012,"i":1133,"p":"اوښتل","f":"awUxtul","g":"awUxtul","e":"to pass over, overturn, be flipped over, spill over, shift, change, diverge, pass, cross, abandon; to be sprained","r":4,"c":"v. intrans.","psp":"اوړ","psf":"awR","ec":"pass","ep":"over"});
|
||||
const khorul = vEntry({"ts":1527812790,"i":6002,"p":"خوړل","f":"khoRul","g":"khoRul","e":"to eat, to bite","r":4,"c":"v. trans.","psp":"خور","psf":"khor","tppp":"خوړ","tppf":"khoR","ec":"eat,eats,eating,ate,eaten"});
|
||||
const azmoyul = vEntry({"ts":1527811605,"i":468,"p":"ازمویل","f":"azmoyul","g":"azmoyul","e":"to attempt, try; to experiment, test","r":4,"c":"v. trans.","sepOo":true,"ec":"try"});
|
||||
const khatul = vEntry({"ts":1527814025,"i":5677,"p":"ختل","f":"khatul","g":"khatul","e":"to climb, ascend, rise, go up; to fall out, to fall off, to leave/dissapear; to turn out to be ...; to give a sentence (in law)","r":3,"c":"v. intrans.","psp":"خېژ","psf":"khejz","tppp":"خوت","tppf":"khot","ec":"climb"});
|
||||
const rasedul = vEntry({"ts":1527813573,"i":7057,"p":"رسېدل","f":"rasedul","g":"rasedul","e":"arrive, reach; (fig.) understand, attain to; mature, ripen","r":4,"c":"v. intrans.","shortIntrans":true,"ec":"arrive"});
|
||||
const weshul = vEntry({"ts":1527811701,"i":15106,"p":"وېشل","f":"weshul","g":"weshul","e":"divide, distribute, share","r":4,"c":"v. trans.","ec":"divide"});
|
||||
|
||||
type RSO = ReturnType<typeof getRootStem>;
|
||||
function getAllRs(verb: T.VerbEntry): (typeof regularVerbs)[0]["result"] {
|
||||
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 }),
|
||||
},
|
||||
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 }),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const regularVerbs: {
|
||||
verb: T.VerbEntry,
|
||||
result: Record<"stem" | "root", {
|
||||
imperfective: RSO,
|
||||
perfective: RSO,
|
||||
}>
|
||||
}[] = [
|
||||
{
|
||||
verb: weshul,
|
||||
result: {
|
||||
stem: {
|
||||
perfective: [
|
||||
ooPrefix,
|
||||
[{ p: "وېش", f: "wesh" }],
|
||||
],
|
||||
imperfective: [
|
||||
[{ p: "وېش", f: "wesh" }],
|
||||
],
|
||||
},
|
||||
root: {
|
||||
perfective: [
|
||||
ooPrefix,
|
||||
{
|
||||
long: [{ p: "وېشل", f: "weshul" }],
|
||||
short: [{ p: "وېش", f: "wesh" }],
|
||||
},
|
||||
],
|
||||
imperfective: [
|
||||
{
|
||||
long: [{ p: "وېشل", f: "weshúl" }],
|
||||
short: [{ p: "وېش", f: "weshX" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
verb: ganul,
|
||||
result: {
|
||||
stem: {
|
||||
perfective: [
|
||||
ooPrefix,
|
||||
[{ p: "ګڼ", f: "gaN" }],
|
||||
],
|
||||
imperfective: [
|
||||
[{ p: "ګڼ", f: "gaN" }],
|
||||
],
|
||||
},
|
||||
root: {
|
||||
perfective: [
|
||||
ooPrefix,
|
||||
{
|
||||
long: [{ p: "ګڼل", f: "gaNul" }],
|
||||
short: [{ p: "ګڼ", f: "gaN" }],
|
||||
},
|
||||
],
|
||||
imperfective: [
|
||||
{
|
||||
long: [{ p: "ګڼل", f: "gaNúl" }],
|
||||
short: [{ p: "ګڼ", f: "gaNX" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const verbsWithIrregularStems: {
|
||||
verb: T.VerbEntry,
|
||||
result: Record<"stem" | "root", {
|
||||
imperfective: RSO,
|
||||
perfective: RSO,
|
||||
}>
|
||||
}[] = [
|
||||
{
|
||||
verb: khorul,
|
||||
result: {
|
||||
stem: {
|
||||
perfective: [
|
||||
ooPrefix,
|
||||
[{ p: "خور", f: "khor" }],
|
||||
],
|
||||
imperfective: [
|
||||
[{ p: "خور", f: "khor" }],
|
||||
],
|
||||
},
|
||||
root: {
|
||||
perfective: [
|
||||
ooPrefix,
|
||||
{
|
||||
long: [{ p: "خوړل", f: "khoRul" }],
|
||||
short: [{ p: "خوړ", f: "khoR" }],
|
||||
},
|
||||
],
|
||||
imperfective: [
|
||||
{
|
||||
long: [{ p: "خوړل", f: "khoRúl" }],
|
||||
short: [{ p: "خوړ", f: "khoRX" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
verb: khatul,
|
||||
result: {
|
||||
stem: {
|
||||
perfective: [
|
||||
ooPrefix,
|
||||
[{ p: "خېژ", f: "khejz" }],
|
||||
],
|
||||
imperfective: [
|
||||
[{ p: "خېژ", f: "khejz" }],
|
||||
],
|
||||
},
|
||||
root: {
|
||||
perfective: [
|
||||
ooPrefix,
|
||||
{
|
||||
long: [{ p: "ختل", f: "khatul" }],
|
||||
short: [{ p: "خت", f: "khat" }],
|
||||
},
|
||||
],
|
||||
imperfective: [
|
||||
{
|
||||
long: [{ p: "ختل", f: "khatúl" }],
|
||||
short: [{ p: "خت", f: "khatX" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
test("basic roots and stems with regular verbs", () => {
|
||||
regularVerbs.forEach(({ verb, result }) => {
|
||||
expect(getAllRs(verb)).toEqual(result);
|
||||
});
|
||||
});
|
||||
|
||||
test("baisc roots and stems with verbs with irregular stems", () => {
|
||||
verbsWithIrregularStems.forEach(({ verb, result }) => {
|
||||
expect(getAllRs(verb)).toEqual(result);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* Copyright (c) 2023 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the GPL3 license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
import {
|
||||
concatPsString,
|
||||
} from "../p-text-helpers";
|
||||
import * as T from "../../../types";
|
||||
import { makePsString, removeFVarientsFromVerb } from "../accent-and-ps-utils";
|
||||
import { accentOnNFromEnd, removeAccents } from "../accent-helpers";
|
||||
|
||||
type RootStemOutput = (T.PH | T.SingleOrLengthOpts<T.PsString[]>)[];
|
||||
|
||||
export const ooPrefix: T.PH = {
|
||||
type: "PH",
|
||||
ps: { p: "و", f: "óo" },
|
||||
};
|
||||
|
||||
export function getRootStem({ verb, part, type, person }: {
|
||||
verb: T.VerbEntry,
|
||||
part: {
|
||||
rs: "root" | "stem",
|
||||
aspect: T.Aspect,
|
||||
} | {
|
||||
participle: "present" | "past",
|
||||
},
|
||||
type: "basic" | "ability" | "passive",
|
||||
person: {
|
||||
gender: T.Gender,
|
||||
number: T.NounNumber,
|
||||
} | undefined,
|
||||
}): RootStemOutput {
|
||||
const v = removeFVarientsFromVerb(verb);
|
||||
if ("participle" in part) {
|
||||
return [];
|
||||
}
|
||||
if (part.rs === "stem") {
|
||||
return getStem(v, part.aspect);
|
||||
} else {
|
||||
return getRoot(v, part.aspect);
|
||||
}
|
||||
}
|
||||
|
||||
function getRoot(verb: T.VerbEntryNoFVars, aspect: T.Aspect): RootStemOutput {
|
||||
if (aspect === "imperfective") {
|
||||
const infinitive = accentOnNFromEnd(makePsString(verb.entry.p, verb.entry.f), 0);
|
||||
return [
|
||||
{
|
||||
long: [infinitive],
|
||||
short: [addTrailingAccent(removeL(infinitive))],
|
||||
},
|
||||
];
|
||||
}
|
||||
if (aspect === "perfective") {
|
||||
const base = removeAccents(
|
||||
(verb.entry.prp && verb.entry.prf)
|
||||
? makePsString(verb.entry.prp, verb.entry.prf)
|
||||
: makePsString(verb.entry.p, verb.entry.f)
|
||||
);
|
||||
// TODO: determine ph and base
|
||||
return [
|
||||
ooPrefix,
|
||||
{
|
||||
long: [base],
|
||||
short: [removeL(base)],
|
||||
},
|
||||
];
|
||||
}
|
||||
throw new Error("unknown aspect");
|
||||
}
|
||||
|
||||
function getStem(verb: T.VerbEntryNoFVars, aspect: T.Aspect): RootStemOutput {
|
||||
if (aspect === "imperfective") {
|
||||
const base = (verb.entry.psp && verb.entry.psf)
|
||||
// with irregular imperfective stem
|
||||
? makePsString(verb.entry.psp, verb.entry.psf)
|
||||
// with regular infinitive based imperfective stem
|
||||
: removeL(makePsString(verb.entry.p, verb.entry.f));
|
||||
return [
|
||||
[base],
|
||||
];
|
||||
}
|
||||
if (aspect === "perfective") {
|
||||
const base = (verb.entry.ssp && verb.entry.ssf)
|
||||
// with irregular perfective stem
|
||||
? makePsString(verb.entry.ssp, verb.entry.ssf)
|
||||
: (verb.entry.psp && verb.entry.psf)
|
||||
// with perfective stem based on irregular perfective root
|
||||
? makePsString(verb.entry.psp, verb.entry.psf)
|
||||
// with regular infinitive based perfective stem
|
||||
: removeL(makePsString(verb.entry.p, verb.entry.f));
|
||||
// TODO: determine ph and base
|
||||
return [
|
||||
ooPrefix,
|
||||
[base],
|
||||
];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function addTrailingAccent(ps: T.PsString): T.PsString {
|
||||
return {
|
||||
p: ps.p,
|
||||
f: ps.f + "X",
|
||||
};
|
||||
}
|
||||
|
||||
function addUl(b: T.PsString): T.PsString {
|
||||
return concatPsString(b, { p: "ل", f: "ul" });
|
||||
}
|
||||
|
||||
// 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),
|
||||
};
|
||||
}
|
|
@ -88,7 +88,7 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
|
|||
]),
|
||||
};
|
||||
const modalBuilders: Record<
|
||||
T.ModalTense,
|
||||
T.AbilityTense,
|
||||
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
|
||||
> = {
|
||||
presentVerbModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
|
@ -215,7 +215,7 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
|
|||
]),
|
||||
}
|
||||
const passiveModalBuilders: Record<
|
||||
T.ModalTense,
|
||||
T.AbilityTense,
|
||||
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
|
||||
> = {
|
||||
presentVerbModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
isAdjectiveEntry,
|
||||
isImperativeTense,
|
||||
isLocativeAdverbEntry,
|
||||
isModalTense,
|
||||
isAbilityTense,
|
||||
isNounEntry,
|
||||
isPattern4Entry,
|
||||
isPerfectTense,
|
||||
|
@ -505,7 +505,7 @@ export function isStativeHelper(v: T.VerbEntry): boolean {
|
|||
}
|
||||
|
||||
function splitUpIfModal(v: T.VerbRenderedBlock): [T.VerbRenderedBlock] | [T.ModalVerbBlock, T.ModalVerbKedulPart] {
|
||||
if (!isModalTense(v.block.tense)) {
|
||||
if (!isAbilityTense(v.block.tense)) {
|
||||
return [v];
|
||||
}
|
||||
const [vrb, k] = splitOffLeapfrogWordFull(v.block.ps);
|
||||
|
@ -561,8 +561,8 @@ function getPsVerbConjugation(conj: T.VerbConjugation, vs: T.VerbSelectionComple
|
|||
const hasBa = hasBaParticle(getLong(verbForm)[0]);
|
||||
if (perfective) {
|
||||
const past = isPastTense(vs.tense);
|
||||
const splitInfo = conj.info[(past || isModalTense(vs.tense)) ? "root" : "stem"].perfectiveSplit;
|
||||
if (!splitInfo || (isTlulVerb(vs.verb.entry) && isModalTense(vs.tense))) {
|
||||
const splitInfo = conj.info[(past || isAbilityTense(vs.tense)) ? "root" : "stem"].perfectiveSplit;
|
||||
if (!splitInfo || (isTlulVerb(vs.verb.entry) && isAbilityTense(vs.tense))) {
|
||||
return { ps: { head: undefined, rest: removeBaFromForm(verbForm) }, hasBa };
|
||||
}
|
||||
// TODO: Either solve this in the inflector or here, it seems silly (or redundant)
|
||||
|
|
|
@ -38,7 +38,7 @@ export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
|||
*/
|
||||
export function getTenseVerbForm(
|
||||
conjR: T.VerbConjugation,
|
||||
tense: T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense,
|
||||
tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense,
|
||||
voice: "active" | "passive",
|
||||
mode: "charts" | "phrase-building",
|
||||
negative: boolean,
|
||||
|
@ -152,8 +152,8 @@ export function removeBa(ps: T.PsString): T.PsString {
|
|||
return psRemove(ps, concatPsString(grammarUnits.baParticle, " "));
|
||||
}
|
||||
|
||||
export function getTenseFromVerbSelection(vs: T.VerbSelection): T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense {
|
||||
function verbTenseToModalTense(tn: T.VerbTense): T.ModalTense {
|
||||
export function getTenseFromVerbSelection(vs: T.VerbSelection): T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense {
|
||||
function verbTenseToModalTense(tn: T.VerbTense): T.AbilityTense {
|
||||
if (tn === "presentVerb") {
|
||||
return "presentVerbModal";
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ export function isPastTense(tense: T.Tense): boolean {
|
|||
return tense.toLowerCase().includes("past");
|
||||
}
|
||||
|
||||
export function tenseHasBa(tense: T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense): boolean {
|
||||
export function tenseHasBa(tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense): boolean {
|
||||
return [
|
||||
"imperfectiveFuture",
|
||||
"perfectiveFuture",
|
||||
|
|
|
@ -222,7 +222,7 @@ export function isVerbTense(tense: T.Tense): tense is T.VerbTense {
|
|||
return verbTenses.some(x => x === tense);
|
||||
}
|
||||
|
||||
export function isModalTense(tense: T.Tense): tense is T.ModalTense {
|
||||
export function isAbilityTense(tense: T.Tense): tense is T.AbilityTense {
|
||||
return tense.endsWith("Modal");
|
||||
}
|
||||
|
||||
|
|
35
src/types.ts
35
src/types.ts
|
@ -142,6 +142,11 @@ export type DictionaryEntry = {
|
|||
}
|
||||
|
||||
export type DictionaryEntryNoFVars = DictionaryEntry & { __brand: "name for a dictionary entry with all the phonetics variations removed" };
|
||||
export type VerbDictionaryEntryNoFVars = VerbDictionaryEntry & { __brand2: "name for a verb dictionary entry with all the phonetics variations removed" };
|
||||
export type VerbEntryNoFVars = {
|
||||
entry: VerbDictionaryEntryNoFVars,
|
||||
complement?: DictionaryEntryNoFVars,
|
||||
} & { __brand: "name for a verb entry with all the phonetics variations removed" };
|
||||
export type PsStringNoFVars = PsString & { __brand: "name for a ps string with all the phonetics variations removed" };
|
||||
export type FStringNoFVars = string & { __brand: "name for a phonetics string with all the phonetics variations removed" };
|
||||
|
||||
|
@ -612,9 +617,9 @@ export type NounNumber = "singular" | "plural";
|
|||
|
||||
export type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive" | "wouldHaveBeen";
|
||||
export type PerfectTense = `${EquativeTense}Perfect`;
|
||||
export type ModalTense = `${VerbTense}Modal`;
|
||||
export type AbilityTense = `${VerbTense}Modal`;
|
||||
export type ImperativeTense = `${Aspect}Imperative`;
|
||||
export type Tense = EquativeTense | VerbTense | PerfectTense | ModalTense | ImperativeTense;
|
||||
export type Tense = EquativeTense | VerbTense | PerfectTense | AbilityTense | ImperativeTense;
|
||||
|
||||
export type SubjectSelection = {
|
||||
type: "subjectSelection",
|
||||
|
@ -655,7 +660,7 @@ export type VPSelectionComplete = {
|
|||
form: FormVersion,
|
||||
};
|
||||
|
||||
export type VerbFormName = VerbTense | PerfectTense | ModalTense | ImperativeTense;
|
||||
export type VerbFormName = VerbTense | PerfectTense | AbilityTense | ImperativeTense;
|
||||
|
||||
export type VerbSelectionComplete = Omit<VerbSelection, "object" | "verbTense" | "perfectTense" | "imperativeTense" | "tenseCategory"> & {
|
||||
tense: VerbFormName,
|
||||
|
@ -1075,6 +1080,9 @@ export type VB = PH | VA | VI | PT | EQ | Welded;
|
|||
export type PH = {
|
||||
type: "PH",
|
||||
ps: PsString,
|
||||
} | {
|
||||
type: "PHComp",
|
||||
comp: Comp,
|
||||
};
|
||||
|
||||
/** verb block with person agreement */
|
||||
|
@ -1105,11 +1113,30 @@ export type EQ = {
|
|||
person: Person,
|
||||
};
|
||||
|
||||
// Complement can be one of
|
||||
// - adjective
|
||||
// - locative adv
|
||||
// - sandwich (TODO)
|
||||
// - noun
|
||||
/** complement block */
|
||||
export type Comp = {
|
||||
type: "AdjComp",
|
||||
ps: PsString,
|
||||
gender: Gender,
|
||||
number: NounNumber,
|
||||
} | {
|
||||
type: "LocAdvComp",
|
||||
ps: PsString,
|
||||
} | {
|
||||
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, // TODO - will get more complex with compounds
|
||||
left: VI | Comp,
|
||||
right: VA | PT | VI,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue