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",
"version": "2.1.1",
"version": "2.1.2",
"author": "lingdocs.com",
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
"homepage": "https://verbs.lingdocs.com",

View File

@ -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 { conjugateVerb } from "../../lib/verb-conjugation";
import * as T from "../../types";
@ -13,7 +16,7 @@ function ChartDisplay({ VS, opts }: { VS: T.VerbSelection, opts: T.TextOptions }
: ("transitive" in rawConjugations)
? rawConjugations[VS.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
: rawConjugations;
const form = getTenseVerbForm(conjugations, VS.tense, VS.tenseCategory, VS.voice);
const form = getTenseVerbForm(conjugations, getTenseFromVerbSelection(VS), VS.voice);
return <div className="mb-4">
<VerbFormDisplay
displayForm={form}

View File

@ -4,7 +4,7 @@ import {
} from "../np-picker/picker-tools";
import * as T from "../../types";
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 }[] = [{
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 }[] = [{
label: "Present Perfect",
value: "present perfect",
value: "presentPerfect",
}, {
label: "Habitual Perfect",
value: "habitual perfect",
value: "habitualPerfect",
}, {
label: "Subjunctive Perfect",
value: "subjunctive perfect",
value: "subjunctivePerfect",
}, {
label: "Future Perfect",
value: "future perfect",
value: "futurePerfect",
}, {
label: "Past Perfect",
value: "past perfect",
value: "pastPerfect",
}, {
label: `"Would Be" Perfect`,
value: "wouldBe perfect",
value: "wouldBePerfect",
}, {
label: "Past Subjunctive Perfect",
value: "pastSubjunctive perfect",
value: "pastSubjunctivePerfect",
}];
export function getRandomTense(type: "basic" | "modal", o?: T.VerbTense): T.VerbTense;
export function getRandomTense(type: "perfect", o?: T.PerfectTense | T.VerbTense): T.PerfectTense;
export function getRandomTense(type: "basic" | "modal" | "perfect", o?: T.PerfectTense | T.VerbTense): T.PerfectTense | T.VerbTense {
let tns: T.PerfectTense | T.VerbTense;
const tenseOptions = type === "perfect" ? perfectTenseOptions : verbTenseOptions;
export function getRandomTense(o?: T.PerfectTense | T.VerbTense | T.ModalTense): T.PerfectTense | T.VerbTense | T.ModalTense {
let tns: T.PerfectTense | T.VerbTense | T.ModalTense;
const oldTenseCategory = !o
? undefined
: getTenseCategory(o);
const tenseOptions = oldTenseCategory === "perfect"
? perfectTenseOptions
: oldTenseCategory === "modal"
? verbTenseOptions.map(x => ({ ...x, value: `${x.value}Modal` as T.ModalTense }))
: verbTenseOptions;
do {
tns = tenseOptions[
Math.floor(Math.random()*tenseOptions.length)
@ -68,40 +73,49 @@ export function getRandomTense(type: "basic" | "modal" | "perfect", o?: T.Perfec
return tns;
}
function TensePicker({ onChange, vps, mode }: {
function TensePicker(props: ({
vps: T.VPSelection,
} | {
vpsComplete: T.VPSelectionComplete,
}) & {
onChange: (p: T.VPSelection) => void,
mode: "charts" | "phrases" | "quiz",
}) {
function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense } | null) {
if ("vpsComplete" in props) return;
const value = o?.value ? o.value : undefined;
if (vps.verb && value) {
if (props.vps.verb && value) {
if (isPerfectTense(value)) {
onChange({
...vps,
props.onChange({
...props.vps,
verb: {
...vps.verb,
tense: value,
...props.vps.verb,
perfectTense: value,
tenseCategory: "perfect",
},
});
} else {
onChange({
...vps,
props.onChange({
...props.vps,
verb: {
...vps.verb,
tense: value,
tenseCategory: vps.verb.tenseCategory === "perfect" ? "basic" : vps.verb.tenseCategory,
...props.vps.verb,
verbTense: value,
tenseCategory: props.vps.verb.tenseCategory === "perfect"
? "basic"
: props.vps.verb.tenseCategory,
},
});
}
}
}
function moveTense(dir: "forward" | "back") {
if (!vps.verb) return;
if ("vpsComplete" in props) return;
if (!props.vps.verb) return;
return () => {
const tenses = vps.verb.tenseCategory === "perfect" ? perfectTenseOptions : verbTenseOptions;
const currIndex = tenses.findIndex(tn => tn.value === vps.verb.tense)
const tenses = props.vps.verb.tenseCategory === "perfect" ? perfectTenseOptions : verbTenseOptions;
const currIndex = tenses.findIndex(tn => tn.value === props.vps.verb[
props.vps.verb.tenseCategory === "perfect" ? "perfectTense" : "verbTense"
]);
if (currIndex === -1) {
console.error("error moving tense", dir);
return;
@ -114,48 +128,42 @@ function TensePicker({ onChange, vps, mode }: {
};
}
function onPosNegSelect(value: string) {
if (vps.verb) {
onChange({
...vps,
if ("vpsComplete" in props) return;
if (props.vps.verb) {
props.onChange({
...props.vps,
verb: {
...vps.verb,
...props.vps.verb,
negative: value === "true",
},
});
}
}
function onTenseCategorySelect(value: "basic" | "modal" | "perfect") {
if (vps.verb) {
if (value === "perfect") {
onChange({
...vps,
if ("vpsComplete" in props) return;
if (props.vps.verb) {
props.onChange({
...props.vps,
verb: {
...vps.verb,
...props.vps.verb,
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.verb?.tenseCategory === "perfect") ? perfectTenseOptions : verbTenseOptions;
const tOptions = ("vps" in props && (props.vps.verb?.tenseCategory === "perfect"))
? perfectTenseOptions
: verbTenseOptions;
return <div>
<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>
{vps.verb && <div className="mb-2">
{("vpsComplete" in props || props.vps.verb) && <div className="mb-2">
<ButtonSelect
small
value={vps.verb.tenseCategory}
value={"vpsComplete" in props
? getTenseCategory(props.vpsComplete.verb.tense)
: props.vps.verb.tenseCategory}
options={[{
label: "Basic",
value: "basic",
@ -166,26 +174,32 @@ function TensePicker({ onChange, vps, mode }: {
label: "Modal",
value: "modal",
}]}
handleChange={mode !== "quiz" ? onTenseCategorySelect : () => null}
handleChange={props.mode !== "quiz" ? onTenseCategorySelect : () => null}
/>
</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}
// 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}
className="mb-2"
options={tOptions}
{...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")}>
<i className="fas fa-chevron-left" />
</div>
{mode === "phrases" && <ButtonSelect
{props.mode === "phrases" && <ButtonSelect
small
value={vps.verb.negative.toString()}
value={props.vps.verb.negative.toString()}
options={[{
label: "Pos.",
value: "false",
@ -204,3 +218,16 @@ function TensePicker({ onChange, vps, mode }: {
}
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 InlinePs from "../InlinePs";
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 { 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 [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">
{(() => {
const twoNPs = (VP.subject === undefined) && (VP.verb.object === undefined);
@ -17,7 +20,7 @@ function VPDisplay({ VP, opts }: { VP: T.VPSelection | T.VPSelectionComplete, op
})()}
</div>;
}
const result = compileVP(renderVP(VP), { ...form, OSV });
const result = compileVP(renderVP(VPComplete), { ...form, OSV });
return <div className="text-center mt-2">
{VP.verb.transitivity === "transitive" && <div className="form-check mb-2">
<input
@ -32,7 +35,7 @@ function VPDisplay({ VP, opts }: { VP: T.VPSelection | T.VPSelectionComplete, op
</label>
</div>}
<AbbreviationFormSelector
adjustable={whatsAdjustable(VP)}
adjustable={whatsAdjustable(VPComplete)}
form={form}
onChange={setForm}
/>

View File

@ -48,7 +48,7 @@ export function VPExplorer(props: {
})) {
const [vps, setVps] = useStickyState<T.VPSelection>(
savedVps => makeVPSelectionState(props.verb, savedVps),
"vpsState1",
"vpsState2",
);
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
savedMode => {
@ -59,7 +59,10 @@ export function VPExplorer(props: {
"verbExplorerMode",
);
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(() => {
setVps(oldVps => {
if (mode === "quiz") {

View File

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

View File

@ -3,7 +3,6 @@ import {
} from "../np-picker/picker-tools";
import * as T from "../../types";
import { getVerbInfo } from "../../lib/verb-info";
import { isPerfectTense } from "../../lib/phrase-building/vp-tools";
export function makeVPSelectionState(
verb: T.VerbEntry,
@ -46,28 +45,15 @@ export function makeVPSelectionState(
: "dynamic" in info
? { entry: info.dynamic.auxVerb } as T.VerbEntry
: 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 {
subject,
verb: {
type: "verb",
verb: verb,
dynAuxVerb,
...tenseSelection,
verbTense: os ? os.verb.verbTense : "presentVerb",
perfectTense: os ? os.verb.perfectTense : "presentPerfect",
tenseCategory: os ? os.verb.tenseCategory : "basic",
object,
transitivity,
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
{
in: {

View File

@ -12,6 +12,7 @@ import {
removeBa,
removeDuplicates,
} from "./vp-tools";
import { isModalTense, isPerfectTense } from "../type-predicates";
type Form = T.FormVersion & { OSV?: boolean };
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[][] {
const hasLeapfrog = V.tenseCategory === "modal" || V.tenseCategory === "perfect";
const hasLeapfrog = isPerfectTense(V.tense) || isModalTense(V.tense);
const rest = (() => {
if (hasLeapfrog) {
const [restF, restLast] = splitOffLeapfrogWord(restRaw);

View File

@ -1,6 +1,11 @@
import * as T from "../../types";
import { getVerbBlockPosFromPerson, parseEc } from "../misc-helpers";
import * as grammarUnits from "../grammar-units";
import {
isPerfectTense,
isVerbTense,
// isModalTense,
} from "../type-predicates";
function engHave(s: T.Person): string {
function isThirdPersonSing(p: T.Person): boolean {
@ -15,7 +20,7 @@ function engHave(s: T.Person): string {
export function renderEnglishVPBase({ subjectPerson, object, vs }: {
subjectPerson: T.Person,
object: T.NPSelection | T.ObjectNP,
vs: T.VerbSelection,
vs: T.VerbSelectionComplete,
}): string[] {
const ec = parseEc(vs.verb.entry.ec || "");
const ep = vs.verb.entry.ep;
@ -79,34 +84,34 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
]),
};
const modalBuilders: Record<
T.VerbTense,
T.ModalTense,
(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]}`,
]),
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]}`,
]),
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]}`,
]),
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]}`,
]),
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 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 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 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 would ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
]),
@ -115,25 +120,25 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
T.PerfectTense,
(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]}`,
]),
"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]}`,
]),
"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]}`,
]),
"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]}`,
]),
"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]}`,
]),
"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]}`,
]),
"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 should${n ? " not" : ""} have ${v[4]}`,
]),
@ -173,64 +178,64 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
T.PerfectTense,
(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]}`,
]),
"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]}`,
]),
"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]}`,
]),
"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]}`,
]),
"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]}`,
]),
"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]}`,
]),
"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]}`,
]),
}
const passiveModalBuilders: Record<
T.VerbTense,
T.ModalTense,
(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 ${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 ${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]}`,
]),
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]}`,
]),
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 ${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]}`,
]),
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]}`,
]),
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]}`,
]),
};
const base = (
(vs.tenseCategory === "perfect")
isPerfectTense(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" ? modalBuilders : passiveModalBuilders)[vs.tense])(subjectPerson, ec, vs.negative);
return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`);

View File

@ -19,10 +19,12 @@ import {
getPersonFromNP,
removeBa,
isPastTense,
isPerfectTense,
getTenseVerbForm,
} from "./vp-tools";
import { isPattern4Entry } from "../type-predicates";
import {
isPattern4Entry,
isPerfectTense,
} from "../type-predicates";
import { renderEnglishVPBase } from "./english-vp-rendering";
// 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 conjugations = conjugateVerb(v.entry, v.complement);
// 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: {
head: T.PsString | undefined,
rest: T.SingleOrLengthOpts<T.PsString[]>,
},
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 perfective = isPerfective(vs.tense);
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);
}
function isPerfective(t: T.VerbTense | T.PerfectTense): boolean {
function isPerfective(t: T.VerbTense | T.PerfectTense | T.ModalTense): boolean {
if (isPerfectTense(t)) return false;
if (t === "presentVerb" || t === "imperfectiveFuture" || t === "imperfectivePast" || t === "habitualImperfectivePast") {
return false;
@ -332,6 +334,9 @@ function isPerfective(t: T.VerbTense | T.PerfectTense): boolean {
if (t === "perfectiveFuture" || t === "subjunctiveVerb" || t === "perfectivePast" || t === "habitualPerfectivePast") {
return true;
}
if (t === "perfectiveFutureModal" || t === "subjunctiveVerbModal" || t === "perfectivePastModal" || t === "habitualPerfectivePastModal") {
return true;
}
throw new Error("tense not implemented yet");
}

View File

@ -4,6 +4,7 @@ import {
psRemove,
psStringEquals,
} from "../../lib/p-text-helpers";
import { isPerfectTense } from "../type-predicates";
import * as grammarUnits from "../../lib/grammar-units";
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;
if (tenseCategory === "basic") {
if (tense === "presentVerb") {
return conj.imperfective.nonImperative;
}
@ -53,52 +53,49 @@ export function getTenseVerbForm(conjR: T.VerbConjugation, tense: T.VerbTense |
if (tense === "habitualPerfectivePast") {
return conj.perfective.habitualPast;
}
}
if (tenseCategory === "modal") {
if (tense === "presentVerb") {
if (tense === "presentVerbModal") {
return conj.imperfective.modal.nonImperative;
}
if (tense === "subjunctiveVerb") {
if (tense === "subjunctiveVerbModal") {
return conj.perfective.modal.nonImperative;
}
if (tense === "imperfectiveFuture") {
if (tense === "imperfectiveFutureModal") {
return conj.imperfective.modal.future;
}
if (tense === "perfectiveFuture") {
if (tense === "perfectiveFutureModal") {
return conj.perfective.modal.future;
}
if (tense === "imperfectivePast") {
if (tense === "imperfectivePastModal") {
return conj.imperfective.modal.past;
}
if (tense === "perfectivePast") {
if (tense === "perfectivePastModal") {
return conj.perfective.modal.past;
}
if (tense === "habitualImperfectivePast") {
if (tense === "habitualImperfectivePastModal") {
return conj.imperfective.modal.habitualPast;
}
if (tense === "habitualPerfectivePast") {
if (tense === "habitualPerfectivePastModal") {
return conj.perfective.modal.habitualPast;
}
}
if (tense === "present perfect") {
if (tense === "presentPerfect") {
return conj.perfect.present;
}
if (tense === "past perfect") {
if (tense === "pastPerfect") {
return conj.perfect.past;
}
if (tense === "future perfect") {
if (tense === "futurePerfect") {
return conj.perfect.future;
}
if (tense === "habitual perfect") {
if (tense === "habitualPerfect") {
return conj.perfect.habitual;
}
if (tense === "subjunctive perfect") {
if (tense === "subjunctivePerfect") {
return conj.perfect.subjunctive;
}
if (tense === "wouldBe perfect") {
if (tense === "wouldBePerfect") {
return conj.perfect.affirmational;
}
if (tense === "pastSubjunctive perfect") {
if (tense === "pastSubjunctivePerfect") {
return conj.perfect.pastSubjunctiveHypothetical;
}
throw new Error("unknown tense");
@ -126,23 +123,45 @@ export function removeBa(ps: T.PsString): T.PsString {
return psRemove(ps, concatPsString(grammarUnits.baParticle, " "));
}
export function isEquativeTense(t: T.VerbTense | T.EquativeTense | T.PerfectTense): t is T.EquativeTense {
return (t === "present" || t === "future" || t === "habitual" || t === "past" || t === "wouldBe" || t === "subjunctive" || t === "pastSubjunctive");
export function getTenseFromVerbSelection(vs: T.VerbSelection): T.VerbTense | T.PerfectTense | T.ModalTense {
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 {
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 {
export function isPastTense(tense: T.VerbTense | T.PerfectTense | T.ModalTense): boolean {
if (isPerfectTense(tense)) return true;
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 {
if (!subject|| !verb || !verb.object || !(typeof verb.object === "object")) {
return { subject, verb };
export function switchSubjObj(vps: T.VPSelection): T.VPSelection;
export function switchSubjObj(vps: T.VPSelectionComplete): T.VPSelectionComplete;
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 {
subject: verb.object,
...vps,
subject: vps.verb.object,
verb: {
...verb,
object: subject,
...vps.verb,
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;
}
export function isVPSelectionComplete(vps: T.VPSelection | T.VPSelectionComplete): vps is T.VPSelectionComplete {
if ((vps.subject !== undefined) && (vps.verb.object !== undefined)) {
return true;
export function isPerfectTense(tense: T.VerbTense | T.EquativeTense | T.ModalTense | T.PerfectTense): tense is T.PerfectTense {
return tense.endsWith("Perfect");
}
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 NounNumber = "singular" | "plural";
export type PerfectTense = `${EquativeTense} perfect`;
export type PerfectTense = `${EquativeTense}Perfect`;
export type ModalTense = `${VerbTense}Modal`;
export type VPSelection = {
subject: NPSelection | undefined,
@ -547,9 +548,10 @@ export type VPSelectionComplete = {
verb: VerbSelectionComplete,
};
export type VerbSelectionComplete = Exclude<VerbSelection, "object"> & {
export type VerbSelectionComplete = Omit<VerbSelection, "object" | "verbTense" | "perfectTense" | "tenseCategory"> & {
object: Exclude<VerbObject, undefined>,
};
tense: VerbTense | PerfectTense | ModalTense,
}
export type VerbSelection = {
type: "verb",
@ -565,15 +567,12 @@ export type VerbSelection = {
// TODO: changeStativeDynamic
// TODO: add in aspect element here??
negative: boolean,
} & ({
tense: VerbTense,
tenseCategory: "basic" | "modal",
} | {
tense: PerfectTense,
tenseCategory: "perfect"
});
verbTense: VerbTense,
perfectTense: PerfectTense,
tenseCategory: "basic" | "modal" | "perfect",
};
export type VerbRendered = Omit<VerbSelection, "object"> & {
export type VerbRendered = Omit<VerbSelectionComplete, "object"> & {
ps: {
head: PsString | undefined,
rest: SingleOrLengthOpts<