From 4aa3568c72c21b40252016d1c5de1d54044ec187 Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Sat, 9 Oct 2021 11:47:03 -0400 Subject: [PATCH] basic start on the equative machine --- src/lib/equative-machine.test.ts | 303 ++++++++++++++++++++++--- src/lib/equative-machine.ts | 364 +++++++++++++++++++++---------- yarn.lock | 8 +- 3 files changed, 524 insertions(+), 151 deletions(-) diff --git a/src/lib/equative-machine.test.ts b/src/lib/equative-machine.test.ts index f19daca..c91aecc 100644 --- a/src/lib/equative-machine.test.ts +++ b/src/lib/equative-machine.test.ts @@ -1,30 +1,63 @@ import { equativeMachine, EquativeMachineOutput, - EquativeNounInput, + SubjectInput, + PredicateInput, + AdjectiveInput, + UnisexNounInput, + ParticipleInput, + assembleEquativeOutput, } from "./equative-machine"; import { Types as T, } from "@lingdocs/pashto-inflector"; +// INPUTS +// Person (pronoun) - subject only +// Noun - subject/predicate +// Unisex Noun - subject/predicate +// Adjective - predicate only +// Participle - subject/predicate + +// COMBINATIONS +// Subject | Predicate +// --------------------------- +// Person | Noun +// Person | Unisex Noun ✔ +// Person | Adjective ✔ +// Person | Participle ✔ +// Noun | Noun ✔ +// Noun | Adjective ✔ +// Noun | Participle ✔ +// Noun | Specified Unisex Noun ✔ +// Specified Unisex Noun | Noun ✔ +// Specified Unisex Noun | Adjective ✔ +// Specified Unisex Noun | Participle ✔ +// Participle | Noun ✔ +// Participle | Adjective ✔ +// Participle | Participle ✔ +// Participle | Specified Unisex noun ✔ + +// TODO: allow unisex subject inputs male or female! + const abilities: { label: string, tests: { in: { - subject: T.Person | EquativeNounInput | T.DictionaryEntry, - predicate: T.DictionaryEntry, + subject: SubjectInput, + predicate: PredicateInput, }, out: EquativeMachineOutput, }[], }[] = [ { - label: "handle person subjects with adjective predicates", + label: "SUBJECT: Person PREDICATE: Adjective", tests: [ // -- inflecting adjectives { in: { subject: T.Person.FirstSingMale, - predicate: {"ts":1527815306,"i":7530,"p":"ستړی","f":"stúRey","g":"stuRey","e":"tired","c":"adj."}, + predicate: {"ts":1527815306,"i":7530,"p":"ستړی","f":"stúRey","g":"stuRey","e":"tired","c":"adj."} as AdjectiveInput, }, out: { subject: [{ p: "زه", f: "zu", e: "I (m.)" }], @@ -35,7 +68,7 @@ const abilities: { { in: { subject: T.Person.SecondPlurFemale, - predicate: {"ts":1527815306,"i":7530,"p":"ستړی","f":"stúRey","g":"stuRey","e":"tired","c":"adj."}, + predicate: {"ts":1527815306,"i":7530,"p":"ستړی","f":"stúRey","g":"stuRey","e":"tired","c":"adj."} as AdjectiveInput, }, out: { subject: [{ p: "تاسو", f: "táaso", e: "You (f. pl.)" }, { p: "تاسې", f: "táase", e: "You (f. pl.)"}], @@ -47,7 +80,7 @@ const abilities: { { in: { subject: T.Person.ThirdSingFemale, - predicate: {"ts":1527812798,"i":5595,"p":"خفه","f":"khufa","g":"khufa","e":"sad, upset, angry; choked, suffocated","c":"adj."}, + predicate: {"ts":1527812798,"i":5595,"p":"خفه","f":"khufa","g":"khufa","e":"sad, upset, angry; choked, suffocated","c":"adj."} as AdjectiveInput, }, out: { subject: [{ p: "هغه", f: "haghá", e: "She/it (f.)" }], @@ -58,45 +91,45 @@ const abilities: { ], }, { - label: "handle person subjects with unisex noun predicate", + label: "SUBJECT: Person PREDICATE: Unisex Noun", tests: [ { in: { subject: T.Person.FirstSingFemale, - predicate: {"ts":1591872915426,"i":696,"p":"افغانی","f":"afghaanéy","g":"afghaaney","e":"Afghan (person)","c":"n. m. unisex"}, + predicate: {"ts":1591872915426,"i":696,"p":"افغانی","f":"afghaanéy","g":"afghaaney","e":"Afghan (person)","c":"n. m. unisex"} as UnisexNounInput, }, out: { subject: [{ p: "زه", f: "zu", e: "I (f.)" }], - predicate: [{ p: "افغانۍ", f: "afghaanúy", e: "Afghan" }], + predicate: [{ p: "افغانۍ", f: "afghaanúy", e: "(a/the) Afghan" }], equative: [{ p: "یم", f: "yum", e: "am" }], } }, { in: { subject: T.Person.FirstPlurFemale, - predicate: {"ts":1527814779,"i":935,"p":"انسان","f":"insaan","g":"insaan","e":"human, person","c":"n. m. anim. unisex"}, + predicate: {"ts":1527814779,"i":935,"p":"انسان","f":"insaan","g":"insaan","e":"human, person","c":"n. m. anim. unisex"} as UnisexNounInput, }, out: { subject: [{ p: "مونږ", f: "moonG", e: "We (f. pl.)" }, { p: "موږ", f: "mooG", e: "We (f. pl.)" }], - predicate: [{ p: "انسانانې", f: "insaanáane", e: "humans" }], + predicate: [{ p: "انسانانې", f: "insaanáane", e: "(the) humans" }], equative: [{ p: "یو", f: "yoo", e: "are" }], }, }, { in: { subject: T.Person.SecondSingFemale, - predicate: {"ts":1527814779,"i":935,"p":"انسان","f":"insaan","g":"insaan","e":"human, person","c":"n. m. anim. unisex"}, + predicate: {"ts":1527814779,"i":935,"p":"انسان","f":"insaan","g":"insaan","e":"human, person","c":"n. m. anim. unisex"} as UnisexNounInput, }, out: { subject: [{ p: "ته", f: "tu", e: "You (f.)" }], - predicate: [{ p: "انسانه", f: "insaana", e: "human" }], + predicate: [{ p: "انسانه", f: "insaana", e: "(a/the) human" }], equative: [{ p: "یې", f: "ye", e: "are" }], }, }, ], }, { - label: "Handle noun subjects with adjective predicates", + label: "SUBJECT: Noun PREDICATE: Adjective", tests: [ { in: { @@ -104,7 +137,7 @@ const abilities: { entry: { "ts":1527812817,"i":9921,"p":"کتاب","f":"kitáab","g":"kitaab","e":"book","c":"n. m." }, plural: false, }, - predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"}, + predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"} as AdjectiveInput, }, out: { subject: [{ p: "کتاب", f: "kitáab", e: "(A/The) book" }], @@ -118,7 +151,7 @@ const abilities: { entry: { "ts":1527812817,"i":9921,"p":"کتاب","f":"kitáab","g":"kitaab","e":"book","c":"n. m." }, plural: true, }, - predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"}, + predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"} as AdjectiveInput, }, out: { subject: [{ p: "کتابونه", f: "kitaabóona", e: "(The) books" }], @@ -132,7 +165,7 @@ const abilities: { entry: {"ts":1527812797,"i":8542,"p":"ښځه","f":"xúdza","g":"xudza","e":"woman, wife","c":"n. f. anim.","ec":"woman","ep":"women"}, plural: false, }, - predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"}, + predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"} as AdjectiveInput, }, out: { subject: [{ p: "ښځه", f: "xúdza", e: "(A/The) woman" }], @@ -146,7 +179,7 @@ const abilities: { entry: {"ts":1527812797,"i":8542,"p":"ښځه","f":"xúdza","g":"xudza","e":"woman, wife","c":"n. f. anim.","ec":"woman","ep":"women"}, plural: true, }, - predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"}, + predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"} as AdjectiveInput, }, out: { subject: [{ p: "ښځې", f: "xúdze", e: "(The) women" }], @@ -161,7 +194,7 @@ const abilities: { entry: {"ts":1527812797,"i":8542,"p":"ښځه","f":"xúdza","g":"xudza","e":"woman, wife","c":"n. f. anim.","ec":"woman","ep":"women"}, plural: true, }, - predicate: {"ts":1527812798,"i":5595,"p":"خفه","f":"khufa","g":"khufa","e":"sad, upset, angry; choked, suffocated","c":"adj."}, + predicate: {"ts":1527812798,"i":5595,"p":"خفه","f":"khufa","g":"khufa","e":"sad, upset, angry; choked, suffocated","c":"adj."} as AdjectiveInput, }, out: { subject: [{ p: "ښځې", f: "xúdze", e: "(The) women" }], @@ -172,12 +205,12 @@ const abilities: { ], }, { - label: "handle participle subjects with adjective predicates", + label: "SUBJECT: Participle PREDICATE: Adjective", tests: [ { in: { - subject: {"ts":1527812790,"i":5747,"p":"خوړل","f":"khoRul","g":"khoRul","e":"to eat, to bite","c":"v. trans.","psp":"خور","psf":"khor","tppp":"خوړ","tppf":"khoR","ec":"eat"}, - predicate: {"ts":1527812796,"i":8578,"p":"ښه","f":"xu","g":"xu","e":"good","c":"adj."}, + subject: {"ts":1527812790,"i":5747,"p":"خوړل","f":"khoRul","g":"khoRul","e":"to eat, to bite","c":"v. trans.","psp":"خور","psf":"khor","tppp":"خوړ","tppf":"khoR","ec":"eat"} as ParticipleInput, + predicate: {"ts":1527812796,"i":8578,"p":"ښه","f":"xu","g":"xu","e":"good","c":"adj."} as AdjectiveInput, }, out: { subject: [{ p: "خوړل", f: "khoRul", e: "eating" }], @@ -187,15 +220,225 @@ const abilities: { }, { in: { - subject: {"ts":1527817298,"i":310,"p":"اخیستل","f":"akheestul","g":"akheestul","e":"to take, buy, purchase, receive; to shave, cut with scissors","c":"v. trans.","psp":"اخل","psf":"akhl","ec":"take,takes,taking,took,taken"}, - predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"}, + subject: {"ts":1527817298,"i":310,"p":"اخیستل","f":"akheestul","g":"akheestul","e":"to take, buy, purchase, receive; to shave, cut with scissors","c":"v. trans.","psp":"اخل","psf":"akhl","ec":"take,takes,taking,took,taken"} as ParticipleInput, + predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"} as AdjectiveInput, }, out: { subject: [{ p: "اخیستل", f: "akheestul", e: "taking" }], predicate: [{ p: "زاړه", f: "zaaRu", e: "old" }], equative: [{ p: "دي", f: "dee", e: "is" }], }, - } + }, + { + in: { + subject: {"ts":1527816854,"i":4365,"p":"جګېدل","f":"jugedul, jigedul","g":"jugedul,jigedul","e":"to get up, be raised up","c":"v. stat. comp. intrans.","l":1527812707,"ec":"get, gets, getting, got, gotten","ep":"up"} as ParticipleInput, + predicate: {"ts":1527815246,"i":7591,"p":"سخت","f":"sakht","g":"sakht","e":"hard, difficult","c":"adj."} as AdjectiveInput, + }, + out: { + subject: [{ p: "جګېدل", f: "jugedul", e: "getting up" }], + predicate: [{ p: "سخت", f: "sakht", e: "hard" }], + equative: [{ p: "دي", f: "dee", e: "is" }], + }, + }, + ], + }, + { + label: "SUBJECT: Person PREDICATE: Participle", + tests: [ + { + in: { + subject: T.Person.SecondSingMale, + predicate: {"ts":1527812856,"i":11521,"p":"لیکل","f":"leekul","g":"leekul","e":"to write","c":"v. trans.","ec":"write,writes,writing,wrote,wrote"} as ParticipleInput, + }, + out: { + subject: [{ p: "ته", f: "tu", e: "You (m.)" }], + predicate: [{ p: "لیکل", f: "leekul", e: "writing" }], + equative: [{ p: "دي", f: "dee", e: "are" }], + } + }, + ], + }, + { + label: "SUBJECT: Noun PREDICATE: Noun", + tests: [ + { + in: { + subject: { + entry: {"ts":1527813477,"i":5790,"p":"خوشحالي","f":"khosh`haalee","g":"khoshhaalee","e":"happiness, joy","c":"n. f."}, + plural: false, + }, + predicate: { + entry: {"ts":1527812788,"i":5729,"p":"خوراک","f":"khoráak, khwaráak","g":"khoraak,khwaraak","e":"food","c":"n. m."}, + plural: false, + }, + }, + out: { + subject: [{ p: "خوشحالي", f: "khosh`haalee", e: "(A/The) happiness" }], + predicate: [{ p: "خوراک", f: "khoráak", e: "(a/the) food" }], + equative: [{ p: "دی", f: "dey", e: "is" }], + }, + }, + ], + }, + { + label: "SUBJECT: Noun PREDICATE: Participle", + tests: [ + { + in: { + subject: { + entry: {"ts":1527822878,"i":14157,"p":"وروروالی","f":"wrorwaaley","g":"wrorwaaley","e":"brotherhood, comradery, tight and good friendship","c":"n. m."}, + plural: false, + }, + predicate: {"ts":1527816064,"i":7097,"p":"زغمل","f":"zghamul","g":"zghamul","e":"to endure, bear, tolerate, take on, digest","c":"v. trans.","tppp":"زغامه","tppf":"zghaamu","ec":"endure"} as ParticipleInput, + }, + out: { + subject: [{ p: "وروروالی", f: "wrorwaaley", e: "(A/The) brotherhood" }], + predicate: [{ p: "زغمل", f: "zghamul", e: "enduring" }], + equative: [{ p: "دي", f: "dee", e: "is" }], + }, + }, + ], + }, + { + label: "SUBJECT: Participle PREDICATE: Noun", + tests: [ + { + in: { + subject: {"ts":1527812856,"i":11521,"p":"لیکل","f":"leekul","g":"leekul","e":"to write","c":"v. trans.","ec":"write,writes,writing,wrote,wrote"} as ParticipleInput, + predicate: { + entry: {"ts":1527813477,"i":5790,"p":"خوشحالي","f":"khosh`haalee","g":"khoshhaalee","e":"happiness, joy","c":"n. f."}, + plural: false, + }, + }, + out: { + subject: [{ p: "لیکل", f: "leekul", e: "writing" }], + predicate: [{ p: "خوشحالي", f: "khosh`haalee", e: "(a/the) happiness" }], + equative: [{ p: "ده", f: "da", e: "is" }], + }, + }, + ], + }, + { + label: "SUBJECT: Participle PREDICATE: Participle", + tests: [ + { + in: { + subject: {"ts":1527812856,"i":11521,"p":"لیکل","f":"leekul","g":"leekul","e":"to write","c":"v. trans.","ec":"write,writes,writing,wrote,wrote"} as ParticipleInput, + predicate: {"ts":1577394057681,"i":2784,"p":"پوهېدل","f":"pohedul","g":"pohedul","e":"to understand (to come to a state of understanding)","c":"v. stat. comp. intrans.","l":1527811469,"ec":"understand,understand,understanding,understood"} as ParticipleInput, + }, + out: { + subject: [{ p: "لیکل", f: "leekul", e: "writing" }], + predicate: [{ p: "پوهېدل", f: "pohedul", e: "understanding" }], + equative: [{ p: "دي", f: "dee", e: "is" }], + }, + }, + ], + }, + { + label: "SUBJECT: Noun PREDICATE: Specified Unisex Noun", + tests: [ + { + in: { + subject: { + entry: {"ts":1527812817,"i":9921,"p":"کتاب","f":"kitáab","g":"kitaab","e":"book","c":"n. m."}, + plural: true, + }, + predicate: { + entry: {"ts":1527815127,"i":13259,"p":"نرس","f":"nars, nursa","g":"nars,nursa","e":"nurse","c":"n. m. anim. unisex"}, + plural: false, + gender: "fem", + }, + }, + out: { + subject: [{ p: "کتابونه", f: "kitaabóona", e: "(The) books" }], + predicate: [{ p: "نرسه", f: "narsa", e: "(a/the) nurse" }], + equative: [{ p: "ده", f: "da", e: "are" }], + }, + }, + ], + }, + { + label: "SUBJECT: Specified Unisex Noun PREDICATE: Adjective", + tests: [ + { + in: { + subject: { + entry: {"ts":1527815127,"i":13259,"p":"نرس","f":"nars, nursa","g":"nars,nursa","e":"nurse","c":"n. m. anim. unisex"}, + plural: true, + gender: "fem", + }, + predicate: {"ts":1527815451,"i":7193,"p":"زوړ","f":"zoR","g":"zoR","e":"old","c":"adj. irreg.","infap":"زاړه","infaf":"zaaRu","infbp":"زړ","infbf":"zaR"} as AdjectiveInput, + }, + out: { + // TODO: should also use نرسې ? + subject: [{ p: "نرسانې", f: "narsáane", e: "(The) nurses" }], + predicate: [{ p: "زړې", f: "zaRe", e: "old" }], + equative: [{ p: "دي", f: "dee", e: "are" }], + }, + }, + ], + }, + { + label: "SUBJECT: Specified Unisex Noun PREDICATE: Predicate", + tests: [ + { + in: { + subject: { + entry: {"ts":1527815127,"i":13259,"p":"نرس","f":"nars, nursa","g":"nars,nursa","e":"nurse","c":"n. m. anim. unisex"}, + plural: false, + gender: "fem", + }, + predicate: { + entry: {"ts":1527812817,"i":9921,"p":"کتاب","f":"kitáab","g":"kitaab","e":"book","c":"n. m."}, + plural: true, + }, + }, + out: { + subject: [{ p: "نرسه", f: "narsa", e: "(A/The) nurse" }], + predicate: [{ p: "کتابونه", f: "kitaabóona", e: "(the) books" }], + equative: [{ p: "دي", f: "dee", e: "is" }], + }, + }, + ], + }, + { + label: "SUBJECT: Specified Unisex Noun PREDICATE: Participle", + tests: [ + { + in: { + subject: { + entry: {"ts":1527815127,"i":13259,"p":"نرس","f":"nars, nursa","g":"nars,nursa","e":"nurse","c":"n. m. anim. unisex"}, + plural: false, + gender: "fem", + }, + predicate: {"ts":1527813680,"i":9131,"p":"غږېدل","f":"ghuGedul, ghaGedul","g":"ghugedul,ghagedul","e":"to converse, speak, talk, sing","c":"v. intrans.","ec":"speak,speaks,speaking,spoke"} as ParticipleInput, + }, + out: { + subject: [{ p: "نرسه", f: "narsa", e: "(A/The) nurse" }], + predicate: [{ p: "غږېدل", f: "ghuGedul", e: "speaking" }], + equative: [{ p: "دي", f: "dee", e: "is" }], + }, + }, + ], + }, + { + label: "SUBJECT: Participle PREDICATE: Specified Unisex Noun", + tests: [ + { + in: { + subject: {"ts":1527812856,"i":11521,"p":"لیکل","f":"leekul","g":"leekul","e":"to write","c":"v. trans.","ec":"write,writes,writing,wrote,wrote"} as ParticipleInput, + predicate: { + entry: {"ts":1527815127,"i":13259,"p":"نرس","f":"nars, nursa","g":"nars,nursa","e":"nurse","c":"n. m. anim. unisex"}, + plural: false, + gender: "fem", + }, + }, + out: { + subject: [{ p: "لیکل", f: "leekul", e: "writing" }], + predicate: [{ p: "نرسه", f: "narsa", e: "(a/the) nurse" }], + equative: [{ p: "ده", f: "da", e: "is" }], + }, + }, ], }, ]; @@ -208,4 +451,12 @@ describe("equativeMachine", () => { }); }); }); +}); + +test("assembleEquativeOutput", () => { + expect(assembleEquativeOutput({ + subject: [{ p: "کتابونه", f: "kitaabóona", e: "(The) books" }], + predicate: [{ p: "زاړه", f: "zaaRu", e: "old" }], + equative: [{ p: "دي", f: "dee", e: "are" }], + })).toEqual([{ p: "کتابونه زاړه دي", f: "kitaabóona zaaRu dee", e: "(The) books are old" }]); }); \ No newline at end of file diff --git a/src/lib/equative-machine.ts b/src/lib/equative-machine.ts index f767a15..bd45abb 100644 --- a/src/lib/equative-machine.ts +++ b/src/lib/equative-machine.ts @@ -10,7 +10,10 @@ import { personGender, getVerbBlockPosFromPerson, addEnglish, + parseEc, + concatPsString, } from "@lingdocs/pashto-inflector"; +import { SingleOrLengthOpts } from "@lingdocs/pashto-inflector/dist/types"; export type EquativeMachineOutput = { subject: T.PsString[], @@ -18,25 +21,30 @@ export type EquativeMachineOutput = { equative: T.SingleOrLengthOpts>, }; -export type EquativeNounInput = { +export type NounInput = { entry: T.DictionaryEntry, plural: boolean, }; -export function equativeMachine(sub: T.Person | EquativeNounInput | T.DictionaryEntry, pred: T.DictionaryEntry): EquativeMachineOutput { - const subjPerson = getSubPerson(sub); - const isParticiple = !!(typeof sub !== "number" && "ts" in sub && sub.c?.startsWith("v.")); - if (!isParticiple && (typeof sub !== "number" && "ts" in sub)) { - throw new Error("non participle subject should be in this form: { entry: T.Dictionary, plural: boolean }"); - } - const subject = typeof sub === "number" - ? makePronounSubject(sub) - : "entry" in sub - ? makeNounSubject(sub) - : makeParticipleSub(sub); - const predicate = makePredicate(pred, subjPerson); - const equative = makeEquative(subjPerson, isParticiple); +export type AdjectiveInput = T.DictionaryEntry & { __brand: "an adjective" }; +export type ParticipleInput = T.DictionaryEntry & { __brand: "a participle" }; +export type UnisexNounInput = T.DictionaryEntry & { __brand: "a unisex noun" }; +export type SpecifiedUnisexNounInput = NounInput & { gender: T.Gender }; +export type PersonInput = T.Person; +export type EntityInput = SubjectInput | PredicateInput; +export type SubjectInput = PersonInput | NounInput | ParticipleInput | SpecifiedUnisexNounInput; +export type PredicateInput = PersonInput | NounInput | AdjectiveInput | SpecifiedUnisexNounInput | UnisexNounInput | ParticipleInput; + +export function equativeMachine(sub: SubjectInput, pred: PredicateInput): EquativeMachineOutput { + // - english equative always agrees with subject + // - pashto equative agrees with predicate, unless it's an adjective, in which case the + // agreement reverts to the subject + const subjPerson = getInputPerson(sub, "subject"); + const predPerson = getInputPerson(pred, "predicate") || subjPerson; + const subject = makeEntity(sub); + const predicate = makeEntity(pred, subjPerson); + const equative = makeEquative(subjPerson, predPerson, isParticipleInput(sub)); return { subject, predicate, @@ -44,7 +52,75 @@ export function equativeMachine(sub: T.Person | EquativeNounInput | T.Dictionary }; } -function makePronounSubject(sub: T.Person): T.PsString[] { +export function assembleEquativeOutput(o: EquativeMachineOutput): SingleOrLengthOpts { + if ("long" in o.equative) { + return { + long: assembleEquativeOutput({ ...o, equative: o.equative.long }) as T.PsString[], + short: assembleEquativeOutput({ ...o, equative: o.equative.short }) as T.PsString[], + } + } + // TODO: make it use all the variations + const ps = concatPsString(o.subject[0], " ", o.predicate[0], " ", o.equative[0]); + const e = `${o.subject[0].e} ${o.equative[0].e} ${o.predicate[0].e}`; + return [{ ...ps, e }]; +} + +// LEVEL 2 FUNCTIONS + +function getInputPerson(e: SubjectInput, part: "subject"): T.Person; +function getInputPerson(e: PredicateInput, part: "predicate"): T.Person | undefined; +function getInputPerson(e: EntityInput, part: "subject" | "predicate"): T.Person | undefined { + function nounPerson(gender: T.Gender, plural: boolean): T.Person { + return plural + ? ((gender === "masc") ? T.Person.ThirdPlurMale : T.Person.ThirdPlurFemale) + : ((gender === "masc") ? T.Person.ThirdSingMale : T.Person.ThirdSingFemale); + } + + if (isPersonInput(e)) return e; + if (isNounInput(e)) { + const gender = e.entry.c?.includes("n. m.") ? "masc" : "fem" + return nounPerson(gender, e.plural); + } + if (isSpecifiedUnisexNounInput(e)) { + return nounPerson(e.gender, e.plural); + } + if (isParticipleInput(e)) return T.Person.ThirdPlurMale; + if (isUnisexNounInput(e)) return undefined; + if (isAdjectiveInput(e)) return undefined; +} + +function makeEntity(e: EntityInput, subjPerson?: T.Person): T.PsString[] { + const isSubject = subjPerson === undefined; + if (typeof e === "number") return makePronoun(e); + if ("entry" in e) { + return makeNoun(e, isSubject ? "subject" : "predicate"); + } + if (isAdjectiveInput(e) && subjPerson !== undefined) { + return makeAdjective(e, subjPerson); + } + if (isUnisexNounInput(e)) { + return makeUnisexNoun(e, subjPerson); + } + if (isParticipleInput(e)) { + return makeParticiple(e); + } + throw new Error(`invalid entity in ${subjPerson ? "predicate" : "subject"}`); +} + +function makeEquative(subj: T.Person, pred: T.Person, subjIsParticipleInput: boolean): T.SentenceForm { + // The subject's person information, for the English equative + const [sRow, sCol] = getVerbBlockPosFromPerson(subjIsParticipleInput ? T.Person.ThirdSingMale : subj); + return addEnglish( + // english agrees with subject + grammarUnits.englishEquative.present[sRow][sCol], + // pashto agrees with predicate (if possible) + getPersonFromVerbForm(grammarUnits.equativeEndings.present, pred), + ); +} + +// LEVEL 3 FUNCTIONS + +function makePronoun(sub: T.Person): T.PsString[] { const [row, col] = getVerbBlockPosFromPerson(sub); return addEnglish( grammarUnits.persons[sub].label.subject, @@ -52,127 +128,124 @@ function makePronounSubject(sub: T.Person): T.PsString[] { ); } -function makeNounSubject(sub: EquativeNounInput): T.PsString[] { - function makeEnglish(): string { - const e = getEnglishWord(sub.entry); - if (!e) { - throw new Error(`unable to get english from subject ${sub.entry.f} - ${sub.entry.ts}`); +function makeUnisexNoun(e: UnisexNounInput, subjPerson: T.Person | undefined): T.PsString[] { + // reuse english from make noun - do the a / an sensitivity + // if it's the predicate - get the inflection according to the subjPerson + const isPredicate = !!subjPerson; + if (isPredicate) { + const inf = inflectWord(e); + // TODO: Use if no inflections // FIX THIS + // BETTER CHECKING / GUARDING HERE + // @ts-ignore - TODO: REMOVE THIS + if (!inf || (!inf.inflections && !("plural" in inf)) || !isUnisexSet(inf.inflections)) { + throw Error("improper unisex noun"); } - if (typeof e === "string") return `(A/The) ${e}`; - if (sub.plural) { - return `(The) ${e.plural}`; - } - if (!e.singular) { - throw new Error(`unable to get english from subject ${sub.entry.f} - ${sub.entry.ts}`); - } - return `(A/The) ${e.singular}`; - } - function getPashto(): T.ArrayOneOrMore { - const infs = inflectWord(sub.entry); - const gender = sub.entry.c?.includes("n. f.") ? "fem" : "masc"; - try { - if (!infs || !sub.plural) { - return [psStringFromEntry(sub.entry, english)]; - } - if (!("plural" in infs)) { - // @ts-ignore - return infs.inflections[gender][sub.plural ? 1 : 0]; - } + // if plural // anim // chose that + // otherwise just chose inflection (or add both) + const pashto = ("plural" in inf && personIsPlural(subjPerson)) // @ts-ignore - return infs.plural[gender][0] - } catch (e) { - throw new Error(`error making noun subject for ${sub.entry.f} ${sub.entry.ts}`); - } + ? inf.plural[personGender(subjPerson)][0] as T.ArrayOneOrMore + : chooseInflection(inf.inflections, subjPerson); + const english = getEnglishFromNoun(e, personIsPlural(subjPerson), "predicate"); + return addEnglish(english, pashto); } - const english = makeEnglish(); + // if it's the subject - TO BE IMPLEMENTED + throw new Error("unisex noun as subject not implemented yet"); +} + +function makeNoun(n: NounInput | SpecifiedUnisexNounInput, entity: "subject" | "predicate"): T.PsString[] { + const english = getEnglishFromNoun(n.entry, n.plural, entity); + + const pashto = ((): T.ArrayOneOrMore => { + const infs = inflectWord(n.entry); + const gender = "gender" in n + ? n.gender + : n.entry.c?.includes("n. f.") ? "fem" : "masc"; + try { + if (n.plural && infs) { + if ("plural" in infs && infs.plural !== undefined) { + // ts-ignore used here because we know we can trust the gender to work + // @ts-ignore + return infs.plural[gender][0] as T.ArrayOneOrMore; + } + // TODO: Add arabic plural? + if ("inflections" in infs && infs.inflections !== undefined) { + // @ts-ignore + return infs.inflections[gender][1] as T.ArrayOneOrMore; + } + return [psStringFromEntry(n.entry, english)]; + } else if (!n.plural && infs && "inflections" in infs && infs.inflections !== undefined) { + // @ts-ignore + return infs.inflections[gender][0] as T.ArrayOneOrMore; + } + return [psStringFromEntry(n.entry, english)]; + } catch(e) { + console.error(e); + throw new Error("error making noun " + n.entry.ts); + } + })(); + return addEnglish(english, pashto); +} + +function makeAdjective(e: AdjectiveInput, pers: T.Person): T.PsString[] { + const inf = inflectWord(e); + const english = getEnglishWord(e); + if (!english) throw new Error("no english available for adjective"); + if (typeof english !== "string") throw new Error("error getting english for adjective, looks like a noun"); + // non-inflecting adjective + if (!inf) return [psStringFromEntry(e, english)]; + if (!inf.inflections) throw new Error("error getting inflections, looks like a noun") + if (!isUnisexSet(inf.inflections)) throw new Error("inflections for adjective were not unisex, looks like a noun"); + // inflecting adjective - inflected based on the subject person return addEnglish( english, - getPashto(), + chooseInflection(inf.inflections, pers), ); } -function makeParticipleSub(sub: T.DictionaryEntry): T.PsString[] { - return [ - psStringFromEntry(sub, getEnglishParticiple(sub)), - ]; +function makeParticiple(e: T.DictionaryEntry): T.PsString[] { + return [psStringFromEntry(e, getEnglishParticiple(e))]; } -function makeEquative(pers: T.Person, isParticiple: boolean): T.SentenceForm { - const [row, col] = getVerbBlockPosFromPerson(pers); - return addEnglish( - isParticiple - ? grammarUnits.englishEquative.present[4][0] - : grammarUnits.englishEquative.present[row][col], - getPersonFromVerbForm(grammarUnits.equativeEndings.present, pers), - ); -} -function getSubPerson(sub: T.Person | EquativeNounInput | T.DictionaryEntry): T.Person { - if (typeof sub === "number") { - return sub; - } - if ("entry" in sub) { - const gender = sub.entry.c?.includes("n. f.") ? "fem" : "masc"; - if (gender === "masc" && !sub.plural) { - return T.Person.ThirdSingMale; - } - if (gender === "masc" && sub.plural) { - return T.Person.ThirdPlurMale; - } - if (gender === "fem" && !sub.plural) { - return T.Person.ThirdSingFemale; - } - //if (gender === "fem" && sub.plural) { - return T.Person.ThirdPlurFemale; - // } - } - if (!sub.c || !sub.c.startsWith("v.")) { - throw new Error("subject should be a participle/verb"); - } - return T.Person.ThirdPlurMale; -} +// LEVEL 4 FUNCTIONS -function makePredicate(pred: T.DictionaryEntry, pers: T.Person): T.PsString[] { - const infs = inflectWord(pred); - const e = retrieveEnglishPredicate(pred, pers); - if (!e) { - throw new Error(`unable to get english from predicate ${pred.f} - ${pred.ts}`); - } - const plural = personIsPlural(pers); - const gender = personGender(pers); - const makePlainPred = () => ([psStringFromEntry(pred, e)]); - if (!infs || !infs.inflections || !isUnisexSet(infs.inflections)) { - return makePlainPred(); - } - if (plural && "plural" in infs && infs.plural) { - const ps = gender in infs.plural - // @ts-ignore - ? infs.plural[gender][0] as T.PsString[] - : makePlainPred(); - return ps.map((p) => ({ ...p, e })); - } - // if (infs.inflections) { - const inflection = chooseInflection(infs.inflections, pers); - return inflection.map((i) => ({ ...i, e })); - // } -} - -function chooseInflection(inflections: T.UnisexSet, pers: T.Person): T.PsString[] { +function chooseInflection(inflections: T.UnisexSet, pers: T.Person): T.ArrayOneOrMore { return inflections[personGender(pers)][personIsPlural(pers) ? 1 : 0]; } -function retrieveEnglishPredicate(pred: T.DictionaryEntry, pers: T.Person): string | undefined { - const english = getEnglishWord(pred); - const plurSing = personIsPlural(pers) ? "plural" : "singular"; - return typeof english === "string" - ? english - : english === undefined - ? undefined - : english[plurSing] - ? english[plurSing] - : undefined; +function getEnglishFromNoun(entry: T.DictionaryEntry, plural: boolean, entity: "subject" | "predicate"): string { + const articles = { + singular: "(A/The)", + plural: "(The)", + }; + const article = articles[plural ? "plural" : "singular"]; + function addArticle(s: string) { + return `${entity === "subject" ? article : article.toLowerCase()} ${s}`; + } + const e = getEnglishWord(entry); + if (!e) throw new Error(`unable to get english from subject ${entry.f} - ${entry.ts}`); + + if (typeof e === "string") return ` ${e}`; + if (plural) return addArticle(e.plural); + if (!e.singular || e.singular === undefined) { + throw new Error(`unable to get english from subject ${entry.f} - ${entry.ts}`); + } + return addArticle(e.singular); } +// function getEnglishForUnisexNoun(pred: UnisexNounInput, pers: T.Person): string | undefined { +// const english = getEnglishWord(pred); +// const plurSing = personIsPlural(pers) ? "plural" : "singular"; +// return typeof english === "string" +// ? english +// : english === undefined +// ? undefined +// : english[plurSing] +// ? english[plurSing] +// : undefined; +// } + function psStringFromEntry(entry: T.DictionaryEntry, e: string): T.PsString { return { p: entry.p, @@ -182,5 +255,54 @@ function psStringFromEntry(entry: T.DictionaryEntry, e: string): T.PsString { } function getEnglishParticiple(entry: T.DictionaryEntry): string { - return "doing"; -} \ No newline at end of file + if (!entry.ec) throw new Error("no english information for participle"); + const ec = parseEc(entry.ec); + const participle = ec[2]; + return (entry.ep) + ? `${participle} ${entry.ep}` + : participle; +} + +function isPersonInput(e: EntityInput): e is PersonInput { + return typeof e === "number"; +} + +function isNounInput(e: EntityInput): e is NounInput { + if (isPersonInput(e)) return false; + if ("entry" in e && !("gender" in e)) { + // e + return true; + } + return false; +} + +function isParticipleInput(e: EntityInput): e is ParticipleInput { + if (isPersonInput(e)) return false; + if ("entry" in e) return false; + return !!e.c?.startsWith("v."); +} + +function isSpecifiedUnisexNounInput(e: EntityInput): e is SpecifiedUnisexNounInput { + if (isPersonInput(e)) return false; + if ("entry" in e && "gender" in e) { + // e + return true; + } + return false; +} + +function isUnisexNounInput(e: EntityInput): e is UnisexNounInput { + if (isPersonInput(e)) return false; + if ("entry" in e) return false; + return !!e.c?.includes("unisex"); +} + +function isAdjectiveInput(e: EntityInput): e is AdjectiveInput { + if (isPersonInput(e)) return false; + if ("entry" in e) return false; + if (isNounInput(e)) return false; + if (isUnisexNounInput(e)) return false; + if (isSpecifiedUnisexNounInput(e)) return false; + return !!e.c?.includes("adj."); +} + diff --git a/yarn.lock b/yarn.lock index a366742..f076c25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1583,10 +1583,10 @@ passport-google-oauth "^2.0.0" passport-twitter "^1.0.4" -"@lingdocs/pashto-inflector@^1.1.3": - version "1.1.3" - resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-1.1.3.tgz#e908b1933bd9dd3962d9757ad9eb270184d9914c" - integrity sha512-kez2oSZOK1RQm4VssyRBeGehtfT8iS3ROqiOjxgFZj0S8gGw4/A8TsfACGuqh1D0/3EaCI7JjBlj/O5tsHZ2DQ== +"@lingdocs/pashto-inflector@^1.1.4": + version "1.1.4" + resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-1.1.4.tgz#1c1373fca53ef27705366663eb4519d51009dbe9" + integrity sha512-2TWXBV/Xnlot0kVz9016TiXMe/liRfghrZDJBdOSq29VMI//23UEuOWpxlkeIyw9XVY+MsYYC2k6dHsRoak7NQ== dependencies: classnames "^2.2.6" pbf "^3.2.1"