UGLY basic ability to shrink servants
This commit is contained in:
parent
06fa7966f8
commit
5c510a6128
|
@ -8,12 +8,13 @@ import {
|
||||||
isInvalidSubjObjCombo,
|
isInvalidSubjObjCombo,
|
||||||
} from "../../lib/np-tools";
|
} from "../../lib/np-tools";
|
||||||
|
|
||||||
function verbPhraseComplete({ subject, verb }: { subject: NPSelection | undefined, verb: VerbSelection | undefined }): VPSelection | undefined {
|
function verbPhraseComplete({ subject, verb, shrinkServant }: { subject: NPSelection | undefined, verb: VerbSelection | undefined, shrinkServant: boolean }): VPSelection | undefined {
|
||||||
if (!subject) return undefined;
|
if (!subject) return undefined;
|
||||||
if (!verb) return undefined;
|
if (!verb) return undefined;
|
||||||
if (verb.object === undefined) return undefined;
|
if (verb.object === undefined) return undefined;
|
||||||
return {
|
return {
|
||||||
type: "VPSelection",
|
type: "VPSelection",
|
||||||
|
shrinkServant,
|
||||||
subject,
|
subject,
|
||||||
object: verb.object,
|
object: verb.object,
|
||||||
verb,
|
verb,
|
||||||
|
@ -23,6 +24,7 @@ function verbPhraseComplete({ subject, verb }: { subject: NPSelection | undefine
|
||||||
export function PhraseBuilder() {
|
export function PhraseBuilder() {
|
||||||
const [subject, setSubject] = useState<NPSelection | undefined>(undefined);
|
const [subject, setSubject] = useState<NPSelection | undefined>(undefined);
|
||||||
const [verb, setVerb] = useState<VerbSelection | undefined>(undefined);
|
const [verb, setVerb] = useState<VerbSelection | undefined>(undefined);
|
||||||
|
const [shrinkServant, setShrinkServant] = useState<boolean>(false);
|
||||||
function handleSubjectChange(subject: NPSelection | undefined) {
|
function handleSubjectChange(subject: NPSelection | undefined) {
|
||||||
const objPronoun = (typeof verb?.object === "object" && verb.object.type === "pronoun")
|
const objPronoun = (typeof verb?.object === "object" && verb.object.type === "pronoun")
|
||||||
? verb.object.person
|
? verb.object.person
|
||||||
|
@ -55,7 +57,10 @@ export function PhraseBuilder() {
|
||||||
object,
|
object,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const verbPhrase: VPSelection | undefined = verbPhraseComplete({ subject, verb });
|
function handleShrinkServantChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||||
|
setShrinkServant(e.target.checked);
|
||||||
|
}
|
||||||
|
const verbPhrase: VPSelection | undefined = verbPhraseComplete({ subject, verb, shrinkServant });
|
||||||
return <div>
|
return <div>
|
||||||
<div className="d-flex flex-row justify-content-between">
|
<div className="d-flex flex-row justify-content-between">
|
||||||
<div className="mr-2">
|
<div className="mr-2">
|
||||||
|
@ -75,6 +80,17 @@ export function PhraseBuilder() {
|
||||||
<VerbPicker verbs={verbs} verb={verb} onChange={setVerb} />
|
<VerbPicker verbs={verbs} verb={verb} onChange={setVerb} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/* TODO: make this appear conditionally */}
|
||||||
|
{(verbPhrase?.object && typeof verbPhrase.object === "object") && <div className="form-group form-check">
|
||||||
|
<input
|
||||||
|
className="form-check-input"
|
||||||
|
name="shrinkServant"
|
||||||
|
type="checkbox"
|
||||||
|
checked={shrinkServant}
|
||||||
|
onChange={handleShrinkServantChange}
|
||||||
|
/>
|
||||||
|
<label className="form-check-label">Shrink servant</label>
|
||||||
|
</div>}
|
||||||
{verbPhrase && <div>
|
{verbPhrase && <div>
|
||||||
<VPDisplay VP={verbPhrase} />
|
<VPDisplay VP={verbPhrase} />
|
||||||
</div>}
|
</div>}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
} from "@lingdocs/pashto-inflector";
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
|
||||||
function VPDisplay({ VP }: { VP: VPSelection }) {
|
function VPDisplay({ VP }: { VP: VPSelection }) {
|
||||||
|
// TODO: Possibly put the servant shrinking in here after the render
|
||||||
const result = compileVP(renderVP(VP));
|
const result = compileVP(renderVP(VP));
|
||||||
const rPs = "long" in result.ps ? result.ps.long : result.ps;
|
const rPs = "long" in result.ps ? result.ps.long : result.ps;
|
||||||
return <div className="text-center mt-2">
|
return <div className="text-center mt-2">
|
||||||
|
|
|
@ -2,97 +2,136 @@ import {
|
||||||
Types as T,
|
Types as T,
|
||||||
concatPsString,
|
concatPsString,
|
||||||
removeAccents,
|
removeAccents,
|
||||||
|
grammarUnits,
|
||||||
|
getVerbBlockPosFromPerson,
|
||||||
} from "@lingdocs/pashto-inflector";
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
|
||||||
|
type ListOfEntities = T.PsString[][];
|
||||||
|
|
||||||
export function compileVP(VP: VPRendered): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
|
export function compileVP(VP: VPRendered): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
|
||||||
console.log(VP);
|
|
||||||
const { head, rest } = VP.verb.ps;
|
const { head, rest } = VP.verb.ps;
|
||||||
const subj = VP.subject.ps;
|
const { kids, NPs } = shrinkEntitiesAndGatherKids(VP);
|
||||||
const obj = typeof VP.object === "object" ? VP.object.ps : undefined;
|
|
||||||
// better: feed in array of NPs [subj, obj, etc...]
|
|
||||||
return {
|
return {
|
||||||
ps: arrangePs(subj, obj, head, rest, VP.verb.negative),
|
ps: compilePs(NPs, head, rest, VP.verb.negative, kids),
|
||||||
e: compileEnglish(VP),
|
e: compileEnglish(VP),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function arrangePs(
|
function compilePs(
|
||||||
subj: T.PsString[],
|
nps: ListOfEntities,
|
||||||
obj: T.PsString[] | undefined,
|
|
||||||
head: T.PsString | undefined,
|
head: T.PsString | undefined,
|
||||||
rest: T.PsString[],
|
rest: T.PsString[],
|
||||||
negative: boolean,
|
negative: boolean,
|
||||||
|
kids: ListOfEntities,
|
||||||
): T.PsString[];
|
): T.PsString[];
|
||||||
function arrangePs(
|
function compilePs(
|
||||||
subj: T.PsString[],
|
nps: ListOfEntities,
|
||||||
obj: T.PsString[] | undefined,
|
|
||||||
head: T.PsString | undefined,
|
head: T.PsString | undefined,
|
||||||
rest: T.SingleOrLengthOpts<T.PsString[]>,
|
rest: T.SingleOrLengthOpts<T.PsString[]>,
|
||||||
negative: boolean,
|
negative: boolean,
|
||||||
|
kids: ListOfEntities,
|
||||||
): T.SingleOrLengthOpts<T.PsString[]>;
|
): T.SingleOrLengthOpts<T.PsString[]>;
|
||||||
function arrangePs(
|
function compilePs(
|
||||||
subj: T.PsString[],
|
nps: ListOfEntities,
|
||||||
obj: T.PsString[] | undefined,
|
|
||||||
head: T.PsString | undefined,
|
head: T.PsString | undefined,
|
||||||
rest: T.SingleOrLengthOpts<T.PsString[]>,
|
rest: T.SingleOrLengthOpts<T.PsString[]>,
|
||||||
negative: boolean,
|
negative: boolean,
|
||||||
|
kids: ListOfEntities,
|
||||||
): T.SingleOrLengthOpts<T.PsString[]> {
|
): T.SingleOrLengthOpts<T.PsString[]> {
|
||||||
if ("long" in rest) {
|
if ("long" in rest) {
|
||||||
return {
|
return {
|
||||||
long: arrangePs(subj, obj, head, rest.long, negative),
|
long: compilePs(nps, head, rest.long, negative, kids),
|
||||||
short: arrangePs(subj, obj, head, rest.short, negative),
|
short: compilePs(nps, head, rest.short, negative, kids),
|
||||||
...rest.mini ? {
|
...rest.mini ? {
|
||||||
mini: arrangePs(subj, obj, head, rest.mini, negative),
|
mini: compilePs(nps, head, rest.mini, negative, kids),
|
||||||
} : {},
|
} : {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const verbWNeg = arrangeVerbWNeg(head, rest, negative);
|
const entities: ListOfEntities = [
|
||||||
if (obj) {
|
...nps,
|
||||||
return subj.flatMap(s => (
|
...compileVerbWNegative(head, rest, negative)
|
||||||
obj.flatMap(o =>
|
];
|
||||||
verbWNeg.flatMap(v => (
|
const entitiesWKids = putKidsInKidsSection(entities, kids);
|
||||||
concatPsString(s, " ", o, " ", v)
|
return combineEntities(entitiesWKids);
|
||||||
// concatPsString(o, " ", s, " ", v),
|
}
|
||||||
))
|
|
||||||
))
|
function shrinkEntitiesAndGatherKids(VP: VPRendered): { kids: ListOfEntities, NPs: ListOfEntities } {
|
||||||
);
|
const main = {
|
||||||
|
subject: VP.subject.ps,
|
||||||
|
object: typeof VP.object === "object" ? VP.object.ps : undefined,
|
||||||
}
|
}
|
||||||
return subj.flatMap(s => (
|
const toShrink = (VP.shrinkServant && VP.servant)
|
||||||
verbWNeg.flatMap(v => (
|
? VP[VP.servant]
|
||||||
concatPsString(s, " ", v)
|
: undefined;
|
||||||
|
if (!toShrink || typeof toShrink !== "object") {
|
||||||
|
return {
|
||||||
|
kids: [],
|
||||||
|
NPs: [main.subject, ...main.object ? [main.object] : []]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const king = main[VP.king];
|
||||||
|
if (!king) {
|
||||||
|
throw new Error("lost the king in the shrinking process");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
kids: [shrink(toShrink)],
|
||||||
|
NPs: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function shrink(np: Rendered<NPSelection>): T.PsString[] {
|
||||||
|
const person: T.Person = np.type === "participle"
|
||||||
|
? T.Person.ThirdPlurMale
|
||||||
|
// @ts-ignore
|
||||||
|
: np.person;
|
||||||
|
const [row, col] = getVerbBlockPosFromPerson(person);
|
||||||
|
return grammarUnits.pronouns.mini[row][col];
|
||||||
|
}
|
||||||
|
|
||||||
|
function putKidsInKidsSection(entities: ListOfEntities, kids: ListOfEntities): ListOfEntities {
|
||||||
|
const first = entities[0];
|
||||||
|
const rest = entities.slice(1);
|
||||||
|
return [
|
||||||
|
first,
|
||||||
|
...kids,
|
||||||
|
...rest,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function combineEntities(loe: ListOfEntities): T.PsString[] {
|
||||||
|
const first = loe[0];
|
||||||
|
const rest = loe.slice(1);
|
||||||
|
if (!rest.length) return first;
|
||||||
|
return combineEntities(rest).flatMap(r => (
|
||||||
|
first.map(ps => concatPsString(
|
||||||
|
ps,
|
||||||
|
ps.p === "و" ? { p: "", f: "-" } : " ",
|
||||||
|
r,
|
||||||
))
|
))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function arrangeVerbWNeg(head: T.PsString | undefined, rest: T.PsString[], negative: boolean): T.PsString[] {
|
|
||||||
if (!negative) {
|
|
||||||
return rest.map(ps => concatPsString(head || "", ps));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
function compileVerbWNegative(head: T.PsString | undefined, rest: T.PsString[], negative: boolean): ListOfEntities {
|
||||||
|
if (!negative) {
|
||||||
|
return [
|
||||||
|
...head ? [[head]] : [],
|
||||||
|
rest,
|
||||||
|
];
|
||||||
|
}
|
||||||
const nu: T.PsString = { p: "نه", f: "nú" };
|
const nu: T.PsString = { p: "نه", f: "nú" };
|
||||||
if (!head) {
|
if (!head) {
|
||||||
return rest.map(r => concatPsString(nu, " ", removeAccents(r)));
|
|
||||||
}
|
|
||||||
const regularPrefix = head.p === "و" || head.p === "وا";
|
|
||||||
const withNuAfterHead = rest.map(r => concatPsString(
|
|
||||||
removeAccents(head),
|
|
||||||
{ p: "", f: "-" },
|
|
||||||
nu,
|
|
||||||
" ",
|
|
||||||
removeAccents(r),
|
|
||||||
));
|
|
||||||
if (regularPrefix) {
|
|
||||||
return withNuAfterHead;
|
|
||||||
}
|
|
||||||
const withNuBeforeHead = rest.map(r => concatPsString(
|
|
||||||
nu,
|
|
||||||
" ",
|
|
||||||
removeAccents(head),
|
|
||||||
removeAccents(r),
|
|
||||||
));
|
|
||||||
return [
|
return [
|
||||||
...withNuAfterHead,
|
[nu],
|
||||||
...withNuBeforeHead,
|
rest.map(r => removeAccents(r)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// const regularPrefix = head.p === "و" || head.p === "وا";
|
||||||
|
// if (regularPrefix) {
|
||||||
|
// dashes for oo-nu etc
|
||||||
|
return [
|
||||||
|
[removeAccents(head)],
|
||||||
|
rest.map(r => concatPsString(nu, " ", removeAccents(r)))
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,16 @@ import {
|
||||||
import {
|
import {
|
||||||
psStringFromEntry,
|
psStringFromEntry,
|
||||||
} from "../text-tools";
|
} from "../text-tools";
|
||||||
|
import {
|
||||||
|
getPersonFromNP,
|
||||||
|
} from "./vp-tools";
|
||||||
|
import { isPattern4Entry } from "../type-predicates";
|
||||||
|
|
||||||
export function renderVP(VP: VPSelection): VPRendered {
|
export function renderVP(VP: VPSelection): VPRendered {
|
||||||
// Sentence Rules Logic
|
// 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);
|
||||||
const kingPerson = getPersonFromNP(VP[king]);
|
const kingPerson = getPersonFromNP(VP[king]);
|
||||||
// TODO: more elegant way of handling this type safety
|
// TODO: more elegant way of handling this type safety
|
||||||
if (kingPerson === undefined) {
|
if (kingPerson === undefined) {
|
||||||
|
@ -26,11 +30,16 @@ export function renderVP(VP: VPSelection): VPRendered {
|
||||||
const subjectPerson = getPersonFromNP(VP.subject);
|
const subjectPerson = getPersonFromNP(VP.subject);
|
||||||
const objectPerson = getPersonFromNP(VP.object);
|
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 && !isSingularAnimatePattern4(VP.subject);
|
||||||
const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object);
|
const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object);
|
||||||
// Render Elements
|
// Render Elements
|
||||||
return {
|
return {
|
||||||
type: "VPRendered",
|
type: "VPRendered",
|
||||||
|
king,
|
||||||
|
servant,
|
||||||
|
isPast,
|
||||||
|
isTransitive,
|
||||||
|
shrinkServant: VP.shrinkServant,
|
||||||
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
|
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
|
||||||
object: renderNPSelection(VP.object, inflectObject, true, "object"),
|
object: renderNPSelection(VP.object, inflectObject, true, "object"),
|
||||||
verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),
|
verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),
|
||||||
|
@ -292,24 +301,6 @@ function getTenseVerbForm(conj: T.VerbConjugation, tense: VerbTense): T.VerbForm
|
||||||
throw new Error("unknown tense");
|
throw new Error("unknown tense");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPersonFromNP(np: NPSelection): T.Person;
|
|
||||||
function getPersonFromNP(np: NPSelection | ObjectNP): T.Person | undefined;
|
|
||||||
function getPersonFromNP(np: NPSelection | ObjectNP): T.Person | undefined {
|
|
||||||
if (np === "none") {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (typeof np === "number") return np;
|
|
||||||
if (np.type === "participle") {
|
|
||||||
return T.Person.ThirdPlurMale;
|
|
||||||
}
|
|
||||||
if (np.type === "pronoun") {
|
|
||||||
return np.person;
|
|
||||||
}
|
|
||||||
return np.number === "plural"
|
|
||||||
? (np.gender === "masc" ? T.Person.ThirdPlurMale : T.Person.ThirdPlurFemale)
|
|
||||||
: (np.gender === "masc" ? T.Person.ThirdSingMale : T.Person.ThirdSingFemale);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEnglishParticiple(entry: T.DictionaryEntry): string {
|
function getEnglishParticiple(entry: T.DictionaryEntry): string {
|
||||||
if (!entry.ec) {
|
if (!entry.ec) {
|
||||||
console.log("errored participle");
|
console.log("errored participle");
|
||||||
|
@ -349,7 +340,6 @@ function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflect
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const iset = infs[t][gender] as T.InflectionSet;
|
const iset = infs[t][gender] as T.InflectionSet;
|
||||||
const inflectionNumber = (inflected ? 1 : 0) + ((t === "inflections" && plural) ? 1 : 0);
|
const inflectionNumber = (inflected ? 1 : 0) + ((t === "inflections" && plural) ? 1 : 0);
|
||||||
console.log({ t, plural, inflectionNumber });
|
|
||||||
return iset[inflectionNumber];
|
return iset[inflectionNumber];
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
|
@ -390,3 +380,10 @@ function isPerfective(t: VerbTense): boolean {
|
||||||
}
|
}
|
||||||
throw new Error("tense not implemented yet");
|
throw new Error("tense not implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSingularAnimatePattern4(np: NPSelection): boolean {
|
||||||
|
if (np.type !== "noun") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isPattern4Entry(np.entry) && np.entry.c.includes("anim.") && (np.number === "singular");
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import {
|
||||||
|
Types as T,
|
||||||
|
} from "@lingdocs/pashto-inflector";
|
||||||
|
|
||||||
|
export function getPersonFromNP(np: NPSelection): T.Person;
|
||||||
|
export function getPersonFromNP(np: NPSelection | ObjectNP): T.Person | undefined;
|
||||||
|
export function getPersonFromNP(np: NPSelection | ObjectNP): T.Person | undefined {
|
||||||
|
if (np === "none") {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (typeof np === "number") return np;
|
||||||
|
if (np.type === "participle") {
|
||||||
|
return T.Person.ThirdPlurMale;
|
||||||
|
}
|
||||||
|
if (np.type === "pronoun") {
|
||||||
|
return np.person;
|
||||||
|
}
|
||||||
|
return np.number === "plural"
|
||||||
|
? (np.gender === "masc" ? T.Person.ThirdPlurMale : T.Person.ThirdPlurFemale)
|
||||||
|
: (np.gender === "masc" ? T.Person.ThirdSingMale : T.Person.ThirdSingFemale);
|
||||||
|
}
|
|
@ -10,11 +10,17 @@ type VPSelection = {
|
||||||
subject: NPSelection,
|
subject: NPSelection,
|
||||||
object: Exclude<VerbObject, undefined>,
|
object: Exclude<VerbObject, undefined>,
|
||||||
verb: Exclude<VerbSelection, "object">,
|
verb: Exclude<VerbSelection, "object">,
|
||||||
|
shrinkServant: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: make this Rendered<VPSelection> with recursive Rendered<>
|
// TODO: make this Rendered<VPSelection> with recursive Rendered<>
|
||||||
type VPRendered = {
|
type VPRendered = {
|
||||||
type: "VPRendered",
|
type: "VPRendered",
|
||||||
|
king: "subject" | "object",
|
||||||
|
servant: "subject" | "object" | undefined,
|
||||||
|
shrinkServant: boolean,
|
||||||
|
isPast: boolean,
|
||||||
|
isTransitive: boolean,
|
||||||
subject: Rendered<NPSelection>,
|
subject: Rendered<NPSelection>,
|
||||||
object: Rendered<NPSelection> | ObjectNP,
|
object: Rendered<NPSelection> | ObjectNP,
|
||||||
verb: VerbRendered,
|
verb: VerbRendered,
|
||||||
|
|
Loading…
Reference in New Issue