better UI and refactor re tenseCategory

This commit is contained in:
lingdocs 2022-04-19 22:56:02 +05:00
parent b6b742c905
commit 875237439b
14 changed files with 404 additions and 242 deletions

View File

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

@ -1,4 +1,7 @@
import { getTenseVerbForm } from "../../lib/phrase-building/vp-tools"; import {
getTenseVerbForm,
getTenseFromVerbSelection,
} from "../../lib/phrase-building/vp-tools";
import VerbFormDisplay from "../VerbFormDisplay"; import VerbFormDisplay from "../VerbFormDisplay";
import { conjugateVerb } from "../../lib/verb-conjugation"; import { conjugateVerb } from "../../lib/verb-conjugation";
import * as T from "../../types"; import * as T from "../../types";
@ -13,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, VS.tense, VS.tenseCategory, VS.voice); const form = getTenseVerbForm(conjugations, getTenseFromVerbSelection(VS), VS.voice);
return <div className="mb-4"> return <div className="mb-4">
<VerbFormDisplay <VerbFormDisplay
displayForm={form} displayForm={form}

View File

@ -4,7 +4,7 @@ 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 { isPerfectTense } from "../../lib/phrase-building/vp-tools"; import { isModalTense, isPerfectTense, isVerbTense } from "../../lib/type-predicates";
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>,
@ -34,32 +34,37 @@ const verbTenseOptions: { label: string | JSX.Element, value: T.VerbTense }[] =
const perfectTenseOptions: { label: string | JSX.Element, value: T.PerfectTense }[] = [{ const perfectTenseOptions: { label: string | JSX.Element, value: T.PerfectTense }[] = [{
label: "Present Perfect", label: "Present Perfect",
value: "present perfect", value: "presentPerfect",
}, { }, {
label: "Habitual Perfect", label: "Habitual Perfect",
value: "habitual perfect", value: "habitualPerfect",
}, { }, {
label: "Subjunctive Perfect", label: "Subjunctive Perfect",
value: "subjunctive perfect", value: "subjunctivePerfect",
}, { }, {
label: "Future Perfect", label: "Future Perfect",
value: "future perfect", value: "futurePerfect",
}, { }, {
label: "Past Perfect", label: "Past Perfect",
value: "past perfect", value: "pastPerfect",
}, { }, {
label: `"Would Be" Perfect`, label: `"Would Be" Perfect`,
value: "wouldBe perfect", value: "wouldBePerfect",
}, { }, {
label: "Past Subjunctive Perfect", label: "Past Subjunctive Perfect",
value: "pastSubjunctive perfect", value: "pastSubjunctivePerfect",
}]; }];
export function getRandomTense(type: "basic" | "modal", o?: T.VerbTense): T.VerbTense; export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense): T.PerfectTense | T.VerbTense | T.ModalTense {
export function getRandomTense(type: "perfect", o?: T.PerfectTense | T.VerbTense): T.PerfectTense; let tns: T.PerfectTense | T.VerbTense | T.ModalTense;
export function getRandomTense(type: "basic" | "modal" | "perfect", o?: T.PerfectTense | T.VerbTense): T.PerfectTense | T.VerbTense { const oldTenseCategory = !o
let tns: T.PerfectTense | T.VerbTense; ? undefined
const tenseOptions = type === "perfect" ? perfectTenseOptions : verbTenseOptions; : getTenseCategory(o);
const tenseOptions = oldTenseCategory === "perfect"
? perfectTenseOptions
: oldTenseCategory === "modal"
? verbTenseOptions.map(x => ({ ...x, value: `${x.value}Modal` as T.ModalTense }))
: verbTenseOptions;
do { do {
tns = tenseOptions[ tns = tenseOptions[
Math.floor(Math.random()*tenseOptions.length) Math.floor(Math.random()*tenseOptions.length)
@ -68,40 +73,49 @@ export function getRandomTense(type: "basic" | "modal" | "perfect", o?: T.Perfec
return tns; return tns;
} }
function TensePicker({ onChange, vps, mode }: { function TensePicker(props: ({
vps: T.VPSelection, vps: T.VPSelection,
} | {
vpsComplete: T.VPSelectionComplete,
}) & {
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 } | null) {
if ("vpsComplete" in props) return;
const value = o?.value ? o.value : undefined; const value = o?.value ? o.value : undefined;
if (vps.verb && value) { if (props.vps.verb && value) {
if (isPerfectTense(value)) { if (isPerfectTense(value)) {
onChange({ props.onChange({
...vps, ...props.vps,
verb: { verb: {
...vps.verb, ...props.vps.verb,
tense: value, perfectTense: value,
tenseCategory: "perfect", tenseCategory: "perfect",
}, },
}); });
} else { } else {
onChange({ props.onChange({
...vps, ...props.vps,
verb: { verb: {
...vps.verb, ...props.vps.verb,
tense: value, verbTense: value,
tenseCategory: vps.verb.tenseCategory === "perfect" ? "basic" : vps.verb.tenseCategory, tenseCategory: props.vps.verb.tenseCategory === "perfect"
? "basic"
: props.vps.verb.tenseCategory,
}, },
}); });
} }
} }
} }
function moveTense(dir: "forward" | "back") { function moveTense(dir: "forward" | "back") {
if (!vps.verb) return; if ("vpsComplete" in props) return;
if (!props.vps.verb) return;
return () => { return () => {
const tenses = vps.verb.tenseCategory === "perfect" ? perfectTenseOptions : verbTenseOptions; const tenses = props.vps.verb.tenseCategory === "perfect" ? perfectTenseOptions : verbTenseOptions;
const currIndex = tenses.findIndex(tn => tn.value === vps.verb.tense) const currIndex = tenses.findIndex(tn => tn.value === props.vps.verb[
props.vps.verb.tenseCategory === "perfect" ? "perfectTense" : "verbTense"
]);
if (currIndex === -1) { if (currIndex === -1) {
console.error("error moving tense", dir); console.error("error moving tense", dir);
return; return;
@ -114,48 +128,42 @@ function TensePicker({ onChange, vps, mode }: {
}; };
} }
function onPosNegSelect(value: string) { function onPosNegSelect(value: string) {
if (vps.verb) { if ("vpsComplete" in props) return;
onChange({ if (props.vps.verb) {
...vps, props.onChange({
...props.vps,
verb: { verb: {
...vps.verb, ...props.vps.verb,
negative: value === "true", negative: value === "true",
}, },
}); });
} }
} }
function onTenseCategorySelect(value: "basic" | "modal" | "perfect") { function onTenseCategorySelect(value: "basic" | "modal" | "perfect") {
if (vps.verb) { if ("vpsComplete" in props) return;
if (value === "perfect") { if (props.vps.verb) {
onChange({ props.onChange({
...vps, ...props.vps,
verb: { verb: {
...vps.verb, ...props.vps.verb,
tenseCategory: value, tenseCategory: value,
tense: isPerfectTense(vps.verb.tense) ? vps.verb.tense : "present perfect",
}, },
}); });
} else {
onChange({
...vps,
verb: {
...vps.verb,
tenseCategory: value,
tense: isPerfectTense(vps.verb.tense) ? "presentVerb" : vps.verb.tense,
}
});
} }
} }
} const tOptions = ("vps" in props && (props.vps.verb?.tenseCategory === "perfect"))
const tOptions = (vps.verb?.tenseCategory === "perfect") ? perfectTenseOptions : verbTenseOptions; ? perfectTenseOptions
: 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="d-flex flex-row justify-content-between align-items-center">
<div className="h5">Tense:</div> <div className="h5">Tense:</div>
{vps.verb && <div className="mb-2"> {("vpsComplete" in props || props.vps.verb) && <div className="mb-2">
<ButtonSelect <ButtonSelect
small small
value={vps.verb.tenseCategory} value={"vpsComplete" in props
? getTenseCategory(props.vpsComplete.verb.tense)
: props.vps.verb.tenseCategory}
options={[{ options={[{
label: "Basic", label: "Basic",
value: "basic", value: "basic",
@ -166,26 +174,32 @@ function TensePicker({ onChange, vps, mode }: {
label: "Modal", label: "Modal",
value: "modal", value: "modal",
}]} }]}
handleChange={mode !== "quiz" ? onTenseCategorySelect : () => null} handleChange={props.mode !== "quiz" ? onTenseCategorySelect : () => null}
/> />
</div>} </div>}
</div> </div>
<Select {"vpsComplete" in props
? <div style={{ fontSize: "larger" }} className="mb-3">
{[...verbTenseOptions, ...perfectTenseOptions].find(o => o.value === props.vpsComplete.verb.tense)?.label}
</div>
: <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={vps.verb && ([...verbTenseOptions, ...perfectTenseOptions].find(o => o.value === vps.verb.tense))} value={props.vps.verb && ([...verbTenseOptions, ...perfectTenseOptions].find(o => o.value === props.vps.verb[
props.vps.verb.tenseCategory === "perfect" ? "perfectTense" : "verbTense"
]))}
onChange={onTenseSelect} onChange={onTenseSelect}
className="mb-2" className="mb-2"
options={tOptions} options={tOptions}
{...zIndexProps} {...zIndexProps}
/> />}
{vps.verb && (mode !== "quiz") && <div className="d-flex flex-row justify-content-between align-items-center mt-3 mb-1" style={{ width: "100%" }}> {"vps" in props && props.vps.verb && (props.mode !== "quiz") && <div className="d-flex flex-row justify-content-between align-items-center mt-3 mb-1" style={{ width: "100%" }}>
<div className="btn btn-light clickable" onClick={moveTense("back")}> <div className="btn btn-light clickable" onClick={moveTense("back")}>
<i className="fas fa-chevron-left" /> <i className="fas fa-chevron-left" />
</div> </div>
{mode === "phrases" && <ButtonSelect {props.mode === "phrases" && <ButtonSelect
small small
value={vps.verb.negative.toString()} value={props.vps.verb.negative.toString()}
options={[{ options={[{
label: "Pos.", label: "Pos.",
value: "false", value: "false",
@ -204,3 +218,16 @@ function TensePicker({ onChange, vps, mode }: {
} }
export default TensePicker; export default TensePicker;
function getTenseCategory(tense: T.VerbTense | T.PerfectTense | T.ModalTense): "basic" | "perfect" | "modal" {
if (isPerfectTense(tense)) {
return "perfect";
}
if (isVerbTense(tense)) {
return "basic";
}
if (isModalTense(tense)) {
return "modal";
}
throw new Error("can't catagorize tense");
}

View File

@ -2,14 +2,17 @@ import { renderVP, compileVP } from "../../lib/phrase-building/index";
import * as T from "../../types"; import * as T from "../../types";
import InlinePs from "../InlinePs"; import InlinePs from "../InlinePs";
import AbbreviationFormSelector from "./AbbreviationFormSelector"; import AbbreviationFormSelector from "./AbbreviationFormSelector";
import { isPastTense } from "../../lib/phrase-building/vp-tools"; import {
isPastTense,
completeVPSelection,
} from "../../lib/phrase-building/vp-tools";
import { useStickyState } from "../../library"; import { useStickyState } from "../../library";
import { isVPSelectionComplete } from "../../lib/type-predicates";
function VPDisplay({ VP, opts }: { VP: T.VPSelection | T.VPSelectionComplete, opts: T.TextOptions }) { function VPDisplay({ VP, opts }: { VP: T.VPSelection, opts: T.TextOptions }) {
const [form, setForm] = useStickyState<T.FormVersion>({ removeKing: false, shrinkServant: false }, "abbreviationForm"); const [form, setForm] = useStickyState<T.FormVersion>({ removeKing: false, shrinkServant: false }, "abbreviationForm");
const [OSV, setOSV] = useStickyState<boolean>(false, "includeOSV"); const [OSV, setOSV] = useStickyState<boolean>(false, "includeOSV");
if (!isVPSelectionComplete(VP)) { const VPComplete = completeVPSelection(VP);
if (!VPComplete) {
return <div className="lead text-muted text-center mt-4"> return <div className="lead text-muted text-center mt-4">
{(() => { {(() => {
const twoNPs = (VP.subject === undefined) && (VP.verb.object === undefined); const twoNPs = (VP.subject === undefined) && (VP.verb.object === undefined);
@ -17,7 +20,7 @@ function VPDisplay({ VP, opts }: { VP: T.VPSelection | T.VPSelectionComplete, op
})()} })()}
</div>; </div>;
} }
const result = compileVP(renderVP(VP), { ...form, OSV }); const result = compileVP(renderVP(VPComplete), { ...form, OSV });
return <div className="text-center mt-2"> return <div className="text-center mt-2">
{VP.verb.transitivity === "transitive" && <div className="form-check mb-2"> {VP.verb.transitivity === "transitive" && <div className="form-check mb-2">
<input <input
@ -32,7 +35,7 @@ function VPDisplay({ VP, opts }: { VP: T.VPSelection | T.VPSelectionComplete, op
</label> </label>
</div>} </div>}
<AbbreviationFormSelector <AbbreviationFormSelector
adjustable={whatsAdjustable(VP)} adjustable={whatsAdjustable(VPComplete)}
form={form} form={form}
onChange={setForm} onChange={setForm}
/> />

View File

@ -48,7 +48,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),
"vpsState1", "vpsState2",
); );
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">( const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
savedMode => { savedMode => {
@ -59,7 +59,10 @@ export function VPExplorer(props: {
"verbExplorerMode", "verbExplorerMode",
); );
const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false); const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false);
const roles = getKingAndServant(isPastTense(vps.verb.tense), vps.verb.transitivity !== "intransitive"); const roles = getKingAndServant(
isPastTense(vps.verb.tenseCategory === "perfect" ? vps.verb.perfectTense : vps.verb.verbTense),
vps.verb.transitivity !== "intransitive",
);
useEffect(() => { useEffect(() => {
setVps(oldVps => { setVps(oldVps => {
if (mode === "quiz") { if (mode === "quiz") {

View File

@ -9,7 +9,7 @@ import InlinePs from "../InlinePs";
import { psStringEquals } from "../../lib/p-text-helpers"; import { psStringEquals } from "../../lib/p-text-helpers";
import { renderVP, compileVP } from "../../lib/phrase-building/index"; import { renderVP, compileVP } from "../../lib/phrase-building/index";
import { getRandomTense } from "./TensePicker"; import { getRandomTense } from "./TensePicker";
import { removeBa, switchSubjObj } from "../../lib/phrase-building/vp-tools"; import { getTenseFromVerbSelection, removeBa, switchSubjObj } from "../../lib/phrase-building/vp-tools";
import playAudio from "../../lib/play-audio"; import playAudio from "../../lib/play-audio";
import TensePicker from "./TensePicker"; import TensePicker from "./TensePicker";
import Keyframes from "../Keyframes"; import Keyframes from "../Keyframes";
@ -57,7 +57,7 @@ function VPExplorerQuiz(props: {
opts: T.TextOptions, opts: T.TextOptions,
vps: T.VPSelection, vps: T.VPSelection,
}) { }) {
const startingQs = tickQuizState(props.vps); const startingQs = tickQuizState(completeVPs(props.vps));
const [quizState, setQuizState] = useState<QuizState>(startingQs); const [quizState, setQuizState] = useState<QuizState>(startingQs);
const [showCheck, setShowCheck] = useState<boolean>(false); const [showCheck, setShowCheck] = useState<boolean>(false);
const [answerBlank, setAnswerBlank] = useState<string>(""); const [answerBlank, setAnswerBlank] = useState<string>("");
@ -115,7 +115,7 @@ function VPExplorerQuiz(props: {
</div>} </div>}
<div className="my-2"> <div className="my-2">
<TensePicker <TensePicker
vps={quizState.vps} vpsComplete={quizState.vps}
onChange={() => null} onChange={() => null}
mode={"quiz"} mode={"quiz"}
/> />
@ -278,7 +278,7 @@ function QuizNPDisplay({ children, stage, opts }: {
* @param startingWith * @param startingWith
* @returns * @returns
*/ */
function tickQuizState(startingWith: T.VPSelection | QuizState): QuizState { function tickQuizState(startingWith: T.VPSelectionComplete | QuizState): QuizState {
function makeRes(x: T.VPSelectionComplete) { function makeRes(x: T.VPSelectionComplete) {
return compileVP(renderVP(x), { removeKing: false, shrinkServant: false }); return compileVP(renderVP(x), { removeKing: false, shrinkServant: false });
} }
@ -369,13 +369,54 @@ function getOptionFromResult(r: {
return ps[0]; return ps[0];
} }
function completeVPs(vps: T.VPSelection): T.VPSelectionComplete {
const oldSubj = vps.subject?.type === "pronoun"
? vps.subject.person
: undefined;
const oldObj = (typeof vps.verb.object === "object" && vps.verb.object.type === "pronoun")
? vps.verb.object.person
: undefined;
const { subj, obj } = randomSubjObj(
oldSubj === undefined
? undefined
: {
subj: oldSubj,
obj: oldObj,
}
);
const verb: T.VerbSelectionComplete = {
...vps.verb,
object: (
(typeof vps.verb.object === "object" && !(vps.verb.object.type === "noun" && vps.verb.object.dynamicComplement))
||
vps.verb.object === undefined
)
? {
type: "pronoun",
distance: "far",
person: obj,
}
: vps.verb.object,
tense: getTenseFromVerbSelection(vps.verb),
};
return {
...vps,
subject: {
type: "pronoun",
distance: "far",
person: subj,
},
verb,
};
}
function getRandomVPSelection(mix: MixType = "both") { function getRandomVPSelection(mix: MixType = "both") {
// TODO: Type safety to make sure it's safe? // TODO: Type safety to make sure it's safe?
return ({ subject, verb }: T.VPSelection): T.VPSelectionComplete => { return ({ subject, verb }: T.VPSelectionComplete): T.VPSelectionComplete => {
const oldSubj = (subject?.type === "pronoun") const oldSubj = (subject.type === "pronoun")
? subject.person ? subject.person
: undefined; : undefined;
const oldObj = (typeof verb?.object === "object" && verb.object.type === "pronoun") const oldObj = (typeof verb.object === "object" && verb.object.type === "pronoun")
? verb.object.person ? verb.object.person
: undefined; : undefined;
const { subj, obj } = randomSubjObj( const { subj, obj } = randomSubjObj(
@ -401,7 +442,6 @@ function getRandomVPSelection(mix: MixType = "both") {
if (mix === "tenses") { if (mix === "tenses") {
return { return {
subject: subject !== undefined ? subject : randSubj, subject: subject !== undefined ? subject : randSubj,
// @ts-ignore
verb: randomizeTense(verb, true), verb: randomizeTense(verb, true),
} }
} }
@ -426,9 +466,6 @@ function randomizeTense(verb: T.VerbSelectionComplete, dontRepeatTense: boolean)
return { return {
...verb, ...verb,
tense: getRandomTense( tense: getRandomTense(
// TODO: WHY ISN'T THE OVERLOADING ON THIS
// @ts-ignore
verb.tenseCategory,
dontRepeatTense ? verb.tense : undefined, dontRepeatTense ? verb.tense : undefined,
), ),
}; };

View File

@ -3,7 +3,6 @@ import {
} from "../np-picker/picker-tools"; } from "../np-picker/picker-tools";
import * as T from "../../types"; import * as T from "../../types";
import { getVerbInfo } from "../../lib/verb-info"; import { getVerbInfo } from "../../lib/verb-info";
import { isPerfectTense } from "../../lib/phrase-building/vp-tools";
export function makeVPSelectionState( export function makeVPSelectionState(
verb: T.VerbEntry, verb: T.VerbEntry,
@ -46,28 +45,15 @@ export function makeVPSelectionState(
: "dynamic" in info : "dynamic" in info
? { entry: info.dynamic.auxVerb } as T.VerbEntry ? { entry: info.dynamic.auxVerb } as T.VerbEntry
: undefined; : undefined;
const tenseSelection = ((): { tenseCategory: "perfect", tense: T.PerfectTense } | {
tenseCategory: "basic" | "modal",
tense: T.VerbTense,
} => {
if (!os) {
return { tense: "presentVerb", tenseCategory: "basic" };
}
if (os.verb.tenseCategory === "modal") {
return { tenseCategory: "modal", tense: isPerfectTense(os.verb.tense) ? "presentVerb" : os.verb.tense };
}
if (os.verb.tenseCategory === "basic") {
return { tenseCategory: "basic", tense: isPerfectTense(os.verb.tense) ? "presentVerb" : os.verb.tense };
}
return { tenseCategory: "perfect", tense: isPerfectTense(os.verb.tense) ? os.verb.tense : "present perfect" };
})();
return { return {
subject, subject,
verb: { verb: {
type: "verb", type: "verb",
verb: verb, verb: verb,
dynAuxVerb, dynAuxVerb,
...tenseSelection, verbTense: os ? os.verb.verbTense : "presentVerb",
perfectTense: os ? os.verb.perfectTense : "presentPerfect",
tenseCategory: os ? os.verb.tenseCategory : "basic",
object, object,
transitivity, transitivity,
isCompound, isCompound,

View File

@ -674,6 +674,22 @@ const nouns: Array<{
} }
} }
}, },
// TODO: uncomment this
// {
// in: {"ts":1527812591,"i":6286,"p":"دواړه","f":"dwáaRu","g":"dwaaRu","e":"both","c":"n. m. pl. unisex / adj."},
// out: {
// plural: {
// masc: [
// [{ p: "دواړه", f: "dwáaRu" }],
// [{ p: "دواړو", f: "dwáaRo" }],
// ],
// fem: [
// [{ p: "دواړې", f: "dwáaRe" }],
// [{ p: "دواړو", f: "dwáaRo" }],
// ],
// }
// }
// },
// Masculine non-inflecting // Masculine non-inflecting
{ {
in: { in: {

View File

@ -12,6 +12,7 @@ import {
removeBa, removeBa,
removeDuplicates, removeDuplicates,
} from "./vp-tools"; } from "./vp-tools";
import { 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 [] };
@ -129,7 +130,7 @@ function putKidsInKidsSection(segments: Segment[], kids: Segment[]): Segment[] {
} }
function arrangeVerbWNegative(head: T.PsString | undefined, restRaw: T.PsString[], V: T.VerbRendered): Segment[][] { function arrangeVerbWNegative(head: T.PsString | undefined, restRaw: T.PsString[], V: T.VerbRendered): Segment[][] {
const hasLeapfrog = V.tenseCategory === "modal" || V.tenseCategory === "perfect"; const hasLeapfrog = isPerfectTense(V.tense) || isModalTense(V.tense);
const rest = (() => { const rest = (() => {
if (hasLeapfrog) { if (hasLeapfrog) {
const [restF, restLast] = splitOffLeapfrogWord(restRaw); const [restF, restLast] = splitOffLeapfrogWord(restRaw);

View File

@ -1,6 +1,11 @@
import * as T from "../../types"; 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 {
isPerfectTense,
isVerbTense,
// isModalTense,
} from "../type-predicates";
function engHave(s: T.Person): string { function engHave(s: T.Person): string {
function isThirdPersonSing(p: T.Person): boolean { function isThirdPersonSing(p: T.Person): boolean {
@ -15,7 +20,7 @@ function engHave(s: T.Person): string {
export function renderEnglishVPBase({ subjectPerson, object, vs }: { export function renderEnglishVPBase({ subjectPerson, object, vs }: {
subjectPerson: T.Person, subjectPerson: T.Person,
object: T.NPSelection | T.ObjectNP, object: T.NPSelection | T.ObjectNP,
vs: T.VerbSelection, vs: T.VerbSelectionComplete,
}): string[] { }): string[] {
const ec = parseEc(vs.verb.entry.ec || ""); const ec = parseEc(vs.verb.entry.ec || "");
const ep = vs.verb.entry.ep; const ep = vs.verb.entry.ep;
@ -79,34 +84,34 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
]), ]),
}; };
const modalBuilders: Record< const modalBuilders: Record<
T.VerbTense, T.ModalTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[] (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = { > = {
presentVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ presentVerbModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ can${n ? "'t" : ""} ${isToBe(v) ? "be" : v[0]}`, `$SUBJ can${n ? "'t" : ""} ${isToBe(v) ? "be" : v[0]}`,
]), ]),
subjunctiveVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ subjunctiveVerbModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ can${n ? "'t" : ""} ${isToBe(v) ? "be" : v[0]}`, `that $SUBJ can${n ? "'t" : ""} ${isToBe(v) ? "be" : v[0]}`,
]), ]),
imperfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ imperfectiveFutureModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`, `$SUBJ will${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
]), ]),
perfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ perfectiveFutureModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`, `$SUBJ will${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
]), ]),
imperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ imperfectivePastModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engEquative("past", s)} ${n ? " not" : ""} able to ${isToBe(v) ? "be" : v[0]}`, `$SUBJ ${engEquative("past", s)} ${n ? " not" : ""} able to ${isToBe(v) ? "be" : v[0]}`,
`$SUBJ could${n ? " not" : ""} ${v[0]}`, `$SUBJ could${n ? " not" : ""} ${v[0]}`,
]), ]),
perfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ perfectivePastModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engEquative("past", s)} ${n ? " not" : ""} able to ${isToBe(v) ? "be" : v[0]}`, `$SUBJ ${engEquative("past", s)} ${n ? " not" : ""} able to ${isToBe(v) ? "be" : v[0]}`,
`$SUBJ could${n ? " not" : ""} ${isToBe(v) ? "be" : v[0]}`, `$SUBJ could${n ? " not" : ""} ${isToBe(v) ? "be" : v[0]}`,
]), ]),
habitualImperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ habitualImperfectivePastModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ used to ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`, `$SUBJ used to ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
`$SUBJ would ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`, `$SUBJ would ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
]), ]),
habitualPerfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ habitualPerfectivePastModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ used to ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`, `$SUBJ used to ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
`$SUBJ would ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`, `$SUBJ would ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
]), ]),
@ -115,25 +120,25 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
T.PerfectTense, T.PerfectTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[] (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = { > = {
"present perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ presentPerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engHave(s)}${n ? " not" : ""} ${v[4]}`, `$SUBJ ${engHave(s)}${n ? " not" : ""} ${v[4]}`,
]), ]),
"past perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ pastPerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ had${n ? " not" : ""} ${v[4]}`, `$SUBJ had${n ? " not" : ""} ${v[4]}`,
]), ]),
"habitual perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ habitualPerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engHave(s)}${n ? " not" : ""} ${v[4]}`, `$SUBJ ${engHave(s)}${n ? " not" : ""} ${v[4]}`,
]), ]),
"subjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ subjunctivePerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ will have${n ? " not" : ""} ${v[4]}`, `that $SUBJ will have${n ? " not" : ""} ${v[4]}`,
]), ]),
"future perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ futurePerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} have ${v[4]}`, `$SUBJ will${n ? " not" : ""} have ${v[4]}`,
]), ]),
"wouldBe perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ wouldBePerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} have ${v[4]}`, `$SUBJ would${n ? " not" : ""} have ${v[4]}`,
]), ]),
"pastSubjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ pastSubjunctivePerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} have ${v[4]}`, `$SUBJ would${n ? " not" : ""} have ${v[4]}`,
`$SUBJ should${n ? " not" : ""} have ${v[4]}`, `$SUBJ should${n ? " not" : ""} have ${v[4]}`,
]), ]),
@ -173,64 +178,64 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
T.PerfectTense, T.PerfectTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[] (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = { > = {
"present perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ presentPerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engHave(s)}${n ? " not" : ""} been ${v[4]}`, `$SUBJ ${engHave(s)}${n ? " not" : ""} been ${v[4]}`,
]), ]),
"past perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ pastPerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ had${n ? " not" : ""} been ${v[4]}`, `$SUBJ had${n ? " not" : ""} been ${v[4]}`,
]), ]),
"habitual perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ habitualPerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engHave(s)}${n ? " not" : ""} been ${v[4]}`, `$SUBJ ${engHave(s)}${n ? " not" : ""} been ${v[4]}`,
]), ]),
"subjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ subjunctivePerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ will${n ? " not" : ""} have been ${v[4]}`, `that $SUBJ will${n ? " not" : ""} have been ${v[4]}`,
]), ]),
"future perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ futurePerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} have been ${v[4]}`, `$SUBJ will${n ? " not" : ""} have been ${v[4]}`,
]), ]),
"wouldBe perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ wouldBePerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} have been ${v[4]}`, `$SUBJ will${n ? " not" : ""} have been ${v[4]}`,
]), ]),
"pastSubjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ pastSubjunctivePerfect: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} have been ${v[4]}`, `$SUBJ would${n ? " not" : ""} have been ${v[4]}`,
]), ]),
} }
const passiveModalBuilders: Record< const passiveModalBuilders: Record<
T.VerbTense, T.ModalTense,
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[] (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
> = { > = {
presentVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ presentVerbModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ can${n ? " not" : ""} be ${v[4]}`, `$SUBJ can${n ? " not" : ""} be ${v[4]}`,
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} able to be ${v[4]}`, `$SUBJ ${engEquative("present", s)}${n ? " not" : ""} able to be ${v[4]}`,
]), ]),
subjunctiveVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ subjunctiveVerbModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`that $SUBJ will${n ? " not" : ""} be able to be ${v[4]}`, `that $SUBJ will${n ? " not" : ""} be able to be ${v[4]}`,
`that $SUBJ ${n ? " not" : ""} be able to be ${v[4]}`, `that $SUBJ ${n ? " not" : ""} be able to be ${v[4]}`,
]), ]),
imperfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ imperfectiveFutureModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} be able to be ${v[4]}`, `$SUBJ will${n ? " not" : ""} be able to be ${v[4]}`,
]), ]),
perfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ perfectiveFutureModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} be able to be ${v[4]}`, `$SUBJ will${n ? " not" : ""} be able to be ${v[4]}`,
]), ]),
imperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ imperfectivePastModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`, `$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} being able to be ${v[4]}`, `$SUBJ ${engEquative("past", s)}${n ? " not" : ""} being able to be ${v[4]}`,
]), ]),
perfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ perfectivePastModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} able to be ${v[4]}`, `$SUBJ ${engEquative("past", s)}${n ? " not" : ""} able to be ${v[4]}`,
]), ]),
habitualPerfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ habitualPerfectivePastModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`, `$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
]), ]),
habitualImperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([ habitualImperfectivePastModal: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`, `$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
]), ]),
}; };
const base = ( const base = (
(vs.tenseCategory === "perfect") isPerfectTense(vs.tense)
? (vs.voice === "active" ? perfectBuilders : passivePerfectBuilders)[vs.tense] ? (vs.voice === "active" ? perfectBuilders : passivePerfectBuilders)[vs.tense]
: vs.tenseCategory === "basic" : isVerbTense(vs.tense)
? (vs.voice === "active" ? basicBuilders : passiveBasicBuilders)[vs.tense] ? (vs.voice === "active" ? basicBuilders : passiveBasicBuilders)[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

@ -19,10 +19,12 @@ import {
getPersonFromNP, getPersonFromNP,
removeBa, removeBa,
isPastTense, isPastTense,
isPerfectTense,
getTenseVerbForm, getTenseVerbForm,
} from "./vp-tools"; } from "./vp-tools";
import { isPattern4Entry } from "../type-predicates"; import {
isPattern4Entry,
isPerfectTense,
} from "../type-predicates";
import { renderEnglishVPBase } from "./english-vp-rendering"; import { renderEnglishVPBase } from "./english-vp-rendering";
// TODO: ISSUE GETTING SPLIT HEAD NOT MATCHING WITH FUTURE VERBS // TODO: ISSUE GETTING SPLIT HEAD NOT MATCHING WITH FUTURE VERBS
@ -129,7 +131,7 @@ function renderParticipleSelection(p: T.ParticipleSelection, inflected: boolean)
}; };
} }
function renderVerbSelection(vs: T.VerbSelection, person: T.Person, objectPerson: T.Person | undefined): T.VerbRendered { function renderVerbSelection(vs: T.VerbSelectionComplete, person: T.Person, objectPerson: T.Person | undefined): T.VerbRendered {
const v = vs.dynAuxVerb || vs.verb; const v = vs.dynAuxVerb || vs.verb;
const conjugations = conjugateVerb(v.entry, v.complement); const conjugations = conjugateVerb(v.entry, v.complement);
// TODO: error handle this? // TODO: error handle this?
@ -148,14 +150,14 @@ function renderVerbSelection(vs: T.VerbSelection, person: T.Person, objectPerson
} }
} }
function getPsVerbConjugation(conj: T.VerbConjugation, vs: T.VerbSelection, person: T.Person, objectPerson: T.Person | undefined): { function getPsVerbConjugation(conj: T.VerbConjugation, vs: T.VerbSelectionComplete, person: T.Person, objectPerson: T.Person | undefined): {
ps: { ps: {
head: T.PsString | undefined, head: T.PsString | undefined,
rest: T.SingleOrLengthOpts<T.PsString[]>, rest: T.SingleOrLengthOpts<T.PsString[]>,
}, },
hasBa: boolean, hasBa: boolean,
} { } {
const f = getTenseVerbForm(conj, vs.tense, vs.tenseCategory, vs.voice); const f = getTenseVerbForm(conj, vs.tense, vs.voice);
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);
@ -324,7 +326,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): boolean { function isPerfective(t: T.VerbTense | T.PerfectTense | T.ModalTense): 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;
@ -332,6 +334,9 @@ function isPerfective(t: T.VerbTense | T.PerfectTense): boolean {
if (t === "perfectiveFuture" || t === "subjunctiveVerb" || t === "perfectivePast" || t === "habitualPerfectivePast") { if (t === "perfectiveFuture" || t === "subjunctiveVerb" || t === "perfectivePast" || t === "habitualPerfectivePast") {
return true; return true;
} }
if (t === "perfectiveFutureModal" || t === "subjunctiveVerbModal" || t === "perfectivePastModal" || t === "habitualPerfectivePastModal") {
return true;
}
throw new Error("tense not implemented yet"); throw new Error("tense not implemented yet");
} }

