From 4e5075ca19ddc07d14a525dc7aa18619cb572731 Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Wed, 1 Jun 2022 19:04:09 -0500 Subject: [PATCH] better format with NP and AP selections etc --- package.json | 2 +- src/components/ap-picker/APPicker.tsx | 12 +- src/components/ep-explorer/EPDisplay.tsx | 6 +- src/components/ep-explorer/EPExplorer.tsx | 4 +- src/components/ep-explorer/eps-reducer.ts | 26 ++-- .../eq-comp-picker/EqCompPicker.tsx | 16 +- src/components/np-picker/NPPicker.tsx | 144 ++++++++++-------- src/components/vp-explorer/VPExplorer.tsx | 4 +- src/components/vp-explorer/VPExplorerQuiz.tsx | 80 ++++++---- src/components/vp-explorer/verb-selection.ts | 6 +- src/components/vp-explorer/vps-reducer.ts | 4 +- src/lib/np-tools.ts | 4 +- src/lib/phrase-building/blocks-utils.ts | 48 +++++- src/lib/phrase-building/compile.ts | 54 +++---- src/lib/phrase-building/np-tools.ts | 117 +++++++------- src/lib/phrase-building/render-ap.ts | 16 +- src/lib/phrase-building/render-ep.ts | 59 ++++--- src/lib/phrase-building/render-np.ts | 29 ++-- src/lib/phrase-building/render-sandwich.ts | 4 +- src/lib/phrase-building/render-vp.ts | 14 +- src/lib/phrase-building/vp-tools.ts | 49 +++--- src/types.ts | 46 +++++- 22 files changed, 452 insertions(+), 292 deletions(-) diff --git a/package.json b/package.json index f4daf97..2410a99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lingdocs/pashto-inflector", - "version": "2.7.3", + "version": "2.8.0", "author": "lingdocs.com", "description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations", "homepage": "https://verbs.lingdocs.com", diff --git a/src/components/ap-picker/APPicker.tsx b/src/components/ap-picker/APPicker.tsx index d3cf39b..d09b858 100644 --- a/src/components/ap-picker/APPicker.tsx +++ b/src/components/ap-picker/APPicker.tsx @@ -16,11 +16,11 @@ function APPicker(props: { onRemove: () => void, }) { const [type, setType] = useState(props.AP - ? props.AP.type + ? props.AP.selection.type : undefined); useEffect(() => { setType(props.AP - ? props.AP.type + ? props.AP.selection.type : undefined); }, [props.AP]); function handleClear() { @@ -73,15 +73,15 @@ function APPicker(props: { {type === "adverb" ? props.onChange(a ? { type: "AP", selection: a } : undefined)} /> : type === "sandwich" ? props.onChange(a ? { type: "AP", selection: a } : undefined)} opts={props.opts} - sandwich={props.AP?.type === "sandwich" ? props.AP : undefined} + sandwich={props.AP?.selection.type === "sandwich" ? props.AP.selection : undefined} entryFeeder={props.entryFeeder} phraseIsComplete={props.phraseIsComplete} onExit={handleSandwichExit} diff --git a/src/components/ep-explorer/EPDisplay.tsx b/src/components/ep-explorer/EPDisplay.tsx index 067acb2..a701900 100644 --- a/src/components/ep-explorer/EPDisplay.tsx +++ b/src/components/ep-explorer/EPDisplay.tsx @@ -49,10 +49,10 @@ function EPDisplay({ eps, opts, setOmitSubject }: { {result.e &&
{result.e.map((e, i) =>
{e}
)}
} - {EP.predicate.selection.type === "participle" &&
-

⚠️ NOTE: This means that the subject {renderedSubject.e ? `(${renderedSubject.e})` : ""} is the action/idea of + {EP.predicate.selection.selection.type === "participle" &&

+

⚠️ NOTE: This means that the subject {renderedSubject.selection.e ? `(${renderedSubject.selection.e})` : ""} is the action/idea of {` `} - "{rendered.predicate.e ? rendered.predicate.e : "the particple"}".

+ "{rendered.predicate.selection.e ? rendered.predicate.selection.e : "the particple"}".

It does not mean that the subject is doing the action, which is what the transaltion sounds like in English.

}
diff --git a/src/components/ep-explorer/EPExplorer.tsx b/src/components/ep-explorer/EPExplorer.tsx index 0cf1453..5e5c63e 100644 --- a/src/components/ep-explorer/EPExplorer.tsx +++ b/src/components/ep-explorer/EPExplorer.tsx @@ -38,7 +38,7 @@ function EPExplorer(props: { entryFeeder: T.EntryFeeder, }) { const [mode, setMode] = useStickyState<"charts" | "phrases">("charts", "EPExplorerMode"); - const [eps, adjustEps] = useStickyReducer(epsReducer, blankEps, "EPState4", flashMessage); + const [eps, adjustEps] = useStickyReducer(epsReducer, blankEps, "EPState5", flashMessage); const [alert, setAlert] = useState(undefined); const [showClipped, setShowClipped] = useState(""); const parent = useRef(null); @@ -57,7 +57,7 @@ function EPExplorer(props: { // eslint-disable-next-line }, []); const subject = getSubjectSelection(eps.blocks).selection; - const king = subject?.type === "pronoun" + const king = subject?.selection.type === "pronoun" ? "subject" : eps.predicate.type === "Complement" ? "subject" diff --git a/src/components/ep-explorer/eps-reducer.ts b/src/components/ep-explorer/eps-reducer.ts index c0c550e..4ec35f5 100644 --- a/src/components/ep-explorer/eps-reducer.ts +++ b/src/components/ep-explorer/eps-reducer.ts @@ -65,15 +65,15 @@ export default function epsReducer(eps: T.EPSelectionState, action: EpsReducerAc blocks: adjustSubjectSelection(eps.blocks, subject), }; } - if (subject.type === "pronoun" && eps.predicate.type === "NP" && eps.predicate.NP?.type === "noun" && isUnisexNounEntry(eps.predicate.NP.entry)) { - const predicate = eps.predicate.NP; + if (subject.selection.type === "pronoun" && eps.predicate.type === "NP" && eps.predicate.NP?.selection.type === "noun" && isUnisexNounEntry(eps.predicate.NP.selection.entry)) { + const predicate = eps.predicate.NP.selection; const adjusted = { ...predicate, ...predicate.numberCanChange ? { - number: personNumber(subject.person), + number: personNumber(subject.selection.person), } : {}, ...predicate.genderCanChange ? { - gender: personGender(subject.person), + gender: personGender(subject.selection.person), } : {}, } return { @@ -81,7 +81,10 @@ export default function epsReducer(eps: T.EPSelectionState, action: EpsReducerAc blocks: adjustSubjectSelection(eps.blocks, subject), predicate: { ...eps.predicate, - NP: adjusted, + NP: { + type: "NP", + selection: adjusted, + }, }, }; } @@ -103,15 +106,18 @@ export default function epsReducer(eps: T.EPSelectionState, action: EpsReducerAc }; } const subject = getSubjectSelection(eps.blocks).selection; - if (subject?.type === "pronoun" && selection.type === "noun" && isUnisexNounEntry(selection.entry)) { - const { gender, number } = selection; - const pronoun = subject.person; + if (subject?.selection.type === "pronoun" && selection.selection.type === "noun" && isUnisexNounEntry(selection.selection.entry)) { + const { gender, number } = selection.selection; + const pronoun = subject.selection.person; const newPronoun = movePersonNumber(movePersonGender(pronoun, gender), number); return { ...eps, blocks: adjustSubjectSelection(eps.blocks, { - ...subject, - person: newPronoun, + type: "NP", + selection: { + ...subject.selection, + person: newPronoun, + }, }), predicate: { ...eps.predicate, diff --git a/src/components/ep-explorer/eq-comp-picker/EqCompPicker.tsx b/src/components/ep-explorer/eq-comp-picker/EqCompPicker.tsx index 32b2da2..f12854a 100644 --- a/src/components/ep-explorer/eq-comp-picker/EqCompPicker.tsx +++ b/src/components/ep-explorer/eq-comp-picker/EqCompPicker.tsx @@ -15,11 +15,11 @@ function EqCompPicker(props: { entryFeeder: T.EntryFeeder, }) { const [compType, setCompType] = useState(props.comp - ? props.comp.type + ? props.comp.selection.type : undefined); useEffect(() => { setCompType(props.comp - ? props.comp.type + ? props.comp.selection.type : undefined); }, [props.comp]); function handleClear() { @@ -68,23 +68,23 @@ function EqCompPicker(props: { {compType === "adjective" ? props.onChange(a ? { type: "EQComp", selection: a } : undefined)} phraseIsComplete={props.phraseIsComplete} /> : compType === "loc. adv." ? props.onChange(a ? { type: "EQComp", selection: a } : undefined)} /> : compType === "sandwich" ? props.onChange(a ? { type: "EQComp", selection: a } : undefined)} opts={props.opts} - sandwich={props.comp?.type === "sandwich" ? props.comp : undefined} + sandwich={props.comp?.selection.type === "sandwich" ? props.comp.selection : undefined} entryFeeder={props.entryFeeder} onExit={handleSandwichExit} // TODO: get phraseIsComplete working here diff --git a/src/components/np-picker/NPPicker.tsx b/src/components/np-picker/NPPicker.tsx index e647680..8c8981b 100644 --- a/src/components/np-picker/NPPicker.tsx +++ b/src/components/np-picker/NPPicker.tsx @@ -25,19 +25,19 @@ function NPPicker(props: { phraseIsComplete: boolean, isShrunk?: boolean, }) { - if (props.is2ndPersonPicker && ((props.np?.type !== "pronoun") || !isSecondPerson(props.np.person))) { + if (props.is2ndPersonPicker && ((props.np?.selection.type !== "pronoun") || !isSecondPerson(props.np.selection.person))) { throw new Error("can't use 2ndPerson NPPicker without a pronoun"); } const [addingPoss, setAddingPoss] = useState(false); - const [npType, setNpType] = useState(props.np ? props.np.type : undefined); + const [npType, setNpType] = useState(props.np ? props.np.selection.type : undefined); const onChange = (np: T.NPSelection | undefined) => { props.onChange(ensureSingleShrink(props.np, np)) } useEffect(() => { - setNpType(props.np ? props.np.type : undefined); + setNpType(props.np ? props.np.selection.type : undefined); }, [props.np]); function handleClear() { - if (props.np && props.np.type === "noun" && props.np.dynamicComplement) return; + if (props.np && props.np.selection.type === "noun" && props.np.selection.dynamicComplement) return; setNpType(undefined); onChange(undefined); } @@ -50,7 +50,7 @@ function NPPicker(props: { distance: "far", }; setNpType(ntp); - onChange(pronoun); + onChange({ type: "NP", selection: pronoun }); } else { if (props.np) { onChange(undefined); @@ -60,39 +60,48 @@ function NPPicker(props: { } // TODO: REMOVE function handlePossesiveChange(p: T.NPSelection | undefined) { - if (!props.np || props.np.type === "pronoun") return; + if (!props.np || props.np.selection.type === "pronoun") return; if (!p) { onChange({ - ...props.np, - possesor: undefined, + type: "NP", + selection: { + ...props.np.selection, + possesor: undefined, + }, }); return; } - const isNewPosesser = checkForNewPossesor(p, props.np.possesor); + const isNewPosesser = checkForNewPossesor(p, props.np.selection.possesor); const possesor: T.PossesorSelection = { np: p, - shrunken: (!isNewPosesser && props.np.possesor) ? props.np.possesor.shrunken : false, + shrunken: (!isNewPosesser && props.np.selection.possesor) ? props.np.selection.possesor.shrunken : false, }; onChange({ - ...props.np, - possesor, - }); - } - function handleToggleShrunken() { - if (!props.np || props.np.type === "pronoun" || !props.np.possesor || !props.phraseIsComplete) return; - onChange({ - ...props.np, - possesor: { - ...props.np.possesor, - shrunken: !props.np.possesor.shrunken, + type: "NP", + selection: { + ...props.np.selection, + possesor, }, }); } - const isDynamicComplement = props.np && props.np.type === "noun" && props.np.dynamicComplement; + function handleToggleShrunken() { + if (!props.np || props.np.selection.type === "pronoun" || !props.np.selection.possesor || !props.phraseIsComplete) return; + onChange({ + type: "NP", + selection: { + ...props.np.selection, + possesor: { + ...props.np.selection.possesor, + shrunken: !props.np.selection.possesor.shrunken, + }, + }, + }); + } + const isDynamicComplement = props.np && props.np.selection.type === "noun" && props.np.selection.dynamicComplement; const clearButton = (!props.cantClear && !props.is2ndPersonPicker && !isDynamicComplement) ? :
; - const possesiveLabel = props.np?.type === "participle" ? "Subj/Obj" : "Possesor"; + const possesiveLabel = props.np?.selection.type === "participle" ? "Subj/Obj" : "Possesor"; return <>
@@ -121,15 +130,15 @@ function NPPicker(props: {
)} } - {(props.np && props.np.type !== "pronoun" && (props.np.possesor || addingPoss)) &&
{possesiveLabel}:
- {(props.np.possesor && !props.isShrunk && props.phraseIsComplete) &&
- {!props.np.possesor.shrunken ? "🪄" : "👶"} + {(props.np.selection.possesor && !props.isShrunk && props.phraseIsComplete) &&
+ {!props.np.selection.possesor.shrunken ? "🪄" : "👶"}
}
{ setAddingPoss(false); @@ -143,7 +152,7 @@ function NPPicker(props: { onChange={handlePossesiveChange} counterPart={undefined} cantClear - np={props.np.possesor ? props.np.possesor.np : undefined} + np={props.np.selection.possesor ? props.np.selection.possesor.np : undefined} role="possesor" opts={props.opts} entryFeeder={props.entryFeeder} @@ -152,11 +161,11 @@ function NPPicker(props: { {(npType === "noun" || npType === "participle") && props.np && !addingPoss &&
setAddingPoss(true)}>+ {possesiveLabel}
} - {(npType === "pronoun" && props.np?.type === "pronoun") + {(npType === "pronoun" && props.np?.selection.type === "pronoun") ? onChange({ type: "NP", selection: p })} is2ndPersonPicker={props.is2ndPersonPicker} opts={props.opts} /> @@ -164,15 +173,15 @@ function NPPicker(props: { ? onChange(s ? { type: "NP", selection: s } : undefined)} opts={props.opts} /> : npType === "participle" ? onChange(s ? { type: "NP", selection: s } : undefined)} opts={props.opts} /> : null @@ -184,44 +193,53 @@ function NPPicker(props: { function ensureSingleShrink(old: T.NPSelection | undefined, s: T.NPSelection | undefined): T.NPSelection | undefined { if (!s) return s; function countShrinks(np: T.NPSelection): number { - if (np.type === "pronoun") return 0; - if (!np.possesor) return 0; - return (np.possesor.shrunken ? 1 : 0) + countShrinks(np.possesor.np); + if (np.selection.type === "pronoun") return 0; + if (!np.selection.possesor) return 0; + return (np.selection.possesor.shrunken ? 1 : 0) + countShrinks(np.selection.possesor.np); } function keepNewShrink(old: T.NPSelection, n: T.NPSelection): T.NPSelection { - if (n.type === "pronoun") return n; - if (old.type === "pronoun" || !n.possesor || !old.possesor) return n; - if (n.possesor.shrunken && !old.possesor.shrunken) { + if (n.selection.type === "pronoun") return n; + if (old.selection.type === "pronoun" || !n.selection.possesor || !old.selection.possesor) return n; + if (n.selection.possesor.shrunken && !old.selection.possesor.shrunken) { return { - ...n, - possesor: { - ...n.possesor, - np: removeShrinks(n.possesor.np), + type: "NP", + selection: { + ...n.selection, + possesor: { + ...n.selection.possesor, + np: removeShrinks(n.selection.possesor.np), + }, }, }; } return { - ...n, - possesor: { - shrunken: false, - np: keepNewShrink(old.possesor.np, n.possesor.np), + type: "NP", + selection:{ + ...n.selection, + possesor: { + shrunken: false, + np: keepNewShrink(old.selection.possesor.np, n.selection.possesor.np), + }, }, - } + }; } function removeShrinks(n: T.NPSelection): T.NPSelection { - if (n.type === "pronoun") return n; - if (!n.possesor) return n; + if (n.selection.type === "pronoun") return n; + if (!n.selection.possesor) return n; return { - ...n, - possesor: { - shrunken: false, - np: removeShrinks(n.possesor.np), + type: "NP", + selection: { + ...n.selection, + possesor: { + shrunken: false, + np: removeShrinks(n.selection.possesor.np), + }, }, }; } if (!old) return s; - if (s.type === "pronoun") return s; - if (!s.possesor) return s; + if (s.selection.type === "pronoun") return s; + if (!s.selection.possesor) return s; const numOfShrinks = countShrinks(s); if (numOfShrinks < 2) return s; return keepNewShrink(old, s); @@ -234,12 +252,12 @@ function checkForNewPossesor(n: T.NPSelection | undefined, old: T.PossesorSelect if (n.type !== old.np.type) { return true; } - if (n.type === "pronoun") return false; - if (n.type === "noun" && old.np.type === "noun") { - return n.entry.ts !== old.np.entry.ts; + if (n.selection.type === "pronoun") return false; + if (n.selection.type === "noun" && old.np.selection.type === "noun") { + return n.selection.entry.ts !== old.np.selection.entry.ts; } - if (n.type === "participle" && old.np.type === "participle") { - return n.verb.entry.ts !== old.np.verb.entry.ts; + if (n.selection.type === "participle" && old.np.selection.type === "participle") { + return n.selection.verb.entry.ts !== old.np.selection.verb.entry.ts; } return false; } diff --git a/src/components/vp-explorer/VPExplorer.tsx b/src/components/vp-explorer/VPExplorer.tsx index 184c9cd..3133679 100644 --- a/src/components/vp-explorer/VPExplorer.tsx +++ b/src/components/vp-explorer/VPExplorer.tsx @@ -44,7 +44,7 @@ function VPExplorer(props: { props.loaded ? props.loaded : savedVps => makeVPSelectionState(props.verb, savedVps), - "vpsState12", + "vpsState14", flashMessage, ); const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">( @@ -217,7 +217,7 @@ function VPExplorer(props: {
:
}
- {(!block || block.type === "adverb" || block.type === "sandwich") + {(!block || block.type === "AP") ? Unspoken 3rd Pers. Masc. Plur.
:
{stage === "blanks" &&
- {children.ps[0]} + {children.selection.ps[0]}
} -
{children.e}
+
{children.selection.e}
}
; } @@ -377,11 +377,11 @@ function getOptionFromResult(r: { function completeVPs(vps: T.VPSelectionState): T.VPSelectionComplete { const vpsSubj = getSubjectSelection(vps.blocks).selection; const vpsObj = getObjectSelection(vps.blocks).selection; - const oldSubj = vpsSubj?.type === "pronoun" - ? vpsSubj.person + const oldSubj = vpsSubj?.selection.type === "pronoun" + ? vpsSubj.selection.person : undefined; - const oldObj = (typeof vpsObj === "object" && vpsObj.type === "pronoun") - ? vpsObj.person + const oldObj = (typeof vpsObj === "object" && vpsObj.selection.type === "pronoun") + ? vpsObj.selection.person : undefined; const { subj, obj } = randomSubjObj( oldSubj === undefined @@ -400,19 +400,25 @@ function completeVPs(vps: T.VPSelectionState): T.VPSelectionComplete { ...vps, blocks: adjustObjectSelection( adjustSubjectSelection(vps.blocks, { - type: "pronoun", - distance: "far", - person: subj, + type: "NP", + selection: { + type: "pronoun", + distance: "far", + person: subj, + }, }), ( - (typeof vpsObj === "object" && !(vpsObj.type === "noun" && vpsObj.dynamicComplement)) + (typeof vpsObj === "object" && !(vpsObj.selection.type === "noun" && vpsObj.selection.dynamicComplement)) || vpsObj === undefined ) ? { - type: "pronoun", - distance: "far", - person: obj, + type: "NP", + selection: { + type: "pronoun", + distance: "far", + person: obj, + } } : vpsObj, ), @@ -426,30 +432,40 @@ function getRandomVPSelection(mix: MixType = "both") { const subject = getSubjectSelection(VPS.blocks).selection; const object = getObjectSelection(VPS.blocks).selection; const verb = VPS.verb; - const oldSubj = (subject.type === "pronoun") - ? subject.person + const oldSubj = (subject.selection.type === "pronoun") + ? subject.selection.person : undefined; - const oldObj = (typeof object === "object" && object.type === "pronoun") - ? object.person + const oldObj = (typeof object === "object" && object.selection.type === "pronoun") + ? object.selection.person : undefined; const { subj, obj } = randomSubjObj( oldSubj !== undefined ? { subj: oldSubj, obj: oldObj } : undefined ); - const randSubj: T.PronounSelection = subject?.type === "pronoun" ? { - ...subject, - person: subj, - } : { - type: "pronoun", - distance: "far", - person: subj, + const randSubj: T.NPSelection = { + type: "NP", + selection: ( + subject?.selection.type === "pronoun" ? { + ...subject.selection, + person: subj, + } : { + type: "pronoun", + distance: "far", + person: subj, + } + ), }; - const randObj: T.PronounSelection = typeof object === "object" && object.type === "pronoun" ? { - ...object, - person: obj, - } : { - type: "pronoun", - distance: "far", - person: obj, + const randObj: T.NPSelection = { + type: "NP", + selection: ( + typeof object === "object" && object.selection.type === "pronoun" ? { + ...object.selection, + person: obj, + } : { + type: "pronoun", + distance: "far", + person: obj, + } + ), }; // ensure that the verb selection is complete if (mix === "tenses") { @@ -466,7 +482,7 @@ function getRandomVPSelection(mix: MixType = "both") { blocks: possibleShuffleArray(adjustObjectSelection( adjustSubjectSelection(VPS.blocks, randSubj), ( - (typeof object === "object" && !(object.type === "noun" && object.dynamicComplement)) + (typeof object === "object" && !(object.selection.type === "noun" && object.selection.dynamicComplement)) || object === undefined ) diff --git a/src/components/vp-explorer/verb-selection.ts b/src/components/vp-explorer/verb-selection.ts index 18833fb..6995461 100644 --- a/src/components/vp-explorer/verb-selection.ts +++ b/src/components/vp-explorer/verb-selection.ts @@ -12,7 +12,7 @@ export function makeVPSelectionState( const info = getVerbInfo(verb.entry, verb.complement); const subject = (os?.verb.voice === "passive" && info.type === "dynamic compound") ? makeNounSelection(info.objComplement.entry as T.NounEntry, undefined, true) - : (os?.blocks ? getSubjectSelection(os.blocks) : undefined); + : (os?.blocks ? getSubjectSelection(os.blocks).selection : undefined); function getTransObjFromos() { const osObj = os ? getObjectSelection(os.blocks).selection : undefined; if ( @@ -20,7 +20,7 @@ export function makeVPSelectionState( osObj === "none" || typeof osObj === "number" || os.verb.isCompound === "dynamic" || - (osObj?.type === "noun" && osObj.dynamicComplement) + (osObj?.selection.type === "noun" && osObj.selection.dynamicComplement) ) return undefined; return osObj; } @@ -85,7 +85,7 @@ export function changeStatDyn(v: T.VPSelectionState, s: "dynamic" | "stative"): blocks: adjustObjectSelection( v.blocks, s === "dynamic" - ? makeNounSelection(info.dynamic.objComplement.entry as T.NounEntry, undefined, true) + ? { type: "NP", selection: makeNounSelection(info.dynamic.objComplement.entry as T.NounEntry, undefined, true) } : undefined, ), verb: { diff --git a/src/components/vp-explorer/vps-reducer.ts b/src/components/vp-explorer/vps-reducer.ts index 47316e7..26347e0 100644 --- a/src/components/vp-explorer/vps-reducer.ts +++ b/src/components/vp-explorer/vps-reducer.ts @@ -285,8 +285,8 @@ export function vpsReducer(vps: T.VPSelectionState, action: VpsReducerAction, se } function hasPronounConflict(subject: T.NPSelection | undefined, object: undefined | T.VerbObject): boolean { - const subjPronoun = (subject && subject.type === "pronoun") ? subject : undefined; - const objPronoun = (object && typeof object === "object" && object.type === "pronoun") ? object : undefined; + const subjPronoun = (subject && subject.selection.type === "pronoun") ? subject.selection : undefined; + const objPronoun = (object && typeof object === "object" && object.selection.type === "pronoun") ? object.selection : undefined; if (!subjPronoun || !objPronoun) return false; return isInvalidSubjObjCombo(subjPronoun.person, objPronoun.person); } \ No newline at end of file diff --git a/src/lib/np-tools.ts b/src/lib/np-tools.ts index cf70887..d1ad359 100644 --- a/src/lib/np-tools.ts +++ b/src/lib/np-tools.ts @@ -11,13 +11,13 @@ export function randomPerson(a?: { prev?: T.Person, counterPart?: T.VerbObject | if (!a) { return getRandPers(); } - if (a.counterPart !== undefined && typeof a.counterPart === "object" && a.counterPart.type === "pronoun") { + if (a.counterPart !== undefined && typeof a.counterPart === "object" && a.counterPart.selection.type === "pronoun") { // with counterpart pronoun let newP = 0; do { newP = getRandPers(); } while ( - isInvalidSubjObjCombo(a.counterPart.person, newP) + isInvalidSubjObjCombo(a.counterPart.selection.person, newP) || (newP === a.prev) ); diff --git a/src/lib/phrase-building/blocks-utils.ts b/src/lib/phrase-building/blocks-utils.ts index 1c2739f..e26fb56 100644 --- a/src/lib/phrase-building/blocks-utils.ts +++ b/src/lib/phrase-building/blocks-utils.ts @@ -56,23 +56,59 @@ export function makeAPBlock(): { key: number, block: undefined } { }; } -export function makeSubjectSelection(selection: T.SubjectSelection | T.NPSelection | undefined): T.SubjectSelection { - if (selection?.type === "subjectSelection") { +export function makeSubjectSelection(selection: T.SubjectSelection | T.NPSelection | T.NPSelection["selection"] | undefined): T.SubjectSelection { + if (!selection) { + return { + type: "subjectSelection", + selection: undefined, + }; + } + if (selection.type === "subjectSelection") { return selection; } + if (selection.type === "NP") { + return { + type: "subjectSelection", + selection, + }; + } return { type: "subjectSelection", - selection, + selection: { + type: "NP", + selection, + } }; } -export function makeObjectSelection(selection: T.ObjectSelection | T.ObjectNP | T.NPSelection | undefined): T.ObjectSelection { - if (selection && typeof selection === "object" && selection.type === "objectSelection") { +export function makeObjectSelection(selection: T.ObjectSelection | T.ObjectNP | T.NPSelection | T.NPSelection["selection"] | undefined): T.ObjectSelection { + if (!selection) { + return { + type: "objectSelection", + selection: undefined, + } + } + if (typeof selection !== "object") { + return { + type: "objectSelection", + selection, + }; + } + if (selection.type === "objectSelection") { return selection; } + if (selection.type === "NP") { + return { + type: "objectSelection", + selection, + }; + } return { type: "objectSelection", - selection: selection, + selection: { + type: "NP", + selection, + }, }; } diff --git a/src/lib/phrase-building/compile.ts b/src/lib/phrase-building/compile.ts index b58f67c..d434e34 100644 --- a/src/lib/phrase-building/compile.ts +++ b/src/lib/phrase-building/compile.ts @@ -125,7 +125,7 @@ export function getVPSegmentsAndKids(VP: T.VPRendered, form?: T.FormVersion): { if (typeof block.selection !== "object") return accum; return [ ...accum, - makeSegment(getPashtoFromRendered(block.selection, subject.person)), + makeSegment(getPashtoFromRendered(block.selection, subject.selection.person)), ] } return [ @@ -478,8 +478,8 @@ export function findPossesivesToShrinkInVP(VP: T.VPRendered, f: { }): T.Rendered[] { return VP.blocks.reduce((found, block) => { if (block.type === "subjectSelection") { - if (block.selection.role === "king" && f.removedKing) return found; - if (block.selection.role === "servant" && f.shrunkServant) return found; + if (block.selection.selection.role === "king" && f.removedKing) return found; + if (block.selection.selection.role === "servant" && f.shrunkServant) return found; return [ ...findPossesivesInNP(block.selection), ...found, @@ -487,19 +487,19 @@ export function findPossesivesToShrinkInVP(VP: T.VPRendered, f: { } if (block.type === "objectSelection") { if (typeof block.selection !== "object") return found; - if (block.selection.role === "king" && f.removedKing) return found; - if (block.selection.role === "servant" && f.shrunkServant) return found; + if (block.selection.selection.role === "king" && f.removedKing) return found; + if (block.selection.selection.role === "servant" && f.shrunkServant) return found; return [ ...findPossesivesInNP(block.selection), ...found, ]; } - if (block.type === "sandwich") { - if (block.inside.type === "pronoun") { + if (block.selection.type === "sandwich") { + if (block.selection.inside.selection.type === "pronoun") { return found; } return [ - ...findPossesivesInNP(block.inside), + ...findPossesivesInNP(block.selection.inside), ...found, ]; } @@ -510,18 +510,18 @@ export function findPossesivesToShrinkInVP(VP: T.VPRendered, f: { function findPossesivesInNP(NP: T.Rendered | T.ObjectNP | undefined): T.Rendered[] { if (NP === undefined) return []; if (typeof NP !== "object") return []; - if (!NP.possesor) return []; - if (NP.adjectives) { - const { adjectives, ...rest } = NP; + if (!NP.selection.possesor) return []; + if (NP.selection.adjectives) { + const { adjectives, ...rest } = NP.selection; return [ ...findPossesivesInAdjectives(adjectives), - ...findPossesivesInNP(rest), + ...findPossesivesInNP({ type: "NP", selection: rest }), ]; } - if (NP.possesor.shrunken) { - return [NP.possesor.np]; + if (NP.selection.possesor.shrunken) { + return [NP.selection.possesor.np]; } - return findPossesivesInNP(NP.possesor.np); + return findPossesivesInNP(NP.selection.possesor.np); } function findPossesivesInAdjectives(a: T.Rendered[]): T.Rendered[] { @@ -551,8 +551,8 @@ export function findPossesivesToShrinkInEP(EP: T.EPRendered): FoundNP[] { ...found, ]; } - if (block.type === "sandwich") { - const found: FoundNP[] = findPossesivesInNP(block.inside).map(np => ({ np, from: "AP" })); + if (block.selection.type === "sandwich") { + const found: FoundNP[] = findPossesivesInNP(block.selection.inside).map(np => ({ np, from: "AP" })); return [ ...accum, ...found, @@ -560,15 +560,15 @@ export function findPossesivesToShrinkInEP(EP: T.EPRendered): FoundNP[] { } return accum; }, [] as FoundNP[]); - const inPredicate: FoundNP[] = ((EP.predicate.type === "loc. adv.") + const inPredicate: FoundNP[] = ((EP.predicate.selection.type === "loc. adv.") ? [] - : (EP.predicate.type === "adjective") - ? findPossesivesInAdjective(EP.predicate) - : EP.predicate.type === "sandwich" - ? findPossesivesInNP(EP.predicate.inside) - : EP.predicate.type === "pronoun" + : (EP.predicate.selection.type === "adjective") + ? findPossesivesInAdjective(EP.predicate.selection) + : EP.predicate.selection.type === "sandwich" + ? findPossesivesInNP(EP.predicate.selection.inside) + : EP.predicate.selection.type === "pronoun" ? [] - : findPossesivesInNP(EP.predicate)).map(np => ({ np, from: "predicate" })); + : findPossesivesInNP({ type: "NP", selection: EP.predicate.selection })).map(np => ({ np, from: "predicate" })); return [ ...inBlocks, ...inPredicate, @@ -587,11 +587,11 @@ export function findPossesivesToShrinkInEP(EP: T.EPRendered): FoundNP[] { export function shrinkNP(np: T.Rendered): Segment { function getFirstSecThird(): 1 | 2 | 3 { - if ([0, 1, 6, 7].includes(np.person)) return 1; - if ([2, 3, 8, 9].includes(np.person)) return 2; + if ([0, 1, 6, 7].includes(np.selection.person)) return 1; + if ([2, 3, 8, 9].includes(np.selection.person)) return 2; return 3; } - const [row, col] = getVerbBlockPosFromPerson(np.person); + const [row, col] = getVerbBlockPosFromPerson(np.selection.person); return makeSegment(pronouns.mini[row][col], ["isKid", getFirstSecThird()]); } diff --git a/src/lib/phrase-building/np-tools.ts b/src/lib/phrase-building/np-tools.ts index 3a903d2..7735c2a 100644 --- a/src/lib/phrase-building/np-tools.ts +++ b/src/lib/phrase-building/np-tools.ts @@ -5,15 +5,15 @@ import { import * as T from "../../types"; import { concatPsString } from "../p-text-helpers"; -function getBaseAndAdjectives(np: T.Rendered): T.PsString[] { - if (np.type === "sandwich") { - return getSandwichPsBaseAndAdjectives(np); +function getBaseAndAdjectives({ selection }: T.Rendered): T.PsString[] { + if (selection.type === "sandwich") { + return getSandwichPsBaseAndAdjectives(selection); } - const adjs = "adjectives" in np && np.adjectives; + const adjs = "adjectives" in selection && selection.adjectives; if (!adjs) { - return np.ps; + return selection.ps; } - return np.ps.map(p => ( + return selection.ps.map(p => ( concatPsString( adjs.reduce((accum, curr) => ( // TODO: with variations of adjs? @@ -27,10 +27,10 @@ function getBaseAndAdjectives(np: T.Rendered>): T.PsString[] { const insideBase = getBaseAndAdjectives(s.inside); - const willContractWithPronoun = s.before && s.before.p === "د" && s.inside.type === "pronoun" - && (isFirstPerson(s.inside.person) || isSecondPerson(s.inside.person)) - const contracted = (willContractWithPronoun && s.inside.type === "pronoun") - ? contractPronoun(s.inside) + const willContractWithPronoun = s.before && s.before.p === "د" && s.inside.selection.type === "pronoun" + && (isFirstPerson(s.inside.selection.person) || isSecondPerson(s.inside.selection.person)) + const contracted = (willContractWithPronoun && s.inside.selection.type === "pronoun") + ? contractPronoun(s.inside.selection) : undefined return insideBase.map((inside) => ( concatPsString( @@ -52,54 +52,63 @@ function contractPronoun(n: T.Rendered): T.PsString | undefi } function trimOffShrunkenPossesive(p: T.Rendered): T.Rendered { - if (!("possesor" in p)) { + if (!("possesor" in p.selection)) { return p; } - if (!p.possesor) { + if (!p.selection.possesor) { return p; } - if (p.possesor.shrunken) { + if (p.selection.possesor.shrunken) { return { - ...p, - possesor: undefined, + type: "NP", + selection: { + ...p.selection, + possesor: undefined, + }, }; } return { - ...p, - possesor: { - ...p.possesor, - np: trimOffShrunkenPossesive(p.possesor.np), - } - } + type: "NP", + selection: { + ...p.selection, + possesor: { + ...p.selection.possesor, + np: trimOffShrunkenPossesive(p.selection.possesor.np), + }, + }, + }; } export function getPashtoFromRendered(b: T.Rendered | T.Rendered | T.Rendered, subjectsPerson: false | T.Person): T.PsString[] { const base = getBaseAndAdjectives(b); - if (b.type === "loc. adv." || b.type === "adverb") { + if (b.selection.type === "loc. adv." || b.selection.type === "adverb") { return base; } - if (b.type === "adjective") { - if (!b.sandwich) { + if (b.selection.type === "adjective") { + if (!b.selection.sandwich) { return base } - const sandwichPs = getPashtoFromRendered(b.sandwich, false); + const sandwichPs = getPashtoFromRendered({ type: "AP", selection: b.selection.sandwich }, false); return base.flatMap(p => ( sandwichPs.flatMap(s => ( concatPsString(s, " ", p) )) )); } - const trimmed = b.type === "sandwich" ? { - ...b, - inside: trimOffShrunkenPossesive(b.inside), - } : trimOffShrunkenPossesive(b); - if (trimmed.type === "sandwich") { - return trimmed.inside.possesor - ? addPossesor(trimmed.inside.possesor.np, base, subjectsPerson) + const trimmed = b.selection.type === "sandwich" ? { + type: b.type, + selection: { + ...b.selection, + inside: trimOffShrunkenPossesive(b.selection.inside), + }, + } : trimOffShrunkenPossesive({ type: "NP", selection: b.selection }); + if (trimmed.selection.type === "sandwich") { + return trimmed.selection.inside.selection.possesor + ? addPossesor(trimmed.selection.inside.selection.possesor.np, base, subjectsPerson) : base; } - if (trimmed.possesor) { - return addPossesor(trimmed.possesor.np, base, subjectsPerson); + if (trimmed.selection.possesor) { + return addPossesor(trimmed.selection.possesor.np, base, subjectsPerson); } return base; } @@ -114,19 +123,19 @@ function addPossesor(owner: T.Rendered, existing: T.PsString[], s } const wPossesor = existing.flatMap(ps => ( getBaseAndAdjectives(owner).map(v => ( - (owner.type === "pronoun" && subjectsPerson !== false && willBeReflexive(subjectsPerson, owner.person)) + (owner.selection.type === "pronoun" && subjectsPerson !== false && willBeReflexive(subjectsPerson, owner.selection.person)) ? concatPsString({ p: "خپل", f: "khpul" }, " ", ps) - : (owner.type === "pronoun" && isFirstPerson(owner.person)) + : (owner.selection.type === "pronoun" && isFirstPerson(owner.selection.person)) ? concatPsString({ p: "ز", f: "z" }, v, " ", ps) - : (owner.type === "pronoun" && isSecondPerson(owner.person)) + : (owner.selection.type === "pronoun" && isSecondPerson(owner.selection.person)) ? concatPsString({ p: "س", f: "s" }, v, " ", ps) : concatPsString({ p: "د", f: "du" }, " ", v, " ", ps) )) )); - if (!owner.possesor) { + if (!owner.selection.possesor) { return wPossesor; } - return addPossesor(owner.possesor.np, wPossesor, subjectsPerson); + return addPossesor(owner.selection.possesor.np, wPossesor, subjectsPerson); } function addArticlesAndAdjs(np: T.Rendered): string | undefined { @@ -156,10 +165,10 @@ function addPossesors(possesor: T.Rendered | undefined, base: str } if (!base) return undefined; if (!possesor) return base; - if (possesor.type === "pronoun") { + if (possesor.selection.type === "pronoun") { return type === "noun" - ? `${pronounPossEng(possesor.person)} ${removeArticles(base)}` - : `(${pronounPossEng(possesor.person)}) ${removeArticles(base)} (${possesor.e})` + ? `${pronounPossEng(possesor.selection.person)} ${removeArticles(base)}` + : `(${pronounPossEng(possesor.selection.person)}) ${removeArticles(base)} (${possesor.selection.e})` } const possesorE = getEnglishFromRendered(possesor); if (!possesorE) return undefined; @@ -191,23 +200,23 @@ function pronounPossEng(p: T.Person): string { } export function getEnglishFromRendered(r: T.Rendered): string | undefined { - if (r.type === "sandwich") { - return getEnglishFromRenderedSandwich(r); + if (r.selection.type === "sandwich") { + return getEnglishFromRenderedSandwich(r.selection); } - if (!r.e) return undefined; - if (r.type === "loc. adv." || r.type === "adverb") { - return r.e; + if (!r.selection.e) return undefined; + if (r.selection.type === "loc. adv." || r.selection.type === "adverb") { + return r.selection.e; } - if (r.type === "adjective") { - return getEnglishFromRenderedAdjective(r); + if (r.selection.type === "adjective") { + return getEnglishFromRenderedAdjective(r.selection); } - if (r.type === "pronoun") { - return r.e; + if (r.selection.type === "pronoun") { + return r.selection.e; } - if (r.type === "participle") { - return addPossesors(r.possesor?.np, r.e, r.type); + if (r.selection.type === "participle") { + return addPossesors(r.selection.possesor?.np, r.selection.e, r.selection.type); } - return addPossesors(r.possesor?.np, addArticlesAndAdjs(r), r.type); + return addPossesors(r.selection.possesor?.np, addArticlesAndAdjs(r.selection), r.selection.type); } function getEnglishFromRenderedSandwich(r: T.Rendered>): string | undefined { diff --git a/src/lib/phrase-building/render-ap.ts b/src/lib/phrase-building/render-ap.ts index 14862ce..e10df26 100644 --- a/src/lib/phrase-building/render-ap.ts +++ b/src/lib/phrase-building/render-ap.ts @@ -2,11 +2,15 @@ import * as T from "../../types"; import { renderAdverbSelection } from "./render-ep"; import { renderSandwich } from "./render-sandwich"; -export function renderAPSelection(ap: T.APSelection): T.Rendered { - if (ap.type === "sandwich") { - return renderSandwich(ap); +export function renderAPSelection({ selection }: T.APSelection): T.Rendered { + if (selection.type === "sandwich") { + return { + type: "AP", + selection: renderSandwich(selection), + }; } - // if (ap.type === "adverb") { - return renderAdverbSelection(ap); - // } + return { + type: "AP", + selection: renderAdverbSelection(selection), + }; } \ No newline at end of file diff --git a/src/lib/phrase-building/render-ep.ts b/src/lib/phrase-building/render-ep.ts index 8d7533f..b78e768 100644 --- a/src/lib/phrase-building/render-ep.ts +++ b/src/lib/phrase-building/render-ep.ts @@ -15,7 +15,7 @@ import { EPSBlocksAreComplete, getSubjectSelection } from "./blocks-utils"; export function renderEP(EP: T.EPSelectionComplete): T.EPRendered { const subject = getSubjectSelection(EP.blocks).selection; - const king = (subject.type === "pronoun") + const king = (subject.selection.type === "pronoun") ? "subject" : EP.predicate.type === "NP" ? "predicate" @@ -27,8 +27,8 @@ export function renderEP(EP: T.EPSelectionComplete): T.EPRendered { ? getPersonFromNP(EP.predicate.selection) : getPersonFromNP(subject); const kingIsParticiple = king === "subject" - ? (subject.type === "participle") - : (EP.predicate.type === "NP" && EP.predicate.selection.type === "participle"); + ? (subject.selection.type === "participle") + : (EP.predicate.type === "NP" && EP.predicate.selection.selection.type === "participle"); return { type: "EPRendered", king: EP.predicate.type === "Complement" ? "subject" : "predicate", @@ -60,11 +60,19 @@ export function getEquativeForm(tense: T.EquativeTense): { hasBa: boolean, form: function renderEPSBlocks(blocks: T.EPSBlockComplete[], king: "subject" | "predicate"): (T.Rendered | T.Rendered)[] { return blocks.map(({ block }): (T.Rendered | T.Rendered) => { - if (block.type === "adverb") { - return renderAdverbSelection(block); - } - if (block.type === "sandwich") { - return renderSandwich(block); + if (block.type === "AP") { + if (block.selection.type === "adverb") { + return { + type: "AP", + selection: renderAdverbSelection(block.selection), + }; + } + // if (block.selection.type === "sandwich") { + return { + type: "AP", + selection: renderSandwich(block.selection), + }; + // } } return { type: "subjectSelection", @@ -98,26 +106,35 @@ export function renderAdverbSelection(a: T.AdverbSelection): T.Rendered { - if (s.type === "sandwich") { - return renderSandwich(s); + if (s.selection.type === "sandwich") { + return { + type: "EQComp", + selection: renderSandwich(s.selection), + }; } - const e = getEnglishWord(s.entry); + const e = getEnglishWord(s.selection.entry); if (!e || typeof e !== "string") { throw new Error("error getting english for compliment"); } - if (isLocativeAdverbEntry(s.entry)) { + if (isLocativeAdverbEntry(s.selection.entry)) { return { - type: "loc. adv.", - entry: s.entry, - ps: [psStringFromEntry(s.entry)], - e, - inflected: false, - person, - role: "none", + type: "EQComp", + selection: { + type: "loc. adv.", + entry: s.selection.entry, + ps: [psStringFromEntry(s.selection.entry)], + e, + inflected: false, + person, + role: "none", + }, }; } - if (s.type === "adjective") { - return renderAdjectiveSelection(s, person, false, "none") + if (s.selection.type === "adjective") { + return { + type: "EQComp", + selection: renderAdjectiveSelection(s.selection, person, false, "none"), + }; } throw new Error("invalid EqCompSelection"); } diff --git a/src/lib/phrase-building/render-np.ts b/src/lib/phrase-building/render-np.ts index 7a157b5..e41cbd3 100644 --- a/src/lib/phrase-building/render-np.ts +++ b/src/lib/phrase-building/render-np.ts @@ -25,14 +25,23 @@ export function renderNPSelection(NP: T.NPSelection | T.ObjectNP, inflected: boo } return NP; } - if (NP.type === "noun") { - return renderNounSelection(NP, inflected, soRole); + if (NP.selection.type === "noun") { + return { + type: "NP", + selection: renderNounSelection(NP.selection, inflected, soRole), + }; } - if (NP.type === "pronoun") { - return renderPronounSelection(NP, inflected, inflectEnglish, soRole); + if (NP.selection.type === "pronoun") { + return { + type: "NP", + selection: renderPronounSelection(NP.selection, inflected, inflectEnglish, soRole), + }; } - if (NP.type === "participle") { - return renderParticipleSelection(NP, inflected, soRole) + if (NP.selection.type === "participle") { + return { + type: "NP", + selection: renderParticipleSelection(NP.selection, inflected, soRole), + }; } throw new Error("unknown NP type"); }; @@ -91,10 +100,10 @@ function renderParticipleSelection(p: T.ParticipleSelection, inflected: boolean, function renderPossesor(possesor: T.PossesorSelection | undefined, possesorRole: "servant" | "king" | "none" | "subj/obj"): T.RenderedPossesorSelection | undefined { if (!possesor) return undefined; - const isSingUnisexAnim5PatternNoun = (possesor.np.type === "noun" - && possesor.np.number === "singular" - && isAnimNounEntry(possesor.np.entry) - && isPattern5Entry(possesor.np.entry) + const isSingUnisexAnim5PatternNoun = (possesor.np.selection.type === "noun" + && possesor.np.selection.number === "singular" + && isAnimNounEntry(possesor.np.selection.entry) + && isPattern5Entry(possesor.np.selection.entry) ); return { shrunken: possesor.shrunken, diff --git a/src/lib/phrase-building/render-sandwich.ts b/src/lib/phrase-building/render-sandwich.ts index b67dac2..9e65b28 100644 --- a/src/lib/phrase-building/render-sandwich.ts +++ b/src/lib/phrase-building/render-sandwich.ts @@ -3,9 +3,9 @@ import { isPattern1Entry, isPattern5Entry, isAnimNounEntry } from "../type-predi import { renderNPSelection } from "./render-np"; export function renderSandwich(s: T.SandwichSelection): T.Rendered> { - const inflectInside = (isLocationSandwich(s) && s.inside.type === "noun" && isPattern1Entry(s.inside.entry) && s.inside.number === "singular") + const inflectInside = (isLocationSandwich(s) && s.inside.selection.type === "noun" && isPattern1Entry(s.inside.selection.entry) && s.inside.selection.number === "singular") ? false - : (s.inside.type === "noun" && isPattern5Entry(s.inside.entry) && isAnimNounEntry(s.inside.entry)) + : (s.inside.selection.type === "noun" && isPattern5Entry(s.inside.selection.entry) && isAnimNounEntry(s.inside.selection.entry)) ? false : true; return { diff --git a/src/lib/phrase-building/render-vp.ts b/src/lib/phrase-building/render-vp.ts index 16ba142..34463f6 100644 --- a/src/lib/phrase-building/render-vp.ts +++ b/src/lib/phrase-building/render-vp.ts @@ -261,8 +261,8 @@ export function getKingAndServant(isPast: boolean, isTransitive: boolean): function isFirstOrSecondPersPronoun(o: "none" | T.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); + if (o.selection.type !== "pronoun") return false; + return [0,1,2,3,6,7,8,9].includes(o.selection.person); } function isPerfective(t: T.Tense): boolean { @@ -283,11 +283,11 @@ function isPerfective(t: T.Tense): boolean { } function isMascSingAnimatePattern4(np: T.NPSelection): boolean { - if (np.type !== "noun") { + if (np.selection.type !== "noun") { return false; } - return isPattern4Entry(np.entry) - && np.entry.c.includes("anim.") - && (np.number === "singular") - && (np.gender === "masc"); + return isPattern4Entry(np.selection.entry) + && np.selection.entry.c.includes("anim.") + && (np.selection.number === "singular") + && (np.selection.gender === "masc"); } diff --git a/src/lib/phrase-building/vp-tools.ts b/src/lib/phrase-building/vp-tools.ts index 2d5c0fe..24877ef 100644 --- a/src/lib/phrase-building/vp-tools.ts +++ b/src/lib/phrase-building/vp-tools.ts @@ -125,15 +125,15 @@ export function getPersonFromNP(np: T.NPSelection | T.ObjectNP): T.Person | unde return undefined; } if (typeof np === "number") return np; - if (np.type === "participle") { + if (np.selection.type === "participle") { return T.Person.ThirdPlurMale; } - if (np.type === "pronoun") { - return np.person; + if (np.selection.type === "pronoun") { + return np.selection.person; } - return np.number === "plural" - ? (np.gender === "masc" ? T.Person.ThirdPlurMale : T.Person.ThirdPlurFemale) - : (np.gender === "masc" ? T.Person.ThirdSingMale : T.Person.ThirdSingFemale); + return np.selection.number === "plural" + ? (np.selection.gender === "masc" ? T.Person.ThirdPlurMale : T.Person.ThirdPlurFemale) + : (np.selection.gender === "masc" ? T.Person.ThirdSingMale : T.Person.ThirdSingFemale); } export function removeBa(ps: T.PsString): T.PsString { @@ -258,14 +258,17 @@ export function isThirdPerson(p: T.Person): boolean { export function ensure2ndPersSubjPronounAndNoConflict(vps: T.VPSelectionState): T.VPSelectionState { const subject = getSubjectSelection(vps.blocks).selection; const object = getObjectSelection(vps.blocks).selection; - const subjIs2ndPerson = (subject?.type === "pronoun") && isSecondPerson(subject.person); + const subjIs2ndPerson = (subject?.selection.type === "pronoun") && isSecondPerson(subject.selection.person); const objIs2ndPerson = (typeof object === "object") - && (object.type === "pronoun") - && isSecondPerson(object.person); - const default2ndPersSubject: T.PronounSelection = { - type: "pronoun", - distance: "far", - person: T.Person.SecondSingMale, + && (object.selection.type === "pronoun") + && isSecondPerson(object.selection.person); + const default2ndPersSubject: T.NPSelection = { + type: "NP", + selection: { + type: "pronoun", + distance: "far", + person: T.Person.SecondSingMale, + }, }; function getNon2ndPersPronoun() { let newObjPerson: T.Person; @@ -278,22 +281,25 @@ export function ensure2ndPersSubjPronounAndNoConflict(vps: T.VPSelectionState): return vps; } if (subjIs2ndPerson && objIs2ndPerson) { - if (typeof object !== "object" || object.type !== "pronoun") { + if (typeof object !== "object" || object.selection.type !== "pronoun") { return vps; } return { ...vps, blocks: adjustObjectSelection(vps.blocks, { - ...object, - person: getNon2ndPersPronoun(), + type: "NP", + selection: { + ...object.selection, + person: getNon2ndPersPronoun(), + }, }), }; } if (!subjIs2ndPerson && objIs2ndPerson) { - if (typeof object !== "object" || object.type !== "pronoun") { + if (typeof object !== "object" || object.selection.type !== "pronoun") { return { ...vps, - blocks: adjustSubjectSelection(vps.blocks, default2ndPersSubject), + blocks: adjustSubjectSelection(vps.blocks, default2ndPersSubject) }; } return { @@ -301,8 +307,11 @@ export function ensure2ndPersSubjPronounAndNoConflict(vps: T.VPSelectionState): blocks: adjustObjectSelection( adjustSubjectSelection(vps.blocks, default2ndPersSubject), { - ...object, - person: getNon2ndPersPronoun(), + type: "NP", + selection: { + ...object.selection, + person: getNon2ndPersPronoun(), + }, }, ), }; diff --git a/src/types.ts b/src/types.ts index e9037d8..363321b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -610,9 +610,15 @@ export type VerbObject = // or intransitive "none" ObjectNP; -export type NPSelection = NounSelection | PronounSelection | ParticipleSelection; +export type NPSelection = { + type: "NP", + selection: NounSelection | PronounSelection | ParticipleSelection, +}; -export type APSelection = AdverbSelection | SandwichSelection; +export type APSelection = { + type: "AP", + selection: AdverbSelection | SandwichSelection, +}; export type NPType = "noun" | "pronoun" | "participle"; @@ -679,7 +685,35 @@ export type RenderedPossesorSelection = { shrunken: boolean, }; -export type Rendered | APSelection | SubjectSelectionComplete | ObjectSelectionComplete> = T extends SandwichSelection +export type Rendered< + T extends + | NPSelection + | NPSelection["selection"] + | APSelection + | APSelection["selection"] + | EqCompSelection + | EqCompSelection["selection"] + | SubjectSelectionComplete + | ObjectSelectionComplete + | AdjectiveSelection + | SandwichSelection +> = + T extends NPSelection + ? { + type: "NP", + selection: Rendered + } + : T extends APSelection + ? { + type: "AP", + selection: Rendered + } + : T extends EqCompSelection + ? { + type: "EQComp", + selection: Rendered + } + : T extends SandwichSelection ? Omit, "inside"> & { inside: Rendered, } @@ -727,7 +761,6 @@ export type Rendered, }, }; -// TODO: recursive changing this down into the possesor etc. export type EPSelectionState = { blocks: EPSBlock[], @@ -772,7 +805,10 @@ export type EPSelectionComplete = Omit }; export type EqCompType = "adjective" | "loc. adv." | "sandwich" -export type EqCompSelection = AdjectiveSelection | LocativeAdverbSelection | SandwichSelection; +export type EqCompSelection = { + type: "EQComp", + selection: AdjectiveSelection | LocativeAdverbSelection | SandwichSelection, +}; export type SandwichSelection = S & { inside: NPSelection,