From ed4e494e5410a3d627dfc0e546b3ac297a023bd5 Mon Sep 17 00:00:00 2001 From: adueck Date: Tue, 11 Apr 2023 11:22:09 +0400 Subject: [PATCH] more --- src/lib/src/accent-helpers.ts | 1 + src/lib/src/new-verb-engine/render-verb.ts | 69 +++++---- .../src/new-verb-engine/roots-and-stems.ts | 138 ++++++++++++------ src/lib/src/new-verb-engine/rs-helpers.ts | 49 ++++++- src/types.ts | 4 +- 5 files changed, 182 insertions(+), 79 deletions(-) diff --git a/src/lib/src/accent-helpers.ts b/src/lib/src/accent-helpers.ts index 347050a..008539d 100644 --- a/src/lib/src/accent-helpers.ts +++ b/src/lib/src/accent-helpers.ts @@ -120,6 +120,7 @@ export function accentPsSyllable(ps: T.PsString): T.PsString { } + export function removeAccentsWLength(s: T.SingleOrLengthOpts): T.SingleOrLengthOpts { if ("long" in s) { return { diff --git a/src/lib/src/new-verb-engine/render-verb.ts b/src/lib/src/new-verb-engine/render-verb.ts index 144786a..4f474d1 100644 --- a/src/lib/src/new-verb-engine/render-verb.ts +++ b/src/lib/src/new-verb-engine/render-verb.ts @@ -18,7 +18,7 @@ import { tenseHasBa } from "../phrase-building/vp-tools"; import { isPastTense } from "../phrase-building/vp-tools"; import { makePsString, removeFVarients } from "../accent-and-ps-utils"; import { pashtoConsonants } from "../pashto-consonants"; -import { getRootStem } from "./roots-and-stems"; +import { getPastParticiple, getRootStem } from "./roots-and-stems"; import { verbEndingConcat } from "./rs-helpers"; // For the chart display of the results: base the length thing on the VBE at the end, if there are other @@ -49,27 +49,24 @@ export function renderVerb({ verb, tense, person, voice }: { hasBa: boolean, vbs: T.VerbRenderedOutput, } { - // TODO: check for transitivity with passive voice ?? - - const hasBa = tenseHasBa(tense); if (isPerfectTense(tense)) { - throw new Error("not implemented yet"); + return renderPerfectVerb({ verb, tense, voice, person }); } - const isPast = isPastTense(tense); - const aspect = getAspect(tense); - const type = isAbilityTense(tense) ? "ability" : "basic"; + const hasBa = tenseHasBa(tense); const genderNumber = { gender: personGender(person), number: personNumber(person), }; + const isPast = isPastTense(tense); + const aspect = getAspect(tense); + const type = isAbilityTense(tense) ? "ability" : "basic"; + // #1 get the appropriate root / stem const [vHead, rest] = getRootStem({ verb, - part: { - rs: isPast ? "root" : "stem", - aspect, - }, + rs: isPast ? "root" : "stem", + aspect, voice, type, genderNumber, @@ -87,28 +84,50 @@ export function renderVerb({ verb, tense, person, voice }: { person, pastThird: isPast && person === T.Person.ThirdSingMale, aspect, + basicForm: type === "basic" && voice === "active", }), ], }; } - // 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 addEnding({ verb, rs, ending, person, pastThird, aspect }: { +function renderPerfectVerb({ tense, verb, voice, person }: { + tense: T.PerfectTense, + verb: T.VerbEntry, + voice: T.Voice, + person: T.Person, +}): { hasBa: boolean, vbs: [[], [T.VBGenNum, T.VBE]] } { + const hasBa = tenseHasBa(tense); + const genderNumber = { + gender: personGender(person), + number: personNumber(person), + }; + // #1 get the past participle + const pp = getPastParticiple(verb, voice, genderNumber); + // #2 get the right equative + const equative = equativeEndings[perfectTenseToEquative(tense)]; + const [row, col] = getVerbBlockPosFromPerson(person); + const equativeBlock: T.VBE = { + type: "VB", + person, + ps: "long" in equative ? { + long: equative.long[row][col], + short: equative.short[row][col], + } : equative[row][col], + }; + return { + hasBa, + vbs: [[], [pp, equativeBlock]], + }; +} + +function addEnding({ verb, rs, ending, person, pastThird, aspect, basicForm }: { rs: [T.VB, T.VBA] | [T.VBA], ending: T.SingleOrLengthOpts, person: T.Person, verb: T.VerbEntry, pastThird: boolean, aspect: T.Aspect, + basicForm: boolean, }): [T.VB, T.VBE] | [T.VBE] { return rs.length === 2 ? [rs[0], addEnd(rs[1], ending)] @@ -138,7 +157,7 @@ function addEnding({ verb, rs, ending, person, pastThird, aspect }: { ...vb, ps: { long: verbEndingConcat(rsLong, endLong), - short: pastThird + short: pastThird && basicForm ? ensure3rdPast(endShort, vb.ps.short, verb, aspect) : verbEndingConcat(vb.ps.short, endShort), }, @@ -164,7 +183,7 @@ function getEnding(person: T.Person, isPast: boolean) { } // TODO: THIS IS PROBABLY SKEEEETCH -function ensure3rdPast(ending: T.PsString[], rs: T.PsString[], verb: T.VerbEntry, aspect: T.Aspect): T.PsString[] { +function ensure3rdPast(rs: T.PsString[], ending: T.PsString[], verb: T.VerbEntry, aspect: T.Aspect): T.PsString[] { if (isKedul(verb) && rs[0].p === "شو") { return [{ p: "شو", f: "sho" }]; } diff --git a/src/lib/src/new-verb-engine/roots-and-stems.ts b/src/lib/src/new-verb-engine/roots-and-stems.ts index e94c097..0995b68 100644 --- a/src/lib/src/new-verb-engine/roots-and-stems.ts +++ b/src/lib/src/new-verb-engine/roots-and-stems.ts @@ -7,13 +7,14 @@ */ import { - concatPsString, getLength, trimOffPs, + concatPsString, trimOffPs, } from "../p-text-helpers"; import * as T from "../../../types"; import { makePsString, removeFVarientsFromVerb } from "../accent-and-ps-utils"; import { accentOnNFromEnd, accentSyllable, removeAccents } from "../accent-helpers"; -import { isKawulVerb } from "../type-predicates"; -import { vEntry, addAbilityEnding, weld, removeL, addTrailingAccent, tlulPerfectiveStem } from "./rs-helpers"; +import { isKawulVerb, isTlulVerb } from "../type-predicates"; +import { vEntry, addAbilityEnding, weld, removeL, addTrailingAccent, tlulPerfectiveStem, getLongVB } from "./rs-helpers"; +import { inflectPattern3 } from "./new-inflectors"; 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"}); @@ -29,15 +30,60 @@ const shVB: T.VBBasic = { ps: [{ p: "ش", f: "sh" }], } -// put the past participle in a different function +// TODO: kuRee shuwey etc +export function getPastParticiple(verb: T.VerbEntry, voice: T.Voice, { gender, number }: { gender: T.Gender, number: T.NounNumber }): T.VBGenNum { + const v = removeFVarientsFromVerb(verb); + if (voice === "passive") { + return getPassivePp(v, { gender, number }); + } + if (verb.entry.pprtp && verb.entry.pprtf) { + const base = makePsString(verb.entry.pprtp, verb.entry.pprtf); + return { + type: "VB", + ps: inflectPattern3(base, { gender, number }), + gender, + number, + }; + } + const [_, [basicRoot]] = getImperfectiveRoot(removeFVarientsFromVerb(verb)); + const longRoot = getLongVB(basicRoot); -export function getRootStem({ verb, part, type, genderNumber, voice }: { + if ("right" in longRoot) { + return { + ...longRoot, + right: { + ...longRoot.right, + ps: addTail(longRoot.right.ps), + }, + gender, + number, + }; + } else { + return { + ...longRoot, + ps: addTail(longRoot.ps), + gender, + number, + }; + } + + function addTail(ps: T.SingleOrLengthOpts): T.SingleOrLengthOpts { + if ("long" in ps) { + return { + long: addTail(ps.long) as T.PsString[], + short: addTail(ps.short) as T.PsString[], + }; + } + const withTail = concatPsString(ps[0], { p: "ی", f: "ey"}); + return inflectPattern3(withTail, { gender, number }); + } +} + +export function getRootStem({ verb, rs, aspect, type, genderNumber, voice }: { verb: T.VerbEntry, - part: { - rs: "root" | "stem", - aspect: T.Aspect, - } | "pastPart", - voice: "active" | "passive", + rs: "root" | "stem", + aspect: T.Aspect, + voice: T.Voice, type: "basic" | "ability", genderNumber: { gender: T.Gender, @@ -45,62 +91,66 @@ export function getRootStem({ verb, part, type, genderNumber, voice }: { }, }): T.RootsStemsOutput { const v = removeFVarientsFromVerb(verb); - if (part === "pastPart") { - throw new Error("not implemented yet"); - } if (type === "ability") { - return getAbilityRs(v, part); + return getAbilityRs(v, aspect, rs, voice); } if (voice === "passive") { - return getPassiveRs(v, part); + return getPassiveRs(v, aspect, rs); } - return part.rs === "stem" - ? part.aspect === "imperfective" + return rs === "stem" + ? aspect === "imperfective" ? getImperfectiveStem(v) : getPerfectiveStem(v, genderNumber) - : part.aspect === "imperfective" + : aspect === "imperfective" ? getImperfectiveRoot(v) : getPerfectiveRoot(v); } -function getAbilityRs(verb: T.VerbEntryNoFVars, { aspect, rs }: { aspect: T.Aspect, rs: "root" | "stem" }): [[] | [T.VHead], [T.VB, T.VBA]] { - const [vHead, [basicRoot]] = (aspect === "imperfective" - ? getImperfectiveRoot - : getPerfectiveRoot - )(verb); +function getAbilityRs( + verb: T.VerbEntryNoFVars, + aspect: T.Aspect, + rs: "root" | "stem", + voice: T.Voice, +): [[] | [T.VHead], [T.VB, T.VBA]] { + const losesAspect = isTlulVerb(verb); // or is intransitive stative compound + const [vhead, [basicroot]] = voice === "passive" + // passive ability loses aspect + ? getPassiveRs(verb, "imperfective", "root") + : aspect === "imperfective" || losesAspect + ? getImperfectiveRoot(verb) + : getPerfectiveRoot(verb); return [ - vHead, + vhead, [ - addAbilityEnding(basicRoot), + addAbilityEnding(basicroot), rs === "root" ? shwulVB : shVB, ], ]; } -function getPassiveRs(verb: T.VerbEntryNoFVars, part: { aspect: T.Aspect, rs: "root" | "stem" }): [[] | [T.VHead], [T.VBA]] { - const [vHead, [basicRoot]] = (part.aspect === "imperfective" +function getPassivePp(verb: T.VerbEntryNoFVars, genderNumber: T.GenderNumber): T.VBGenNum { + const [_, [basicRoot]] = getImperfectiveRoot(verb); + const longRoot = getLongVB(basicRoot); + const kedulVbGenNum = getPastParticiple(kedulStat, "active", genderNumber) as T.VBBasic & T.GenderNumber; + const kedulVb: T.VBBasic = { + type: "VB", + ps: kedulVbGenNum.ps, + }; + return weld(longRoot, kedulVb, genderNumber); +} + +function getPassiveRs(verb: T.VerbEntryNoFVars, aspect: T.Aspect, rs: "root" | "stem"): [[] | [T.VHead], [T.VBA]] { + const [vHead, [basicRoot]] = (aspect === "imperfective" ? getImperfectiveRoot : getPerfectiveRoot )(verb); const longRoot = getLongVB(basicRoot); - const kedulVba = getRootStem({ verb: kedulStat, part, type: "basic", voice: "active", genderNumber: { gender: "masc", number: "singular" }})[1][0] as T.VBBasic; + const kedulVba = getRootStem({ verb: kedulStat, aspect, rs, type: "basic", voice: "active", genderNumber: { gender: "masc", number: "singular" }})[1][0] as T.VBBasic; return [ vHead, [weld(longRoot, kedulVba)], ]; - function getLongVB(vb: T.VBA): T.VBA { - if (vb.type === "welded") { - return { - ...vb, - right: getLongVB(vb) as T.VBBasic, - }; - } - return { - ...vb, - ps: getLength(vb.ps, "long"), - }; - } -} +} function getImperfectiveRoot(verb: T.VerbEntryNoFVars): [[], [T.VBA]] { const infinitive = accentOnNFromEnd(makePsString(verb.entry.p, verb.entry.f), 0); @@ -211,12 +261,6 @@ function getPerfectiveStem(verb: T.VerbEntryNoFVars, person: { gender: T.Gender, ]; } -// function getPastPart(verb: T.VerbEntryNoFVars, person: { gender: T.Gender, number: T.NounNumber }): T.SingleOrLengthOpts { -// 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 diff --git a/src/lib/src/new-verb-engine/rs-helpers.ts b/src/lib/src/new-verb-engine/rs-helpers.ts index 8410f08..c8e54e9 100644 --- a/src/lib/src/new-verb-engine/rs-helpers.ts +++ b/src/lib/src/new-verb-engine/rs-helpers.ts @@ -4,6 +4,7 @@ import { accentPsSyllable, removeAccents, removeAccentsWLength } from "../accent import { concatPsString, trimOffPs } from "../p-text-helpers"; import { getRootStem } from "./roots-and-stems"; import { inflectPattern1 } from "./new-inflectors"; +import { getLength } from "../p-text-helpers"; export function vEntry(e: any, c?: any): T.VerbEntryNoFVars { return { @@ -26,12 +27,12 @@ export function getAllRs(verb: T.VerbEntry): { } { return { stem: { - perfective: getRootStem({ verb, type: "basic", voice: "active", part: { rs: "stem", aspect: "perfective" }, genderNumber: { gender: "masc", number: "singular" } }), - imperfective: getRootStem({ verb, type: "basic", voice: "active", part: { rs: "stem", aspect: "imperfective" }, genderNumber: { gender: "masc", number: "singular" } }), + perfective: getRootStem({ verb, type: "basic", voice: "active", rs: "stem", aspect: "perfective", genderNumber: { gender: "masc", number: "singular" } }), + imperfective: getRootStem({ verb, type: "basic", voice: "active", rs: "stem", aspect: "imperfective", genderNumber: { gender: "masc", number: "singular" } }), }, root: { - perfective: getRootStem({ verb, type: "basic", voice: "active", part: { rs: "root", aspect: "perfective" }, genderNumber: { gender: "masc", number: "singular" } }), - imperfective: getRootStem({ verb, type: "basic", voice: "active", part: { rs: "root", aspect: "imperfective" }, genderNumber: { gender: "masc", number: "singular" } }), + perfective: getRootStem({ verb, type: "basic", voice: "active", rs: "root", aspect: "perfective", genderNumber: { gender: "masc", number: "singular" } }), + imperfective: getRootStem({ verb, type: "basic", voice: "active", rs: "root", aspect: "imperfective", genderNumber: { gender: "masc", number: "singular" } }), }, }; } @@ -45,6 +46,14 @@ export function getAllRs(verb: T.VerbEntry): { * @returns */ export function verbEndingConcat(ps: T.PsString[], end: T.PsString[]): T.PsString[] { + if (ps[0].f === "shw") { + if (end[1]?.f === "o") { + return [{ p: "شو", f: "sho" }]; + } + if (end[0].f === "oo") { + return [{ p: "شو", f: "oo" }]; + } + } return ps.flatMap(v => ( end.map(e => { if (v.f.charAt(v.f.length-1) === "X") { @@ -58,17 +67,26 @@ export function verbEndingConcat(ps: T.PsString[], end: T.PsString[]): T.PsStrin )); } -export function weld(left: T.Welded["left"], right: T.Welded["right"]): T.Welded { +// TODO: better to have the genderNumber included and inferred in the right? +export function weld(left: T.Welded["left"], right: T.Welded["right"]): T.Welded; +export function weld(left: T.Welded["left"], right: T.Welded["right"], genderNum: T.GenderNumber): T.Welded & T.GenderNumber; +export function weld(left: T.Welded["left"], right: T.Welded["right"], genderNum?: T.GenderNumber): T.Welded { return { type: "welded", left: removeAccentsFromLeft(left), right, + ...genderNum ? { + ...genderNum, + } : {}, } function removeAccentsFromLeft(left: T.Welded["left"]): T.Welded["left"] { if (left.type === "VB") { return { ...left, ps: removeAccentsWLength(left.ps), + ...genderNum ? { + ...genderNum, + } : {}, } } if (left.type === "NComp") { @@ -77,7 +95,10 @@ export function weld(left: T.Welded["left"], right: T.Welded["right"]): T.Welded comp: { ...left.comp, ps: removeAccents(left.comp.ps), - } + }, + ...genderNum ? { + ...genderNum, + } : {}, }; } return { @@ -86,6 +107,9 @@ export function weld(left: T.Welded["left"], right: T.Welded["right"]): T.Welded ...left.right, ps: removeAccentsWLength(left.right.ps), }, + ...genderNum ? { + ...genderNum, + } : {}, }; } } @@ -148,4 +172,17 @@ export function addToVBBasicEnd(vb: T.VBBasic, end: T.PsString[]): T.VBBasic { ...vb, ps: verbEndingConcat(vb.ps, end), }; +} + +export function getLongVB(vb: T.VBA): T.VBA { + if (vb.type === "welded") { + return { + ...vb, + right: getLongVB(vb) as T.VBBasic, + }; + } + return { + ...vb, + ps: getLength(vb.ps, "long"), + }; } \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index 44fb9a9..aa138fb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1090,7 +1090,9 @@ export type VBBasic = { ps: SingleOrLengthOpts, }; -export type VBGenNum = VBBasic & GenderNumber; +// TODO: might be a better design decision to keep the GenderNuber stuff +// in the RIGHT side of the weld +export type VBGenNum = (VBBasic | Welded) & GenderNumber; export type GenderNumber = { gender: Gender,