better format with NP and AP selections etc

This commit is contained in:
lingdocs 2022-06-01 19:04:09 -05:00
parent bb0e2daf0d
commit 4e5075ca19
22 changed files with 452 additions and 292 deletions

View File

@ -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",

View File

@ -16,11 +16,11 @@ function APPicker(props: {
onRemove: () => void,
}) {
const [type, setType] = useState<APType | undefined>(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" ?
<AdverbPicker
entryFeeder={props.entryFeeder.adverbs}
adjective={props.AP?.type === "adverb" ? props.AP : undefined}
adjective={props.AP?.selection.type === "adverb" ? props.AP.selection : undefined}
opts={props.opts}
onChange={props.onChange}
onChange={(a) => props.onChange(a ? { type: "AP", selection: a } : undefined)}
/>
: type === "sandwich" ?
<SandwichPicker
onChange={props.onChange}
onChange={(a) => 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}

View File

@ -49,10 +49,10 @@ function EPDisplay({ eps, opts, setOmitSubject }: {
{result.e && <div className="text-muted mt-3">
{result.e.map((e, i) => <div key={i}>{e}</div>)}
</div>}
{EP.predicate.selection.type === "participle" && <div style={{ maxWidth: "6 00px", margin: "0 auto" }} className="alert alert-warning mt-3 pt-4">
<p> NOTE: This means that the subject {renderedSubject.e ? `(${renderedSubject.e})` : ""} is <strong>the action/idea</strong> of
{EP.predicate.selection.selection.type === "participle" && <div style={{ maxWidth: "6 00px", margin: "0 auto" }} className="alert alert-warning mt-3 pt-4">
<p> NOTE: This means that the subject {renderedSubject.selection.e ? `(${renderedSubject.selection.e})` : ""} is <strong>the action/idea</strong> of
{` `}
"{rendered.predicate.e ? rendered.predicate.e : "the particple"}".</p>
"{rendered.predicate.selection.e ? rendered.predicate.selection.e : "the particple"}".</p>
<p>It <strong>does not</strong> mean that the subject is doing the action, which is what the transaltion sounds like in English.</p>
</div>}
</div>

View File

@ -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<string | undefined>(undefined);
const [showClipped, setShowClipped] = useState<string>("");
const parent = useRef<HTMLDivElement>(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"

View File

@ -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,

View File

@ -15,11 +15,11 @@ function EqCompPicker(props: {
entryFeeder: T.EntryFeeder,
}) {
const [compType, setCompType] = useState<T.EqCompType | undefined>(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" ?
<AdjectivePicker
entryFeeder={props.entryFeeder}
adjective={props.comp?.type === "adjective" ? props.comp : undefined}
adjective={props.comp?.selection.type === "adjective" ? props.comp.selection : undefined}
opts={props.opts}
onChange={props.onChange}
onChange={(a) => props.onChange(a ? { type: "EQComp", selection: a } : undefined)}
phraseIsComplete={props.phraseIsComplete}
/>
: compType === "loc. adv."
? <LocativeAdverbPicker
entryFeeder={props.entryFeeder.locativeAdverbs}
adjective={props.comp?.type === "loc. adv." ? props.comp : undefined}
adjective={props.comp?.selection.type === "loc. adv." ? props.comp.selection : undefined}
opts={props.opts}
onChange={props.onChange}
onChange={(a) => props.onChange(a ? { type: "EQComp", selection: a } : undefined)}
/>
: compType === "sandwich"
? <SandwichPicker
onChange={props.onChange}
onChange={(a) => 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

View File

@ -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<boolean>(false);
const [npType, setNpType] = useState<T.NPType | undefined>(props.np ? props.np.type : undefined);
const [npType, setNpType] = useState<T.NPType | undefined>(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)
? <button className="btn btn-sm btn-light mb-2" onClick={handleClear}>X</button>
: <div></div>;
const possesiveLabel = props.np?.type === "participle" ? "Subj/Obj" : "Possesor";
const possesiveLabel = props.np?.selection.type === "participle" ? "Subj/Obj" : "Possesor";
return <>
<div className="d-flex flex-row justify-content-between">
<div></div>
@ -121,15 +130,15 @@ function NPPicker(props: {
</button>
</div>)}
</div>}
{(props.np && props.np.type !== "pronoun" && (props.np.possesor || addingPoss)) && <div className="mb-3" style={{
{(props.np && props.np.selection.type !== "pronoun" && (props.np.selection.possesor || addingPoss)) && <div className="mb-3" style={{
paddingLeft: "0.65rem",
borderLeft: "2px solid grey",
background: (props.np.possesor?.shrunken && !props.isShrunk) ? shrunkenBackground : "inherit",
background: (props.np.selection.possesor?.shrunken && !props.isShrunk) ? shrunkenBackground : "inherit",
}}>
<div className="d-flex flex-row text-muted mb-2">
<div>{possesiveLabel}:</div>
{(props.np.possesor && !props.isShrunk && props.phraseIsComplete) && <div className="clickable ml-3 mr-2" onClick={handleToggleShrunken}>
{!props.np.possesor.shrunken ? "🪄" : "👶"}
{(props.np.selection.possesor && !props.isShrunk && props.phraseIsComplete) && <div className="clickable ml-3 mr-2" onClick={handleToggleShrunken}>
{!props.np.selection.possesor.shrunken ? "🪄" : "👶"}
</div>}
<div className="clickable ml-2" onClick={() => {
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 && <div>
<span className="clickable text-muted" onClick={() => setAddingPoss(true)}>+ {possesiveLabel}</span>
</div>}
{(npType === "pronoun" && props.np?.type === "pronoun")
{(npType === "pronoun" && props.np?.selection.type === "pronoun")
? <PronounPicker
role={props.role}
pronoun={props.np}
onChange={onChange}
pronoun={props.np.selection}
onChange={(p) => onChange({ type: "NP", selection: p })}
is2ndPersonPicker={props.is2ndPersonPicker}
opts={props.opts}
/>
@ -164,15 +173,15 @@ function NPPicker(props: {
? <NounPicker
phraseIsComplete={props.phraseIsComplete}
entryFeeder={props.entryFeeder}
noun={(props.np && props.np.type === "noun") ? props.np : undefined}
onChange={onChange}
noun={(props.np && props.np.selection.type === "noun") ? props.np.selection : undefined}
onChange={(s) => onChange(s ? { type: "NP", selection: s } : undefined)}
opts={props.opts}
/>
: npType === "participle"
? <ParticiplePicker
entryFeeder={props.entryFeeder.verbs}
participle={(props.np && props.np.type === "participle") ? props.np : undefined}
onChange={onChange}
participle={(props.np && props.np.selection.type === "participle") ? props.np.selection : undefined}
onChange={(s) => 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;
}

View File

@ -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: {
<i className="fas fa-chevron-right" />
</div> : <div/>}
</div>
{(!block || block.type === "adverb" || block.type === "sandwich")
{(!block || block.type === "AP")
? <APPicker
phraseIsComplete={phraseIsComplete}
heading="AP"

View File

@ -269,9 +269,9 @@ function QuizNPDisplay({ children, stage, opts }: {
? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div>
: <div className="text-centered" style={{ fontSize: "large" }}>
{stage === "blanks" && <div>
<InlinePs opts={opts}>{children.ps[0]}</InlinePs>
<InlinePs opts={opts}>{children.selection.ps[0]}</InlinePs>
</div>}
<div>{children.e}</div>
<div>{children.selection.e}</div>
</div>}
</div>;
}
@ -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
)

View File

@ -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: {

View File

@ -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);
}

View File

@ -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)
);

View File

@ -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,
},
};
}

View File

@ -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<T.NPSelection>[] {
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.NPSelection> | T.ObjectNP | undefined): T.Rendered<T.NPSelection>[] {
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.AdjectiveSelection>[]): T.Rendered<T.NPSelection>[] {
@ -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<T.NPSelection>): 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()]);
}

View File

@ -5,15 +5,15 @@ import {
import * as T from "../../types";
import { concatPsString } from "../p-text-helpers";
function getBaseAndAdjectives(np: T.Rendered<T.NPSelection | T.EqCompSelection | T.APSelection>): T.PsString[] {
if (np.type === "sandwich") {
return getSandwichPsBaseAndAdjectives(np);
function getBaseAndAdjectives({ selection }: T.Rendered<T.NPSelection | T.EqCompSelection | T.APSelection>): 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.NPSelection | T.EqCompSelection |
function getSandwichPsBaseAndAdjectives(s: T.Rendered<T.SandwichSelection<T.Sandwich>>): 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.PronounSelection>): T.PsString | undefi
}
function trimOffShrunkenPossesive(p: T.Rendered<T.NPSelection>): T.Rendered<T.NPSelection> {
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.NPSelection> | T.Rendered<T.EqCompSelection> | T.Rendered<T.APSelection>, 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<T.NPSelection>, 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<T.NounSelection>): string | undefined {
@ -156,10 +165,10 @@ function addPossesors(possesor: T.Rendered<T.NPSelection> | 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<T.NPSelection | T.EqCompSelection | T.APSelection>): 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<T.SandwichSelection<T.Sandwich>>): string | undefined {

View File

@ -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<T.APSelection> {
if (ap.type === "sandwich") {
return renderSandwich(ap);
export function renderAPSelection({ selection }: T.APSelection): T.Rendered<T.APSelection> {
if (selection.type === "sandwich") {
return {
type: "AP",
selection: renderSandwich(selection),
};
}
// if (ap.type === "adverb") {
return renderAdverbSelection(ap);
// }
return {
type: "AP",
selection: renderAdverbSelection(selection),
};
}

View File

@ -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.SubjectSelectionComplete> | T.Rendered<T.APSelection>)[] {
return blocks.map(({ block }): (T.Rendered<T.SubjectSelectionComplete> | T.Rendered<T.APSelection>) => {
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<T.Adverb
}
function renderEqCompSelection(s: T.EqCompSelection, person: T.Person): T.Rendered<T.EqCompSelection> {
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");
}

View File

@ -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,

View File

@ -3,9 +3,9 @@ import { isPattern1Entry, isPattern5Entry, isAnimNounEntry } from "../type-predi
import { renderNPSelection } from "./render-np";
export function renderSandwich(s: T.SandwichSelection<T.Sandwich>): T.Rendered<T.SandwichSelection<T.Sandwich>> {
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 {

View File

@ -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");
}

View File

@ -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(),
},
},
),
};

View File

@ -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<Sandwich>;
export type APSelection = {
type: "AP",
selection: AdverbSelection | SandwichSelection<Sandwich>,
};
export type NPType = "noun" | "pronoun" | "participle";
@ -679,7 +685,35 @@ export type RenderedPossesorSelection = {
shrunken: boolean,
};
export type Rendered<T extends NPSelection | EqCompSelection | AdjectiveSelection | SandwichSelection<Sandwich> | APSelection | SubjectSelectionComplete | ObjectSelectionComplete> = T extends SandwichSelection<Sandwich>
export type Rendered<
T extends
| NPSelection
| NPSelection["selection"]
| APSelection
| APSelection["selection"]
| EqCompSelection
| EqCompSelection["selection"]
| SubjectSelectionComplete
| ObjectSelectionComplete
| AdjectiveSelection
| SandwichSelection<Sandwich>
> =
T extends NPSelection
? {
type: "NP",
selection: Rendered<NPSelection["selection"]>
}
: T extends APSelection
? {
type: "AP",
selection: Rendered<APSelection["selection"]>
}
: T extends EqCompSelection
? {
type: "EQComp",
selection: Rendered<EqCompSelection["selection"]>
}
: T extends SandwichSelection<Sandwich>
? Omit<SandwichSelection<Sandwich>, "inside"> & {
inside: Rendered<NPSelection>,
}
@ -727,7 +761,6 @@ export type Rendered<T extends NPSelection | EqCompSelection | AdjectiveSelectio
np: Rendered<NPSelection>,
},
};
// TODO: recursive changing this down into the possesor etc.
export type EPSelectionState = {
blocks: EPSBlock[],
@ -772,7 +805,10 @@ export type EPSelectionComplete = Omit<EPSelectionState, "predicate" | "blocks">
};
export type EqCompType = "adjective" | "loc. adv." | "sandwich"
export type EqCompSelection = AdjectiveSelection | LocativeAdverbSelection | SandwichSelection<Sandwich>;
export type EqCompSelection = {
type: "EQComp",
selection: AdjectiveSelection | LocativeAdverbSelection | SandwichSelection<Sandwich>,
};
export type SandwichSelection<S extends Sandwich> = S & {
inside: NPSelection,