View File

@ -4,6 +4,7 @@ import {
psRemove, psRemove,
psStringEquals, psStringEquals,
} from "../../lib/p-text-helpers"; } from "../../lib/p-text-helpers";
import { isPerfectTense } from "../type-predicates";
import * as grammarUnits from "../../lib/grammar-units"; import * as grammarUnits from "../../lib/grammar-units";
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean { export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
@ -26,9 +27,8 @@ export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
); );
} }
export function getTenseVerbForm(conjR: T.VerbConjugation, tense: T.VerbTense | T.PerfectTense, tenseCategory: "basic" | "modal" | "perfect", voice: "active" | "passive"): T.VerbForm { export function getTenseVerbForm(conjR: T.VerbConjugation, tense: T.VerbTense | T.PerfectTense | T.ModalTense, voice: "active" | "passive"): T.VerbForm {
const conj = (voice === "passive" && conjR.passive) ? conjR.passive : conjR; const conj = (voice === "passive" && conjR.passive) ? conjR.passive : conjR;
if (tenseCategory === "basic") {
if (tense === "presentVerb") { if (tense === "presentVerb") {
return conj.imperfective.nonImperative; return conj.imperfective.nonImperative;
} }
@ -53,52 +53,49 @@ export function getTenseVerbForm(conjR: T.VerbConjugation, tense: T.VerbTense |
if (tense === "habitualPerfectivePast") { if (tense === "habitualPerfectivePast") {
return conj.perfective.habitualPast; return conj.perfective.habitualPast;
} }
} if (tense === "presentVerbModal") {
if (tenseCategory === "modal") {
if (tense === "presentVerb") {
return conj.imperfective.modal.nonImperative; return conj.imperfective.modal.nonImperative;
} }
if (tense === "subjunctiveVerb") { if (tense === "subjunctiveVerbModal") {
return conj.perfective.modal.nonImperative; return conj.perfective.modal.nonImperative;
} }
if (tense === "imperfectiveFuture") { if (tense === "imperfectiveFutureModal") {
return conj.imperfective.modal.future; return conj.imperfective.modal.future;
} }
if (tense === "perfectiveFuture") { if (tense === "perfectiveFutureModal") {
return conj.perfective.modal.future; return conj.perfective.modal.future;
} }
if (tense === "imperfectivePast") { if (tense === "imperfectivePastModal") {
return conj.imperfective.modal.past; return conj.imperfective.modal.past;
} }
if (tense === "perfectivePast") { if (tense === "perfectivePastModal") {
return conj.perfective.modal.past; return conj.perfective.modal.past;
} }
if (tense === "habitualImperfectivePast") { if (tense === "habitualImperfectivePastModal") {
return conj.imperfective.modal.habitualPast; return conj.imperfective.modal.habitualPast;
} }
if (tense === "habitualPerfectivePast") { if (tense === "habitualPerfectivePastModal") {
return conj.perfective.modal.habitualPast; return conj.perfective.modal.habitualPast;
} }
} if (tense === "presentPerfect") {
if (tense === "present perfect") {
return conj.perfect.present; return conj.perfect.present;
} }
if (tense === "past perfect") { if (tense === "pastPerfect") {
return conj.perfect.past; return conj.perfect.past;
} }
if (tense === "future perfect") { if (tense === "futurePerfect") {
return conj.perfect.future; return conj.perfect.future;
} }
if (tense === "habitual perfect") { if (tense === "habitualPerfect") {
return conj.perfect.habitual; return conj.perfect.habitual;
} }
if (tense === "subjunctive perfect") { if (tense === "subjunctivePerfect") {
return conj.perfect.subjunctive; return conj.perfect.subjunctive;
} }
if (tense === "wouldBe perfect") { if (tense === "wouldBePerfect") {
return conj.perfect.affirmational; return conj.perfect.affirmational;
} }
if (tense === "pastSubjunctive perfect") { if (tense === "pastSubjunctivePerfect") {
return conj.perfect.pastSubjunctiveHypothetical; return conj.perfect.pastSubjunctiveHypothetical;
} }
throw new Error("unknown tense"); throw new Error("unknown tense");
@ -126,23 +123,45 @@ export function removeBa(ps: T.PsString): T.PsString {
return psRemove(ps, concatPsString(grammarUnits.baParticle, " ")); return psRemove(ps, concatPsString(grammarUnits.baParticle, " "));
} }
export function isEquativeTense(t: T.VerbTense | T.EquativeTense | T.PerfectTense): t is T.EquativeTense { export function getTenseFromVerbSelection(vs: T.VerbSelection): T.VerbTense | T.PerfectTense | T.ModalTense {
return (t === "present" || t === "future" || t === "habitual" || t === "past" || t === "wouldBe" || t === "subjunctive" || t === "pastSubjunctive"); function verbTenseToModalTense(tn: T.VerbTense): T.ModalTense {
if (tn === "presentVerb") {
return "presentVerbModal";
}
if (tn === "subjunctiveVerb") {
return "subjunctiveVerbModal";
}
if (tn === "imperfectiveFuture") {
return "imperfectiveFutureModal";
}
if (tn === "perfectiveFuture") {
return "perfectiveFutureModal";
}
if (tn === "perfectivePast") {
return "perfectiveFutureModal";
}
if (tn === "imperfectivePast") {
return "imperfectivePastModal";
}
if (tn === "habitualImperfectivePast") {
return "habitualImperfectivePastModal";
}
if (tn === "habitualPerfectivePast") {
return "habitualPerfectivePastModal";
}
throw new Error("can't convert non verbTense to modalTense");
}
if (vs.tenseCategory === "basic") {
return vs.verbTense;
}
if (vs.tenseCategory === "perfect") {
return vs.perfectTense;
}
// vs.tenseCategory === "modal"
return verbTenseToModalTense(vs.verbTense);
} }
export function isPerfectTense(t: T.VerbTense | T.EquativeTense | T.PerfectTense): t is T.PerfectTense { export function isPastTense(tense: T.VerbTense | T.PerfectTense | T.ModalTense): boolean {
return (
t === "present perfect" ||
t === "habitual perfect" ||
t === "future perfect" ||
t === "past perfect" ||
t === "wouldBe perfect" ||
t === "subjunctive perfect" ||
t === "pastSubjunctive perfect"
);
}
export function isPastTense(tense: T.VerbTense | T.PerfectTense): boolean {
if (isPerfectTense(tense)) return true; if (isPerfectTense(tense)) return true;
return tense.toLowerCase().includes("past"); return tense.toLowerCase().includes("past");
} }
@ -155,15 +174,52 @@ export function removeDuplicates(psv: T.PsString[]): T.PsString[] {
)); ));
} }
export function switchSubjObj({ subject, verb }: T.VPSelection): T.VPSelection { export function switchSubjObj(vps: T.VPSelection): T.VPSelection;
if (!subject|| !verb || !verb.object || !(typeof verb.object === "object")) { export function switchSubjObj(vps: T.VPSelectionComplete): T.VPSelectionComplete;
return { subject, verb }; export function switchSubjObj(vps: T.VPSelection | T.VPSelectionComplete): T.VPSelection | T.VPSelectionComplete {
if ("tenseCategory" in vps.verb) {
if (!vps.subject || !(typeof vps.verb.object === "object")) {
return vps;
} }
return { return {
subject: verb.object, ...vps,
subject: vps.verb.object,
verb: { verb: {
...verb, ...vps.verb,
object: subject, object: vps.subject,
},
};
}
if (!vps.subject|| !vps.verb || !(typeof vps.verb.object === "object")) {
return vps;
}
return {
...vps,
subject: vps.verb.object,
verb: {
...vps.verb,
object: vps.subject,
} }
}; };
} }
export function completeVPSelection(vps: T.VPSelection): T.VPSelectionComplete | undefined {
if (vps.subject === undefined) {
return undefined;
}
if (vps.verb.object === undefined) {
return undefined;
}
// necessary for this version on typscript ...
const verb: T.VerbSelectionComplete = {
...vps.verb,
object: vps.verb.object,
tense: getTenseFromVerbSelection(vps.verb),
};
const subject = vps.subject;
return {
...vps,
subject,
verb,
};
}

