fix not-allowed pronoun combos

This commit is contained in:
lingdocs 2022-03-15 19:09:29 +04:00
parent a000731a4a
commit 5d632f095e
6 changed files with 131 additions and 33 deletions

View File

@ -7,12 +7,18 @@ import {
Types as T, Types as T,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
const tenseOptions = [{ const tenseOptions: { label: string, value: VerbTense }[] = [{
label: "present", label: "present",
value: "present", value: "present",
}, { }, {
label: "subjunctive", label: "subjunctive",
value: "subjunctive", value: "subjunctive",
}, {
label: "simple past",
value: "perfectivePast",
}, {
label: "continuous past",
value: "imperfectivePast",
}]; }];
function makeVerbSelection(verb: VerbEntry, oldVerbSelection?: VerbSelection): VerbSelection { function makeVerbSelection(verb: VerbEntry, oldVerbSelection?: VerbSelection): VerbSelection {
@ -49,7 +55,7 @@ function VerbPicker({ onChange, verb, verbs }: { verbs: VerbEntry[], verb: VerbS
} }
onChange(makeVerbSelection(v, verb)); onChange(makeVerbSelection(v, verb));
} }
function onTenseSelect({ value }: { label: string, value: "present" | "subjunctive" }) { function onTenseSelect({ value }: { label: string, value: VerbTense }) {
if (verb) { if (verb) {
onChange({ onChange({
...verb, ...verb,
@ -80,7 +86,7 @@ function VerbPicker({ onChange, verb, verbs }: { verbs: VerbEntry[], verb: VerbS
// @ts-ignore // @ts-ignore
options={tenseOptions} options={tenseOptions}
isSearchable 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} {...zIndexProps}
/> />
</div>; </div>;

View File

@ -4,6 +4,6 @@ title: Phrase Builder
import PhraseBuilder from "../../components/phrase-builder/PhraseBuilder"; 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. 👷🚧
<PhraseBuilder /> <PhraseBuilder />

View File

@ -12,13 +12,39 @@ import { useState } from "react";
import { import {
randomPerson, randomPerson,
randomSubjObj, randomSubjObj,
isInvalidSubjObjCombo,
} from "../../lib/np-tools"; } from "../../lib/np-tools";
export function RPicker() { export function RPicker() {
// TODO: Pull this into a type safe file
const startSubjObj = randomSubjObj(); const startSubjObj = randomSubjObj();
const [subject, setSubject] = useState({ type: "pronoun", pronounType: "far", person: startSubjObj.subj }); const [subject, setSubject] = useState({ type: "pronoun", pronounType: "far", person: startSubjObj.subj });
const [object, setObject] = useState({ type: "pronoun", pronounType: "far", person: startSubjObj.obj }); const [object, setObject] = useState({ type: "pronoun", pronounType: "far", person: startSubjObj.obj });
const [mode, setMode] = useState("single"); 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() { function setRandomSubjObj() {
const { subj, obj } = randomSubjObj(); const { subj, obj } = randomSubjObj();
setSubject(s => ({ setSubject(s => ({
@ -64,12 +90,12 @@ export function RPicker() {
<div className="row"> <div className="row">
<div className="col my-2" style={{ maxWidth: "375px", margin: "0 auto" }}> <div className="col my-2" style={{ maxWidth: "375px", margin: "0 auto" }}>
{mode === "subjObj" && <h5>Subject</h5>} {mode === "subjObj" && <h5>Subject</h5>}
<PronounPicker pronoun={subject} onChange={setSubject} /> <PronounPicker pronoun={subject} onChange={handleSetSubject} />
</div> </div>
{mode === "subjObj" && {mode === "subjObj" &&
<div className="col my-2" style={{ maxWidth: "375px", margin: "0 auto" }}> <div className="col my-2" style={{ maxWidth: "375px", margin: "0 auto" }}>
<h5>Object</h5> <h5>Object</h5>
<PronounPicker pronoun={object} onChange={setObject} isObject /> <PronounPicker pronoun={object} onChange={handleSetObject} isObject />
</div> </div>
} }
</div> </div>

View File

@ -14,22 +14,25 @@ import {
export function renderVP(VP: VPSelection): VPRendered { export function renderVP(VP: VPSelection): VPRendered {
// TODO: Will be based on past tense etc // TODO: Will be based on past tense etc
const king = "subject"; const isPast = isPastTense(VP.verb.tense);
// const servant = VP.object ? "object" : undefined; const isTransitive = VP.object !== "none";
const { king, /* servant */ } = getKingAndServant(isPast, isTransitive);
console.log({ king, isPast, isTransitive });
const verbPerson = getPersonFromNP(VP[king]); const verbPerson = getPersonFromNP(VP[king]);
const subjectPerson = getPersonFromNP(VP.subject); 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<NPSelection> = { const subject: Rendered<NPSelection> = {
...VP.subject, ...VP.subject,
inflected: false, inflected: inflectSubject,
// TODO: possibility for inflecting ...textOfNP(VP.subject, inflectSubject, false),
...textOfNP(VP.subject, false, false),
}; };
const inflectObject = isFirstOrSecondPersPronoun(VP.object); const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object);
const object: "none" | Rendered<NPSelection> | T.Person.ThirdPlurMale = typeof VP.object === "object" const object: "none" | Rendered<NPSelection> | T.Person.ThirdPlurMale = typeof VP.object === "object"
? { ? {
...VP.subject, ...VP.subject,
inflected: inflectObject, inflected: inflectObject,
// TODO: possibility for inflecting
...textOfNP(VP.object, inflectObject, true), ...textOfNP(VP.object, inflectObject, true),
} : VP.object; } : VP.object;
// TODO: error handle this? // TODO: error handle this?
@ -64,11 +67,20 @@ export function compileVP(VP: VPRendered | VPSelection): { ps: T.SingleOrLengthO
if (VP.type === "VPSelection") { if (VP.type === "VPSelection") {
return compileVP(renderVP(VP)); 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 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 obj = typeof VP.object === "object" ? VP.object : undefined;
const ps = VP.subject.ps.flatMap(s => ( const ps = VP.subject.ps.flatMap(s => (
// TODO: fix double space thing
obj ? obj.ps.flatMap(o => ( obj ? obj.ps.flatMap(o => (
vPs.flatMap(v => ( vPs.flatMap(v => (
concatPsString(s, " ", o, " ", v) concatPsString(s, " ", o, " ", v)
@ -77,7 +89,27 @@ export function compileVP(VP: VPRendered | VPSelection): { ps: T.SingleOrLengthO
concatPsString(s, " ", v) 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 { 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); 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<T.PsString[]> { function getPsVerbConjugation(conj: T.VerbConjugation, tense: VerbTense, person: T.Person): T.SingleOrLengthOpts<T.PsString[]> {
const f = conj[tense === "present" ? "imperfective" : "perfective"].nonImperative; const f = getTenseVerbForm(conj, tense);
// TODO: ability to grab the correct part of matrix // TODO: ability to grab the correct part of matrix
const block = "mascSing" in f const block = "mascSing" in f
? f.mascSing ? f.mascSing
@ -108,12 +140,28 @@ function getPsVerbConjugation(conj: T.VerbConjugation, tense: "present" | "subju
return grabFromBlock(block, pos); 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 }: { function getEnglishVerbConjugation({ subjectPerson, object, ep, v, tense, n }: {
subjectPerson: T.Person, subjectPerson: T.Person,
object: "none" | NPSelection | T.Person.ThirdPlurMale, object: "none" | NPSelection | T.Person.ThirdPlurMale,
v: T.EnglishVerbConjugationEc, v: T.EnglishVerbConjugationEc,
ep: string | undefined, ep: string | undefined,
tense: "present" | "subjunctive", tense: VerbTense,
n: boolean, n: boolean,
}): string[] { }): string[] {
function engEquative(tense: "past" | "present", s: T.Person): 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"); return (v[2] === "being");
} }
const builders: Record< const builders: Record<
string, VerbTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[] (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = { > = {
present: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ 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]}`, `that $SUBJ ${n ? " won't" : " will"} ${isToBe(v) ? "be" : v[0]}`,
`should $SUBJ ${n ? " not" : ""} ${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); const base = builders[tense](subjectPerson, v, n);
return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`); 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 (typeof np === "number") return np;
if (np.type === "participle") { if (np.type === "participle") {
return T.Person.ThirdPlurMale; 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 } { function textOfNP(np: NPSelection, inflected: boolean, englishInflected: boolean): { ps: T.PsString[], e: string } {
if (np.type === "participle") { if (np.type === "participle") {
// TODO: Implement ability to inflect participles
return textOfParticiple(np, inflected); return textOfParticiple(np, inflected);
} }
if (np.type === "pronoun") { if (np.type === "pronoun") {
return textOfPronoun(np, inflected, englishInflected); return textOfPronoun(np, inflected, englishInflected);
} }
// TODO: Implement ability to inflect nouns
return textOfNoun(np, inflected); return textOfNoun(np, inflected);
} }
function textOfParticiple({ verb: { entry }}: ParticipleSelection, inflected: boolean): { ps: T.PsString[], e: string } { function textOfParticiple({ verb: { entry }}: ParticipleSelection, inflected: boolean): { ps: T.PsString[], e: string } {
// TODO: ability to inflect participles // TODO: ability to inflect participles
return { 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), e: getEnglishParticiple(entry),
}; };
} }
@ -218,11 +281,11 @@ function textOfNoun(n: NounSelection, inflected: boolean): { ps: T.PsString[], e
const pashto = ((): T.PsString[] => { const pashto = ((): T.PsString[] => {
const infs = inflectWord(n.entry); const infs = inflectWord(n.entry);
const ps = n.number === "singular" 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, "plural", n.gender, true, inflected),
...getInf(infs, "arabicPlural", n.gender, true), ...getInf(infs, "arabicPlural", n.gender, true, inflected),
...getInf(infs, "inflections", n.gender, true), ...getInf(infs, "inflections", n.gender, true, inflected),
]; ];
return ps.length > 0 return ps.length > 0
? ps ? ps
@ -231,13 +294,14 @@ function textOfNoun(n: NounSelection, inflected: boolean): { ps: T.PsString[], e
return { ps: pashto, e: english }; 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 // @ts-ignore
if (infs && t in infs && infs[t] !== undefined && gender in infs[t] && infs[t][gender] !== undefined) { if (infs && t in infs && infs[t] !== undefined && gender in infs[t] && infs[t][gender] !== undefined) {
// @ts-ignore // @ts-ignore
const iset = infs[t][gender] as T.InflectionSet; const iset = infs[t][gender] as T.InflectionSet;
const ipick = iset[(t === "inflections" && plural) ? 1 : 0]; const inflectionNumber = (inflected ? 1 : 0) + ((t === "inflections" && plural) ? 1 : 0);
return ipick; console.log({ t, plural, inflectionNumber });
return iset[inflectionNumber];
} }
return []; return [];
} }

View File

@ -23,7 +23,7 @@ export function randomPerson(p?: T.Person) {
return newP; return newP;
} }
function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean { export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
const firstPeople = [ const firstPeople = [
T.Person.FirstSingMale, T.Person.FirstSingMale,
T.Person.FirstSingFemale, T.Person.FirstSingFemale,

View File

@ -20,10 +20,12 @@ type VPRendered = {
verb: VerbRendered, verb: VerbRendered,
} }
type VerbTense = "present" | "subjunctive" | "perfectivePast" | "imperfectivePast";
type VerbSelection = { type VerbSelection = {
type: "verb", type: "verb",
verb: VerbEntry, verb: VerbEntry,
tense: "present" | "subjunctive", tense: VerbTense,
object: VerbObject, object: VerbObject,
}; };