some refactoring

This commit is contained in:
lingdocs 2022-03-16 16:12:45 +04:00
parent a8bd1a337f
commit e4cf7558ee
6 changed files with 232 additions and 182 deletions

View File

@ -5,6 +5,7 @@ import {
} from "./np-picker/picker-tools"; } from "./np-picker/picker-tools";
import { import {
Types as T, Types as T,
// ButtonSelect,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
const tenseOptions: { label: string, value: VerbTense }[] = [{ const tenseOptions: { label: string, value: VerbTense }[] = [{
@ -42,6 +43,7 @@ function makeVerbSelection(verb: VerbEntry, oldVerbSelection?: VerbSelection): V
verb, verb,
tense: oldVerbSelection ? oldVerbSelection.tense : "present", tense: oldVerbSelection ? oldVerbSelection.tense : "present",
object, object,
negative: oldVerbSelection ? oldVerbSelection.negative : false,
}; };
} }
@ -63,6 +65,14 @@ function VerbPicker({ onChange, verb, verbs }: { verbs: VerbEntry[], verb: VerbS
}); });
} }
} }
// function onPosNegSelect(value: string) {
// if (verb) {
// onChange({
// ...verb,
// negative: value === "true",
// });
// }
// }
return <div style={{ maxWidth: "225px" }}> return <div style={{ maxWidth: "225px" }}>
<div>Verb:</div> <div>Verb:</div>
<Select <Select
@ -89,6 +99,21 @@ function VerbPicker({ onChange, verb, verbs }: { verbs: VerbEntry[], verb: VerbS
placeholder={verb ? tenseOptions.find(o => o.value === verb.tense)?.label : "Select Tense..."} placeholder={verb ? tenseOptions.find(o => o.value === verb.tense)?.label : "Select Tense..."}
{...zIndexProps} {...zIndexProps}
/> />
{/* The negative is not ready yet for people to use */}
{/* {verb && <div className="text-center my-3">
<ButtonSelect
small
value={verb.negative.toString()}
options={[{
label: "Pos.",
value: "false",
}, {
label: "Neg.",
value: "true",
}]}
handleChange={onPosNegSelect}
/>
</div>} */}
</div>; </div>;
} }

View File

@ -1,4 +1,4 @@
import { renderVP, compileVP } from "../../lib/eval-vp"; import { renderVP, compileVP } from "../../lib/phrase-building";
import { import {
InlinePs, InlinePs,
defaultTextOptions as opts, defaultTextOptions as opts,

View File

@ -0,0 +1,37 @@
import {
Types as T,
concatPsString,
} from "@lingdocs/pashto-inflector";
const nu: T.PsString = { p: "نه", f: "nu" };
export function compileVP(VP: VPRendered): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
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 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.englishBase && engSubj && engObj) ? VP.englishBase.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 => (
obj ? obj.ps.flatMap(o => (
vPs.flatMap(v => (
VP.verb.negative
// this will not work yet for perfectives etc - super rough start
? concatPsString(s, " ", o, " ", nu, " ", v)
: concatPsString(s, " ", o, " ", v)
))
)) : vPs.flatMap(v => (
VP.verb.negative
? concatPsString(s, " ", nu, " ", v)
: concatPsString(s, " ", v)
))
));
return { ps, e };
}

View File

@ -0,0 +1,7 @@
import { renderVP } from "./render-vp";
import { compileVP } from "./compile-vp";
export {
renderVP,
compileVP,
};

View File

