This commit is contained in:
lingdocs 2022-04-26 13:13:32 +05:00
parent b4a84645ea
commit e6a13c61f7
3 changed files with 3 additions and 319 deletions

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import { useState } from "react";
import { import {
VerbFormDisplay, VerbFormDisplay,
ButtonSelect, ButtonSelect,
@ -10,9 +10,10 @@ function EquativeFormChoice({forms, opts}) {
<div> <div>
<div className="text-center my-3"> <div className="text-center my-3">
<ButtonSelect <ButtonSelect
small
options={[ options={[
{ label: "Equative", value: "pure" }, { label: "Equative", value: "pure" },
{ label: "w/ Sentences", value: "sentence" }, { label: "w/ Pronouns", value: "sentence" },
]} ]}
value={choice} value={choice}
handleChange={(p) => setChoice(p)} handleChange={(p) => setChoice(p)}

View File

@ -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)),
};
}

View File

@ -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);
}