This commit is contained in:
parent
b4a84645ea
commit
e6a13c61f7
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
VerbFormDisplay,
|
||||
ButtonSelect,
|
||||
|
@ -10,9 +10,10 @@ function EquativeFormChoice({forms, opts}) {
|
|||
<div>
|
||||
<div className="text-center my-3">
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Equative", value: "pure" },
|
||||
{ label: "w/ Sentences", value: "sentence" },
|
||||
{ label: "w/ Pronouns", value: "sentence" },
|
||||
]}
|
||||
value={choice}
|
||||
handleChange={(p) => setChoice(p)}
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
import {
|
||||
Types as T,
|
||||
grammarUnits,
|
||||
getVerbBlockPosFromPerson,
|
||||
getPersonFromVerbForm,
|
||||
concatPsString,
|
||||
removeAccents,
|
||||
typePredicates as tp,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
import {
|
||||
personFromNP,
|
||||
evaluateNP,
|
||||
} from "./np-tools";
|
||||
import {
|
||||
evaluateCompliment,
|
||||
} from "./compliment-tools";
|
||||
|
||||
// Equative Rules
|
||||
// - An equative equates a SUBJECT: Noun Phrase and a PREDICATE: Noun Phrase | Compliment
|
||||
// - In Pashto, the equative agrees with the predicate when the predicate is a Noun Phrase,
|
||||
// otherwise it agrees with the subject
|
||||
// - If the subject is a pronoun, always agree with the subject
|
||||
// - In English, the equative agrees with the subject
|
||||
|
||||
export function equativeMachine(e: EquativeClause): EquativeClauseOutput {
|
||||
const ba = (e.tense === "future" || e.tense === "wouldBe");
|
||||
const subject = evaluateNP(e.subject);
|
||||
const predicate = ("type" in e.predicate && e.predicate.type === "compliment")
|
||||
? evaluateCompliment(e.predicate, personFromNP(e.subject))
|
||||
: evaluateNP(e.predicate);
|
||||
const equative = makeEquative(e);
|
||||
const negative = !!e?.negative;
|
||||
return {
|
||||
ba,
|
||||
subject,
|
||||
predicate,
|
||||
equative,
|
||||
negative,
|
||||
};
|
||||
}
|
||||
|
||||
export function assembleEquativeOutput(o: EquativeClauseOutput): T.SingleOrLengthOpts<T.ArrayOneOrMore<T.PsString>> {
|
||||
if ("long" in o.equative.ps) {
|
||||
return {
|
||||
long: assembleEquativeOutput({ ...o, equative: { ...o.equative, ps: o.equative.ps.long }}) as T.ArrayOneOrMore<T.PsString>,
|
||||
short: assembleEquativeOutput({ ...o, equative: { ...o.equative, ps:o.equative.ps.short }}) as T.ArrayOneOrMore<T.PsString>,
|
||||
}
|
||||
}
|
||||
// get all possible combinations of subject, predicate, and equative
|
||||
// soooo cool how this works 🤓
|
||||
const equatives = o.equative.ps;
|
||||
const predicates = o.predicate.ps;
|
||||
const ba = o.ba ? { p: " به", f: " ba" } : "";
|
||||
const neg = o.negative ? { p: "نه ", f: "nú " } : "";
|
||||
const ps = o.subject.ps.flatMap(subj => (
|
||||
predicates.flatMap(pred => (
|
||||
equatives.map(eq => (
|
||||
concatPsString(
|
||||
subj,
|
||||
ba,
|
||||
" ",
|
||||
pred,
|
||||
" ",
|
||||
neg,
|
||||
o.negative ? removeAccents(eq) : eq,
|
||||
))
|
||||
)
|
||||
))
|
||||
));
|
||||
const e = `${o.subject.e} ${o.equative.e[0]} ${o.predicate.e}`;
|
||||
return ps.map(x => ({ ...x, e })) as T.ArrayOneOrMore<T.PsString>;
|
||||
}
|
||||
|
||||
function makeEquative(e: EquativeClause) {
|
||||
function getEngEq(row: number, col: number): string[] {
|
||||
const t = grammarUnits.englishEquative[(e.tense === "subjunctive" || e.tense === "habitual") ? "present" : e.tense];
|
||||
return typeof t === "string"
|
||||
? [t]
|
||||
: [t[row][col]];
|
||||
}
|
||||
const baseTense = (e.tense === "future")
|
||||
? "habitual"
|
||||
: e.tense === "wouldBe"
|
||||
? "past"
|
||||
: e.tense;
|
||||
const subjP = personFromNP(e.subject);
|
||||
const englishPerson = (e.subject.type === "participle" || (e.subject.type === "noun" && tp.isPluralNounEntry(e.subject.entry)))
|
||||
? T.Person.ThirdSingMale
|
||||
: subjP
|
||||
const pashtoPerson = (e.subject.type === "pronoun")
|
||||
? e.subject.person
|
||||
: ("type" in e.predicate && e.predicate.type === "compliment")
|
||||
? subjP
|
||||
: personFromNP(e.predicate);
|
||||
return {
|
||||
ps: getPersonFromVerbForm(
|
||||
grammarUnits.equativeEndings[baseTense],
|
||||
pashtoPerson,
|
||||
),
|
||||
e: getEngEq(...getVerbBlockPosFromPerson(englishPerson)),
|
||||
};
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
import {
|
||||
Types as T,
|
||||
getEnglishWord,
|
||||
parseEc,
|
||||
getVerbBlockPosFromPerson,
|
||||
grammarUnits,
|
||||
inflectWord,
|
||||
psStringFromEntry,
|
||||
typePredicates as tp,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
|
||||
function getRandPers(): T.Person {
|
||||
return Math.floor(Math.random() * 12);
|
||||
}
|
||||
|
||||
export function randomPerson(a?: { prev?: T.Person, counterPart?: T.VerbObject | T.NPSelection }) {
|
||||
// no restrictions, just get any person
|
||||
if (!a) {
|
||||
return getRandPers();
|
||||
}
|
||||
if (a.counterPart !== undefined && typeof a.counterPart === "object" && a.counterPart.type === "pronoun") {
|
||||
// with counterpart pronoun
|
||||
let newP = 0;
|
||||
do {
|
||||
newP = getRandPers();
|
||||
} while (
|
||||
isInvalidSubjObjCombo(a.counterPart.person, newP)
|
||||
||
|
||||
(newP === a.prev)
|
||||
);
|
||||
return newP;
|
||||
}
|
||||
// without counterpart pronoun, just previous
|
||||
let newP = 0;
|
||||
do {
|
||||
newP = getRandPers();
|
||||
} while (newP === a.prev);
|
||||
return newP;
|
||||
}
|
||||
|
||||
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
||||
const firstPeople = [
|
||||
T.Person.FirstSingMale,
|
||||
T.Person.FirstSingFemale,
|
||||
T.Person.FirstPlurMale,
|
||||
T.Person.FirstPlurFemale,
|
||||
];
|
||||
const secondPeople = [
|
||||
T.Person.SecondSingMale,
|
||||
T.Person.SecondSingFemale,
|
||||
T.Person.SecondPlurMale,
|
||||
T.Person.SecondPlurFemale,
|
||||
];
|
||||
return (
|
||||
(firstPeople.includes(subj) && firstPeople.includes(obj))
|
||||
||
|
||||
(secondPeople.includes(subj) && secondPeople.includes(obj))
|
||||
);
|
||||
}
|
||||
|
||||
export function randomSubjObj(old?: { subj: T.Person, obj: T.Person }): { subj: T.Person, obj: T.Person } {
|
||||
let subj = 0;
|
||||
let obj = 0;
|
||||
do {
|
||||
subj = getRandPers();
|
||||
obj = getRandPers();
|
||||
} while (
|
||||
(old && ((old.subj === subj) || (old.obj === obj)))
|
||||
||
|
||||
isInvalidSubjObjCombo(subj, obj)
|
||||
);
|
||||
return { subj, obj };
|
||||
}
|
||||
|
||||
export function personFromNP(np: NounPhrase): T.Person {
|
||||
if (np.type === "participle") {
|
||||
return T.Person.ThirdPlurMale;
|
||||
}
|
||||
if (np.type === "pronoun") {
|
||||
return np.person;
|
||||
}
|
||||
const gender = nounGender(np);
|
||||
const number = nounNumber(np);
|
||||
return number === "plural"
|
||||
? (gender === "masc" ? T.Person.ThirdPlurMale : T.Person.ThirdPlurFemale)
|
||||
: (gender === "masc" ? T.Person.ThirdSingMale : T.Person.ThirdSingFemale);
|
||||
}
|
||||
|
||||
export function evaluateNP(np: NounPhrase): { ps: T.PsString[], e: string } {
|
||||
if (np.type === "participle") {
|
||||
return evaluateParticiple(np);
|
||||
}
|
||||
if (np.type === "pronoun") {
|
||||
return evaluatePronoun(np);
|
||||
}
|
||||
return evaluateNoun(np);
|
||||
}
|
||||
|
||||
function nounGender(n: Noun): T.Gender {
|
||||
const nGender = tp.isUnisexNounEntry(n.entry)
|
||||
? "unisex"
|
||||
: tp.isMascNounEntry(n.entry)
|
||||
? "masc"
|
||||
: "fem";
|
||||
return (nGender === "unisex" && n.gender)
|
||||
? n.gender
|
||||
: (nGender === "unisex")
|
||||
? "masc"
|
||||
: nGender;
|
||||
}
|
||||
|
||||
function nounNumber(n: Noun): NounNumber {
|
||||
const nNumber = tp.isPluralNounEntry(n.entry)
|
||||
? "plural"
|
||||
: "singular";
|
||||
return nNumber === "plural"
|
||||
? "plural"
|
||||
: n.number
|
||||
? n.number
|
||||
: nNumber;
|
||||
}
|
||||
|
||||
function evaluatePronoun(p: Pronoun): { ps: T.PsString[], e: string } {
|
||||
// TODO: Will need to handle inflecting and inflecting english pronouns etc.
|
||||
const [row, col] = getVerbBlockPosFromPerson(p.person);
|
||||
return {
|
||||
ps: grammarUnits.pronouns[p.pronounType].plain[row][col],
|
||||
e: grammarUnits.persons[p.person].label.subject,
|
||||
};
|
||||
}
|
||||
|
||||
function evaluateNoun(n: Noun): { ps: T.PsString[], e: string } {
|
||||
const number = nounNumber(n);
|
||||
const english = getEnglishFromNoun(n.entry, number);
|
||||
const pashto = ((): T.PsString[] => {
|
||||
const infs = inflectWord(n.entry);
|
||||
const gender = nounGender(n);
|
||||
const ps = number === "singular"
|
||||
? getInf(infs, "inflections", gender, false)
|
||||
: [
|
||||
...getInf(infs, "plural", gender, true),
|
||||
...getInf(infs, "arabicPlural", gender, true),
|
||||
...getInf(infs, "inflections", gender, true),
|
||||
];
|
||||
return ps.length > 0
|
||||
? ps
|
||||
: [psStringFromEntry(n.entry)];
|
||||
})();
|
||||
return { ps: pashto, e: english };
|
||||
}
|
||||
|
||||
function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflections", gender: T.Gender, plural: 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;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export function getEnglishVerb(entry: T.DictionaryEntry): string {
|
||||
if (!entry.ec) {
|
||||
console.log("errored verb");
|
||||
console.log(entry);
|
||||
throw new Error("no english information for verb");
|
||||
}
|
||||
if (entry.ep) {
|
||||
const ec = entry.ec.includes(",") ? parseEc(entry.ec)[0] : entry.ec;
|
||||
return `to ${ec} ${entry.ep}`;
|
||||
}
|
||||
const ec = parseEc(entry.ec);
|
||||
return `to ${ec[0]}`;
|
||||
}
|
||||
|
||||
export function getEnglishParticiple(entry: T.DictionaryEntry): string {
|
||||
if (!entry.ec) {
|
||||
console.log("errored participle");
|
||||
console.log(entry);
|
||||
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 evaluateParticiple({ entry: { entry }}: Participle): { ps: T.PsString[], e: string } {
|
||||
return {
|
||||
ps: [psStringFromEntry(entry)],
|
||||
e: getEnglishParticiple(entry),
|
||||
};
|
||||
}
|
||||
|
||||
function getEnglishFromNoun(entry: T.DictionaryEntry, number: NounNumber): string {
|
||||
const articles = {
|
||||
singular: "(a/the)",
|
||||
plural: "(the)",
|
||||
};
|
||||
const article = articles[number];
|
||||
function addArticle(s: string) {
|
||||
return `${article} ${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 (number === "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);
|
||||
}
|
Loading…
Reference in New Issue