better format with NP and AP selections etc
This commit is contained in:
parent
bb0e2daf0d
commit
4e5075ca19
|
@ -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",
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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()]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
},
|
||||
},
|
||||
),
|
||||
};
|
||||
|
|
46
src/types.ts
46
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<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,
|
||||
|
|
Loading…
Reference in New Issue