From e4cf7558ee4707866d9e80c58d8c5223f2e77691 Mon Sep 17 00:00:00 2001
From: lingdocs <71590811+lingdocs@users.noreply.github.com>
Date: Wed, 16 Mar 2022 16:12:45 +0400
Subject: [PATCH] some refactoring
---
src/components/VerbPicker.tsx | 25 ++
src/components/phrase-builder/VPDisplay.tsx | 2 +-
src/lib/phrase-building/compile-vp.ts | 37 ++
src/lib/phrase-building/index.ts | 7 +
.../render-vp.ts} | 328 ++++++++----------
src/types/gen-g.d.ts | 15 +-
6 files changed, 232 insertions(+), 182 deletions(-)
create mode 100644 src/lib/phrase-building/compile-vp.ts
create mode 100644 src/lib/phrase-building/index.ts
rename src/lib/{eval-vp.ts => phrase-building/render-vp.ts} (68%)
diff --git a/src/components/VerbPicker.tsx b/src/components/VerbPicker.tsx
index cd3ed65..a804bcd 100644
--- a/src/components/VerbPicker.tsx
+++ b/src/components/VerbPicker.tsx
@@ -5,6 +5,7 @@ import {
} from "./np-picker/picker-tools";
import {
Types as T,
+ // ButtonSelect,
} from "@lingdocs/pashto-inflector";
const tenseOptions: { label: string, value: VerbTense }[] = [{
@@ -42,6 +43,7 @@ function makeVerbSelection(verb: VerbEntry, oldVerbSelection?: VerbSelection): V
verb,
tense: oldVerbSelection ? oldVerbSelection.tense : "present",
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
Verb:
;
}
diff --git a/src/components/phrase-builder/VPDisplay.tsx b/src/components/phrase-builder/VPDisplay.tsx
index b44fb48..7a14d45 100644
--- a/src/components/phrase-builder/VPDisplay.tsx
+++ b/src/components/phrase-builder/VPDisplay.tsx
@@ -1,4 +1,4 @@
-import { renderVP, compileVP } from "../../lib/eval-vp";
+import { renderVP, compileVP } from "../../lib/phrase-building";
import {
InlinePs,
defaultTextOptions as opts,
diff --git a/src/lib/phrase-building/compile-vp.ts b/src/lib/phrase-building/compile-vp.ts
new file mode 100644
index 0000000..e386f6a
--- /dev/null
+++ b/src/lib/phrase-building/compile-vp.ts
@@ -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, 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 };
+}
\ No newline at end of file
diff --git a/src/lib/phrase-building/index.ts b/src/lib/phrase-building/index.ts
new file mode 100644
index 0000000..88b75b6
--- /dev/null
+++ b/src/lib/phrase-building/index.ts
@@ -0,0 +1,7 @@
+import { renderVP } from "./render-vp";
+import { compileVP } from "./compile-vp";
+
+export {
+ renderVP,
+ compileVP,
+};
\ No newline at end of file
diff --git a/src/lib/eval-vp.ts b/src/lib/phrase-building/render-vp.ts
similarity index 68%
rename from src/lib/eval-vp.ts
rename to src/lib/phrase-building/render-vp.ts
index f5ab69e..1beee40 100644
--- a/src/lib/eval-vp.ts
+++ b/src/lib/phrase-building/render-vp.ts
@@ -10,112 +10,120 @@ import {
} from "@lingdocs/pashto-inflector";
import {
psStringFromEntry,
-} from "./text-tools";
+} from "../text-tools";
export function renderVP(VP: VPSelection): VPRendered {
- // TODO: Will be based on past tense etc
+ // Sentence Rules Logic
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 kingPerson = getPersonFromNP(VP[king]);
const subjectPerson = getPersonFromNP(VP.subject);
+ // const objectPerson = getPersonFromNP(VP.object);
// 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: inflectSubject,
- ...textOfNP(VP.subject, inflectSubject, false),
- };
+ const inflectSubject = isPast && isTransitive;
const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object);
- const object: "none" | Rendered | T.Person.ThirdPlurMale = typeof VP.object === "object"
- ? {
- ...VP.subject,
- inflected: inflectObject,
- ...textOfNP(VP.object, inflectObject, true),
- } : VP.object;
+ // Render Elements
+ return {
+ type: "VPRendered",
+ subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
+ object: renderNPSelection(VP.object, inflectObject, true, "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
+function renderNPSelection(NP: NPSelection | ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "object"): Rendered | T.Person.ThirdPlurMale | "none";
+function renderNPSelection(NP: NPSelection | ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "subject" | "object"): Rendered | 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?
- const conjugations = conjugateVerb(VP.verb.verb.entry, VP.verb.verb.complement);
// TODO: option to manually select these
const conj = "grammaticallyTransitive" in conjugations
? conjugations.grammaticallyTransitive
: "stative" in conjugations
? conjugations.stative
: conjugations;
+ // TODO: get the object person from the matrix on stative compounds
return {
- type: "VPRendered",
- subject,
- object,
- verb: {
- ...VP.verb,
- person: verbPerson,
- ps: getPsVerbConjugation(conj, VP.verb.tense, verbPerson),
- e: getEnglishVerbConjugation({
- subjectPerson,
- object: VP.object,
- v: parseEc(VP.verb.verb.entry.ec || ""),
- ep: VP.verb.verb.entry.ep,
- tense: VP.verb.tense,
- n: false,
- }),
- },
+ ...vs,
+ person,
+ ps: getPsVerbConjugation(conj, vs.tense, person),
+ }
+}
+
+function renderEnglishVPBase({ subjectPerson, object, vs }: {
+ subjectPerson: T.Person,
+ object: NPSelection | ObjectNP,
+ vs: VerbSelection,
+}): string[] {
+ const ec = parseEc(vs.verb.entry.ec || "");
+ const ep = vs.verb.entry.ep;
+ 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]}`}`,
+ ]),
};
-}
-
-export function compileVP(VP: VPRendered | VPSelection): { ps: T.SingleOrLengthOpts, 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);
+ const base = builders[tense](subjectPerson, ec, vs.negative);
+ return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`);
}
function getPsVerbConjugation(conj: T.VerbConjugation, tense: VerbTense, person: T.Person): T.SingleOrLengthOpts {
@@ -156,63 +164,7 @@ function getTenseVerbForm(conj: T.VerbConjugation, tense: VerbTense): T.VerbForm
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: 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 {
+function getPersonFromNP(np: NPSelection | ObjectNP): T.Person {
if (np === "none") {
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 } {
// TODO: Will need to handle inflecting and inflecting english pronouns etc.
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 {
const articles = {
singular: "(a/the)",
@@ -276,24 +259,6 @@ function getEnglishFromNoun(entry: T.DictionaryEntry, number: NounNumber): strin
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[] {
// @ts-ignore
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 [];
}
-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 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);
+}
\ No newline at end of file
diff --git a/src/types/gen-g.d.ts b/src/types/gen-g.d.ts
index fef3ad7..da83943 100644
--- a/src/types/gen-g.d.ts
+++ b/src/types/gen-g.d.ts
@@ -16,8 +16,9 @@ type VPSelection = {
type VPRendered = {
type: "VPRendered",
subject: Rendered,
- object: "none" | Rendered | import("@lingdocs/pashto-inflector").Types.Person.ThirdPlurMale,
- verb: VerbRendered,
+ object: Rendered | ObjectNP,
+ verb: VerbRendered,
+ englishBase?: string[],
}
type VerbTense = "present" | "subjunctive" | "perfectivePast" | "imperfectivePast";
@@ -27,6 +28,7 @@ type VerbSelection = {
verb: VerbEntry,
tense: VerbTense,
object: VerbObject,
+ negative: boolean,
};
type VerbRendered = Omit & {
@@ -34,22 +36,23 @@ type VerbRendered = Omit & {
import("@lingdocs/pashto-inflector").Types.PsString[]
>,
person: import("@lingdocs/pashto-inflector").Types.Person,
- e?: string[],
};
-type VerbObject = // intransitive verb
- "none" |
+type VerbObject =
// transitive verb - object not selected yet
undefined |
// transitive verb - obect selected
NPSelection |
// 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 NPType = "noun" | "pronoun" | "participle";
+type ObjectNP = "none" | import("@lingdocs/pashto-inflector").Types.Person.ThirdPlurMale;
+
// TODO require/import Person and PsString
type NounSelection = {
type: "noun",