added possesives! - still not quite there with participles
This commit is contained in:
parent
c469c0f2f3
commit
e2a90e6315
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@lingdocs/pashto-inflector",
|
"name": "@lingdocs/pashto-inflector",
|
||||||
"version": "2.3.4",
|
"version": "2.3.5",
|
||||||
"author": "lingdocs.com",
|
"author": "lingdocs.com",
|
||||||
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
|
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
|
||||||
"homepage": "https://verbs.lingdocs.com",
|
"homepage": "https://verbs.lingdocs.com",
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { isAdjectiveEntry, isLocativeAdverbEntry, isNounEntry } from "./lib/type
|
||||||
import defualtTextOptions from "./lib/default-text-options";
|
import defualtTextOptions from "./lib/default-text-options";
|
||||||
import PhraseBuilder from "./components/vp-explorer/VPExplorer";
|
import PhraseBuilder from "./components/vp-explorer/VPExplorer";
|
||||||
import useStickyState from "./lib/useStickyState";
|
import useStickyState from "./lib/useStickyState";
|
||||||
|
import { EPExplorer } from "./library";
|
||||||
type VerbType = "simple" | "stative compound" | "dynamic compound";
|
type VerbType = "simple" | "stative compound" | "dynamic compound";
|
||||||
const verbTypes: VerbType[] = [
|
const verbTypes: VerbType[] = [
|
||||||
"simple",
|
"simple",
|
||||||
|
@ -276,6 +277,11 @@ function App() {
|
||||||
opts={textOptions}
|
opts={textOptions}
|
||||||
/>
|
/>
|
||||||
</div>}
|
</div>}
|
||||||
|
<h4>🆕 Equative Phrase Builder</h4>
|
||||||
|
<EPExplorer
|
||||||
|
opts={textOptions}
|
||||||
|
entryFeeder={entryFeeder}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<Modal show={showingTextOptions} onHide={() => setShowingTextOptions(false)}>
|
<Modal show={showingTextOptions} onHide={() => setShowingTextOptions(false)}>
|
||||||
|
|
|
@ -15,12 +15,14 @@ import { getForms } from "../lib/conjugation-forms";
|
||||||
import { conjugateVerb } from "../lib/verb-conjugation";
|
import { conjugateVerb } from "../lib/verb-conjugation";
|
||||||
import PersonSelection from "./PersonSelection";
|
import PersonSelection from "./PersonSelection";
|
||||||
import {
|
import {
|
||||||
personIsAllowed,
|
|
||||||
randomPerson,
|
|
||||||
incrementPerson,
|
incrementPerson,
|
||||||
parseEc,
|
parseEc,
|
||||||
} from "../lib/misc-helpers";
|
} from "../lib/misc-helpers";
|
||||||
import * as T from "../types";
|
import * as T from "../types";
|
||||||
|
import {
|
||||||
|
randomPerson,
|
||||||
|
isInvalidSubjObjCombo,
|
||||||
|
} from "../lib/np-tools";
|
||||||
|
|
||||||
const VerbChoiceWarning = () => (
|
const VerbChoiceWarning = () => (
|
||||||
<>
|
<>
|
||||||
|
@ -100,7 +102,7 @@ function reducer(state: State, action: Action): State {
|
||||||
let newPerson = person;
|
let newPerson = person;
|
||||||
let otherPerson = state[oppositeRole(setting)];
|
let otherPerson = state[oppositeRole(setting)];
|
||||||
let otherSetting = oppositeRole(setting);
|
let otherSetting = oppositeRole(setting);
|
||||||
while (!personIsAllowed(newPerson, otherPerson)) {
|
while (isInvalidSubjObjCombo(newPerson, otherPerson)) {
|
||||||
otherPerson = incrementPerson(otherPerson);
|
otherPerson = incrementPerson(otherPerson);
|
||||||
}
|
}
|
||||||
return { ...state, [setting]: newPerson, [otherSetting]: otherPerson };
|
return { ...state, [setting]: newPerson, [otherSetting]: otherPerson };
|
||||||
|
@ -127,9 +129,9 @@ function reducer(state: State, action: Action): State {
|
||||||
case "randomPerson":
|
case "randomPerson":
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
[action.payload]: randomPerson(
|
[action.payload]: randomPerson({
|
||||||
state[action.payload === "subject" ? "object" : "subject"]
|
prev: state[action.payload === "subject" ? "object" : "subject"]
|
||||||
),
|
}),
|
||||||
};
|
};
|
||||||
case "setShowingFormInfo":
|
case "setShowingFormInfo":
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -31,7 +31,8 @@ function EPExplorer(props: {
|
||||||
tense: "present",
|
tense: "present",
|
||||||
negative: false,
|
negative: false,
|
||||||
},
|
},
|
||||||
}, "EPSelectionState2");
|
shrunkenPossesive: undefined,
|
||||||
|
}, "EPSelectionState3");
|
||||||
function handlePredicateTypeChange(type: "NP" | "Complement") {
|
function handlePredicateTypeChange(type: "NP" | "Complement") {
|
||||||
setEps(o => ({
|
setEps(o => ({
|
||||||
...o,
|
...o,
|
||||||
|
@ -56,6 +57,12 @@ function EPExplorer(props: {
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
function handleShrinkPossesive(shrunkenPossesive: number | undefined) {
|
||||||
|
setEps(o => ({
|
||||||
|
...o,
|
||||||
|
shrunkenPossesive,
|
||||||
|
}));
|
||||||
|
}
|
||||||
const king = eps.subject?.type === "pronoun"
|
const king = eps.subject?.type === "pronoun"
|
||||||
? "subject"
|
? "subject"
|
||||||
: eps.predicate.type === "Complement"
|
: eps.predicate.type === "Complement"
|
||||||
|
@ -76,6 +83,8 @@ function EPExplorer(props: {
|
||||||
{mode === "phrases" && <>
|
{mode === "phrases" && <>
|
||||||
<div className="my-2">
|
<div className="my-2">
|
||||||
<NPPicker
|
<NPPicker
|
||||||
|
shrunkenPossesiveInPhrase={eps.shrunkenPossesive}
|
||||||
|
handleShrinkPossesive={handleShrinkPossesive}
|
||||||
heading={<div className="h5 text-center">Subject {king === "subject" ? roleIcon.king : ""}</div>}
|
heading={<div className="h5 text-center">Subject {king === "subject" ? roleIcon.king : ""}</div>}
|
||||||
entryFeeder={props.entryFeeder}
|
entryFeeder={props.entryFeeder}
|
||||||
np={eps.subject}
|
np={eps.subject}
|
||||||
|
@ -99,6 +108,8 @@ function EPExplorer(props: {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{eps.predicate.type === "NP" ? <NPPicker
|
{eps.predicate.type === "NP" ? <NPPicker
|
||||||
|
shrunkenPossesiveInPhrase={eps.shrunkenPossesive}
|
||||||
|
handleShrinkPossesive={handleShrinkPossesive}
|
||||||
entryFeeder={props.entryFeeder}
|
entryFeeder={props.entryFeeder}
|
||||||
np={eps.predicate.type === "NP" ? eps.predicate.NP : undefined}
|
np={eps.predicate.type === "NP" ? eps.predicate.NP : undefined}
|
||||||
counterPart={undefined}
|
counterPart={undefined}
|
||||||
|
|
|
@ -36,14 +36,12 @@ function AdjectiveManager(props: {
|
||||||
// flippedList.reverse();
|
// flippedList.reverse();
|
||||||
// console.log(props.adjectives);
|
// console.log(props.adjectives);
|
||||||
return <div className="mb-1">
|
return <div className="mb-1">
|
||||||
{!!props.adjectives.length && <div className="d-flex flex-row justify-content-between">
|
|
||||||
<h6>Adjectives</h6>
|
|
||||||
{!adding ? <h6 onClick={() => setAdding(true)}>+ Adj.</h6> : <div></div>}
|
|
||||||
</div>}
|
|
||||||
{adding && <div>
|
{adding && <div>
|
||||||
<div className="d-flex flex-row justify-content-between">
|
<div className="d-flex flex-row justify-content-between mb-1">
|
||||||
<div>Add Adjective</div>
|
<div>Add Adjective</div>
|
||||||
<div onClick={() => setAdding(false)}>Cancel</div>
|
<div className="clickable" onClick={() => setAdding(false)}>
|
||||||
|
<i className="fas fa-trash" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AdjectivePicker
|
<AdjectivePicker
|
||||||
noTitle
|
noTitle
|
||||||
|
@ -53,8 +51,18 @@ function AdjectiveManager(props: {
|
||||||
onChange={handleAddNew}
|
onChange={handleAddNew}
|
||||||
/>
|
/>
|
||||||
</div>}
|
</div>}
|
||||||
{props.adjectives.map((adj, i) => (
|
{props.adjectives.map((adj, i) => <div key={i}>
|
||||||
|
<div className="d-flex flex-row justify-content-between">
|
||||||
|
<div>Adjective</div>
|
||||||
<div className="d-flex flex-row align-items-baseline">
|
<div className="d-flex flex-row align-items-baseline">
|
||||||
|
{!!props.adjectives.length && !adding && <div>
|
||||||
|
<h6 onClick={() => setAdding(true)}>+ Adj.</h6>
|
||||||
|
</div>}
|
||||||
|
<div onClick={deleteAdj(i)} className="ml-4">
|
||||||
|
<div className="fas fa-trash" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<AdjectivePicker
|
<AdjectivePicker
|
||||||
noTitle
|
noTitle
|
||||||
key={`adj${i}`}
|
key={`adj${i}`}
|
||||||
|
@ -63,11 +71,7 @@ function AdjectiveManager(props: {
|
||||||
opts={props.opts}
|
opts={props.opts}
|
||||||
onChange={handleChange(i)}
|
onChange={handleChange(i)}
|
||||||
/>
|
/>
|
||||||
<div onClick={deleteAdj(i)} className="ml-4">
|
</div>)}
|
||||||
<div className="fas fa-trash" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
{!adding && !props.adjectives.length && <h6 className="clickable" style={{ float: "right" }}>
|
{!adding && !props.adjectives.length && <h6 className="clickable" style={{ float: "right" }}>
|
||||||
<div onClick={() => setAdding(true)}>+ Adj.</div>
|
<div onClick={() => setAdding(true)}>+ Adj.</div>
|
||||||
</h6>}
|
</h6>}
|
||||||
|
|
|
@ -5,6 +5,7 @@ function makeParticipleSelection(verb: T.VerbEntry): T.ParticipleSelection {
|
||||||
return {
|
return {
|
||||||
type: "participle",
|
type: "participle",
|
||||||
verb,
|
verb,
|
||||||
|
possesor: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,10 @@ function NPPicker(props: {
|
||||||
onChange: (nps: T.NPSelection | undefined) => void,
|
onChange: (nps: T.NPSelection | undefined) => void,
|
||||||
np: T.NPSelection | undefined,
|
np: T.NPSelection | undefined,
|
||||||
counterPart: T.NPSelection | T.VerbObject | undefined,
|
counterPart: T.NPSelection | T.VerbObject | undefined,
|
||||||
role: "subject" | "object" | "ergative",
|
role: "subject" | "object" | "ergative" | "possesor",
|
||||||
opts: T.TextOptions,
|
opts: T.TextOptions,
|
||||||
|
handleShrinkPossesive: (uid: number | undefined) => void,
|
||||||
|
shrunkenPossesiveInPhrase: number | undefined,
|
||||||
cantClear?: boolean,
|
cantClear?: boolean,
|
||||||
is2ndPersonPicker?: boolean,
|
is2ndPersonPicker?: boolean,
|
||||||
entryFeeder: T.EntryFeeder,
|
entryFeeder: T.EntryFeeder,
|
||||||
|
@ -27,6 +29,7 @@ function NPPicker(props: {
|
||||||
if (props.is2ndPersonPicker && ((props.np?.type !== "pronoun") || !isSecondPerson(props.np.person))) {
|
if (props.is2ndPersonPicker && ((props.np?.type !== "pronoun") || !isSecondPerson(props.np.person))) {
|
||||||
throw new Error("can't use 2ndPerson NPPicker without a pronoun");
|
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.type : undefined);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNpType(props.np ? props.np.type : undefined);
|
setNpType(props.np ? props.np.type : undefined);
|
||||||
|
@ -51,10 +54,32 @@ function NPPicker(props: {
|
||||||
setNpType(ntp);
|
setNpType(ntp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function handlePossesiveChange(p: T.NPSelection | undefined) {
|
||||||
|
if (!props.np || props.np.type === "pronoun") return;
|
||||||
|
if (!p) {
|
||||||
|
props.onChange({
|
||||||
|
...props.np,
|
||||||
|
possesor: undefined,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const isNewPosesser = checkForNewPossesor(p, props.np.possesor);
|
||||||
|
const possesor = {
|
||||||
|
np: p,
|
||||||
|
uid: (!isNewPosesser && props.np.possesor) ? props.np.possesor.uid : makeUID(),
|
||||||
|
};
|
||||||
|
props.onChange({
|
||||||
|
...props.np,
|
||||||
|
possesor,
|
||||||
|
});
|
||||||
|
}
|
||||||
const isDynamicComplement = props.np && props.np.type === "noun" && props.np.dynamicComplement;
|
const isDynamicComplement = props.np && props.np.type === "noun" && props.np.dynamicComplement;
|
||||||
const clearButton = (!props.cantClear && !props.is2ndPersonPicker && !isDynamicComplement)
|
const clearButton = (!props.cantClear && !props.is2ndPersonPicker && !isDynamicComplement)
|
||||||
? <button className="btn btn-sm btn-light mb-2" onClick={handleClear}>X</button>
|
? <button className="btn btn-sm btn-light mb-2" onClick={handleClear}>X</button>
|
||||||
: <div></div>;
|
: <div></div>;
|
||||||
|
const possesiveUid = (props.np && props.np.type !== "pronoun" && props.np.possesor)
|
||||||
|
? props.np.possesor.uid
|
||||||
|
: undefined;
|
||||||
return <>
|
return <>
|
||||||
<div className="d-flex flex-row justify-content-between">
|
<div className="d-flex flex-row justify-content-between">
|
||||||
<div></div>
|
<div></div>
|
||||||
|
@ -83,6 +108,39 @@ function NPPicker(props: {
|
||||||
</button>
|
</button>
|
||||||
</div>)}
|
</div>)}
|
||||||
</div>}
|
</div>}
|
||||||
|
{(props.np && props.np.type !== "pronoun" && (props.np.possesor || addingPoss)) && <div className="mb-3" style={{ paddingLeft: "0.5rem", borderLeft: "1px solid grey" }}>
|
||||||
|
<div className="d-flex flex-row text-muted mb-2">
|
||||||
|
<div>Possesive:</div>
|
||||||
|
{props.np.possesor && <div className="clickable mx-2" onClick={() => {
|
||||||
|
props.handleShrinkPossesive(possesiveUid === props.shrunkenPossesiveInPhrase
|
||||||
|
? undefined
|
||||||
|
: possesiveUid
|
||||||
|
);
|
||||||
|
}}>
|
||||||
|
{possesiveUid === props.shrunkenPossesiveInPhrase ? "👶 Shrunken" : "Shrink"}
|
||||||
|
</div>}
|
||||||
|
<div className="clickable ml-2" onClick={() => {
|
||||||
|
setAddingPoss(false);
|
||||||
|
handlePossesiveChange(undefined);
|
||||||
|
}}>
|
||||||
|
<i className="fas fa-trash" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NPPicker
|
||||||
|
onChange={handlePossesiveChange}
|
||||||
|
counterPart={undefined}
|
||||||
|
cantClear
|
||||||
|
np={props.np.possesor ? props.np.possesor.np : undefined}
|
||||||
|
handleShrinkPossesive={props.handleShrinkPossesive}
|
||||||
|
shrunkenPossesiveInPhrase={props.shrunkenPossesiveInPhrase}
|
||||||
|
role="possesor"
|
||||||
|
opts={props.opts}
|
||||||
|
entryFeeder={props.entryFeeder}
|
||||||
|
/>
|
||||||
|
</div>}
|
||||||
|
{(npType === "noun" || npType === "participle") && props.np && !addingPoss && <div>
|
||||||
|
<span className="clickable text-muted" onClick={() => setAddingPoss(true)}>+ Possesive</span>
|
||||||
|
</div>}
|
||||||
{(npType === "pronoun" && props.np?.type === "pronoun")
|
{(npType === "pronoun" && props.np?.type === "pronoun")
|
||||||
? <PronounPicker
|
? <PronounPicker
|
||||||
role={props.role}
|
role={props.role}
|
||||||
|
@ -111,6 +169,26 @@ function NPPicker(props: {
|
||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// {(npType && !isDynamicComplement) && }
|
function checkForNewPossesor(n: T.NPSelection | undefined, old: T.PossesorSelection | undefined): boolean {
|
||||||
|
if (!old || !n) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
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.type === "participle" && old.np.type === "participle") {
|
||||||
|
return n.verb.entry.ts !== old.np.verb.entry.ts;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: BETTER UID
|
||||||
|
function makeUID() {
|
||||||
|
return Math.floor(Math.random() * 50000);
|
||||||
|
}
|
||||||
|
|
||||||
export default NPPicker;
|
export default NPPicker;
|
|
@ -12,7 +12,7 @@ const gColors = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: better logic on this
|
// TODO: better logic on this
|
||||||
const labels = (role: "subject" | "object" | "ergative") => ({
|
const labels = (role: "subject" | "object" | "ergative" | "possesor") => ({
|
||||||
// persons: [
|
// persons: [
|
||||||
// ["1st", "1st pl."],
|
// ["1st", "1st pl."],
|
||||||
// ["2nd", "2nd pl."],
|
// ["2nd", "2nd pl."],
|
||||||
|
@ -20,11 +20,15 @@ const labels = (role: "subject" | "object" | "ergative") => ({
|
||||||
// ],
|
// ],
|
||||||
e: role === "object" ? [
|
e: role === "object" ? [
|
||||||
["me", "us"],
|
["me", "us"],
|
||||||
["you", "you pl."],
|
["you", "y'all"],
|
||||||
[{ masc: "him/it", fem: "her/it"}, "them"],
|
[{ masc: "him/it", fem: "her/it"}, "them"],
|
||||||
|
] : role === "possesor" ? [
|
||||||
|
["my", "our"],
|
||||||
|
["your", "y'all's"],
|
||||||
|
[{ masc: "his/its", fem: "her/its"}, "their"],
|
||||||
] : [
|
] : [
|
||||||
["I", "We"],
|
["I", "We"],
|
||||||
["You", "You pl."],
|
["You", "Y'all"],
|
||||||
[{ masc: "He/It", fem: "She/It"}, "They"],
|
[{ masc: "He/It", fem: "She/It"}, "They"],
|
||||||
],
|
],
|
||||||
p: role === "subject" ? {
|
p: role === "subject" ? {
|
||||||
|
@ -49,6 +53,17 @@ const labels = (role: "subject" | "object" | "ergative") => ({
|
||||||
["ته", "تاسو"],
|
["ته", "تاسو"],
|
||||||
[{ masc: "دهٔ", fem: "دې" }, "دوي"],
|
[{ masc: "دهٔ", fem: "دې" }, "دوي"],
|
||||||
],
|
],
|
||||||
|
} : role === "possesor" ? {
|
||||||
|
far: [
|
||||||
|
["زما", "زمونږ"],
|
||||||
|
["ستا", "ستاسو"],
|
||||||
|
[{ masc: "د هغهٔ", fem: "د هغې" }, "د هغوي"],
|
||||||
|
],
|
||||||
|
near: [
|
||||||
|
["زما", "زمونږ"],
|
||||||
|
["ستا", "ستاسو"],
|
||||||
|
[{ masc: "د دهٔ", fem: "د دې" }, "د دوي"],
|
||||||
|
],
|
||||||
} : {
|
} : {
|
||||||
far: [
|
far: [
|
||||||
["ما", "مونږ"],
|
["ما", "مونږ"],
|
||||||
|
@ -79,11 +94,10 @@ function pickerStateToPerson(s: PickerState): T.Person {
|
||||||
+ (6 * s.col);
|
+ (6 * s.col);
|
||||||
}
|
}
|
||||||
|
|
||||||
function NPPronounPicker({ onChange, pronoun, role, clearButton, opts, is2ndPersonPicker }: {
|
function NPPronounPicker({ onChange, pronoun, role, opts, is2ndPersonPicker }: {
|
||||||
pronoun: T.PronounSelection,
|
pronoun: T.PronounSelection,
|
||||||
onChange: (p: T.PronounSelection) => void,
|
onChange: (p: T.PronounSelection) => void,
|
||||||
role: "object" | "subject" | "ergative",
|
role: "object" | "subject" | "ergative" | "possesor",
|
||||||
clearButton?: JSX.Element,
|
|
||||||
opts: T.TextOptions,
|
opts: T.TextOptions,
|
||||||
is2ndPersonPicker?: boolean,
|
is2ndPersonPicker?: boolean,
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -106,6 +106,7 @@ export function makeNounSelection(entry: T.NounEntry, dynamicComplement?: true):
|
||||||
number,
|
number,
|
||||||
numberCanChange: number === "singular",
|
numberCanChange: number === "singular",
|
||||||
adjectives: [],
|
adjectives: [],
|
||||||
|
possesor: undefined,
|
||||||
dynamicComplement,
|
dynamicComplement,
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -45,7 +45,7 @@ export function VPExplorer(props: {
|
||||||
}) {
|
}) {
|
||||||
const [vps, setVps] = useStickyState<T.VPSelectionState>(
|
const [vps, setVps] = useStickyState<T.VPSelectionState>(
|
||||||
savedVps => makeVPSelectionState(props.verb, savedVps),
|
savedVps => makeVPSelectionState(props.verb, savedVps),
|
||||||
"vpsState5",
|
"vpsState6",
|
||||||
);
|
);
|
||||||
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
|
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
|
||||||
savedMode => {
|
savedMode => {
|
||||||
|
@ -97,6 +97,12 @@ export function VPExplorer(props: {
|
||||||
if (vps.verb?.isCompound === "dynamic") return;
|
if (vps.verb?.isCompound === "dynamic") return;
|
||||||
setVps(switchSubjObj)
|
setVps(switchSubjObj)
|
||||||
}
|
}
|
||||||
|
function handleShrinkPossesive(shrunkenPossesive: number | undefined) {
|
||||||
|
setVps(o => ({
|
||||||
|
...o,
|
||||||
|
shrunkenPossesive,
|
||||||
|
}));
|
||||||
|
}
|
||||||
function quizLock<T>(f: T) {
|
function quizLock<T>(f: T) {
|
||||||
if (mode === "quiz") {
|
if (mode === "quiz") {
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -142,10 +148,12 @@ export function VPExplorer(props: {
|
||||||
? "ergative"
|
? "ergative"
|
||||||
: "subject"
|
: "subject"
|
||||||
}
|
}
|
||||||
|
shrunkenPossesiveInPhrase={vps.shrunkenPossesive}
|
||||||
is2ndPersonPicker={vps.verb.tenseCategory === "imperative"}
|
is2ndPersonPicker={vps.verb.tenseCategory === "imperative"}
|
||||||
np={vps.subject}
|
np={vps.subject}
|
||||||
counterPart={vps.verb ? vps.verb.object : undefined}
|
counterPart={vps.verb ? vps.verb.object : undefined}
|
||||||
onChange={handleSubjectChange}
|
onChange={handleSubjectChange}
|
||||||
|
handleShrinkPossesive={handleShrinkPossesive}
|
||||||
opts={props.opts}
|
opts={props.opts}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -153,6 +161,8 @@ export function VPExplorer(props: {
|
||||||
{(typeof vps.verb.object === "number")
|
{(typeof vps.verb.object === "number")
|
||||||
? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div>
|
? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div>
|
||||||
: <NPPicker
|
: <NPPicker
|
||||||
|
shrunkenPossesiveInPhrase={vps.shrunkenPossesive}
|
||||||
|
handleShrinkPossesive={handleShrinkPossesive}
|
||||||
heading={roles.king === "object"
|
heading={roles.king === "object"
|
||||||
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}</div>
|
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}</div>
|
||||||
: <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>Object {roleIcon.servant}</div>}
|
: <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>Object {roleIcon.servant}</div>}
|
||||||
|
|
|
@ -445,6 +445,7 @@ function getRandomVPSelection(mix: MixType = "both") {
|
||||||
return {
|
return {
|
||||||
subject: subject !== undefined ? subject : randSubj,
|
subject: subject !== undefined ? subject : randSubj,
|
||||||
verb: randomizeTense(verb, true),
|
verb: randomizeTense(verb, true),
|
||||||
|
shrunkenPossesive: undefined,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const v: T.VerbSelectionComplete = {
|
const v: T.VerbSelectionComplete = {
|
||||||
|
@ -460,6 +461,7 @@ function getRandomVPSelection(mix: MixType = "both") {
|
||||||
return {
|
return {
|
||||||
subject: randSubj,
|
subject: randSubj,
|
||||||
verb: randomizeTense(v, true),
|
verb: randomizeTense(v, true),
|
||||||
|
shrunkenPossesive: undefined,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -95,5 +95,6 @@ export function makeVPSelectionState(
|
||||||
},
|
},
|
||||||
} : {},
|
} : {},
|
||||||
},
|
},
|
||||||
|
shrunkenPossesive: os ? os.shrunkenPossesive : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,41 +162,8 @@ export function randFromArray<M>(arr: M[]): M {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: deprecate this because we have it in np-tools?
|
export const isFirstPerson = (p: T.Person) => [0, 1, 6, 7].includes(p);
|
||||||
/**
|
export const isSecondPerson = (p: T.Person) => [2, 3, 8, 9].includes(p);
|
||||||
* Sees if a possiblePerson (for subject/object) is possible, given the other person
|
|
||||||
*
|
|
||||||
* @param possiblePerson
|
|
||||||
* @param existingPerson
|
|
||||||
*/
|
|
||||||
export function personIsAllowed(possiblePerson: T.Person, existingPerson?: T.Person): boolean {
|
|
||||||
const isFirstPerson = (p: T.Person) => [0, 1, 6, 7].includes(p);
|
|
||||||
const isSecondPerson = (p: T.Person) => [2, 3, 8, 9].includes(p);
|
|
||||||
// can't have both subject and object be 1st person
|
|
||||||
if (isFirstPerson(possiblePerson) && (existingPerson && isFirstPerson(existingPerson))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// can't have both subject and object be 2nd person
|
|
||||||
if (isSecondPerson(possiblePerson) && (existingPerson && isSecondPerson(existingPerson))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// otherwise it's ok
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: deprecate this because we have it in np-tools?
|
|
||||||
/**
|
|
||||||
* Picks a random person while assuring that the other person is not in conflict
|
|
||||||
*
|
|
||||||
* @param other
|
|
||||||
*/
|
|
||||||
export function randomPerson(other?: T.Person): T.Person {
|
|
||||||
let newPerson: T.Person;
|
|
||||||
do {
|
|
||||||
newPerson = randomNumber(0, 12);
|
|
||||||
} while(!personIsAllowed(newPerson, other));
|
|
||||||
return newPerson;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function incrementPerson(p: T.Person): T.Person {
|
export function incrementPerson(p: T.Person): T.Person {
|
||||||
return (p + 1) % 12;
|
return (p + 1) % 12;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as T from "../types";
|
import * as T from "../types";
|
||||||
import { parseEc } from "../lib/misc-helpers";
|
import { isFirstPerson, parseEc } from "../lib/misc-helpers";
|
||||||
|
import { isSecondPerson } from "./phrase-building/vp-tools";
|
||||||
|
|
||||||
function getRandPers(): T.Person {
|
function getRandPers(): T.Person {
|
||||||
return Math.floor(Math.random() * 12);
|
return Math.floor(Math.random() * 12);
|
||||||
|
@ -31,22 +32,10 @@ export function randomPerson(a?: { prev?: T.Person, counterPart?: T.VerbObject |
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
||||||
const firstPeople = [
|
|
||||||
T.Person.FirstSingMale,
|
|
||||||
T.Person.FirstSingFemale,
|
|
||||||
T.Person.FirstPlurMale,
|
|
||||||
T.Person.FirstPlurFemale,
|
|
||||||
];
|
|
||||||
const secondPeople = [
|
|
||||||
T.Person.SecondSingMale,
|
|
||||||
T.Person.SecondSingFemale,
|
|
||||||
T.Person.SecondPlurMale,
|
|
||||||
T.Person.SecondPlurFemale,
|
|
||||||
];
|
|
||||||
return (
|
return (
|
||||||
(firstPeople.includes(subj) && firstPeople.includes(obj))
|
(isFirstPerson(subj) && isFirstPerson(obj))
|
||||||
||
|
||
|
||||||
(secondPeople.includes(subj) && secondPeople.includes(obj))
|
(isSecondPerson(subj) && isSecondPerson(obj))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,11 @@ import {
|
||||||
} from "./segment";
|
} from "./segment";
|
||||||
import { removeAccents } from "../accent-helpers";
|
import { removeAccents } from "../accent-helpers";
|
||||||
import { getEnglishFromRendered, getPashtoFromRendered } from "./np-tools";
|
import { getEnglishFromRendered, getPashtoFromRendered } from "./np-tools";
|
||||||
|
import {
|
||||||
|
orderKidsSection,
|
||||||
|
findPossesiveToShrink,
|
||||||
|
shrinkNP,
|
||||||
|
} from "./compile-tools";
|
||||||
|
|
||||||
export function compileEP(EP: T.EPRendered, form: T.FormVersion): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string[] };
|
export function compileEP(EP: T.EPRendered, form: T.FormVersion): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string[] };
|
||||||
export function compileEP(EP: T.EPRendered, form: T.FormVersion, combineLengths: true): { ps: T.PsString[], e?: string[] };
|
export function compileEP(EP: T.EPRendered, form: T.FormVersion, combineLengths: true): { ps: T.PsString[], e?: string[] };
|
||||||
|
@ -37,12 +42,20 @@ function getSegmentsAndKids(EP: T.EPRendered, form: T.FormVersion): { kids: Segm
|
||||||
}
|
}
|
||||||
return [s];
|
return [s];
|
||||||
}
|
}
|
||||||
const subject = makeSegment(getPashtoFromRendered(EP.subject));
|
const possToShrink = findPossesiveToShrink(EP);
|
||||||
const predicate = makeSegment(getPashtoFromRendered(EP.predicate));
|
const shrunkenPossAllowed = !(form.removeKing && possToShrink?.role === "king");
|
||||||
|
const possUid = shrunkenPossAllowed ? EP.shrunkenPossesive : undefined;
|
||||||
|
const subject = makeSegment(getPashtoFromRendered(EP.subject, possUid, false));
|
||||||
|
const predicate = makeSegment(getPashtoFromRendered(EP.predicate, possUid, false));
|
||||||
return {
|
return {
|
||||||
kids: EP.equative.hasBa
|
kids: orderKidsSection([
|
||||||
|
...EP.equative.hasBa
|
||||||
? [makeSegment(grammarUnits.baParticle, ["isBa", "isKid"])]
|
? [makeSegment(grammarUnits.baParticle, ["isBa", "isKid"])]
|
||||||
: [],
|
: [],
|
||||||
|
...(possToShrink && shrunkenPossAllowed)
|
||||||
|
? [shrinkNP(possToShrink)]
|
||||||
|
: [],
|
||||||
|
]),
|
||||||
NPs: [
|
NPs: [
|
||||||
...ifNotRemoved(subject, "subject"),
|
...ifNotRemoved(subject, "subject"),
|
||||||
...ifNotRemoved(predicate, "predicate"),
|
...ifNotRemoved(predicate, "predicate"),
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
import * as T from "../../types";
|
||||||
|
import {
|
||||||
|
Segment,
|
||||||
|
makeSegment,
|
||||||
|
} from "./segment";
|
||||||
|
import { getVerbBlockPosFromPerson } from "../misc-helpers";
|
||||||
|
import { pronouns } from "../grammar-units";
|
||||||
|
|
||||||
|
export function orderKidsSection(kids: Segment[]): Segment[] {
|
||||||
|
const sorted = [...kids];
|
||||||
|
return sorted.sort((a, b) => {
|
||||||
|
// ba first
|
||||||
|
if (a.isBa) return -1;
|
||||||
|
// kinds lined up 1st 2nd 3rd person
|
||||||
|
if (a.isMiniPronoun && b.isMiniPronoun) {
|
||||||
|
if (a.isMiniPronoun < b.isMiniPronoun) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.isMiniPronoun > b.isMiniPronoun) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// TODO: is this enough?
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findPossesiveToShrink(VP: T.VPRendered | T.EPRendered): T.Rendered<T.NPSelection> | undefined {
|
||||||
|
const uid = VP.shrunkenPossesive;
|
||||||
|
function findPossesiveInNP(NP: T.Rendered<T.NPSelection> | T.ObjectNP | undefined): T.Rendered<T.NPSelection> | undefined {
|
||||||
|
if (NP === undefined) return undefined;
|
||||||
|
if (typeof NP !== "object") return undefined;
|
||||||
|
if (!NP.possesor) return undefined;
|
||||||
|
if (NP.possesor.uid === uid) {
|
||||||
|
return NP.possesor.np;
|
||||||
|
}
|
||||||
|
return findPossesiveInNP(NP.possesor.np);
|
||||||
|
}
|
||||||
|
if (uid === undefined) return undefined;
|
||||||
|
const objPred: T.Rendered<T.NPSelection> | undefined = ("object" in VP)
|
||||||
|
? (typeof VP.object === "object" ? VP.object : undefined)
|
||||||
|
: (VP.predicate.type === "noun" || VP.predicate.type === "participle" || VP.predicate.type === "pronoun")
|
||||||
|
// typescript is dumb here;
|
||||||
|
? VP.predicate as T.Rendered<T.NPSelection>
|
||||||
|
: undefined;
|
||||||
|
return (
|
||||||
|
findPossesiveInNP(VP.subject)
|
||||||
|
||
|
||||||
|
findPossesiveInNP(objPred)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
const [row, col] = getVerbBlockPosFromPerson(np.person);
|
||||||
|
return makeSegment(pronouns.mini[row][col], ["isKid", getFirstSecThird()]);
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as T from "../../types";
|
import * as T from "../../types";
|
||||||
import {
|
import {
|
||||||
concatPsString,
|
concatPsString, psStringEquals,
|
||||||
} from "../p-text-helpers";
|
} from "../p-text-helpers";
|
||||||
import {
|
import {
|
||||||
Segment,
|
Segment,
|
||||||
|
@ -13,7 +13,6 @@ import {
|
||||||
import {
|
import {
|
||||||
removeAccents,
|
removeAccents,
|
||||||
} from "../accent-helpers";
|
} from "../accent-helpers";
|
||||||
import { getVerbBlockPosFromPerson } from "../misc-helpers";
|
|
||||||
import * as grammarUnits from "../grammar-units";
|
import * as grammarUnits from "../grammar-units";
|
||||||
import {
|
import {
|
||||||
removeBa,
|
removeBa,
|
||||||
|
@ -21,6 +20,11 @@ import {
|
||||||
} from "./vp-tools";
|
} from "./vp-tools";
|
||||||
import { isImperativeTense, isModalTense, isPerfectTense } from "../type-predicates";
|
import { isImperativeTense, isModalTense, isPerfectTense } from "../type-predicates";
|
||||||
import { getEnglishFromRendered, getPashtoFromRendered } from "./np-tools";
|
import { getEnglishFromRendered, getPashtoFromRendered } from "./np-tools";
|
||||||
|
import {
|
||||||
|
orderKidsSection,
|
||||||
|
findPossesiveToShrink,
|
||||||
|
shrinkNP,
|
||||||
|
} from "./compile-tools";
|
||||||
|
|
||||||
type Form = T.FormVersion & { OSV?: boolean };
|
type Form = T.FormVersion & { OSV?: boolean };
|
||||||
export function compileVP(VP: T.VPRendered, form: Form): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] };
|
export function compileVP(VP: T.VPRendered, form: Form): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] };
|
||||||
|
@ -79,20 +83,33 @@ function compilePs({ NPs, kids, verb: { head, rest }, VP }: CompilePsInput): T.S
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSegmentsAndKids(VP: T.VPRendered, form: Form): { kids: Segment[], NPs: Segment[][] } {
|
function getSegmentsAndKids(VP: T.VPRendered, form: Form): { kids: Segment[], NPs: Segment[][] } {
|
||||||
const SO = {
|
|
||||||
subject: getPashtoFromRendered(VP.subject),
|
|
||||||
object: typeof VP.object === "object" ? getPashtoFromRendered(VP.object) : undefined,
|
|
||||||
}
|
|
||||||
const removeKing = form.removeKing && !(VP.isCompound === "dynamic" && VP.isPast);
|
const removeKing = form.removeKing && !(VP.isCompound === "dynamic" && VP.isPast);
|
||||||
const shrinkServant = form.shrinkServant && !(VP.isCompound === "dynamic" && !VP.isPast);
|
const shrinkServant = form.shrinkServant && !(VP.isCompound === "dynamic" && !VP.isPast);
|
||||||
|
const toShrinkServant = (() => {
|
||||||
const toShrink = (() => {
|
|
||||||
if (!shrinkServant) return undefined;
|
if (!shrinkServant) return undefined;
|
||||||
if (!VP.servant) return undefined;
|
if (!VP.servant) return undefined;
|
||||||
const servant = VP[VP.servant];
|
const servant = VP[VP.servant];
|
||||||
if (typeof servant !== "object") return undefined;
|
if (typeof servant !== "object") return undefined;
|
||||||
return servant;
|
return servant;
|
||||||
})();
|
})();
|
||||||
|
const shrunkenServant = toShrinkServant ? shrinkNP(toShrinkServant) : undefined;
|
||||||
|
const possToShrink = findPossesiveToShrink(VP);
|
||||||
|
const shrunkenPossesive = possToShrink ? shrinkNP(possToShrink) : undefined;
|
||||||
|
const shrunkenPossAllowed = possToShrink && shrunkenPossesive && (
|
||||||
|
!shrunkenServant || !psStringEquals(shrunkenPossesive.ps[0], shrunkenServant.ps[0])
|
||||||
|
) && (
|
||||||
|
// can only shrink the possesive if the parent of the possesive is still in full form
|
||||||
|
!(possToShrink.role === "king" && removeKing)
|
||||||
|
&&
|
||||||
|
!(possToShrink.role === "servant" && shrinkServant)
|
||||||
|
);
|
||||||
|
const shrinkPossUid = shrunkenPossAllowed
|
||||||
|
? VP.shrunkenPossesive
|
||||||
|
: undefined;
|
||||||
|
const SO = {
|
||||||
|
subject: getPashtoFromRendered(VP.subject, shrinkPossUid, false),
|
||||||
|
object: typeof VP.object === "object" ? getPashtoFromRendered(VP.object, shrinkPossUid, VP.subject.person) : undefined,
|
||||||
|
};
|
||||||
function getSegment(t: "subject" | "object"): Segment | undefined {
|
function getSegment(t: "subject" | "object"): Segment | undefined {
|
||||||
const word = (VP.servant === t)
|
const word = (VP.servant === t)
|
||||||
? (!shrinkServant ? SO[t] : undefined)
|
? (!shrinkServant ? SO[t] : undefined)
|
||||||
|
@ -106,12 +123,14 @@ function getSegmentsAndKids(VP: T.VPRendered, form: Form): { kids: Segment[], NP
|
||||||
const object = getSegment("object");
|
const object = getSegment("object");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
kids: [
|
kids: orderKidsSection([
|
||||||
...VP.verb.hasBa
|
...VP.verb.hasBa
|
||||||
? [makeSegment(grammarUnits.baParticle, ["isBa", "isKid"])] : [],
|
? [makeSegment(grammarUnits.baParticle, ["isBa", "isKid"])] : [],
|
||||||
...toShrink
|
...shrunkenServant
|
||||||
? [shrinkNP(toShrink)] : [],
|
? [shrunkenServant] : [],
|
||||||
],
|
...(shrunkenPossesive && shrunkenPossAllowed)
|
||||||
|
? [shrunkenPossesive] : [],
|
||||||
|
]),
|
||||||
NPs: [
|
NPs: [
|
||||||
[
|
[
|
||||||
...subject ? [subject] : [],
|
...subject ? [subject] : [],
|
||||||
|
@ -236,11 +255,6 @@ function arrangeVerbWNegative(head: T.PsString | undefined, restRaw: T.PsString[
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function shrinkNP(np: T.Rendered<T.NPSelection>): Segment {
|
|
||||||
const [row, col] = getVerbBlockPosFromPerson(np.person);
|
|
||||||
return makeSegment(grammarUnits.pronouns.mini[row][col], ["isKid", "isMiniPronoun"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mergeSegments(s1: Segment, s2: Segment, noSpace?: "no space"): Segment {
|
function mergeSegments(s1: Segment, s2: Segment, noSpace?: "no space"): Segment {
|
||||||
if (noSpace) {
|
if (noSpace) {
|
||||||
return s2.adjust({ ps: (p) => concatPsString(s1.ps[0], p) });
|
return s2.adjust({ ps: (p) => concatPsString(s1.ps[0], p) });
|
||||||
|
@ -295,4 +309,3 @@ function compileEnglish(VP: T.VPRendered): string[] | undefined {
|
||||||
}))
|
}))
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
import {
|
||||||
|
isFirstPerson,
|
||||||
|
isSecondPerson,
|
||||||
|
} from "../../lib/misc-helpers";
|
||||||
import * as T from "../../types";
|
import * as T from "../../types";
|
||||||
import { concatPsString } from "../p-text-helpers";
|
import { concatPsString } from "../p-text-helpers";
|
||||||
|
|
||||||
export function getPashtoFromRendered(np: T.Rendered<T.NPSelection | T.EqCompSelection>): T.PsString[] {
|
function getBaseAndAdjectives(np: T.Rendered<T.NPSelection | T.EqCompSelection>): T.PsString[] {
|
||||||
const adjs = np.adjectives;
|
const adjs = np.adjectives;
|
||||||
if (!adjs) {
|
if (!adjs) {
|
||||||
return np.ps;
|
return np.ps;
|
||||||
|
@ -18,9 +22,42 @@ export function getPashtoFromRendered(np: T.Rendered<T.NPSelection | T.EqCompSel
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEnglishFromRendered(np: T.Rendered<T.NPSelection | T.EqCompSelection>): string | undefined {
|
export function getPashtoFromRendered(np: T.Rendered<T.NPSelection | T.EqCompSelection>, shrunkenPossesive: number | undefined, subjectsPerson: false | T.Person): T.PsString[] {
|
||||||
|
const base = getBaseAndAdjectives(np);
|
||||||
|
if (!np.possesor || np.possesor.uid === shrunkenPossesive) {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
return addPossesor(np.possesor.np, base, subjectsPerson);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function addPossesor(owner: T.Rendered<T.NPSelection>, existing: T.PsString[], subjectsPerson: false | T.Person): T.PsString[] {
|
||||||
|
function willBeReflexive(subj: T.Person, obj: T.Person): boolean {
|
||||||
|
return (
|
||||||
|
([0, 1].includes(subj) && [0, 1].includes(obj))
|
||||||
|
||
|
||||||
|
([2, 3].includes(subj) && [8, 9].includes(obj))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const wPossesor = existing.flatMap(ps => (
|
||||||
|
getBaseAndAdjectives(owner).map(v => (
|
||||||
|
(owner.type === "pronoun" && subjectsPerson !== false && willBeReflexive(subjectsPerson, owner.person))
|
||||||
|
? concatPsString({ p: "خپل", f: "khpul" }, " ", ps)
|
||||||
|
: (owner.type === "pronoun" && isFirstPerson(owner.person))
|
||||||
|
? concatPsString({ p: "ز", f: "z" }, v, " ", ps)
|
||||||
|
: (owner.type === "pronoun" && isSecondPerson(owner.person))
|
||||||
|
? concatPsString({ p: "س", f: "s" }, v, " ", ps)
|
||||||
|
: concatPsString({ p: "د", f: "du" }, " ", v, " ", ps)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
if (!owner.possesor) {
|
||||||
|
return wPossesor;
|
||||||
|
}
|
||||||
|
return addPossesor(owner.possesor.np, wPossesor, subjectsPerson);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addArticlesAndAdjs(np: T.Rendered<T.NounSelection>): string | undefined {
|
||||||
if (!np.e) return undefined;
|
if (!np.e) return undefined;
|
||||||
if (np.type === "noun") {
|
|
||||||
try {
|
try {
|
||||||
// split out the atricles so adjectives can be stuck inbetween them and the word
|
// split out the atricles so adjectives can be stuck inbetween them and the word
|
||||||
const chunks = np.e.split("the)");
|
const chunks = np.e.split("the)");
|
||||||
|
@ -38,5 +75,53 @@ export function getEnglishFromRendered(np: T.Rendered<T.NPSelection | T.EqCompSe
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return np.e;
|
|
||||||
|
function addPossesors(possesor: T.Rendered<T.NPSelection> | undefined, base: string | undefined): string | undefined {
|
||||||
|
function removeArticles(s: string): string {
|
||||||
|
return s.replace("(the) ", "").replace("(a/the) ", "");
|
||||||
|
}
|
||||||
|
if (!base) return undefined;
|
||||||
|
if (!possesor) return base;
|
||||||
|
if (possesor.type === "pronoun") {
|
||||||
|
return `${pronounPossEng(possesor.person)} ${removeArticles(base)}`;
|
||||||
|
}
|
||||||
|
const possesorE = getEnglishFromRendered(possesor);
|
||||||
|
if (!possesorE) return undefined;
|
||||||
|
return `${possesorE}'s ${removeArticles(base)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pronounPossEng(p: T.Person): string {
|
||||||
|
if (p === T.Person.FirstSingMale || p === T.Person.FirstSingFemale) {
|
||||||
|
return "my";
|
||||||
|
}
|
||||||
|
if (p === T.Person.FirstPlurMale || p === T.Person.FirstPlurFemale) {
|
||||||
|
return "our";
|
||||||
|
}
|
||||||
|
if (p === T.Person.SecondSingMale || p === T.Person.SecondSingFemale) {
|
||||||
|
return "your";
|
||||||
|
}
|
||||||
|
if (p === T.Person.SecondPlurMale || p === T.Person.SecondPlurFemale) {
|
||||||
|
return "your (pl.)";
|
||||||
|
}
|
||||||
|
if (p === T.Person.ThirdSingMale) {
|
||||||
|
return "his/its";
|
||||||
|
}
|
||||||
|
if (p === T.Person.ThirdSingFemale) {
|
||||||
|
return "her/its";
|
||||||
|
}
|
||||||
|
return "their";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getEnglishFromRendered(r: T.Rendered<T.NPSelection | T.EqCompSelection>): string | undefined {
|
||||||
|
if (!r.e) return undefined;
|
||||||
|
if (r.type === "loc. adv." || r.type === "adjective") {
|
||||||
|
return r.e;
|
||||||
|
}
|
||||||
|
if (r.type === "noun") {
|
||||||
|
// TODO: shouldn't have to do this 'as' - should be automatically narrowing
|
||||||
|
const np = r as T.Rendered<T.NounSelection>;
|
||||||
|
return addPossesors(np.possesor?.np, addArticlesAndAdjs(np));
|
||||||
|
}
|
||||||
|
// TODO: possesives in English for participles and pronouns too!
|
||||||
|
return r.e;
|
||||||
}
|
}
|
|
@ -17,7 +17,7 @@ function chooseInflection(inflections: T.UnisexSet<T.InflectionSet>, pers: T.Per
|
||||||
return inflections[gender][infNumber];
|
return inflections[gender][infNumber];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderAdjectiveSelection(a: T.AdjectiveSelection, person: T.Person, inflected: boolean): T.Rendered<T.AdjectiveSelection> {
|
export function renderAdjectiveSelection(a: T.AdjectiveSelection, person: T.Person, inflected: boolean, role: "king" | "servant" | "none"): T.Rendered<T.AdjectiveSelection> {
|
||||||
const infs = inflectWord(a.entry);
|
const infs = inflectWord(a.entry);
|
||||||
const eWord = getEnglishWord(a.entry);
|
const eWord = getEnglishWord(a.entry);
|
||||||
const e = !eWord
|
const e = !eWord
|
||||||
|
@ -31,6 +31,7 @@ export function renderAdjectiveSelection(a: T.AdjectiveSelection, person: T.Pers
|
||||||
ps: [psStringFromEntry(a.entry)],
|
ps: [psStringFromEntry(a.entry)],
|
||||||
e,
|
e,
|
||||||
inflected: false,
|
inflected: false,
|
||||||
|
role,
|
||||||
person,
|
person,
|
||||||
}
|
}
|
||||||
if (!infs.inflections || !isUnisexSet(infs.inflections)) {
|
if (!infs.inflections || !isUnisexSet(infs.inflections)) {
|
||||||
|
@ -42,6 +43,7 @@ export function renderAdjectiveSelection(a: T.AdjectiveSelection, person: T.Pers
|
||||||
ps: chooseInflection(infs.inflections, person, inflected),
|
ps: chooseInflection(infs.inflections, person, inflected),
|
||||||
e,
|
e,
|
||||||
inflected: false,
|
inflected: false,
|
||||||
|
role,
|
||||||
person,
|
person,
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -8,12 +8,17 @@ import { getPersonFromVerbForm } from "../../lib/misc-helpers";
|
||||||
import { getVerbBlockPosFromPerson } from "../misc-helpers";
|
import { getVerbBlockPosFromPerson } from "../misc-helpers";
|
||||||
import { getEnglishWord } from "../get-english-word";
|
import { getEnglishWord } from "../get-english-word";
|
||||||
import { psStringFromEntry } from "../p-text-helpers";
|
import { psStringFromEntry } from "../p-text-helpers";
|
||||||
import { personGender, personIsPlural } from "../../library";
|
|
||||||
import { isLocativeAdverbEntry } from "../type-predicates";
|
import { isLocativeAdverbEntry } from "../type-predicates";
|
||||||
import { renderAdjectiveSelection } from "./render-adj";
|
import { renderAdjectiveSelection } from "./render-adj";
|
||||||
|
|
||||||
export function renderEP(EP: T.EPSelectionComplete): T.EPRendered {
|
export function renderEP(EP: T.EPSelectionComplete): T.EPRendered {
|
||||||
const kingPerson = (EP.subject.type === "pronoun")
|
const king = (EP.subject.type === "pronoun")
|
||||||
|
? "subject"
|
||||||
|
: EP.predicate.type === "NP"
|
||||||
|
? "predicate"
|
||||||
|
: "subject";
|
||||||
|
// TODO: less repetative logic
|
||||||
|
const kingPerson = king === "subject"
|
||||||
? getPersonFromNP(EP.subject)
|
? getPersonFromNP(EP.subject)
|
||||||
: EP.predicate.type === "NP"
|
: EP.predicate.type === "NP"
|
||||||
? getPersonFromNP(EP.predicate.selection)
|
? getPersonFromNP(EP.predicate.selection)
|
||||||
|
@ -21,12 +26,13 @@ export function renderEP(EP: T.EPSelectionComplete): T.EPRendered {
|
||||||
return {
|
return {
|
||||||
type: "EPRendered",
|
type: "EPRendered",
|
||||||
king: EP.predicate.type === "Complement" ? "subject" : "predicate",
|
king: EP.predicate.type === "Complement" ? "subject" : "predicate",
|
||||||
subject: renderNPSelection(EP.subject, false, false, "subject"),
|
subject: renderNPSelection(EP.subject, false, false, "subject", king === "subject" ? "king" : "none"),
|
||||||
predicate: EP.predicate.type === "NP"
|
predicate: EP.predicate.type === "NP"
|
||||||
? renderNPSelection(EP.predicate.selection, false, true, "subject")
|
? renderNPSelection(EP.predicate.selection, false, true, "subject", "king")
|
||||||
: renderEqCompSelection(EP.predicate.selection, kingPerson),
|
: renderEqCompSelection(EP.predicate.selection, kingPerson),
|
||||||
equative: renderEquative(EP.equative, kingPerson),
|
equative: renderEquative(EP.equative, kingPerson),
|
||||||
englishBase: equativeBuilders[EP.equative.tense](kingPerson, EP.equative.negative),
|
englishBase: equativeBuilders[EP.equative.tense](kingPerson, EP.equative.negative),
|
||||||
|
shrunkenPossesive: EP.shrunkenPossesive,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,10 +74,11 @@ function renderEqCompSelection(s: T.EqCompSelection, person: T.Person): T.Render
|
||||||
e,
|
e,
|
||||||
inflected: false,
|
inflected: false,
|
||||||
person,
|
person,
|
||||||
|
role: "none",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (s.type === "adjective") {
|
if (s.type === "adjective") {
|
||||||
return renderAdjectiveSelection(s, person, false)
|
return renderAdjectiveSelection(s, person, false, "none")
|
||||||
}
|
}
|
||||||
throw new Error("invalid EqCompSelection");
|
throw new Error("invalid EqCompSelection");
|
||||||
}
|
}
|
||||||
|
@ -136,9 +143,9 @@ function getEnglishConj(p: T.Person, e: string | T.EnglishBlock): string {
|
||||||
return e[row][col];
|
return e[row][col];
|
||||||
}
|
}
|
||||||
|
|
||||||
function chooseInflection(inflections: T.UnisexSet<T.InflectionSet>, pers: T.Person): T.ArrayOneOrMore<T.PsString> {
|
// function chooseInflection(inflections: T.UnisexSet<T.InflectionSet>, pers: T.Person): T.ArrayOneOrMore<T.PsString> {
|
||||||
const gender = personGender(pers);
|
// const gender = personGender(pers);
|
||||||
const plural = personIsPlural(pers);
|
// const plural = personIsPlural(pers);
|
||||||
return inflections[gender][plural ? 1 : 0];
|
// return inflections[gender][plural ? 1 : 0];
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,11 @@ import {
|
||||||
import { parseEc } from "../misc-helpers";
|
import { parseEc } from "../misc-helpers";
|
||||||
import { getEnglishWord } from "../get-english-word";
|
import { getEnglishWord } from "../get-english-word";
|
||||||
import { renderAdjectiveSelection } from "./render-adj";
|
import { renderAdjectiveSelection } from "./render-adj";
|
||||||
|
import { isPattern5Entry, isUnisexNounEntry } from "../type-predicates";
|
||||||
|
|
||||||
export function renderNPSelection(NP: T.NPSelection, inflected: boolean, inflectEnglish: boolean, role: "subject"): T.Rendered<T.NPSelection>
|
export function renderNPSelection(NP: T.NPSelection, inflected: boolean, inflectEnglish: boolean, role: "subject", soRole: "servant" | "king" | "none"): T.Rendered<T.NPSelection>;
|
||||||
export function renderNPSelection(NP: T.NPSelection | T.ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "object"): T.Rendered<T.NPSelection> | T.Person.ThirdPlurMale | "none";
|
export function renderNPSelection(NP: T.NPSelection | T.ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "object", soRole: "servant" | "king" | "none"): T.Rendered<T.NPSelection> | T.Person.ThirdPlurMale | "none";
|
||||||
export function renderNPSelection(NP: T.NPSelection | T.ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "subject" | "object"): T.Rendered<T.NPSelection> | T.Person.ThirdPlurMale | "none" {
|
export function renderNPSelection(NP: T.NPSelection | T.ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "subject" | "object", soRole: "servant" | "king" | "none"): T.Rendered<T.NPSelection> | T.Person.ThirdPlurMale | "none" {
|
||||||
if (typeof NP !== "object") {
|
if (typeof NP !== "object") {
|
||||||
if (role !== "object") {
|
if (role !== "object") {
|
||||||
throw new Error("ObjectNP only allowed for objects");
|
throw new Error("ObjectNP only allowed for objects");
|
||||||
|
@ -23,18 +24,18 @@ export function renderNPSelection(NP: T.NPSelection | T.ObjectNP, inflected: boo
|
||||||
return NP;
|
return NP;
|
||||||
}
|
}
|
||||||
if (NP.type === "noun") {
|
if (NP.type === "noun") {
|
||||||
return renderNounSelection(NP, inflected);
|
return renderNounSelection(NP, inflected, soRole);
|
||||||
}
|
}
|
||||||
if (NP.type === "pronoun") {
|
if (NP.type === "pronoun") {
|
||||||
return renderPronounSelection(NP, inflected, inflectEnglish);
|
return renderPronounSelection(NP, inflected, inflectEnglish, soRole);
|
||||||
}
|
}
|
||||||
if (NP.type === "participle") {
|
if (NP.type === "participle") {
|
||||||
return renderParticipleSelection(NP, inflected)
|
return renderParticipleSelection(NP, inflected, soRole)
|
||||||
}
|
}
|
||||||
throw new Error("unknown NP type");
|
throw new Error("unknown NP type");
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderNounSelection(n: T.NounSelection, inflected: boolean): T.Rendered<T.NounSelection> {
|
function renderNounSelection(n: T.NounSelection, inflected: boolean, role: "servant" | "king" | "none"): T.Rendered<T.NounSelection> {
|
||||||
const english = getEnglishFromNoun(n.entry, n.number);
|
const english = getEnglishFromNoun(n.entry, n.number);
|
||||||
const pashto = ((): T.PsString[] => {
|
const pashto = ((): T.PsString[] => {
|
||||||
const infs = inflectWord(n.entry);
|
const infs = inflectWord(n.entry);
|
||||||
|
@ -52,32 +53,51 @@ function renderNounSelection(n: T.NounSelection, inflected: boolean): T.Rendered
|
||||||
const person = getPersonNumber(n.gender, n.number);
|
const person = getPersonNumber(n.gender, n.number);
|
||||||
return {
|
return {
|
||||||
...n,
|
...n,
|
||||||
adjectives: n.adjectives.map(a => renderAdjectiveSelection(a, person, inflected)),
|
adjectives: n.adjectives.map(a => renderAdjectiveSelection(a, person, inflected, role)),
|
||||||
person,
|
person,
|
||||||
inflected,
|
inflected,
|
||||||
|
role,
|
||||||
ps: pashto,
|
ps: pashto,
|
||||||
e: english,
|
e: english,
|
||||||
|
possesor: renderPossesor(n.possesor, role),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPronounSelection(p: T.PronounSelection, inflected: boolean, englishInflected: boolean): T.Rendered<T.PronounSelection> {
|
function renderPronounSelection(p: T.PronounSelection, inflected: boolean, englishInflected: boolean, role: "servant" | "king" | "none"): T.Rendered<T.PronounSelection> {
|
||||||
const [row, col] = getVerbBlockPosFromPerson(p.person);
|
const [row, col] = getVerbBlockPosFromPerson(p.person);
|
||||||
return {
|
return {
|
||||||
...p,
|
...p,
|
||||||
inflected,
|
inflected,
|
||||||
|
role,
|
||||||
ps: grammarUnits.pronouns[p.distance][inflected ? "inflected" : "plain"][row][col],
|
ps: grammarUnits.pronouns[p.distance][inflected ? "inflected" : "plain"][row][col],
|
||||||
e: grammarUnits.persons[p.person].label[englishInflected ? "object" : "subject"],
|
e: grammarUnits.persons[p.person].label[englishInflected ? "object" : "subject"],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderParticipleSelection(p: T.ParticipleSelection, inflected: boolean): T.Rendered<T.ParticipleSelection> {
|
function renderParticipleSelection(p: T.ParticipleSelection, inflected: boolean, role: "servant" | "king" | "none"): T.Rendered<T.ParticipleSelection> {
|
||||||
return {
|
return {
|
||||||
...p,
|
...p,
|
||||||
inflected,
|
inflected,
|
||||||
|
role,
|
||||||
person: T.Person.ThirdPlurMale,
|
person: T.Person.ThirdPlurMale,
|
||||||
// TODO: More robust inflection of inflecting pariticiples - get from the conjugation engine
|
// TODO: More robust inflection of inflecting pariticiples - get from the conjugation engine
|
||||||
ps: [psStringFromEntry(p.verb.entry)].map(ps => inflected ? concatPsString(ps, { p: "و", f: "o" }) : ps),
|
ps: [psStringFromEntry(p.verb.entry)].map(ps => inflected ? concatPsString(ps, { p: "و", f: "o" }) : ps),
|
||||||
e: getEnglishParticiple(p.verb.entry),
|
e: getEnglishParticiple(p.verb.entry),
|
||||||
|
possesor: renderPossesor(p.possesor, role),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPossesor(possesor: { np: T.NPSelection, uid: number } | undefined, possesorRole: "servant" | "king" | "none"): { np: T.Rendered<T.NPSelection>, uid: number } | undefined {
|
||||||
|
if (!possesor) return undefined;
|
||||||
|
return {
|
||||||
|
uid: possesor.uid,
|
||||||
|
np: renderNPSelection(
|
||||||
|
possesor.np,
|
||||||
|
!(possesor.np.type === "noun" && isUnisexNounEntry(possesor.np.entry) && isPattern5Entry(possesor.np.entry)),
|
||||||
|
false,
|
||||||
|
"subject",
|
||||||
|
possesorRole,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,11 +47,12 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
|
||||||
type: "VPRendered",
|
type: "VPRendered",
|
||||||
king,
|
king,
|
||||||
servant,
|
servant,
|
||||||
|
shrunkenPossesive: VP.shrunkenPossesive,
|
||||||
isPast,
|
isPast,
|
||||||
isTransitive,
|
isTransitive,
|
||||||
isCompound: VP.verb.isCompound,
|
isCompound: VP.verb.isCompound,
|
||||||
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
|
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject", king === "subject" ? "king" : "servant"),
|
||||||
object: renderNPSelection(VP.verb.object, inflectObject, true, "object"),
|
object: renderNPSelection(VP.verb.object, inflectObject, true, "object", king === "object" ? "king" : "servant"),
|
||||||
verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),
|
verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),
|
||||||
englishBase: renderEnglishVPBase({
|
englishBase: renderEnglishVPBase({
|
||||||
subjectPerson,
|
subjectPerson,
|
||||||
|
|
|
@ -12,7 +12,7 @@ type SegmentDescriptions = {
|
||||||
isVerbHead?: boolean,
|
isVerbHead?: boolean,
|
||||||
isOoOrWaaHead?: boolean,
|
isOoOrWaaHead?: boolean,
|
||||||
isVerbRest?: boolean,
|
isVerbRest?: boolean,
|
||||||
isMiniPronoun?: boolean,
|
isMiniPronoun?: number,
|
||||||
isKid?: boolean,
|
isKid?: boolean,
|
||||||
// TODO: Simplify to just isKidAfterHead?
|
// TODO: Simplify to just isKidAfterHead?
|
||||||
isKidBetweenHeadAndRest?: boolean,
|
isKidBetweenHeadAndRest?: boolean,
|
||||||
|
@ -25,28 +25,23 @@ export type Segment = { ps: T.PsString[] } & SegmentDescriptions & {
|
||||||
adjust: (o: { ps?: T.PsString | T.PsString[] | ((ps: T.PsString) => T.PsString), desc?: SDT[] }) => Segment,
|
adjust: (o: { ps?: T.PsString | T.PsString[] | ((ps: T.PsString) => T.PsString), desc?: SDT[] }) => Segment,
|
||||||
};
|
};
|
||||||
|
|
||||||
function addAdjectives(ps: T.PsString[], adjectives?: T.Rendered<T.AdjectiveSelection>[]): T.PsString[] {
|
|
||||||
if (!adjectives) return ps;
|
|
||||||
return ps.map(p => {
|
|
||||||
// TODO: more thorough use of all possible variends?
|
|
||||||
return concatPsString(...adjectives.map(a => a.ps[0]), p);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function makeSegment(
|
export function makeSegment(
|
||||||
input: T.Rendered<T.NounSelection> | T.PsString | T.PsString[],
|
input: T.PsString | T.PsString[],
|
||||||
options?: (keyof SegmentDescriptions)[],
|
options?: (keyof SegmentDescriptions | 1 | 2 | 3)[],
|
||||||
): Segment {
|
): Segment {
|
||||||
const ps: T.PsString[] = Array.isArray(input)
|
const ps: T.PsString[] = Array.isArray(input)
|
||||||
? input
|
? input
|
||||||
: "type" in input
|
|
||||||
? addAdjectives(input.ps, input.adjectives)
|
|
||||||
: [input];
|
: [input];
|
||||||
return {
|
return {
|
||||||
ps: Array.isArray(ps) ? ps : [ps],
|
ps: Array.isArray(ps) ? ps : [ps],
|
||||||
...options && options.reduce((all, curr) => ({
|
...options && options.reduce((all, curr) => ({
|
||||||
...all,
|
...all,
|
||||||
|
...typeof curr === "number" ? {
|
||||||
|
isMiniPronoun: curr,
|
||||||
|
} : {
|
||||||
[curr]: true,
|
[curr]: true,
|
||||||
|
},
|
||||||
}), {}),
|
}), {}),
|
||||||
adjust: function(o): Segment {
|
adjust: function(o): Segment {
|
||||||
return {
|
return {
|
||||||
|
|
19
src/types.ts
19
src/types.ts
|
@ -501,6 +501,7 @@ export type VPRendered = {
|
||||||
type: "VPRendered",
|
type: "VPRendered",
|
||||||
king: "subject" | "object",
|
king: "subject" | "object",
|
||||||
servant: "subject" | "object" | undefined,
|
servant: "subject" | "object" | undefined,
|
||||||
|
shrunkenPossesive: number | undefined,
|
||||||
isPast: boolean,
|
isPast: boolean,
|
||||||
isTransitive: boolean,
|
isTransitive: boolean,
|
||||||
isCompound: "stative" | "dynamic" | false,
|
isCompound: "stative" | "dynamic" | false,
|
||||||
|
@ -529,11 +530,13 @@ export type Tense = EquativeTense | VerbTense | PerfectTense | ModalTense | Impe
|
||||||
export type VPSelectionState = {
|
export type VPSelectionState = {
|
||||||
subject: NPSelection | undefined,
|
subject: NPSelection | undefined,
|
||||||
verb: VerbSelection,
|
verb: VerbSelection,
|
||||||
|
shrunkenPossesive: undefined | number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type VPSelectionComplete = {
|
export type VPSelectionComplete = {
|
||||||
subject: NPSelection,
|
subject: NPSelection,
|
||||||
verb: VerbSelectionComplete,
|
verb: VerbSelectionComplete,
|
||||||
|
shrunkenPossesive: undefined | number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type VerbSelectionComplete = Omit<VerbSelection, "object" | "verbTense" | "perfectTense" | "imperfectiveTense" | "tenseCategory"> & {
|
export type VerbSelectionComplete = Omit<VerbSelection, "object" | "verbTense" | "perfectTense" | "imperfectiveTense" | "tenseCategory"> & {
|
||||||
|
@ -587,6 +590,11 @@ export type NPType = "noun" | "pronoun" | "participle";
|
||||||
|
|
||||||
export type ObjectNP = "none" | Person.ThirdPlurMale;
|
export type ObjectNP = "none" | Person.ThirdPlurMale;
|
||||||
|
|
||||||
|
export type PossesorSelection = {
|
||||||
|
uid: number,
|
||||||
|
np: NPSelection,
|
||||||
|
}
|
||||||
|
|
||||||
// TODO require/import Person and PsString
|
// TODO require/import Person and PsString
|
||||||
export type NounSelection = {
|
export type NounSelection = {
|
||||||
type: "noun",
|
type: "noun",
|
||||||
|
@ -597,6 +605,7 @@ export type NounSelection = {
|
||||||
numberCanChange: boolean,
|
numberCanChange: boolean,
|
||||||
dynamicComplement?: boolean,
|
dynamicComplement?: boolean,
|
||||||
adjectives: AdjectiveSelection[],
|
adjectives: AdjectiveSelection[],
|
||||||
|
possesor: undefined | PossesorSelection,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AdjectiveSelection = {
|
export type AdjectiveSelection = {
|
||||||
|
@ -619,6 +628,7 @@ export type PronounSelection = {
|
||||||
export type ParticipleSelection = {
|
export type ParticipleSelection = {
|
||||||
type: "participle",
|
type: "participle",
|
||||||
verb: VerbEntry,
|
verb: VerbEntry,
|
||||||
|
possesor: undefined | PossesorSelection,
|
||||||
};
|
};
|
||||||
|
|
||||||
// not object
|
// not object
|
||||||
|
@ -629,7 +639,7 @@ export type ReplaceKey<T, K extends string, R> = T extends Record<K, unknown> ?
|
||||||
export type FormVersion = { removeKing: boolean, shrinkServant: boolean };
|
export type FormVersion = { removeKing: boolean, shrinkServant: boolean };
|
||||||
|
|
||||||
export type Rendered<T extends NPSelection | EqCompSelection | AdjectiveSelection> = ReplaceKey<
|
export type Rendered<T extends NPSelection | EqCompSelection | AdjectiveSelection> = ReplaceKey<
|
||||||
Omit<T, "changeGender" | "changeNumber" | "changeDistance" | "adjectives">,
|
Omit<T, "changeGender" | "changeNumber" | "changeDistance" | "adjectives" | "possesor">,
|
||||||
"e",
|
"e",
|
||||||
string
|
string
|
||||||
> & {
|
> & {
|
||||||
|
@ -637,8 +647,13 @@ export type Rendered<T extends NPSelection | EqCompSelection | AdjectiveSelectio
|
||||||
e?: string,
|
e?: string,
|
||||||
inflected: boolean,
|
inflected: boolean,
|
||||||
person: Person,
|
person: Person,
|
||||||
|
role: "king" | "servant" | "none",
|
||||||
// TODO: better recursive thing
|
// TODO: better recursive thing
|
||||||
adjectives?: Rendered<AdjectiveSelection>[],
|
adjectives?: Rendered<AdjectiveSelection>[],
|
||||||
|
possesor?: {
|
||||||
|
uid: number,
|
||||||
|
np: Rendered<NPSelection>,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
// TODO: recursive changing this down into the possesor etc.
|
// TODO: recursive changing this down into the possesor etc.
|
||||||
|
|
||||||
|
@ -650,6 +665,7 @@ export type EPSelectionState = {
|
||||||
Complement: EqCompSelection | undefined,
|
Complement: EqCompSelection | undefined,
|
||||||
},
|
},
|
||||||
equative: EquativeSelection,
|
equative: EquativeSelection,
|
||||||
|
shrunkenPossesive: undefined | number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EPSelectionComplete = Omit<EPSelectionState, "subject" | "predicate"> & {
|
export type EPSelectionComplete = Omit<EPSelectionState, "subject" | "predicate"> & {
|
||||||
|
@ -684,6 +700,7 @@ export type EPRendered = {
|
||||||
predicate: Rendered<NPSelection | EqCompSelection>,
|
predicate: Rendered<NPSelection | EqCompSelection>,
|
||||||
equative: EquativeRendered,
|
equative: EquativeRendered,
|
||||||
englishBase?: string[],
|
englishBase?: string[],
|
||||||
|
shrunkenPossesive: undefined | number,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EntryFeeder = {
|
export type EntryFeeder = {
|
||||||
|
|
Loading…
Reference in New Issue