View File

@ -160,9 +160,30 @@ export function isArrayOneOrMore<U>(a: U[]): a is T.ArrayOneOrMore<U> {
return a.length > 0; return a.length > 0;
} }
export function isVPSelectionComplete(vps: T.VPSelection | T.VPSelectionComplete): vps is T.VPSelectionComplete { export function isPerfectTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense | T.PerfectTense): tense is T.PerfectTense {
if ((vps.subject !== undefined) && (vps.verb.object !== undefined)) { return tense.endsWith("Perfect");
return true;
} }
return false;
export function isVerbTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense | T.PerfectTense): tense is T.VerbTense {
const verbTenses: T.VerbTense[] = [
"presentVerb",
"subjunctiveVerb",
"perfectiveFuture",
"imperfectiveFuture",
"perfectivePast",
"imperfectivePast",
"habitualPerfectivePast",
"habitualImperfectivePast",
];
return verbTenses.some(x => x === tense);
} }
export function isModalTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense | T.PerfectTense): tense is T.ModalTense {
return tense.endsWith("Modal");
}
export function isEquativeTense(t: T.VerbTense | T.EquativeTense | T.PerfectTense | T.ModalTense): t is T.EquativeTense {
return (t === "present" || t === "future" || t === "habitual" || t === "past" || t === "wouldBe" || t === "subjunctive" || t === "pastSubjunctive");
}