@ -10,112 +10,120 @@ import {
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import { import {
psStringFromEntry, psStringFromEntry,
} from "./text-tools"; } from "../text-tools";
export function renderVP(VP: VPSelection): VPRendered { export function renderVP(VP: VPSelection): VPRendered {
// TODO: Will be based on past tense etc // Sentence Rules Logic
const isPast = isPastTense(VP.verb.tense); const isPast = isPastTense(VP.verb.tense);
const isTransitive = VP.object !== "none"; const isTransitive = VP.object !== "none";
const { king, /* servant */ } = getKingAndServant(isPast, isTransitive); const { king, /* servant */ } = getKingAndServant(isPast, isTransitive);
console.log({ king, isPast, isTransitive }); const kingPerson = getPersonFromNP(VP[king]);
const verbPerson = getPersonFromNP(VP[king]);
const subjectPerson = getPersonFromNP(VP.subject); const subjectPerson = getPersonFromNP(VP.subject);
// const objectPerson = getPersonFromNP(VP.object);
// TODO: also don't inflect if it's a pattern one animate noun // TODO: also don't inflect if it's a pattern one animate noun
const inflectSubject = isPast && isTransitive; const inflectSubject = isPast && isTransitive;
console.log({ inflectSubject });
const subject: Rendered<NPSelection> = {
...VP.subject,
inflected: inflectSubject,
...textOfNP(VP.subject, inflectSubject, false),
};
const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object); const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object);
const object: "none" | Rendered<NPSelection> | T.Person.ThirdPlurMale = typeof VP.object === "object" // Render Elements
? { return {
...VP.subject, type: "VPRendered",
inflected: inflectObject, subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
...textOfNP(VP.object, inflectObject, true), object: renderNPSelection(VP.object, inflectObject, true, "object"),
} : VP.object; verb: renderVerbSelection(VP.verb, kingPerson),
englishBase: renderEnglishVPBase({
subjectPerson,
object: VP.object,
vs: VP.verb,
}),
};
}
function renderNPSelection(NP: NPSelection, inflected: boolean, inflectEnglish: boolean, role: "subject"): Rendered<NPSelection>
function renderNPSelection(NP: NPSelection | ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "object"): Rendered<NPSelection> | T.Person.ThirdPlurMale | "none";
function renderNPSelection(NP: NPSelection | ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "subject" | "object"): Rendered<NPSelection> | T.Person.ThirdPlurMale | "none" {
if (typeof NP !== "object") {
if (role !== "object") {
throw new Error("ObjectNP only allowed for objects");
}
return NP;
}
return {
...NP,
inflected,
...textOfNP(NP, inflected, inflectEnglish),
};
};
function renderVerbSelection(vs: VerbSelection, person: T.Person): VerbRendered {
const conjugations = conjugateVerb(vs.verb.entry, vs.verb.complement);
// TODO: error handle this? // TODO: error handle this?
const conjugations = conjugateVerb(VP.verb.verb.entry, VP.verb.verb.complement);
// TODO: option to manually select these // TODO: option to manually select these
const conj = "grammaticallyTransitive" in conjugations const conj = "grammaticallyTransitive" in conjugations
? conjugations.grammaticallyTransitive ? conjugations.grammaticallyTransitive
: "stative" in conjugations : "stative" in conjugations
? conjugations.stative ? conjugations.stative
: conjugations; : conjugations;
// TODO: get the object person from the matrix on stative compounds
return { return {
type: "VPRendered", ...vs,
subject, person,
object, ps: getPsVerbConjugation(conj, vs.tense, person),
verb: { }
...VP.verb, }
person: verbPerson,
ps: getPsVerbConjugation(conj, VP.verb.tense, verbPerson), function renderEnglishVPBase({ subjectPerson, object, vs }: {
e: getEnglishVerbConjugation({ subjectPerson: T.Person,
subjectPerson, object: NPSelection | ObjectNP,
object: VP.object, vs: VerbSelection,
v: parseEc(VP.verb.verb.entry.ec || ""), }): string[] {
ep: VP.verb.verb.entry.ep, const ec = parseEc(vs.verb.entry.ec || "");
tense: VP.verb.tense, const ep = vs.verb.entry.ep;
n: false, const tense = vs.tense;
}), function engEquative(tense: "past" | "present", s: T.Person): string {
}, const [row, col] = getVerbBlockPosFromPerson(s);
return grammarUnits.englishEquative[tense][row][col];
}
function engPresC(s: T.Person, ec: T.EnglishVerbConjugationEc | [string, string]): string {
function isThirdPersonSing(p: T.Person): boolean {
return (
p === T.Person.ThirdSingMale ||
p === T.Person.ThirdSingFemale
);
}
return isThirdPersonSing(s) ? ec[1] : ec[0];
}
function isToBe(v: T.EnglishVerbConjugationEc): boolean {
return (v[2] === "being");
}
const builders: Record<
VerbTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = {
present: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${isToBe(ec)
? `${engEquative("present", s)}${n ? " not" : ""}`
: `${n ? engPresC(s, ["don't", "doesn't"]) : ""} ${n ? ec[0] : engPresC(s, ec)}`}`,
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} ${ec[2]}`,
]),
subjunctive: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ ${n ? " won't" : " will"} ${isToBe(ec) ? "be" : ec[0]}`,
`should $SUBJ ${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
]),
imperfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
// - subj pastEquative (N && "not") ec.2 obj
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} ${ec[2]}`,
// - subj "would" (N && "not") ec.0 obj
`$SUBJ would${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
// - subj pastEquative (N && "not") going to" ec.0 obj
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} going to ${isToBe(ec) ? "be" : ec[0]}`,
]),
perfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ${isToBe(ec)
? ` ${engEquative("past", s)}${n ? " not" : ""}`
: `${n ? " did not" : ""} ${ec[3]}`}`,
]),
}; };
} const base = builders[tense](subjectPerson, ec, vs.negative);
return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`);
export function compileVP(VP: VPRendered | VPSelection): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
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 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 => (
obj ? obj.ps.flatMap(o => (
vPs.flatMap(v => (
concatPsString(s, " ", o, " ", v)
))
)) : vPs.flatMap(v => (
concatPsString(s, " ", v)
))
));
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 {
if (typeof o !== "object") return false;
if (o.type !== "pronoun") return false;
return [0,1,2,3,6,7,8,9].includes(o.person);
} }
function getPsVerbConjugation(conj: T.VerbConjugation, tense: VerbTense, person: T.Person): T.SingleOrLengthOpts<T.PsString[]> { function getPsVerbConjugation(conj: T.VerbConjugation, tense: VerbTense, person: T.Person): T.SingleOrLengthOpts<T.PsString[]> {
@ -156,63 +164,7 @@ function getTenseVerbForm(conj: T.VerbConjugation, tense: VerbTense): T.VerbForm
throw new Error("unknown tense"); throw new Error("unknown tense");
} }
function getEnglishVerbConjugation({ subjectPerson, object, ep, v, tense, n }: { function getPersonFromNP(np: NPSelection | ObjectNP): T.Person {
subjectPerson: T.Person,
object: "none" | NPSelection | T.Person.ThirdPlurMale,
v: T.EnglishVerbConjugationEc,
ep: string | undefined,
tense: VerbTense,
n: boolean,
}): string[] {
function engEquative(tense: "past" | "present", s: T.Person): string {
const [row, col] = getVerbBlockPosFromPerson(s);
return grammarUnits.englishEquative[tense][row][col];
}
function engPresC(s: T.Person, ec: T.EnglishVerbConjugationEc | [string, string]): string {
function isThirdPersonSing(p: T.Person): boolean {
return (
p === T.Person.ThirdSingMale ||
p === T.Person.ThirdSingFemale
);
}
return isThirdPersonSing(s) ? ec[1] : ec[0];
}
function isToBe(v: T.EnglishVerbConjugationEc): boolean {
return (v[2] === "being");
}
const builders: Record<
VerbTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = {
present: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${isToBe(v)
? `${engEquative("present", s)}${n ? " not" : ""}`
: `${n ? engPresC(s, ["don't", "doesn't"]) : ""} ${n ? v[0] : engPresC(s, v)}`}`,
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} ${v[2]}`,
]),
subjunctive: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`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 | "none"): T.Person {
if (np === "none") { if (np === "none") {
throw new Error("empty entity"); throw new Error("empty entity");
} }
@ -247,6 +199,19 @@ function textOfParticiple({ verb: { entry }}: ParticipleSelection, inflected: bo
}; };
} }
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 textOfPronoun(p: PronounSelection, inflected: boolean, englishInflected: boolean): { ps: T.PsString[], e: string } { function textOfPronoun(p: PronounSelection, inflected: boolean, englishInflected: boolean): { ps: T.PsString[], e: string } {
// TODO: Will need to handle inflecting and inflecting english pronouns etc. // TODO: Will need to handle inflecting and inflecting english pronouns etc.
const [row, col] = getVerbBlockPosFromPerson(p.person); const [row, col] = getVerbBlockPosFromPerson(p.person);
@ -256,6 +221,24 @@ function textOfPronoun(p: PronounSelection, inflected: boolean, englishInflected
}; };
} }
function textOfNoun(n: NounSelection, inflected: boolean): { ps: T.PsString[], e: string } {
const english = getEnglishFromNoun(n.entry, n.number);
const pashto = ((): T.PsString[] => {
const infs = inflectWord(n.entry);
const ps = n.number === "singular"
? getInf(infs, "inflections", n.gender, false, inflected)
: [
...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
: [psStringFromEntry(n.entry)];
})();
return { ps: pashto, e: english };
}
function getEnglishFromNoun(entry: T.DictionaryEntry, number: NounNumber): string { function getEnglishFromNoun(entry: T.DictionaryEntry, number: NounNumber): string {
const articles = { const articles = {
singular: "(a/the)", singular: "(a/the)",
@ -276,24 +259,6 @@ function getEnglishFromNoun(entry: T.DictionaryEntry, number: NounNumber): strin
return addArticle(e.singular); return addArticle(e.singular);
} }
function textOfNoun(n: NounSelection, inflected: boolean): { ps: T.PsString[], e: string } {
const english = getEnglishFromNoun(n.entry, n.number);
const pashto = ((): T.PsString[] => {
const infs = inflectWord(n.entry);
const ps = n.number === "singular"
? getInf(infs, "inflections", n.gender, false, inflected)
: [
...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
: [psStringFromEntry(n.entry)];
})();
return { ps: pashto, e: english };
}
function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflections", gender: T.Gender, plural: boolean, inflected: 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) {
@ -306,15 +271,28 @@ function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflect
return []; return [];
} }
export function getEnglishParticiple(entry: T.DictionaryEntry): string { function isPastTense(tense: VerbTense): boolean {
if (!entry.ec) { return tense.toLowerCase().includes("past");
console.log("errored participle"); }
console.log(entry);
throw new Error("no english information for participle"); function getKingAndServant(isPast: boolean, isTransitive: boolean):
} { king: "subject", servant: "object" } |
const ec = parseEc(entry.ec); { king: "object", servant: "subject" } |
const participle = ec[2]; { king: "subject", servant: undefined } {
return (entry.ep) if (!isTransitive) {
? `${participle} ${entry.ep}` return { king: "subject", servant: undefined };
: participle; }
return isPast ? {
king: "object",
servant: "subject",
} : {
king: "subject",
servant: "object",
};
}
function isFirstOrSecondPersPronoun(o: "none" | NPSelection | T.Person.ThirdPlurMale): boolean {
if (typeof o !== "object") return false;
if (o.type !== "pronoun") return false;
return [0,1,2,3,6,7,8,9].includes(o.person);
} }

13
src/types/gen-g.d.ts vendored
View File

@ -16,8 +16,9 @@ type VPSelection = {
type VPRendered = { type VPRendered = {
type: "VPRendered", type: "VPRendered",
subject: Rendered<NPSelection>, subject: Rendered<NPSelection>,
object: "none" | Rendered<NPSelection> | import("@lingdocs/pashto-inflector").Types.Person.ThirdPlurMale, object: Rendered<NPSelection> | ObjectNP,
verb: VerbRendered, verb: VerbRendered,
englishBase?: string[],
} }
type VerbTense = "present" | "subjunctive" | "perfectivePast" | "imperfectivePast"; type VerbTense = "present" | "subjunctive" | "perfectivePast" | "imperfectivePast";
@ -27,6 +28,7 @@ type VerbSelection = {
verb: VerbEntry, verb: VerbEntry,
tense: VerbTense, tense: VerbTense,
object: VerbObject, object: VerbObject,
negative: boolean,
}; };
type VerbRendered = Omit<VerbSelection, "object"> & { type VerbRendered = Omit<VerbSelection, "object"> & {
@ -34,22 +36,23 @@ type VerbRendered = Omit<VerbSelection, "object"> & {
import("@lingdocs/pashto-inflector").Types.PsString[] import("@lingdocs/pashto-inflector").Types.PsString[]
>, >,
person: import("@lingdocs/pashto-inflector").Types.Person, person: import("@lingdocs/pashto-inflector").Types.Person,
e?: string[],
}; };
type VerbObject = // intransitive verb type VerbObject =
"none" |
// transitive verb - object not selected yet // transitive verb - object not selected yet
undefined | undefined |
// transitive verb - obect selected // transitive verb - obect selected
NPSelection | NPSelection |
// grammatically transitive verb with unspoken 3rd pers masc plur entity // grammatically transitive verb with unspoken 3rd pers masc plur entity
import("@lingdocs/pashto-inflector").Types.Person.ThirdPlurMale; // or intransitive "none"
ObjectNP
type NPSelection = NounSelection | PronounSelection | ParticipleSelection; type NPSelection = NounSelection | PronounSelection | ParticipleSelection;
type NPType = "noun" | "pronoun" | "participle"; type NPType = "noun" | "pronoun" | "participle";
type ObjectNP = "none" | import("@lingdocs/pashto-inflector").Types.Person.ThirdPlurMale;
// TODO require/import Person and PsString // TODO require/import Person and PsString
type NounSelection = { type NounSelection = {
type: "noun", type: "noun",