phrase builder working better

This commit is contained in:
lingdocs 2022-03-18 23:28:51 +04:00
parent 10f78df818
commit 1bf14eb44f
5 changed files with 101 additions and 56 deletions

View File

@ -3,28 +3,30 @@ import NPPicker from "../np-picker/NPPicker";
import VerbPicker from "../VerbPicker";
import VPDisplay from "./VPDisplay";
import ObjectDisplay from "./ObjectDisplay";
import { verbs } from "../../words/words";
import { verbs as verbsRaw } from "../../words/words";
import {
isInvalidSubjObjCombo,
} from "../../lib/np-tools";
function verbPhraseComplete({ subject, verb, shrinkServant }: { subject: NPSelection | undefined, verb: VerbSelection | undefined, shrinkServant: boolean }): VPSelection | undefined {
const verbs = verbsRaw.filter(v => !v.entry.c?.includes("gramm."))
function verbPhraseComplete({ subject, verb }: { subject: NPSelection | undefined, verb: VerbSelection | undefined }): VPSelection | undefined {
if (!subject) return undefined;
if (!verb) return undefined;
if (verb.object === undefined) return undefined;
return {
type: "VPSelection",
shrinkServant,
subject,
object: verb.object,
verb,
};
}
// TODO: BIG ISSUE, IF YOU OPEN THE OBJECT PRONOUN BOX AND IT CONFLICTS WITH THE SUBJECT
// IT CAN SAY THE COMBO IS NOT ALLOWED AND SHOW SOMETHING BLANK
export function PhraseBuilder() {
const [subject, setSubject] = useState<NPSelection | undefined>(undefined);
const [verb, setVerb] = useState<VerbSelection | undefined>(undefined);
const [shrinkServant, setShrinkServant] = useState<boolean>(false);
function handleSubjectChange(subject: NPSelection | undefined) {
const objPronoun = (typeof verb?.object === "object" && verb.object.type === "pronoun")
? verb.object.person
@ -57,40 +59,26 @@ export function PhraseBuilder() {
object,
});
}
function handleShrinkServantChange(e: React.ChangeEvent<HTMLInputElement>) {
setShrinkServant(e.target.checked);
}
const verbPhrase: VPSelection | undefined = verbPhraseComplete({ subject, verb, shrinkServant });
return <div>
<div className="d-flex flex-row justify-content-between">
<div className="mr-2">
<div className="h5">Subject</div>
const verbPhrase: VPSelection | undefined = verbPhraseComplete({ subject, verb });
return <div className="mt-3">
<div className="row">
<div className="col mb-2">
<div className="h4">Subject</div>
<NPPicker
np={subject}
counterPart={verb ? verb.object : undefined}
onChange={handleSubjectChange}
/>
</div>
{verb && (verb.object !== "none") && <div className="mr-2">
<div className="h5">Object</div>
{verb && (verb.object !== "none") && <div className="col mb-2">
<div className="h4">Object</div>
<ObjectDisplay object={verb.object} counterPart={subject} onChange={handleObjectChange} />
</div>}
<div>
<div className="h5">Verb</div>
<div className="col mb-2">
<div className="h4">Verb</div>
<VerbPicker verbs={verbs} verb={verb} onChange={setVerb} />
</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>
<VPDisplay VP={verbPhrase} />
</div>}

View File

@ -1,21 +1,68 @@
import { useState } from "react";
import { renderVP, compileVP } from "../../lib/phrase-building";
import {
InlinePs,
defaultTextOptions as opts,
ButtonSelect,
Types as T,
} from "@lingdocs/pashto-inflector";
function adjustForm(form: FormVersion, servantShrinkable: boolean): FormVersion {
if (!servantShrinkable) {
return form === "shortest"
? "no king"
: form === "mini servant"
? "full"
: form;
}
return form;
}
function VPDisplay({ VP }: { VP: VPSelection }) {
const [form, setForm] = useState<FormVersion>("full");
// TODO: Possibly put the servant shrinking in here after the render
const result = compileVP(renderVP(VP));
const rPs = "long" in result.ps ? result.ps.long : result.ps;
const result = compileVP(renderVP(VP), form);
const servantShrinkable = VP.object && typeof VP.object === "object";
return <div className="text-center mt-2">
{rPs.map((r, i) => <div key={i}>
<InlinePs opts={opts}>{r}</InlinePs>
</div>)}
<div className="my-3">
<ButtonSelect
small
options={[
{ value: "full", label: "Full" },
{ value: "no king", label: "No King" },
...servantShrinkable ? [{ value: "mini servant", label: "Mini Servant" }] : [],
...servantShrinkable ? [{ value: "shortest", label: "Shortest" }] : [],
]}
value={adjustForm(form, servantShrinkable)}
// @ts-ignore
handleChange={setForm}
/>
</div>
{"long" in result.ps ?
<div>
<div className="h6">Long Verb:</div>
<VariationLayer vs={result.ps.long} />
<div className="h6">Short Verb:</div>
<VariationLayer vs={result.ps.short} />
{result.ps.mini && <>
<div className="h6">Mini Verb:</div>
<VariationLayer vs={result.ps.mini} />
</>}
</div>
: <VariationLayer vs={result.ps} />
}
{result.e && <div className="text-muted">
{result.e.map((e, i) => <div key={i}>{e}</div>)}
</div>}
</div>
}
function VariationLayer({ vs }: { vs: T.PsString[] }) {
return <div className="mb-2">
{vs.map((r, i) => <div key={i}>
<InlinePs opts={opts}>{r}</InlinePs>
</div>)}
</div>;
}
export default VPDisplay;

View File

@ -6,17 +6,19 @@ import {
getVerbBlockPosFromPerson,
} from "@lingdocs/pashto-inflector";
type ListOfEntities = T.PsString[][];
type ListOfEntities = (T.PsString & { isVerbPrefix?: boolean, prefixFollowedByParticle?: boolean })[][];
export function compileVP(VP: VPRendered): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
export function compileVP(VP: VPRendered, form: FormVersion): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
const { head, rest } = VP.verb.ps;
const { kids, NPs } = shrinkEntitiesAndGatherKids(VP);
const { kids, NPs } = shrinkEntitiesAndGatherKids(VP, form);
return {
ps: compilePs(NPs, head, rest, VP.verb.negative, kids),
e: compileEnglish(VP),
};
}
// TODO: ISSUE off prefix-nu in the phonetics
function compilePs(
nps: ListOfEntities,
head: T.PsString | undefined,
@ -49,33 +51,37 @@ function compilePs(
}
const entities: ListOfEntities = [
...nps,
...compileVerbWNegative(head, rest, negative)
...compileVerbWNegative(head, rest, negative),
];
const entitiesWKids = putKidsInKidsSection(entities, kids);
return combineEntities(entitiesWKids);
}
function shrinkEntitiesAndGatherKids(VP: VPRendered): { kids: ListOfEntities, NPs: ListOfEntities } {
function shrinkEntitiesAndGatherKids(VP: VPRendered, form: FormVersion): { kids: ListOfEntities, NPs: ListOfEntities } {
const main = {
subject: VP.subject.ps,
object: typeof VP.object === "object" ? VP.object.ps : undefined,
}
const toShrink = (VP.shrinkServant && VP.servant)
const removeKing = form === "no king" || form === "shortest";
const shrinkServant = form === "mini servant" || form === "shortest";
const shrinkCanditate = ((form === "mini servant" || form === "shortest") && VP.servant)
? VP[VP.servant]
: undefined;
if (!toShrink || typeof toShrink !== "object") {
return {
kids: [],
NPs: [main.subject, ...main.object ? [main.object] : []]
};
}
const toShrink = (!shrinkCanditate || typeof shrinkCanditate !== "object")
? undefined
: shrinkCanditate;
// TODO: big problem, the king removal doesn't work with grammatically transitive things
const king = main[VP.king];
if (!king) {
throw new Error("lost the king in the shrinking process");
}
const showSubject = (VP.king === "subject" && !removeKing && king) || (VP.servant === "subject" && !shrinkServant);
const showObject = (
(VP.king === "object" && !removeKing && king) || (VP.servant === "object" && !shrinkServant)
);
return {
kids: [shrink(toShrink)],
NPs: [king],
kids: [...toShrink ? [shrink(toShrink)] : []],
NPs: [
...showSubject ? [main.subject] : [],
...(showObject && main.object) ? [main.object] : [],
],
}
}
@ -92,7 +98,11 @@ function putKidsInKidsSection(entities: ListOfEntities, kids: ListOfEntities): L
const first = entities[0];
const rest = entities.slice(1);
return [
first,
first.map(x => (
x.isVerbPrefix &&
// TODO: This isn't quite working
(kids.length)
) ? { ...x, prefixFollowedByParticle: true } : x),
...kids,
...rest,
];
@ -105,7 +115,9 @@ function combineEntities(loe: ListOfEntities): T.PsString[] {
return combineEntities(rest).flatMap(r => (
first.map(ps => concatPsString(
ps,
ps.p === "و" ? { p: "", f: "-" } : " ",
(ps.prefixFollowedByParticle
? { p: "", f: "-" }
: ps.isVerbPrefix ? "" : " "),
r,
))
));
@ -115,7 +127,7 @@ function combineEntities(loe: ListOfEntities): T.PsString[] {
function compileVerbWNegative(head: T.PsString | undefined, rest: T.PsString[], negative: boolean): ListOfEntities {
if (!negative) {
return [
...head ? [[head]] : [],
...head ? [[{...head, isVerbPrefix: true}]] : [],
rest,
];
}
@ -130,7 +142,7 @@ function compileVerbWNegative(head: T.PsString | undefined, rest: T.PsString[],
// if (regularPrefix) {
// dashes for oo-nu etc
return [
[removeAccents(head)],
[{ ...removeAccents(head), isVerbPrefix: true }],
rest.map(r => concatPsString(nu, " ", removeAccents(r)))
];
}

View File

@ -39,7 +39,6 @@ export function renderVP(VP: VPSelection): VPRendered {
servant,
isPast,
isTransitive,
shrinkServant: VP.shrinkServant,
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
object: renderNPSelection(VP.object, inflectObject, true, "object"),
verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),

View File

@ -10,7 +10,6 @@ type VPSelection = {
subject: NPSelection,
object: Exclude<VerbObject, undefined>,
verb: Exclude<VerbSelection, "object">,
shrinkServant: boolean,
};
// TODO: make this Rendered<VPSelection> with recursive Rendered<>
@ -18,7 +17,6 @@ type VPRendered = {
type: "VPRendered",
king: "subject" | "object",
servant: "subject" | "object" | undefined,
shrinkServant: boolean,
isPast: boolean,
isTransitive: boolean,
subject: Rendered<NPSelection>,
@ -96,6 +94,7 @@ type ParticipleSelection = {
// If T has key K ("user"), replace it
type ReplaceKey<T, K extends string, R> = T extends Record<K, unknown> ? (Omit<T, K> & Record<K, R>) : T;
type FormVersion = "full" | "no king" | "mini servant" | "shortest"; // TODO: "all";
type Rendered<T extends NPSelection> = ReplaceKey<
Omit<T, "changeGender" | "changeNumber" | "changeDistance">,