From 5d632f095e77d311d51c6727118106ea4d521242 Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Tue, 15 Mar 2022 19:09:29 +0400 Subject: [PATCH] fix not-allowed pronoun combos --- src/components/VerbPicker.tsx | 12 +- src/content/practice-tools/phrase-builder.mdx | 2 +- src/content/practice-tools/pronoun-picker.mdx | 30 ++++- src/lib/eval-vp.ts | 114 ++++++++++++++---- src/lib/np-tools.ts | 2 +- src/types/gen-g.d.ts | 4 +- 6 files changed, 131 insertions(+), 33 deletions(-) diff --git a/src/components/VerbPicker.tsx b/src/components/VerbPicker.tsx index 989da49..cd3ed65 100644 --- a/src/components/VerbPicker.tsx +++ b/src/components/VerbPicker.tsx @@ -7,12 +7,18 @@ import { Types as T, } from "@lingdocs/pashto-inflector"; -const tenseOptions = [{ +const tenseOptions: { label: string, value: VerbTense }[] = [{ label: "present", value: "present", }, { label: "subjunctive", value: "subjunctive", +}, { + label: "simple past", + value: "perfectivePast", +}, { + label: "continuous past", + value: "imperfectivePast", }]; function makeVerbSelection(verb: VerbEntry, oldVerbSelection?: VerbSelection): VerbSelection { @@ -49,7 +55,7 @@ function VerbPicker({ onChange, verb, verbs }: { verbs: VerbEntry[], verb: VerbS } onChange(makeVerbSelection(v, verb)); } - function onTenseSelect({ value }: { label: string, value: "present" | "subjunctive" }) { + function onTenseSelect({ value }: { label: string, value: VerbTense }) { if (verb) { onChange({ ...verb, @@ -80,7 +86,7 @@ function VerbPicker({ onChange, verb, verbs }: { verbs: VerbEntry[], verb: VerbS // @ts-ignore options={tenseOptions} isSearchable - placeholder={verb ? tenseOptions.find(o => o.value === verb.tense)?.value : "Select Tense..."} + placeholder={verb ? tenseOptions.find(o => o.value === verb.tense)?.label : "Select Tense..."} {...zIndexProps} /> ; diff --git a/src/content/practice-tools/phrase-builder.mdx b/src/content/practice-tools/phrase-builder.mdx index d4c482e..467e248 100644 --- a/src/content/practice-tools/phrase-builder.mdx +++ b/src/content/practice-tools/phrase-builder.mdx @@ -4,6 +4,6 @@ title: Phrase Builder import PhraseBuilder from "../../components/phrase-builder/PhraseBuilder"; -This is under construction... It's not quite working yet. 👷🚧 +##### This is under construction... It's not fully working yet. 👷🚧 \ No newline at end of file diff --git a/src/content/practice-tools/pronoun-picker.mdx b/src/content/practice-tools/pronoun-picker.mdx index 9c5c3a1..7914841 100644 --- a/src/content/practice-tools/pronoun-picker.mdx +++ b/src/content/practice-tools/pronoun-picker.mdx @@ -12,13 +12,39 @@ import { useState } from "react"; import { randomPerson, randomSubjObj, + isInvalidSubjObjCombo, } from "../../lib/np-tools"; export function RPicker() { + // TODO: Pull this into a type safe file const startSubjObj = randomSubjObj(); const [subject, setSubject] = useState({ type: "pronoun", pronounType: "far", person: startSubjObj.subj }); const [object, setObject] = useState({ type: "pronoun", pronounType: "far", person: startSubjObj.obj }); const [mode, setMode] = useState("single"); + function handleSetSubject(incoming) { + if (mode !== "single" && isInvalidSubjObjCombo(incoming.person, object.person)) { + alert("That combination of pronouns is not allowed"); + return; + // let newP = 0; + // do { + // newP = randomPerson(); + // } while (isInvalidSubjObjCombo(newP, object.person)); + // return setSubject({ ...incoming, person: newP }); + } + return setSubject(incoming); + } + function handleSetObject(incoming) { + if (isInvalidSubjObjCombo(subject.person, incoming.person)) { + alert("That combination of pronouns is not allowed"); + return; + // let newP = 0; + // do { + // newP = randomPerson(); + // } while (isInvalidSubjObjCombo(newP, subject.person)); + // return setObject({ ...incoming, person: newP }); + } + return setObject(incoming); + } function setRandomSubjObj() { const { subj, obj } = randomSubjObj(); setSubject(s => ({ @@ -64,12 +90,12 @@ export function RPicker() {
{mode === "subjObj" &&
Subject
} - +
{mode === "subjObj" &&
Object
- +
}
diff --git a/src/lib/eval-vp.ts b/src/lib/eval-vp.ts index 3e84ce8..f5ab69e 100644 --- a/src/lib/eval-vp.ts +++ b/src/lib/eval-vp.ts @@ -14,22 +14,25 @@ import { export function renderVP(VP: VPSelection): VPRendered { // TODO: Will be based on past tense etc - const king = "subject"; - // const servant = VP.object ? "object" : undefined; + const isPast = isPastTense(VP.verb.tense); + const isTransitive = VP.object !== "none"; + const { king, /* servant */ } = getKingAndServant(isPast, isTransitive); + console.log({ king, isPast, isTransitive }); const verbPerson = getPersonFromNP(VP[king]); const subjectPerson = getPersonFromNP(VP.subject); + // TODO: also don't inflect if it's a pattern one animate noun + const inflectSubject = isPast && isTransitive; + console.log({ inflectSubject }); const subject: Rendered = { ...VP.subject, - inflected: false, - // TODO: possibility for inflecting - ...textOfNP(VP.subject, false, false), + inflected: inflectSubject, + ...textOfNP(VP.subject, inflectSubject, false), }; - const inflectObject = isFirstOrSecondPersPronoun(VP.object); + const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object); const object: "none" | Rendered | T.Person.ThirdPlurMale = typeof VP.object === "object" ? { ...VP.subject, inflected: inflectObject, - // TODO: possibility for inflecting ...textOfNP(VP.object, inflectObject, true), } : VP.object; // TODO: error handle this? @@ -64,11 +67,20 @@ export function compileVP(VP: VPRendered | VPSelection): { ps: T.SingleOrLengthO if (VP.type === "VPSelection") { return compileVP(renderVP(VP)); } + function insertEWords(e: string, { subject, object }: { subject: string, object?: string }): string { + return e.replace("$SUBJ", subject).replace("$OBJ", object || ""); + } + // TODO: display of short and long options etc. const vPs = "long" in VP.verb.ps ? VP.verb.ps.long : VP.verb.ps; - // const vE = VP.verb.e; + const engSubj = VP.subject.e || undefined; + const engObj = (typeof VP.object === "object" && VP.object.e) ? VP.object.e : undefined; + // require all English parts for making the English phrase + const e = (VP.verb.e && engSubj && engObj) ? VP.verb.e.map(e => insertEWords(e, { + subject: engSubj, + object: engObj, + })) : undefined; const obj = typeof VP.object === "object" ? VP.object : undefined; const ps = VP.subject.ps.flatMap(s => ( - // TODO: fix double space thing obj ? obj.ps.flatMap(o => ( vPs.flatMap(v => ( concatPsString(s, " ", o, " ", v) @@ -77,7 +89,27 @@ export function compileVP(VP: VPRendered | VPSelection): { ps: T.SingleOrLengthO concatPsString(s, " ", v) )) )); - return { ps }; + return { ps, e }; +} + +function isPastTense(tense: VerbTense): boolean { + return tense.toLowerCase().includes("past"); +} + +function getKingAndServant(isPast: boolean, isTransitive: boolean): + { king: "subject", servant: "object" } | + { king: "object", servant: "subject" } | + { king: "subject", servant: undefined } { + if (!isTransitive) { + return { king: "subject", servant: undefined }; + } + return isPast ? { + king: "object", + servant: "subject", + } : { + king: "subject", + servant: "object", + }; } function isFirstOrSecondPersPronoun(o: "none" | NPSelection | T.Person.ThirdPlurMale): boolean { @@ -86,8 +118,8 @@ function isFirstOrSecondPersPronoun(o: "none" | NPSelection | T.Person.ThirdPlur return [0,1,2,3,6,7,8,9].includes(o.person); } -function getPsVerbConjugation(conj: T.VerbConjugation, tense: "present" | "subjunctive", person: T.Person): T.SingleOrLengthOpts { - const f = conj[tense === "present" ? "imperfective" : "perfective"].nonImperative; +function getPsVerbConjugation(conj: T.VerbConjugation, tense: VerbTense, person: T.Person): T.SingleOrLengthOpts { + const f = getTenseVerbForm(conj, tense); // TODO: ability to grab the correct part of matrix const block = "mascSing" in f ? f.mascSing @@ -108,12 +140,28 @@ function getPsVerbConjugation(conj: T.VerbConjugation, tense: "present" | "subju return grabFromBlock(block, pos); } +function getTenseVerbForm(conj: T.VerbConjugation, tense: VerbTense): T.VerbForm { + if (tense === "present") { + return conj.imperfective.nonImperative; + } + if (tense === "subjunctive") { + return conj.perfective.nonImperative; + } + if (tense === "imperfectivePast") { + return conj.imperfective.past; + } + if (tense === "perfectivePast") { + return conj.perfective.past; + } + throw new Error("unknown tense"); +} + function getEnglishVerbConjugation({ subjectPerson, object, ep, v, tense, n }: { subjectPerson: T.Person, object: "none" | NPSelection | T.Person.ThirdPlurMale, v: T.EnglishVerbConjugationEc, ep: string | undefined, - tense: "present" | "subjunctive", + tense: VerbTense, n: boolean, }): string[] { function engEquative(tense: "past" | "present", s: T.Person): string { @@ -133,7 +181,7 @@ function getEnglishVerbConjugation({ subjectPerson, object, ep, v, tense, n }: { return (v[2] === "being"); } const builders: Record< - string, + VerbTense, (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[] > = { present: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ @@ -146,12 +194,28 @@ function getEnglishVerbConjugation({ subjectPerson, object, ep, v, tense, n }: { `that $SUBJ ${n ? " won't" : " will"} ${isToBe(v) ? "be" : v[0]}`, `should $SUBJ ${n ? " not" : ""} ${isToBe(v) ? "be" : v[0]}`, ]), + imperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ + // - subj pastEquative (N && "not") v.2 obj + `$SUBJ ${engEquative("past", s)}${n ? " not" : ""} ${v[2]}`, + // - subj "would" (N && "not") v.0 obj + `$SUBJ would${n ? " not" : ""} ${isToBe(v) ? "be" : v[0]}`, + // - subj pastEquative (N && "not") going to" v.0 obj + `$SUBJ ${engEquative("past", s)}${n ? " not" : ""} going to ${isToBe(v) ? "be" : v[0]}`, + ]), + perfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ + `$SUBJ${isToBe(v) + ? ` ${engEquative("past", s)}${n ? " not" : ""}` + : `${n ? " did not" : ""} ${v[3]}`}`, + ]), }; const base = builders[tense](subjectPerson, v, n); return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`); } -function getPersonFromNP(np: NPSelection | T.Person.ThirdPlurMale): T.Person { +function getPersonFromNP(np: NPSelection | T.Person.ThirdPlurMale | "none"): T.Person { + if (np === "none") { + throw new Error("empty entity"); + } if (typeof np === "number") return np; if (np.type === "participle") { return T.Person.ThirdPlurMale; @@ -166,20 +230,19 @@ function getPersonFromNP(np: NPSelection | T.Person.ThirdPlurMale): T.Person { function textOfNP(np: NPSelection, inflected: boolean, englishInflected: boolean): { ps: T.PsString[], e: string } { if (np.type === "participle") { - // TODO: Implement ability to inflect participles return textOfParticiple(np, inflected); } if (np.type === "pronoun") { return textOfPronoun(np, inflected, englishInflected); } - // TODO: Implement ability to inflect nouns return textOfNoun(np, inflected); } function textOfParticiple({ verb: { entry }}: ParticipleSelection, inflected: boolean): { ps: T.PsString[], e: string } { // TODO: ability to inflect participles return { - ps: [psStringFromEntry(entry)], + // TODO: More robust inflection of inflecting pariticiples - get from the conjugation engine + ps: [psStringFromEntry(entry)].map(ps => inflected ? concatPsString(ps, { p: "Ùˆ", f: "o" }) : ps), e: getEnglishParticiple(entry), }; } @@ -218,11 +281,11 @@ function textOfNoun(n: NounSelection, inflected: boolean): { ps: T.PsString[], e const pashto = ((): T.PsString[] => { const infs = inflectWord(n.entry); const ps = n.number === "singular" - ? getInf(infs, "inflections", n.gender, false) + ? getInf(infs, "inflections", n.gender, false, inflected) : [ - ...getInf(infs, "plural", n.gender, true), - ...getInf(infs, "arabicPlural", n.gender, true), - ...getInf(infs, "inflections", n.gender, true), + ...getInf(infs, "plural", n.gender, true, inflected), + ...getInf(infs, "arabicPlural", n.gender, true, inflected), + ...getInf(infs, "inflections", n.gender, true, inflected), ]; return ps.length > 0 ? ps @@ -231,13 +294,14 @@ function textOfNoun(n: NounSelection, inflected: boolean): { ps: T.PsString[], e return { ps: pashto, e: english }; } -function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflections", gender: T.Gender, plural: boolean): T.PsString[] { +function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflections", gender: T.Gender, plural: boolean, inflected: boolean): T.PsString[] { // @ts-ignore if (infs && t in infs && infs[t] !== undefined && gender in infs[t] && infs[t][gender] !== undefined) { // @ts-ignore const iset = infs[t][gender] as T.InflectionSet; - const ipick = iset[(t === "inflections" && plural) ? 1 : 0]; - return ipick; + const inflectionNumber = (inflected ? 1 : 0) + ((t === "inflections" && plural) ? 1 : 0); + console.log({ t, plural, inflectionNumber }); + return iset[inflectionNumber]; } return []; } diff --git a/src/lib/np-tools.ts b/src/lib/np-tools.ts index 424fe4a..e80a66a 100644 --- a/src/lib/np-tools.ts +++ b/src/lib/np-tools.ts @@ -23,7 +23,7 @@ export function randomPerson(p?: T.Person) { return newP; } -function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean { +export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean { const firstPeople = [ T.Person.FirstSingMale, T.Person.FirstSingFemale, diff --git a/src/types/gen-g.d.ts b/src/types/gen-g.d.ts index 5ad94cf..fef3ad7 100644 --- a/src/types/gen-g.d.ts +++ b/src/types/gen-g.d.ts @@ -20,10 +20,12 @@ type VPRendered = { verb: VerbRendered, } +type VerbTense = "present" | "subjunctive" | "perfectivePast" | "imperfectivePast"; + type VerbSelection = { type: "verb", verb: VerbEntry, - tense: "present" | "subjunctive", + tense: VerbTense, object: VerbObject, };