View File

@ -535,7 +535,8 @@ export type VerbTense = "presentVerb"
export type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive"; export type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive";
export type NounNumber = "singular" | "plural"; export type NounNumber = "singular" | "plural";
export type PerfectTense = `${EquativeTense} perfect`; export type PerfectTense = `${EquativeTense}Perfect`;
export type ModalTense = `${VerbTense}Modal`;
export type VPSelection = { export type VPSelection = {
subject: NPSelection | undefined, subject: NPSelection | undefined,
@ -547,9 +548,10 @@ export type VPSelectionComplete = {
verb: VerbSelectionComplete, verb: VerbSelectionComplete,
}; };
export type VerbSelectionComplete = Exclude<VerbSelection, "object"> & { export type VerbSelectionComplete = Omit<VerbSelection, "object" | "verbTense" | "perfectTense" | "tenseCategory"> & {
object: Exclude<VerbObject, undefined>, object: Exclude<VerbObject, undefined>,
}; tense: VerbTense | PerfectTense | ModalTense,
}
export type VerbSelection = { export type VerbSelection = {
type: "verb", type: "verb",
@ -565,15 +567,12 @@ export type VerbSelection = {
// TODO: changeStativeDynamic // TODO: changeStativeDynamic
// TODO: add in aspect element here?? // TODO: add in aspect element here??
negative: boolean, negative: boolean,
} & ({ verbTense: VerbTense,
tense: VerbTense, perfectTense: PerfectTense,
tenseCategory: "basic" | "modal", tenseCategory: "basic" | "modal" | "perfect",
} | { };
tense: PerfectTense,
tenseCategory: "perfect"
});
export type VerbRendered = Omit<VerbSelection, "object"> & { export type VerbRendered = Omit<VerbSelectionComplete, "object"> & {
ps: { ps: {
head: PsString | undefined, head: PsString | undefined,
rest: SingleOrLengthOpts< rest: SingleOrLengthOpts<