include imperative

This commit is contained in:
lingdocs 2022-04-20 19:05:15 +05:00
parent 875237439b
commit 10532cb3bb
19 changed files with 310 additions and 102 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@lingdocs/pashto-inflector", "name": "@lingdocs/pashto-inflector",
"version": "2.1.2", "version": "2.1.3",
"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",

View File

@ -69,7 +69,6 @@ function App() {
}, [theme]) }, [theme])
const handleVerbIndexChange = (e: any) => { const handleVerbIndexChange = (e: any) => {
console.log("changing to", e.target.value);
setVerbTs(parseInt(e.target.value)); setVerbTs(parseInt(e.target.value));
} }
const handleTypeSelection = (e: any) => { const handleTypeSelection = (e: any) => {

View File

@ -14,7 +14,6 @@ type PsStringWSub = T.PsString & { sub?: any };
function EnglishContent({ children }: { children: (string | JSX.Element)[] | (string | JSX.Element) }) { function EnglishContent({ children }: { children: (string | JSX.Element)[] | (string | JSX.Element) }) {
if (Array.isArray(children)) { if (Array.isArray(children)) {
console.log(children);
return <> return <>
{children.map((x) => <EnglishContent>{x}</EnglishContent>)} {children.map((x) => <EnglishContent>{x}</EnglishContent>)}
</> </>

View File

@ -40,7 +40,7 @@ function agreementInfo(info: T.NonComboVerbInfo, displayForm: T.DisplayForm): Re
} }
function VerbFormDisplay({ displayForm, textOptions, info, showingFormInfo, english, shortDefault }: { function VerbFormDisplay({ displayForm, textOptions, info, showingFormInfo, english, shortDefault }: {
displayForm: T.DisplayForm | T.VerbForm, displayForm: T.DisplayForm | T.VerbForm | T.ImperativeForm,
english?: T.EnglishBlock | string, english?: T.EnglishBlock | string,
textOptions: T.TextOptions, textOptions: T.TextOptions,
showingFormInfo: boolean, showingFormInfo: boolean,

View File

@ -8,6 +8,7 @@ import {
} from "../../lib/np-tools"; } from "../../lib/np-tools";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import * as T from "../../types"; import * as T from "../../types";
import { isSecondPerson } from "../../lib/phrase-building/vp-tools";
// import { capitalizeFirstLetter } from "../../lib/text-tools"; // import { capitalizeFirstLetter } from "../../lib/text-tools";
const npTypes: T.NPType[] = ["pronoun", "noun", "participle"]; const npTypes: T.NPType[] = ["pronoun", "noun", "participle"];
@ -19,6 +20,7 @@ function NPPicker(props: {
asObject?: boolean, asObject?: boolean,
opts: T.TextOptions, opts: T.TextOptions,
cantClear?: boolean, cantClear?: boolean,
is2ndPersonPicker?: boolean,
} & ({ } & ({
nouns: (s: string) => T.NounEntry[], nouns: (s: string) => T.NounEntry[],
verbs: (s: string) => T.VerbEntry[], verbs: (s: string) => T.VerbEntry[],
@ -28,6 +30,9 @@ function NPPicker(props: {
nouns: T.NounEntry[], nouns: T.NounEntry[],
verbs: T.VerbEntry[], verbs: T.VerbEntry[],
})) { })) {
if (props.is2ndPersonPicker && ((props.np?.type !== "pronoun") || !isSecondPerson(props.np.person))) {
throw new Error("can't use 2ndPerson NPPicker without a pronoun");
}
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);
@ -78,6 +83,7 @@ function NPPicker(props: {
pronoun={props.np} pronoun={props.np}
onChange={props.onChange} onChange={props.onChange}
clearButton={clearButton} clearButton={clearButton}
is2ndPersonPicker={props.is2ndPersonPicker}
opts={props.opts} opts={props.opts}
/> />
: npType === "noun" : npType === "noun"

View File

@ -2,6 +2,9 @@ import * as T from "../../types";
import ButtonSelect from "../ButtonSelect"; import ButtonSelect from "../ButtonSelect";
import useStickyState from "../../lib/useStickyState"; import useStickyState from "../../lib/useStickyState";
import classNames from "classnames"; import classNames from "classnames";
import {
isSecondPerson, isThirdPerson,
} from "../../lib/phrase-building/vp-tools";
const gColors = { const gColors = {
masc: "LightSkyBlue", masc: "LightSkyBlue",
@ -53,15 +56,18 @@ function pickerStateToPerson(s: PickerState): T.Person {
+ (6 * s.col); + (6 * s.col);
} }
function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: { function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts, is2ndPersonPicker }: {
pronoun: T.PronounSelection, pronoun: T.PronounSelection,
onChange: (p: T.PronounSelection) => void, onChange: (p: T.PronounSelection) => void,
asObject?: boolean, asObject?: boolean,
clearButton?: JSX.Element, clearButton?: JSX.Element,
opts: T.TextOptions, opts: T.TextOptions,
is2ndPersonPicker?: boolean,
}) { }) {
if (is2ndPersonPicker && !isSecondPerson(pronoun.person)) {
throw new Error("can't use 2ndPerson NPProunounPicker without a pronoun");
}
const [display, setDisplay] = useStickyState<"persons" | "p" | "e">("e", "prounoun-picker-display"); const [display, setDisplay] = useStickyState<"persons" | "p" | "e">("e", "prounoun-picker-display");
const p = personToPickerState(pronoun.person); const p = personToPickerState(pronoun.person);
function handleClick(row: number, col: number) { function handleClick(row: number, col: number) {
const person = pickerStateToPerson({ ...p, row, col }); const person = pickerStateToPerson({ ...p, row, col });
@ -92,11 +98,14 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: {
setDisplay(newPerson); setDisplay(newPerson);
} }
const prs = labels(!!asObject)[display]; const prs = labels(!!asObject)[display];
const pSpec = "near" in prs ? prs[pronoun.distance] : prs; const pSpecA = "near" in prs ? prs[pronoun.distance] : prs;
const pSpec = is2ndPersonPicker
? [pSpecA[1]]
: pSpecA;
return <div style={{ maxWidth: "145px", padding: 0 }}> return <div style={{ maxWidth: "145px", padding: 0 }}>
{clearButton} {clearButton}
<div className="d-flex flex-row justify-content-around mb-3"> <div className="d-flex flex-row justify-content-between mb-3">
<ButtonSelect {isThirdPerson(pronoun.person) ? <ButtonSelect
xSmall xSmall
options={[ options={[
{ label: "Far", value: "far" }, { label: "Far", value: "far" },
@ -104,7 +113,7 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: {
]} ]}
value={pronoun.distance} value={pronoun.distance}
handleChange={(g) => handlePronounTypeChange(g as "far" | "near")} handleChange={(g) => handlePronounTypeChange(g as "far" | "near")}
/> /> : <div>{` `}</div>}
<button className="btn btn-sm btn-outline-secondary" onClick={handleDisplayChange}> <button className="btn btn-sm btn-outline-secondary" onClick={handleDisplayChange}>
{display === "persons" ? "#" : display === "p" ? "PS" : "EN"} {display === "persons" ? "#" : display === "p" ? "PS" : "EN"}
</button> </button>
@ -114,9 +123,13 @@ function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: {
{pSpec.map((rw, i) => ( {pSpec.map((rw, i) => (
<tr> <tr>
{rw.map((r, j) => { {rw.map((r, j) => {
const active = (p.row === i && p.col === j) const active = is2ndPersonPicker
? (p.col === j)
: (p.row === i && p.col === j);
return <td return <td
onClick={() => handleClick(i, j)} onClick={() => {
handleClick(is2ndPersonPicker ? 1 : i, j);
}}
className={classNames({ "table-active": active, "text-on-gender-color": active })} className={classNames({ "table-active": active, "text-on-gender-color": active })}
style={{ style={{
backgroundColor: active ? gColors[p.gender] : "inherit", backgroundColor: active ? gColors[p.gender] : "inherit",

View File

@ -16,7 +16,7 @@ function ChartDisplay({ VS, opts }: { VS: T.VerbSelection, opts: T.TextOptions }
: ("transitive" in rawConjugations) : ("transitive" in rawConjugations)
? rawConjugations[VS.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"] ? rawConjugations[VS.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
: rawConjugations; : rawConjugations;
const form = getTenseVerbForm(conjugations, getTenseFromVerbSelection(VS), VS.voice); const form = getTenseVerbForm(conjugations, getTenseFromVerbSelection(VS), VS.voice, VS.negative);
return <div className="mb-4"> return <div className="mb-4">
<VerbFormDisplay <VerbFormDisplay
displayForm={form} displayForm={form}

View File

@ -4,7 +4,8 @@ import {
} from "../np-picker/picker-tools"; } from "../np-picker/picker-tools";
import * as T from "../../types"; import * as T from "../../types";
import ButtonSelect from "../ButtonSelect"; import ButtonSelect from "../ButtonSelect";
import { isModalTense, isPerfectTense, isVerbTense } from "../../lib/type-predicates"; import { isImperativeTense, isModalTense, isPerfectTense, isVerbTense } from "../../lib/type-predicates";
import { ensure2ndPersSubjPronounAndNoConflict } from "../../lib/phrase-building/vp-tools";
const verbTenseOptions: { label: string | JSX.Element, value: T.VerbTense }[] = [{ const verbTenseOptions: { label: string | JSX.Element, value: T.VerbTense }[] = [{
label: <div><i className="fas fa-video mr-2" />present</div>, label: <div><i className="fas fa-video mr-2" />present</div>,
@ -55,8 +56,16 @@ const perfectTenseOptions: { label: string | JSX.Element, value: T.PerfectTense
value: "pastSubjunctivePerfect", value: "pastSubjunctivePerfect",
}]; }];
export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense): T.PerfectTense | T.VerbTense | T.ModalTense { const imperativeTenseOptions: { label: string | JSX.Element, value: T.ImperativeTense }[] = [{
let tns: T.PerfectTense | T.VerbTense | T.ModalTense; label: <div><i className="fas fa-video mr-2" />imperfective imp.</div>,
value: "imperfectiveImperative",
}, {
label: <div><i className="fas fa-camera mr-2" />perfective imp.</div>,
value: "perfectiveImperative",
}];
export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense): T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense {
let tns: T.PerfectTense | T.VerbTense | T.ModalTense | T.ImperativeTense;
const oldTenseCategory = !o const oldTenseCategory = !o
? undefined ? undefined
: getTenseCategory(o); : getTenseCategory(o);
@ -64,6 +73,8 @@ export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense):
? perfectTenseOptions ? perfectTenseOptions
: oldTenseCategory === "modal" : oldTenseCategory === "modal"
? verbTenseOptions.map(x => ({ ...x, value: `${x.value}Modal` as T.ModalTense })) ? verbTenseOptions.map(x => ({ ...x, value: `${x.value}Modal` as T.ModalTense }))
: oldTenseCategory === "imperative"
? imperativeTenseOptions
: verbTenseOptions; : verbTenseOptions;
do { do {
tns = tenseOptions[ tns = tenseOptions[
@ -81,7 +92,7 @@ function TensePicker(props: ({
onChange: (p: T.VPSelection) => void, onChange: (p: T.VPSelection) => void,
mode: "charts" | "phrases" | "quiz", mode: "charts" | "phrases" | "quiz",
}) { }) {
function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense } | null) { function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense | T.ImperativeTense } | null) {
if ("vpsComplete" in props) return; if ("vpsComplete" in props) return;
const value = o?.value ? o.value : undefined; const value = o?.value ? o.value : undefined;
if (props.vps.verb && value) { if (props.vps.verb && value) {
@ -94,6 +105,15 @@ function TensePicker(props: ({
tenseCategory: "perfect", tenseCategory: "perfect",
}, },
}); });
} else if (isImperativeTense(value)) {
props.onChange({
...props.vps,
verb: {
...props.vps.verb,
imperativeTense: value,
tenseCategory: "imperative",
},
});
} else { } else {
props.onChange({ props.onChange({
...props.vps, ...props.vps,
@ -112,9 +132,19 @@ function TensePicker(props: ({
if ("vpsComplete" in props) return; if ("vpsComplete" in props) return;
if (!props.vps.verb) return; if (!props.vps.verb) return;
return () => { return () => {
const tenses = props.vps.verb.tenseCategory === "perfect" ? perfectTenseOptions : verbTenseOptions; // TODO: ABSTRACT THIS - SAFER
const tenses = props.vps.verb.tenseCategory === "perfect"
? perfectTenseOptions
: props.vps.verb.tenseCategory === "imperative"
? imperativeTenseOptions
: verbTenseOptions;
const currIndex = tenses.findIndex(tn => tn.value === props.vps.verb[ const currIndex = tenses.findIndex(tn => tn.value === props.vps.verb[
props.vps.verb.tenseCategory === "perfect" ? "perfectTense" : "verbTense" // TODO: ABSTRACT THIS? - SAFER
props.vps.verb.tenseCategory === "perfect"
? "perfectTense"
: props.vps.verb.tenseCategory === "imperative"
? "imperativeTense"
: "verbTense"
]); ]);
if (currIndex === -1) { if (currIndex === -1) {
console.error("error moving tense", dir); console.error("error moving tense", dir);
@ -139,9 +169,19 @@ function TensePicker(props: ({
}); });
} }
} }
function onTenseCategorySelect(value: "basic" | "modal" | "perfect") { function onTenseCategorySelect(value: "basic" | "modal" | "perfect" | "imperative") {
if ("vpsComplete" in props) return; if ("vpsComplete" in props) return;
if (props.vps.verb) { if (props.vps.verb) {
if (value === "imperative") {
props.onChange(ensure2ndPersSubjPronounAndNoConflict({
...props.vps,
verb: {
...props.vps.verb,
tenseCategory: value,
},
}));
return;
}
props.onChange({ props.onChange({
...props.vps, ...props.vps,
verb: { verb: {
@ -153,40 +193,47 @@ function TensePicker(props: ({
} }
const tOptions = ("vps" in props && (props.vps.verb?.tenseCategory === "perfect")) const tOptions = ("vps" in props && (props.vps.verb?.tenseCategory === "perfect"))
? perfectTenseOptions ? perfectTenseOptions
: ("vps" in props && (props.vps.verb?.tenseCategory === "imperative"))
? imperativeTenseOptions
: verbTenseOptions; : verbTenseOptions;
return <div> return <div>
<div style={{ maxWidth: "300px", minWidth: "250px", margin: "0 auto" }}> <div style={{ maxWidth: "300px", minWidth: "250px", margin: "0 auto" }}>
<div className="d-flex flex-row justify-content-between align-items-center"> <div className="h5">Tense:</div>
<div className="h5">Tense:</div> {("vpsComplete" in props || props.vps.verb) && <div className="mb-2">
{("vpsComplete" in props || props.vps.verb) && <div className="mb-2"> <ButtonSelect
<ButtonSelect small
small value={"vpsComplete" in props
value={"vpsComplete" in props ? getTenseCategory(props.vpsComplete.verb.tense)
? getTenseCategory(props.vpsComplete.verb.tense) : props.vps.verb.tenseCategory}
: props.vps.verb.tenseCategory} options={[{
options={[{ label: "Basic",
label: "Basic", value: "basic",
value: "basic", }, {
}, { label: "Perfect",
label: "Perfect", value: "perfect",
value: "perfect", }, {
}, { label: "Modal",
label: "Modal", value: "modal",
value: "modal", }, {
}]} label: "Imperative",
handleChange={props.mode !== "quiz" ? onTenseCategorySelect : () => null} value: "imperative",
/> }]}
</div>} handleChange={props.mode !== "quiz" ? onTenseCategorySelect : () => null}
</div> />
</div>}
{"vpsComplete" in props {"vpsComplete" in props
? <div style={{ fontSize: "larger" }} className="mb-3"> ? <div style={{ fontSize: "larger" }} className="mb-3">
{[...verbTenseOptions, ...perfectTenseOptions].find(o => o.value === props.vpsComplete.verb.tense)?.label} {[...verbTenseOptions, ...perfectTenseOptions, ...imperativeTenseOptions].find(o => o.value === props.vpsComplete.verb.tense)?.label}
</div> </div>
: <Select : <Select
isSearchable={false} isSearchable={false}
// for some reason can't use tOptions with find here; // for some reason can't use tOptions with find here;
value={props.vps.verb && ([...verbTenseOptions, ...perfectTenseOptions].find(o => o.value === props.vps.verb[ value={props.vps.verb && ([...verbTenseOptions, ...perfectTenseOptions, ...imperativeTenseOptions].find(o => o.value === props.vps.verb[
props.vps.verb.tenseCategory === "perfect" ? "perfectTense" : "verbTense" props.vps.verb.tenseCategory === "perfect"
? "perfectTense"
: props.vps.verb.tenseCategory === "imperative"
? "imperativeTense"
: "verbTense"
]))} ]))}
onChange={onTenseSelect} onChange={onTenseSelect}
className="mb-2" className="mb-2"
@ -219,7 +266,7 @@ function TensePicker(props: ({
export default TensePicker; export default TensePicker;
function getTenseCategory(tense: T.VerbTense | T.PerfectTense | T.ModalTense): "basic" | "perfect" | "modal" { function getTenseCategory(tense: T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense): "basic" | "perfect" | "modal" | "imperative" {
if (isPerfectTense(tense)) { if (isPerfectTense(tense)) {
return "perfect"; return "perfect";
} }
@ -229,5 +276,8 @@ function getTenseCategory(tense: T.VerbTense | T.PerfectTense | T.ModalTense): "
if (isModalTense(tense)) { if (isModalTense(tense)) {
return "modal"; return "modal";
} }
if (isImperativeTense(tense)) {
return "imperative";
}
throw new Error("can't catagorize tense"); throw new Error("can't catagorize tense");
} }

View File

@ -17,6 +17,10 @@ import VPExplorerQuiz from "./VPExplorerQuiz";
import { switchSubjObj } from "../../lib/phrase-building/vp-tools"; import { switchSubjObj } from "../../lib/phrase-building/vp-tools";
import VPExplorerExplanationModal, { roleIcon } from "./VPExplorerExplanationModal"; import VPExplorerExplanationModal, { roleIcon } from "./VPExplorerExplanationModal";
// TO FINISH IMPERATIVE STUFF!!
// TODO: English Builders for imperatives
// TODO: Quiz with imperatives
// TODO: make answerFeedback emojis appear at random translate angles a little bit // TODO: make answerFeedback emojis appear at random translate angles a little bit
// add energy drinks? // add energy drinks?
@ -48,7 +52,7 @@ export function VPExplorer(props: {
})) { })) {
const [vps, setVps] = useStickyState<T.VPSelection>( const [vps, setVps] = useStickyState<T.VPSelection>(
savedVps => makeVPSelectionState(props.verb, savedVps), savedVps => makeVPSelectionState(props.verb, savedVps),
"vpsState2", "vpsState5",
); );
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">( const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
savedMode => { savedMode => {
@ -129,10 +133,16 @@ export function VPExplorer(props: {
{ label: "Phrases", value: "phrases" }, { label: "Phrases", value: "phrases" },
{ label: "Quiz", value: "quiz" }, { label: "Quiz", value: "quiz" },
]} ]}
handleChange={setMode} handleChange={(x) => {
// TODO: remove this and implement the imperative in quiz
// if (x === "quiz") {
// }
setMode(x);
}}
/> />
</div> </div>
{(vps.verb && (typeof vps.verb.object === "object") && (vps.verb.isCompound !== "dynamic") && (mode === "phrases")) && {(vps.verb && (typeof vps.verb.object === "object") && (vps.verb.isCompound !== "dynamic") && (vps.verb.tenseCategory !== "imperative") &&(mode === "phrases")) &&
<div className="text-center mt-4"> <div className="text-center mt-4">
<button onClick={handleSubjObjSwap} className="btn btn-sm btn-light"> <button onClick={handleSubjObjSwap} className="btn btn-sm btn-light">
<i className="fas fa-exchange-alt mr-2" /> subj/obj <i className="fas fa-exchange-alt mr-2" /> subj/obj
@ -154,6 +164,7 @@ export function VPExplorer(props: {
nouns: props.nouns, nouns: props.nouns,
verbs: props.verbs, verbs: props.verbs,
}} }}
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}

View File

@ -16,6 +16,7 @@ import Keyframes from "../Keyframes";
import energyDrink from "./energy-drink.jpg"; import energyDrink from "./energy-drink.jpg";
import { flattenLengths } from "../../lib/phrase-building/compile-vp"; import { flattenLengths } from "../../lib/phrase-building/compile-vp";
import { concatPsString } from "../../lib/p-text-helpers"; import { concatPsString } from "../../lib/p-text-helpers";
import { isImperativeTense } from "../../lib/type-predicates";
const correctEmoji = ["✅", '🤓', "✅", '😊', "🌹", "✅", "✅", '🥳', "👏", "✅", "💯", "😎", "✅", "👍"]; const correctEmoji = ["✅", '🤓', "✅", '😊', "🌹", "✅", "✅", '🥳', "👏", "✅", "💯", "😎", "✅", "👍"];
@ -384,6 +385,7 @@ function completeVPs(vps: T.VPSelection): T.VPSelectionComplete {
obj: oldObj, obj: oldObj,
} }
); );
const t = getTenseFromVerbSelection(vps.verb);
const verb: T.VerbSelectionComplete = { const verb: T.VerbSelectionComplete = {
...vps.verb, ...vps.verb,
object: ( object: (
@ -397,7 +399,7 @@ function completeVPs(vps: T.VPSelection): T.VPSelectionComplete {
person: obj, person: obj,
} }
: vps.verb.object, : vps.verb.object,
tense: getTenseFromVerbSelection(vps.verb), tense: isImperativeTense(t) ? "presentVerb" : t,
}; };
return { return {
...vps, ...vps,

View File

@ -53,6 +53,7 @@ export function makeVPSelectionState(
dynAuxVerb, dynAuxVerb,
verbTense: os ? os.verb.verbTense : "presentVerb", verbTense: os ? os.verb.verbTense : "presentVerb",
perfectTense: os ? os.verb.perfectTense : "presentPerfect", perfectTense: os ? os.verb.perfectTense : "presentPerfect",
imperativeTense: os ? os.verb.imperativeTense : "imperfectiveImperative",
tenseCategory: os ? os.verb.tenseCategory : "basic", tenseCategory: os ? os.verb.tenseCategory : "basic",
object, object,
transitivity, transitivity,

View File

@ -103,6 +103,7 @@ const kedulStatModal: T.ModalContent = {
}; };
const kawulStatOrDynImperfectivePassive: T.AspectContentPassive = { const kawulStatOrDynImperfectivePassive: T.AspectContentPassive = {
imperative: undefined,
nonImperative: [ nonImperative: [
[[{p: "کول کېږم", f: "kawul kéGum"}], [{p: "کول کېږو", f: "kawul kéGoo"}]], [[{p: "کول کېږم", f: "kawul kéGum"}], [{p: "کول کېږو", f: "kawul kéGoo"}]],
[[{p: "کول کېږم", f: "kawul kéGum"}], [{p: "کول کېږو", f: "kawul kéGoo"}]], [[{p: "کول کېږم", f: "kawul kéGum"}], [{p: "کول کېږو", f: "kawul kéGoo"}]],
@ -1303,6 +1304,7 @@ export const kawulStat: T.VerbConjugation = {
passive: { passive: {
imperfective: kawulStatOrDynImperfectivePassive, imperfective: kawulStatOrDynImperfectivePassive,
perfective: { perfective: {
imperative: undefined,
nonImperative: [ nonImperative: [
[[{p: "وکړل شم", f: "óokRul shum"}], [{p: "وکړل شو", f: "óokRul shoo"}]], [[{p: "وکړل شم", f: "óokRul shum"}], [{p: "وکړل شو", f: "óokRul shoo"}]],
[[{p: "وکړل شم", f: "óokRul shum"}], [{p: "وکړل شو", f: "óokRul shoo"}]], [[{p: "وکړل شم", f: "óokRul shum"}], [{p: "وکړل شو", f: "óokRul shoo"}]],
@ -1808,6 +1810,7 @@ export const kawulDyn: T.VerbConjugation = {
passive: { passive: {
imperfective: kawulStatOrDynImperfectivePassive, imperfective: kawulStatOrDynImperfectivePassive,
perfective: { perfective: {
imperative: undefined,
nonImperative: [ nonImperative: [
[[{p: "کړل شم", f: "kRul shum"}], [{p: "کړل شو", f: "kRul shoo"}]], [[{p: "کړل شم", f: "kRul shum"}], [{p: "کړل شو", f: "kRul shoo"}]],
[[{p: "کړل شم", f: "kRul shum"}], [{p: "کړل شو", f: "kRul shoo"}]], [[{p: "کړل شم", f: "kRul shum"}], [{p: "کړل شو", f: "kRul shoo"}]],

View File

@ -12,7 +12,7 @@ import {
removeBa, removeBa,
removeDuplicates, removeDuplicates,
} from "./vp-tools"; } from "./vp-tools";
import { isModalTense, isPerfectTense } from "../type-predicates"; import { isImperativeTense, isModalTense, isPerfectTense } from "../type-predicates";
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 [] };
@ -159,7 +159,9 @@ function arrangeVerbWNegative(head: T.PsString | undefined, restRaw: T.PsString[
headSegment ? [headSegment, rest] : [rest], headSegment ? [headSegment, rest] : [rest],
]; ];
} }
const nu: T.PsString = { p: "نه", f: "nú" }; const nu: T.PsString = isImperativeTense(V.tense)
? { p: "مه", f: "mú" }
: { p: "نه", f: "nú" };
if (!headSegment) { if (!headSegment) {
if ("front" in rest) { if ("front" in rest) {
return [ return [

View File

@ -2,6 +2,7 @@ import * as T from "../../types";
import { getVerbBlockPosFromPerson, parseEc } from "../misc-helpers"; import { getVerbBlockPosFromPerson, parseEc } from "../misc-helpers";
import * as grammarUnits from "../grammar-units"; import * as grammarUnits from "../grammar-units";
import { import {
isImperativeTense,
isPerfectTense, isPerfectTense,
isVerbTense, isVerbTense,
// isModalTense, // isModalTense,
@ -232,11 +233,24 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`, `$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
]), ]),
}; };
const imperativeBuilders: Record<
T.ImperativeTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = {
imperfectiveImperative: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`${n ? "don't " : ""}${ec[0]}`,
]),
perfectiveImperative: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`${n ? "don't " : ""}${ec[0]}`,
]),
};
const base = ( const base = (
isPerfectTense(vs.tense) isPerfectTense(vs.tense)
? (vs.voice === "active" ? perfectBuilders : passivePerfectBuilders)[vs.tense] ? (vs.voice === "active" ? perfectBuilders : passivePerfectBuilders)[vs.tense]
: isVerbTense(vs.tense) : isVerbTense(vs.tense)
? (vs.voice === "active" ? basicBuilders : passiveBasicBuilders)[vs.tense] ? (vs.voice === "active" ? basicBuilders : passiveBasicBuilders)[vs.tense]
: isImperativeTense(vs.tense)
? imperativeBuilders[vs.tense]
: (vs.voice === "active" ? modalBuilders : passiveModalBuilders)[vs.tense])(subjectPerson, ec, vs.negative); : (vs.voice === "active" ? modalBuilders : passiveModalBuilders)[vs.tense])(subjectPerson, ec, vs.negative);
return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`); return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`);
} }

View File

@ -13,6 +13,7 @@ import {
hasBaParticle, hasBaParticle,
psStringFromEntry, psStringFromEntry,
getLong, getLong,
isImperativeBlock,
} from "../p-text-helpers"; } from "../p-text-helpers";
import { removeAccents } from "../accent-helpers"; import { removeAccents } from "../accent-helpers";
import { import {
@ -26,6 +27,7 @@ import {
isPerfectTense, isPerfectTense,
} from "../type-predicates"; } from "../type-predicates";
import { renderEnglishVPBase } from "./english-vp-rendering"; import { renderEnglishVPBase } from "./english-vp-rendering";
import { personGender } from "../../library";
// TODO: ISSUE GETTING SPLIT HEAD NOT MATCHING WITH FUTURE VERBS // TODO: ISSUE GETTING SPLIT HEAD NOT MATCHING WITH FUTURE VERBS
@ -157,7 +159,8 @@ function getPsVerbConjugation(conj: T.VerbConjugation, vs: T.VerbSelectionComple
}, },
hasBa: boolean, hasBa: boolean,
} { } {
const f = getTenseVerbForm(conj, vs.tense, vs.voice); // TODO: handle the imperative form here
const f = getTenseVerbForm(conj, vs.tense, vs.voice, vs.negative);
const block = getMatrixBlock(f, objectPerson, person); const block = getMatrixBlock(f, objectPerson, person);
const perfective = isPerfective(vs.tense); const perfective = isPerfective(vs.tense);
const verbForm = getVerbFromBlock(block, person); const verbForm = getVerbFromBlock(block, person);
@ -178,8 +181,11 @@ function getPsVerbConjugation(conj: T.VerbConjugation, vs: T.VerbSelectionComple
return { hasBa, ps: { head: undefined, rest: verbForm }}; return { hasBa, ps: { head: undefined, rest: verbForm }};
} }
function getVerbFromBlock(block: T.SingleOrLengthOpts<T.VerbBlock>, person: T.Person): T.SingleOrLengthOpts<T.PsString[]> { function getVerbFromBlock(block: T.SingleOrLengthOpts<T.VerbBlock | T.ImperativeBlock>, person: T.Person): T.SingleOrLengthOpts<T.PsString[]> {
function grabFromBlock(b: T.VerbBlock, [row, col]: [ row: number, col: number ]): T.PsString[] { function grabFromBlock(b: T.VerbBlock | T.ImperativeBlock, [row, col]: [ row: number, col: number ]): T.PsString[] {
if (isImperativeBlock(b)) {
return b[personGender(person) === "masc" ? 0 : 1][col];
}
return b[row][col]; return b[row][col];
} }
const pos = getVerbBlockPosFromPerson(person); const pos = getVerbBlockPosFromPerson(person);
@ -326,7 +332,7 @@ function isFirstOrSecondPersPronoun(o: "none" | T.NPSelection | T.Person.ThirdPl
return [0,1,2,3,6,7,8,9].includes(o.person); return [0,1,2,3,6,7,8,9].includes(o.person);
} }
function isPerfective(t: T.VerbTense | T.PerfectTense | T.ModalTense): boolean { function isPerfective(t: T.Tense): boolean {
if (isPerfectTense(t)) return false; if (isPerfectTense(t)) return false;
if (t === "presentVerb" || t === "imperfectiveFuture" || t === "imperfectivePast" || t === "habitualImperfectivePast") { if (t === "presentVerb" || t === "imperfectiveFuture" || t === "imperfectivePast" || t === "habitualImperfectivePast") {
return false; return false;
@ -337,7 +343,10 @@ function isPerfective(t: T.VerbTense | T.PerfectTense | T.ModalTense): boolean {
if (t === "perfectiveFutureModal" || t === "subjunctiveVerbModal" || t === "perfectivePastModal" || t === "habitualPerfectivePastModal") { if (t === "perfectiveFutureModal" || t === "subjunctiveVerbModal" || t === "perfectivePastModal" || t === "habitualPerfectivePastModal") {
return true; return true;
} }
throw new Error("tense not implemented yet"); if (t === "perfectiveImperative") {
return true;
}
return false;
} }
function isMascSingAnimatePattern4(np: T.NPSelection): boolean { function isMascSingAnimatePattern4(np: T.NPSelection): boolean {

View File

@ -4,8 +4,9 @@ import {
psRemove, psRemove,
psStringEquals, psStringEquals,
} from "../../lib/p-text-helpers"; } from "../../lib/p-text-helpers";
import { isPerfectTense } from "../type-predicates"; import { isImperativeTense, isPerfectTense } from "../type-predicates";
import * as grammarUnits from "../../lib/grammar-units"; import * as grammarUnits from "../../lib/grammar-units";
import { randomNumber } from "../../lib/misc-helpers";
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean { export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
const firstPeople = [ const firstPeople = [
@ -27,8 +28,23 @@ export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
); );
} }
export function getTenseVerbForm(conjR: T.VerbConjugation, tense: T.VerbTense | T.PerfectTense | T.ModalTense, voice: "active" | "passive"): T.VerbForm { export function getTenseVerbForm(
conjR: T.VerbConjugation,
tense: T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense,
voice: "active" | "passive",
negative: boolean,
): T.VerbForm | T.ImperativeForm {
const conj = (voice === "passive" && conjR.passive) ? conjR.passive : conjR; const conj = (voice === "passive" && conjR.passive) ? conjR.passive : conjR;
if (isImperativeTense(tense)) {
const impPassError = new Error("can't use imperative tenses with passive voice")
if (voice === "passive") {
throw impPassError;
}
if (!conj.imperfective.imperative || !conj.perfective.imperative) throw impPassError;
return (tense === "perfectiveImperative" && !negative)
? conj.perfective.imperative
: conj.imperfective.imperative;
}
if (tense === "presentVerb") { if (tense === "presentVerb") {
return conj.imperfective.nonImperative; return conj.imperfective.nonImperative;
} }
@ -123,7 +139,7 @@ export function removeBa(ps: T.PsString): T.PsString {
return psRemove(ps, concatPsString(grammarUnits.baParticle, " ")); return psRemove(ps, concatPsString(grammarUnits.baParticle, " "));
} }
export function getTenseFromVerbSelection(vs: T.VerbSelection): T.VerbTense | T.PerfectTense | T.ModalTense { export function getTenseFromVerbSelection(vs: T.VerbSelection): T.VerbTense | T.PerfectTense | T.ModalTense | T.ImperativeTense {
function verbTenseToModalTense(tn: T.VerbTense): T.ModalTense { function verbTenseToModalTense(tn: T.VerbTense): T.ModalTense {
if (tn === "presentVerb") { if (tn === "presentVerb") {
return "presentVerbModal"; return "presentVerbModal";
@ -157,11 +173,14 @@ export function getTenseFromVerbSelection(vs: T.VerbSelection): T.VerbTense | T.
if (vs.tenseCategory === "perfect") { if (vs.tenseCategory === "perfect") {
return vs.perfectTense; return vs.perfectTense;
} }
if (vs.tenseCategory === "imperative") {
return vs.imperativeTense;
}
// vs.tenseCategory === "modal" // vs.tenseCategory === "modal"
return verbTenseToModalTense(vs.verbTense); return verbTenseToModalTense(vs.verbTense);
} }
export function isPastTense(tense: T.VerbTense | T.PerfectTense | T.ModalTense): boolean { export function isPastTense(tense: T.Tense): boolean {
if (isPerfectTense(tense)) return true; if (isPerfectTense(tense)) return true;
return tense.toLowerCase().includes("past"); return tense.toLowerCase().includes("past");
} }
@ -178,7 +197,7 @@ export function switchSubjObj(vps: T.VPSelection): T.VPSelection;
export function switchSubjObj(vps: T.VPSelectionComplete): T.VPSelectionComplete; export function switchSubjObj(vps: T.VPSelectionComplete): T.VPSelectionComplete;
export function switchSubjObj(vps: T.VPSelection | T.VPSelectionComplete): T.VPSelection | T.VPSelectionComplete { export function switchSubjObj(vps: T.VPSelection | T.VPSelectionComplete): T.VPSelection | T.VPSelectionComplete {
if ("tenseCategory" in vps.verb) { if ("tenseCategory" in vps.verb) {
if (!vps.subject || !(typeof vps.verb.object === "object")) { if (!vps.subject || !(typeof vps.verb.object === "object") || (vps.verb.tenseCategory === "imperative")) {
return vps; return vps;
} }
return { return {
@ -222,4 +241,91 @@ export function completeVPSelection(vps: T.VPSelection): T.VPSelectionComplete |
subject, subject,
verb, verb,
}; };
}
export function isSecondPerson(p: T.Person): boolean {
return (
p === T.Person.SecondSingMale ||
p === T.Person.SecondSingFemale ||
p === T.Person.SecondPlurMale ||
p === T.Person.SecondPlurFemale
);
}
export function isThirdPerson(p: T.Person): boolean {
return (
p === T.Person.ThirdSingMale ||
p === T.Person.ThirdSingFemale ||
p === T.Person.ThirdPlurMale ||
p === T.Person.ThirdPlurFemale
);
}
export function ensure2ndPersSubjPronounAndNoConflict(vps: T.VPSelection): T.VPSelection {
console.log("checking more...", vps);
const subjIs2ndPerson = (vps.subject?.type === "pronoun") && isSecondPerson(vps.subject.person);
const objIs2ndPerson = (typeof vps.verb.object === "object")
&& (vps.verb.object.type === "pronoun")
&& isSecondPerson(vps.verb.object.person);
console.log({ subjIs2ndPerson, objIs2ndPerson });
const default2ndPersSubject: T.PronounSelection = {
type: "pronoun",
distance: "far",
person: T.Person.SecondSingMale,
};
function getNon2ndPersPronoun() {
let newObjPerson: T.Person;
do {
newObjPerson = randomNumber(0, 12);
} while(isSecondPerson(newObjPerson));
return newObjPerson;
}
if (subjIs2ndPerson && !objIs2ndPerson) {
return vps;
}
if (subjIs2ndPerson && objIs2ndPerson) {
if (typeof vps.verb.object !== "object" || vps.verb.object.type !== "pronoun") {
return vps;
}
return {
...vps,
verb: {
...vps.verb,
object: {
...vps.verb.object,
person: getNon2ndPersPronoun(),
},
},
};
}
if (!subjIs2ndPerson && objIs2ndPerson) {
if (typeof vps.verb.object !== "object" || vps.verb.object.type !== "pronoun") {
return {
...vps,
subject: default2ndPersSubject,
};
}
return {
...vps,
subject: default2ndPersSubject,
verb: {
...vps.verb,
object: {
...vps.verb.object,
person: getNon2ndPersPronoun(),
},
},
};
}
if (!subjIs2ndPerson && !objIs2ndPerson) {
console.log("returning last");
return {
...vps,
subject: default2ndPersSubject,
verb: {
...vps.verb,
},
};
}
throw new Error("error ensuring compatible VPSelection for imperative verb");
} }

View File

@ -160,11 +160,11 @@ export function isArrayOneOrMore<U>(a: U[]): a is T.ArrayOneOrMore<U> {
return a.length > 0; return a.length > 0;
} }
export function isPerfectTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense | T.PerfectTense): tense is T.PerfectTense { export function isPerfectTense(tense: T.Tense): tense is T.PerfectTense {
return tense.endsWith("Perfect"); return tense.endsWith("Perfect");
} }
export function isVerbTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense | T.PerfectTense): tense is T.VerbTense { export function isVerbTense(tense: T.Tense): tense is T.VerbTense {
const verbTenses: T.VerbTense[] = [ const verbTenses: T.VerbTense[] = [
"presentVerb", "presentVerb",
"subjunctiveVerb", "subjunctiveVerb",
@ -178,12 +178,15 @@ export function isVerbTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense
return verbTenses.some(x => x === tense); return verbTenses.some(x => x === tense);
} }
export function isModalTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense | T.PerfectTense): tense is T.ModalTense { export function isModalTense(tense: T.Tense): tense is T.ModalTense {
return tense.endsWith("Modal"); return tense.endsWith("Modal");
} }
export function isEquativeTense(t: T.VerbTense | T.EquativeTense | T.PerfectTense | T.ModalTense): t is T.EquativeTense { export function isEquativeTense(t: T.Tense): t is T.EquativeTense {
return (t === "present" || t === "future" || t === "habitual" || t === "past" || t === "wouldBe" || t === "subjunctive" || t === "pastSubjunctive"); return (t === "present" || t === "future" || t === "habitual" || t === "past" || t === "wouldBe" || t === "subjunctive" || t === "pastSubjunctive");
} }
export function isImperativeTense(tense: T.Tense): tense is T.ImperativeTense {
return tense === "imperfectiveImperative" || tense === "perfectiveImperative";
}

View File

@ -106,11 +106,11 @@ export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.Dictionar
} }
function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjugation { function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjugation {
const willUseImperative = !( // const willUseImperative = !(
info.type === "dynamic compound" // info.type === "dynamic compound"
&& info.transitivity === "intransitive" // && info.transitivity === "intransitive"
&& info.auxVerb.p === "کېدل" // && info.auxVerb.p === "کېدل"
); // );
const auxConj = enforceObject( const auxConj = enforceObject(
conjugateVerb(info.auxVerb, info.auxVerbComplement) as T.VerbConjugation, conjugateVerb(info.auxVerb, info.auxVerbComplement) as T.VerbConjugation,
info.objComplement.person, info.objComplement.person,
@ -136,18 +136,14 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
const ac = auxConj[aspect]; const ac = auxConj[aspect];
const nonImperative = addToForm([complement, " "], ac.nonImperative); const nonImperative = addToForm([complement, " "], ac.nonImperative);
const future = addToForm([baParticle, " "], nonImperative); const future = addToForm([baParticle, " "], nonImperative);
const imperative = (ac.imperative && willUseImperative) const imperative = addToForm([complement, " "], ac.imperative);
? addToForm([complement, " "], ac.imperative)
: null;
const past = addToForm([complement, " "], auxConj[aspect].past); const past = addToForm([complement, " "], auxConj[aspect].past);
const habitualPast = addToForm([baParticle, " "], past); const habitualPast = addToForm([baParticle, " "], past);
const modal = makeDynamicModalContent(); const modal = makeDynamicModalContent();
return { return {
nonImperative, nonImperative,
future, future,
...imperative ? { imperative,
imperative,
} : {},
past, past,
habitualPast, habitualPast,
modal, modal,
@ -183,6 +179,7 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
const habitualPast = addToForm([baParticle, " "], past); const habitualPast = addToForm([baParticle, " "], past);
const modal = makePassiveModalSection([complement, " "], stativeAux.intransitive.imperfective.modal); const modal = makePassiveModalSection([complement, " "], stativeAux.intransitive.imperfective.modal);
return { return {
imperative: undefined,
nonImperative, nonImperative,
future, future,
past, past,
@ -317,9 +314,7 @@ function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbIn
stativeAux[transitivity][aspect].nonImperative, stativeAux[transitivity][aspect].nonImperative,
); );
const future = addToForm([baParticle, " "], nonImperative); const future = addToForm([baParticle, " "], nonImperative);
const imperative = aux.imperative const imperative = addToForm([presentComplement, " "], aux.imperative);
? addToForm([presentComplement, " "], aux.imperative)
: null;
const past = addToForm([info.complement, " "], aux.past); const past = addToForm([info.complement, " "], aux.past);
const habitualPast = addToForm([baParticle, " "], past); const habitualPast = addToForm([baParticle, " "], past);
return { return {
@ -327,9 +322,7 @@ function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbIn
future, future,
past, past,
habitualPast, habitualPast,
...imperative ? { imperative,
imperative,
} : {},
modal: info.transitivity === "transitive" modal: info.transitivity === "transitive"
? makeTransitiveStativeModalContent() ? makeTransitiveStativeModalContent()
: makeJoinedModalContent(info, "imperfective"), : makeJoinedModalContent(info, "imperfective"),
@ -458,6 +451,7 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
noPersInfs(info.root.imperfective).long, " ", noPersInfs(info.root.imperfective).long, " ",
], stativeAux.intransitive.imperfective.modal); ], stativeAux.intransitive.imperfective.modal);
return { return {
imperative: undefined,
nonImperative, nonImperative,
future, future,
past, past,
@ -474,6 +468,7 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
const auxModal = aux.modal; const auxModal = aux.modal;
const modal = makePassiveModalSection([noPersInfs(info.root.imperfective).long, " "], auxModal); const modal = makePassiveModalSection([noPersInfs(info.root.imperfective).long, " "], auxModal);
return { return {
imperative: undefined,
nonImperative, // ROOT LONG + kedulStat[aspect].nonImperative nonImperative, // ROOT LONG + kedulStat[aspect].nonImperative
future, // به ba + ROOT LONG + this.nonImperative future, // به ba + ROOT LONG + this.nonImperative
past, // ROOT LONG + kedulStat[aspect].past past, // ROOT LONG + kedulStat[aspect].past
@ -560,9 +555,7 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
const modifyPastInAspect = (as: T.AspectContent): T.AspectContent => ({ const modifyPastInAspect = (as: T.AspectContent): T.AspectContent => ({
nonImperative: allOnePersonInflection(as.nonImperative, person), nonImperative: allOnePersonInflection(as.nonImperative, person),
future: allOnePersonInflection(as.future, person), future: allOnePersonInflection(as.future, person),
...as.imperative ? { imperative: allOnePersonInflection(as.imperative, person),
imperative: allOnePersonInflection(as.imperative, person),
} : {},
past: allOnePersonVerbForm(as.past, person), past: allOnePersonVerbForm(as.past, person),
habitualPast: allOnePersonInflection(as.habitualPast, person), habitualPast: allOnePersonInflection(as.habitualPast, person),
modal: { modal: {
@ -586,6 +579,7 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
pastSubjunctiveHypothetical: allOnePersonVerbForm(perf.pastSubjunctiveHypothetical, person), pastSubjunctiveHypothetical: allOnePersonVerbForm(perf.pastSubjunctiveHypothetical, person),
}); });
const modifyPassiveAspect = (as: T.AspectContentPassive): T.AspectContentPassive => ({ const modifyPassiveAspect = (as: T.AspectContentPassive): T.AspectContentPassive => ({
imperative: undefined,
nonImperative: allOnePersonVerbForm(as.nonImperative, person), nonImperative: allOnePersonVerbForm(as.nonImperative, person),
future: allOnePersonVerbForm(as.future, person), future: allOnePersonVerbForm(as.future, person),
past: allOnePersonVerbForm(as.past, person), past: allOnePersonVerbForm(as.past, person),

View File

@ -296,13 +296,17 @@ export type AspectContent = {
// ROOT = info.root[ASPECT] // ROOT = info.root[ASPECT]
nonImperative: VerbForm; // STEM + pres ending nonImperative: VerbForm; // STEM + pres ending
future: VerbForm; // به + this.nonImperative future: VerbForm; // به + this.nonImperative
imperative?: ImperativeForm; // STEM + imperative ending imperative: ImperativeForm; // STEM + imperative ending
// -- optional because not used for intransitive verison of kawul dynamic compounds
past: VerbForm; // ROOT + past ending past: VerbForm; // ROOT + past ending
habitualPast: VerbForm; // ba + past habitualPast: VerbForm; // ba + past
modal: ModalContent; modal: ModalContent;
} }
// ASPECT -> AspectContentPssive
export type AspectContentPassive = Omit<AspectContent, "imperative"> & {
imperative: undefined,
};
export type ModalContent = { export type ModalContent = {
nonImperative: VerbForm; // ROOT + ey + kedulStat.perfective.nonImperative nonImperative: VerbForm; // ROOT + ey + kedulStat.perfective.nonImperative
future: VerbForm; // به + this.nonImperative future: VerbForm; // به + this.nonImperative
@ -311,16 +315,6 @@ export type ModalContent = {
hypotheticalPast: VerbForm; // ROOT + ey + shw + ey hypotheticalPast: VerbForm; // ROOT + ey + shw + ey
} }
// ASPECT -> AspectContentPssive
export type AspectContentPassive = {
// ROOT = info.root[ASPECT]
nonImperative: VerbForm; // ROOT LONG + kedulStat[ASPECT].nonImperative
future: VerbForm; // ba + this.nonImperative
past: VerbForm; // ROOT LONG + kedulStat[ASPECT].past
habitualPast: VerbForm;
modal: ModalContent,
}
export type ParticipleForm = SingleOrLengthOpts<UnisexInflections> | SingleOrLengthOpts<PsString>; export type ParticipleForm = SingleOrLengthOpts<UnisexInflections> | SingleOrLengthOpts<PsString>;
export type ParticipleContent = { export type ParticipleContent = {
@ -531,12 +525,13 @@ export type VerbTense = "presentVerb"
| "imperfectivePast" | "imperfectivePast"
| "habitualPerfectivePast" | "habitualPerfectivePast"
| "habitualImperfectivePast"; | "habitualImperfectivePast";
export type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive";
export type NounNumber = "singular" | "plural"; export type NounNumber = "singular" | "plural";
export type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive";
export type PerfectTense = `${EquativeTense}Perfect`; export type PerfectTense = `${EquativeTense}Perfect`;
export type ModalTense = `${VerbTense}Modal`; export type ModalTense = `${VerbTense}Modal`;
export type ImperativeTense = `${Aspect}Imperative`;
export type Tense = EquativeTense | VerbTense | PerfectTense | ModalTense | ImperativeTense;
export type VPSelection = { export type VPSelection = {
subject: NPSelection | undefined, subject: NPSelection | undefined,
@ -550,7 +545,7 @@ export type VPSelectionComplete = {
export type VerbSelectionComplete = Omit<VerbSelection, "object" | "verbTense" | "perfectTense" | "tenseCategory"> & { export type VerbSelectionComplete = Omit<VerbSelection, "object" | "verbTense" | "perfectTense" | "tenseCategory"> & {
object: Exclude<VerbObject, undefined>, object: Exclude<VerbObject, undefined>,
tense: VerbTense | PerfectTense | ModalTense, tense: VerbTense | PerfectTense | ModalTense | ImperativeTense,
} }
export type VerbSelection = { export type VerbSelection = {
@ -569,7 +564,8 @@ export type VerbSelection = {
negative: boolean, negative: boolean,
verbTense: VerbTense, verbTense: VerbTense,
perfectTense: PerfectTense, perfectTense: PerfectTense,
tenseCategory: "basic" | "modal" | "perfect", imperativeTense: ImperativeTense,
tenseCategory: "basic" | "modal" | "perfect" | "imperative",
}; };
export type VerbRendered = Omit<VerbSelectionComplete, "object"> & { export type VerbRendered = Omit<VerbSelectionComplete, "object"> & {