pretty much working with new verb engine and verb explorer ... quiz doesn't seem to be working right now
This commit is contained in:
parent
5f8c4ba876
commit
3b6d013402
|
@ -10,6 +10,7 @@
|
|||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fp-ts": "^2.16.0",
|
||||
"react-select": "^5.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -10735,6 +10736,11 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fp-ts": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.0.tgz",
|
||||
"integrity": "sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ=="
|
||||
},
|
||||
"node_modules/fragment-cache": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
||||
|
@ -31006,6 +31012,11 @@
|
|||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
||||
"dev": true
|
||||
},
|
||||
"fp-ts": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.0.tgz",
|
||||
"integrity": "sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ=="
|
||||
},
|
||||
"fragment-cache": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
||||
|
|
|
@ -77,7 +77,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"fp-ts": "^2.16.0",
|
||||
"react-media-hook": "^0.5.0",
|
||||
"react-select": "^5.4.0"
|
||||
}
|
||||
}
|
100
src/App.tsx
100
src/App.tsx
|
@ -9,9 +9,7 @@
|
|||
import { useEffect, useState } from "react";
|
||||
|
||||
import ButtonSelect from "./components/src/ButtonSelect";
|
||||
import {
|
||||
Modal
|
||||
} from "react-bootstrap";
|
||||
import { Modal } from "react-bootstrap";
|
||||
import * as T from "./types";
|
||||
import defualtTextOptions from "./lib/src/default-text-options";
|
||||
import useStickyState from "./components/src/useStickyState";
|
||||
|
@ -23,28 +21,43 @@ import InflectionDemo from "./demo-components/InflectionDemo";
|
|||
import SpellingDemo from "./demo-components/SpellingDemo";
|
||||
|
||||
function App() {
|
||||
const [showingTextOptions, setShowingTextOptions] = useStickyState<boolean>(false, "showTextOpts1");
|
||||
const [textOptions, setTextOptions] = useStickyState<T.TextOptions>(defualtTextOptions, "textOpts1");
|
||||
const [showingTextOptions, setShowingTextOptions] = useStickyState<boolean>(
|
||||
false,
|
||||
"showTextOpts1"
|
||||
);
|
||||
const [textOptions, setTextOptions] = useStickyState<T.TextOptions>(
|
||||
defualtTextOptions,
|
||||
"textOpts1"
|
||||
);
|
||||
const [theme, setTheme] = useStickyState<"light" | "dark">("light", "theme1");
|
||||
const [showing, setShowing] = useState<string>("");
|
||||
function handleHiderClick(label: string) {
|
||||
setShowing(os => os === label
|
||||
? ""
|
||||
: label);
|
||||
setShowing((os) => (os === label ? "" : label));
|
||||
}
|
||||
useEffect(() => {
|
||||
document.documentElement.setAttribute("data-theme", theme);
|
||||
}, [theme]);
|
||||
|
||||
return <>
|
||||
return (
|
||||
<>
|
||||
<main className="flex-shrink-0 mb-4">
|
||||
<div className="container" style={{ maxWidth: "800px" }}>
|
||||
<div style={{ position: "absolute", top: "1.5rem", right: "1.5rem", display: "flex", flexDirection: "row" }}>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "1.5rem",
|
||||
right: "1.5rem",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="clickable mr-3"
|
||||
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
|
||||
>
|
||||
<i className={`fa-lg fas fa-${theme === "light" ? "sun" : "moon"}`} />
|
||||
<i
|
||||
className={`fa-lg fas fa-${theme === "light" ? "sun" : "moon"}`}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="clickable"
|
||||
|
@ -53,14 +66,36 @@ function App() {
|
|||
<i className="fa-lg fas fa-cog" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center mb-4" style={{ marginTop: "3rem", marginBottom: "1rem" }}>
|
||||
<h1 className="display-4 mt-2"><code>Pashto Inflector</code></h1>
|
||||
<p className="lead my-3" style={{ maxWidth: "600px", margin: "0 auto" }}>
|
||||
An open source TypeScript/React library for Pashto inflection, verb conjugation, phrase generation, text conversion, and more
|
||||
<div
|
||||
className="text-center mb-4"
|
||||
style={{ marginTop: "3rem", marginBottom: "1rem" }}
|
||||
>
|
||||
<h1 className="display-4 mt-2">
|
||||
<code>Pashto Inflector</code>
|
||||
</h1>
|
||||
<p
|
||||
className="lead my-3"
|
||||
style={{ maxWidth: "600px", margin: "0 auto" }}
|
||||
>
|
||||
An open source TypeScript/React library for Pashto inflection,
|
||||
verb conjugation, phrase generation, text conversion, and more
|
||||
</p>
|
||||
<p>
|
||||
Used in the{" "}
|
||||
<a href="https://dictionary.lingdocs.com">
|
||||
LingDocs Pashto Dictionary
|
||||
</a>{" "}
|
||||
and{" "}
|
||||
<a href="https://grammar.lingdocs.com">LingDocs Pashto Grammar</a>
|
||||
</p>
|
||||
<p>
|
||||
by <a href="https://adueck.github.io">Adam Dueck</a> - GPLv3
|
||||
licensed{" "}
|
||||
<a href="https://github.com/lingdocs/pashto-inflector">
|
||||
Source Code
|
||||
</a>{" "}
|
||||
on GitHub
|
||||
</p>
|
||||
<p>Used in the <a href="https://dictionary.lingdocs.com">LingDocs Pashto Dictionary</a> and <a href="https://grammar.lingdocs.com">LingDocs Pashto Grammar</a></p>
|
||||
<p>by <a href="https://adueck.github.io">Adam Dueck</a> - GPLv3 licensed <a href="https://github.com/lingdocs/pashto-inflector">Source Code</a> on GitHub</p>
|
||||
|
||||
</div>
|
||||
<h2 className="mb-3">Demos:</h2>
|
||||
<Hider
|
||||
|
@ -78,10 +113,7 @@ function App() {
|
|||
handleChange={() => handleHiderClick("equatives")}
|
||||
>
|
||||
<div className="mt-4" style={{ paddingBottom: "20px" }}>
|
||||
<EPExplorer
|
||||
opts={textOptions}
|
||||
entryFeeder={entryFeeder}
|
||||
/>
|
||||
<EPExplorer opts={textOptions} entryFeeder={entryFeeder} />
|
||||
</div>
|
||||
</Hider>
|
||||
<Hider
|
||||
|
@ -102,7 +134,10 @@ function App() {
|
|||
</Hider>
|
||||
</div>
|
||||
</main>
|
||||
<Modal show={showingTextOptions} onHide={() => setShowingTextOptions(false)}>
|
||||
<Modal
|
||||
show={showingTextOptions}
|
||||
onHide={() => setShowingTextOptions(false)}
|
||||
>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Settings</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
@ -129,7 +164,9 @@ function App() {
|
|||
{ label: "Off", value: "false" },
|
||||
]}
|
||||
value={textOptions.diacritics.toString()}
|
||||
handleChange={(p) => setTextOptions({ ...textOptions, diacritics: p === "true" })}
|
||||
handleChange={(p) =>
|
||||
setTextOptions({ ...textOptions, diacritics: p === "true" })
|
||||
}
|
||||
/>
|
||||
<h6 className="mt-3">Pashto Text Size</h6>
|
||||
<ButtonSelect
|
||||
|
@ -139,7 +176,9 @@ function App() {
|
|||
{ label: "X-Large", value: "largest" },
|
||||
]}
|
||||
value={textOptions.pTextSize}
|
||||
handleChange={(p) => setTextOptions({ ...textOptions, pTextSize: p })}
|
||||
handleChange={(p) =>
|
||||
setTextOptions({ ...textOptions, pTextSize: p })
|
||||
}
|
||||
/>
|
||||
<h6 className="mt-3">Phonetics</h6>
|
||||
<ButtonSelect
|
||||
|
@ -150,11 +189,17 @@ function App() {
|
|||
// { label: "None", value: "none" },
|
||||
]}
|
||||
value={textOptions.phonetics}
|
||||
handleChange={(p) => setTextOptions({ ...textOptions, phonetics: p })}
|
||||
handleChange={(p) =>
|
||||
setTextOptions({ ...textOptions, phonetics: p })
|
||||
}
|
||||
/>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<button type="button" className="btn btn-primary clb" onClick={() => setShowingTextOptions(false)}>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary clb"
|
||||
onClick={() => setShowingTextOptions(false)}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
|
@ -165,6 +210,7 @@ function App() {
|
|||
</div>
|
||||
</footer> */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,4 @@
|
|||
import {
|
||||
makeNounSelection,
|
||||
} from "../../../lib/src/phrase-building/make-selections";
|
||||
import { makeNounSelection } from "../../../lib/src/phrase-building/make-selections";
|
||||
|
||||
import * as T from "../../../types";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
|
@ -57,12 +55,13 @@ import AdjectiveManager from "./AdjectiveManager";
|
|||
// }
|
||||
|
||||
function NPNounPicker(props: {
|
||||
entryFeeder: T.EntryFeeder,
|
||||
noun: T.NounSelection | undefined,
|
||||
onChange: (p: T.NounSelection | undefined) => void,
|
||||
opts: T.TextOptions,
|
||||
phraseIsComplete: boolean,
|
||||
entryFeeder: T.EntryFeeder;
|
||||
noun: T.NounSelection | undefined;
|
||||
onChange: (p: T.NounSelection | undefined) => void;
|
||||
opts: T.TextOptions;
|
||||
phraseIsComplete: boolean;
|
||||
}) {
|
||||
console.log({ noun: props.noun });
|
||||
// const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
|
||||
// const [showFilter, setShowFilter] = useState<boolean>(false)
|
||||
// const nounsFiltered = props.nouns
|
||||
|
@ -86,7 +85,9 @@ function NPNounPicker(props: {
|
|||
});
|
||||
}
|
||||
}
|
||||
function handleDemonstrativeUpdate(demonstrative: undefined | T.NounSelection["demonstrative"]) {
|
||||
function handleDemonstrativeUpdate(
|
||||
demonstrative: undefined | T.NounSelection["demonstrative"]
|
||||
) {
|
||||
if (props.noun) {
|
||||
props.onChange({
|
||||
...props.noun,
|
||||
|
@ -94,7 +95,8 @@ function NPNounPicker(props: {
|
|||
});
|
||||
}
|
||||
}
|
||||
return <div style={{ maxWidth: "225px", minWidth: "125px" }}>
|
||||
return (
|
||||
<div style={{ maxWidth: "225px", minWidth: "125px" }}>
|
||||
{/* {showFilter && <div className="mb-2 text-center">
|
||||
<div className="d-flex flex-row justify-content-between">
|
||||
<div className="text-small mb-1">Filter by inflection pattern</div>
|
||||
|
@ -108,7 +110,8 @@ function NPNounPicker(props: {
|
|||
handleChange={setPatternFilter}
|
||||
/>
|
||||
</div>} */}
|
||||
{props.noun && <AdjectiveManager
|
||||
{props.noun && (
|
||||
<AdjectiveManager
|
||||
phraseIsComplete={props.phraseIsComplete}
|
||||
adjectives={props.noun?.adjectives}
|
||||
demonstrative={props.noun.demonstrative}
|
||||
|
@ -116,9 +119,14 @@ function NPNounPicker(props: {
|
|||
opts={props.opts}
|
||||
onChange={handelAdjectivesUpdate}
|
||||
onDemonstrativeChange={handleDemonstrativeUpdate}
|
||||
/>}
|
||||
/>
|
||||
)}
|
||||
<div className="h6">Noun</div>
|
||||
{!(props.noun && props.noun.dynamicComplement) ? <div>
|
||||
{!(
|
||||
props.noun &&
|
||||
(props.noun.dynamicComplement || props.noun.genStativeComplement)
|
||||
) ? (
|
||||
<div>
|
||||
<EntrySelect
|
||||
value={props.noun?.entry}
|
||||
entryFeeder={props.entryFeeder.nouns}
|
||||
|
@ -126,20 +134,31 @@ function NPNounPicker(props: {
|
|||
name="Noun"
|
||||
opts={props.opts}
|
||||
/>
|
||||
</div> : <div>
|
||||
{props.noun && <div>
|
||||
<div className="mb-2">Included in Dyn. Compound:</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
{props.noun && (
|
||||
<div>
|
||||
<div className="mb-2">
|
||||
Included in{" "}
|
||||
{props.noun.genStativeComplement ? "Gen. Stat." : "Dyn."}{" "}
|
||||
Compound:
|
||||
</div>
|
||||
<div className="mb-3 text-center">
|
||||
<InlinePs opts={props.opts}>
|
||||
{{ p: props.noun.entry.p, f: props.noun.entry.f }}
|
||||
</InlinePs>
|
||||
<div className="text-muted">{props.noun.entry.e}</div>
|
||||
</div>
|
||||
</div>}
|
||||
</div>}
|
||||
{props.noun && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{props.noun && (
|
||||
<div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
<div>
|
||||
{props.noun.genderCanChange ? <ButtonSelect
|
||||
{props.noun.genderCanChange ? (
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Masc", value: "masc" },
|
||||
|
@ -153,10 +172,16 @@ function NPNounPicker(props: {
|
|||
gender,
|
||||
});
|
||||
}}
|
||||
/> : props.noun.gender === "masc" ? "Masc." : "Fem."}
|
||||
/>
|
||||
) : props.noun.gender === "masc" ? (
|
||||
"Masc."
|
||||
) : (
|
||||
"Fem."
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{props.noun.numberCanChange ? <ButtonSelect
|
||||
{props.noun.numberCanChange ? (
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Sing.", value: "singular" },
|
||||
|
@ -170,10 +195,17 @@ function NPNounPicker(props: {
|
|||
number,
|
||||
});
|
||||
}}
|
||||
/> : props.noun.number === "singular" ? "Sing." : "Plur."}
|
||||
/>
|
||||
) : props.noun.number === "singular" ? (
|
||||
"Sing."
|
||||
) : (
|
||||
"Plur."
|
||||
)}
|
||||
</div>
|
||||
</div>}
|
||||
</div>;
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default NPNounPicker;
|
|
@ -9,13 +9,21 @@ import Hider from "../Hider";
|
|||
import * as T from "../../../types";
|
||||
import useStickyState from "../useStickyState";
|
||||
import { isImperativeTense } from "../../../lib/src/type-predicates";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
import { VpsReducerAction } from "../../../lib/src/phrase-building/vps-reducer";
|
||||
import { useState } from "react";
|
||||
import { statVerb } from "../../../lib/src/new-verb-engine/roots-and-stems";
|
||||
// import { conjugateVerb } from "../../../lib/src/verb-conjugation";
|
||||
|
||||
function AllTensesDisplay({
|
||||
VS,
|
||||
opts,
|
||||
onChange,
|
||||
object,
|
||||
}: {
|
||||
onChange: (p: VpsReducerAction) => void;
|
||||
VS: T.VerbSelection;
|
||||
object: T.NPSelection | T.ObjectNP | undefined;
|
||||
opts: T.TextOptions;
|
||||
}) {
|
||||
const [showing, setShowing] = useStickyState<string[]>([], "VPTensesShowing");
|
||||
|
@ -23,6 +31,11 @@ function AllTensesDisplay({
|
|||
false,
|
||||
"showFormulasWithCharts"
|
||||
);
|
||||
const [objectNPNumber, setObjectNPNumber] = useState<T.NounNumber>(
|
||||
object && typeof object === "object" && object.selection.type === "noun"
|
||||
? object.selection.number
|
||||
: "singular"
|
||||
);
|
||||
const adjustShowing = (v: string) => {
|
||||
if (showing.includes(v)) {
|
||||
setShowing((os) => os.filter((x) => x !== v));
|
||||
|
@ -56,14 +69,69 @@ function AllTensesDisplay({
|
|||
? (`${baseTense}Modal` as T.AbilityTense)
|
||||
: baseTense;
|
||||
}
|
||||
const objectNP: T.NPSelection | undefined =
|
||||
object && typeof object === "object" && object.selection.type === "noun"
|
||||
? object
|
||||
: undefined;
|
||||
const verb =
|
||||
VS.isCompound === "generative stative"
|
||||
? statVerb[
|
||||
VS.transitivity === "intransitive" ? "intransitive" : "transitive"
|
||||
]
|
||||
: VS.dynAuxVerb
|
||||
? VS.dynAuxVerb
|
||||
: VS.verb;
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className="clickable mb-2 small text-center"
|
||||
onClick={() => setShowFormulas((x) => !x)}
|
||||
className="small clickable text-right mb-2"
|
||||
>
|
||||
🧪 {!showFormulas ? "Show" : "Hide"} Formulas
|
||||
</div>
|
||||
<div className="mb-2 d-flex flex-row justify-content-around align-items-center">
|
||||
{objectNP?.selection.type === "noun" &&
|
||||
objectNP.selection.numberCanChange && (
|
||||
<div>
|
||||
<span className="text-muted small mr-2">comp. noun:</span>
|
||||
<ButtonSelect
|
||||
xSmall
|
||||
value={objectNPNumber}
|
||||
options={[
|
||||
{
|
||||
label: "sing.",
|
||||
value: "singular",
|
||||
},
|
||||
{
|
||||
label: "plur.",
|
||||
value: "plural",
|
||||
},
|
||||
]}
|
||||
handleChange={(number) => {
|
||||
setObjectNPNumber(number);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<ButtonSelect
|
||||
xSmall
|
||||
value={VS.negative.toString() as "true" | "false"}
|
||||
options={[
|
||||
{
|
||||
label: "Pos.",
|
||||
value: "false",
|
||||
},
|
||||
{
|
||||
label: "Neg.",
|
||||
value: "true",
|
||||
},
|
||||
]}
|
||||
handleChange={(payload) =>
|
||||
onChange({ type: "set negativity", payload })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{options.map((tense) => {
|
||||
const t = getTense(tense.value);
|
||||
return (
|
||||
|
@ -81,7 +149,20 @@ function AllTensesDisplay({
|
|||
)}
|
||||
{showing && (
|
||||
<ChartDisplay
|
||||
verb={VS.verb}
|
||||
verb={verb}
|
||||
objectNP={
|
||||
objectNP?.selection.type === "noun"
|
||||
? {
|
||||
...objectNP,
|
||||
selection: {
|
||||
...objectNP.selection,
|
||||
number: objectNP.selection.numberCanChange
|
||||
? objectNPNumber
|
||||
: objectNP.selection.number,
|
||||
},
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
negative={VS.negative}
|
||||
tense={t}
|
||||
transitivity={VS.transitivity}
|
||||
|
|
|
@ -8,7 +8,13 @@ import { choosePersInf, getLength } from "../../../lib/src/p-text-helpers";
|
|||
import genderColors from "../gender-colors";
|
||||
import { eqPsStringWVars } from "../../../lib/src/fp-ps";
|
||||
import PersInfsPicker from "../PersInfsPicker";
|
||||
import { useMediaPredicate } from "react-media-hook";
|
||||
import "./form-display.css";
|
||||
import {
|
||||
makeBlock,
|
||||
makeKid,
|
||||
} from "../../../lib/src/phrase-building/blocks-utils";
|
||||
import InlinePs from "../InlinePs";
|
||||
import { personToGenNum } from "../../../lib/src/misc-helpers";
|
||||
|
||||
export const roleIcon = {
|
||||
king: <i className="mx-1 fas fa-crown" />,
|
||||
|
@ -21,14 +27,21 @@ function VerbChartDisplay({
|
|||
shortDefault,
|
||||
transitivity,
|
||||
past,
|
||||
negative,
|
||||
imperative,
|
||||
}: {
|
||||
chart: T.OptionalPersonInflections<
|
||||
chart: {
|
||||
objNP: T.Rendered<T.NPSelection> | undefined;
|
||||
vbs: T.OptionalPersonInflections<
|
||||
T.SingleOrLengthOpts<T.RenderVerbOutput[]>
|
||||
>;
|
||||
};
|
||||
opts: T.TextOptions;
|
||||
shortDefault?: boolean;
|
||||
transitivity: T.Transitivity;
|
||||
past: boolean;
|
||||
negative: boolean;
|
||||
imperative: boolean;
|
||||
}) {
|
||||
const [length, setLength] = useState<T.Length>(
|
||||
shortDefault ? "short" : "long"
|
||||
|
@ -37,13 +50,23 @@ function VerbChartDisplay({
|
|||
useEffect(() => {
|
||||
setLength("long");
|
||||
}, [chart]);
|
||||
const desktop = useMediaPredicate("(min-width: 600px)");
|
||||
const chartWPers = choosePersInf(chart, persInf);
|
||||
const chartWPers = choosePersInf(chart.vbs, persInf);
|
||||
const chartWLength = getLength(chartWPers, length);
|
||||
|
||||
const x = chartWLength.map(renderVerbOutputToText(false));
|
||||
const x = chartWLength.map(
|
||||
renderVerbOutputToText({
|
||||
objNP: chart.objNP,
|
||||
negative,
|
||||
hasBa: chartWLength[0].hasBa,
|
||||
imperative,
|
||||
intransitive: transitivity === "intransitive",
|
||||
})
|
||||
);
|
||||
const verbBlock =
|
||||
x.length === 12
|
||||
x.length === 1
|
||||
? // unchanging gramm trans or dynamic compound past transitive
|
||||
[[[x[0]]]]
|
||||
: x.length === 12
|
||||
? [
|
||||
// 1st pers
|
||||
[
|
||||
|
@ -83,10 +106,15 @@ function VerbChartDisplay({
|
|||
</div>
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<AgreementInfo transitivity={transitivity} past={past} />
|
||||
<AgreementInfo
|
||||
opts={opts}
|
||||
transitivity={transitivity}
|
||||
past={past}
|
||||
objNP={chart.objNP}
|
||||
/>
|
||||
</div>
|
||||
<div className="col">
|
||||
{"long" in chartWPers && (
|
||||
{"long" in chartWPers && lengthsMakeADiff(chartWPers) && (
|
||||
<LengthSelection
|
||||
hasMini={"mini" in chartWPers}
|
||||
value={length}
|
||||
|
@ -94,8 +122,13 @@ function VerbChartDisplay({
|
|||
/>
|
||||
)}
|
||||
</div>
|
||||
{desktop && <div className="col" />}
|
||||
<div className="hide-on-mobile col" />
|
||||
</div>
|
||||
{verbBlock.length === 1 ? (
|
||||
<div className="d-flex flex-row justify-content-center mt-3 text-center">
|
||||
<TableCell item={verbBlock[0][0][0]} textOptions={opts} />
|
||||
</div>
|
||||
) : (
|
||||
<table className="table mt-2" style={{ tableLayout: "fixed" }}>
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -118,6 +151,7 @@ function VerbChartDisplay({
|
|||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -224,32 +258,93 @@ function LengthSelection({
|
|||
);
|
||||
}
|
||||
|
||||
function renderVerbOutputToText(negative: boolean) {
|
||||
return function (v: T.RenderVerbOutput): T.PsString[] {
|
||||
const blocks = insertNegative(
|
||||
v.vbs,
|
||||
function renderVerbOutputToText({
|
||||
objNP,
|
||||
negative,
|
||||
false /* TODO: apply imperative */
|
||||
hasBa,
|
||||
imperative,
|
||||
intransitive,
|
||||
}: {
|
||||
objNP: T.Rendered<T.NPSelection> | undefined;
|
||||
negative: boolean;
|
||||
hasBa: boolean;
|
||||
imperative: boolean;
|
||||
intransitive: boolean;
|
||||
}) {
|
||||
return function (v: T.RenderVerbOutput): T.PsString[] {
|
||||
const blocks: T.Block[][] = insertNegative(v.vbs, negative, imperative).map(
|
||||
(b) => {
|
||||
if (!objNP) return b;
|
||||
return [
|
||||
...(objNP
|
||||
? [makeBlock({ type: "objectSelection", selection: objNP })]
|
||||
: []),
|
||||
...b,
|
||||
];
|
||||
}
|
||||
);
|
||||
return combineIntoText(blocks, 0 /* TODO: why is this needed */);
|
||||
|
||||
const b = hasBa
|
||||
? blocks.flatMap((v) => [
|
||||
[
|
||||
{ p: " ... ", f: " ... " },
|
||||
...[makeKid({ type: "ba" }), { p: " ... ", f: " ... " }],
|
||||
...v,
|
||||
],
|
||||
...(v.length > 1 && intransitive
|
||||
? [[v[0], makeKid({ type: "ba" }), ...v.slice(1)]]
|
||||
: []),
|
||||
])
|
||||
: blocks;
|
||||
return combineIntoText(b, 0 /* TODO: why is this needed */);
|
||||
};
|
||||
}
|
||||
|
||||
function AgreementInfo({
|
||||
transitivity,
|
||||
past,
|
||||
objNP,
|
||||
opts,
|
||||
}: {
|
||||
transitivity: T.Transitivity;
|
||||
past: boolean;
|
||||
objNP: T.Rendered<T.NPSelection> | undefined;
|
||||
opts: T.TextOptions;
|
||||
}) {
|
||||
function printGenNum({ gender, number }: T.GenderNumber): string {
|
||||
return `${gender === "masc" ? "m." : "f."} ${
|
||||
number === "singular" ? "s." : "pl."
|
||||
}`;
|
||||
}
|
||||
return (
|
||||
<div className="text-muted small mt-1">
|
||||
<div>
|
||||
{roleIcon.king} agrees w/{" "}
|
||||
<strong>
|
||||
{transitivity !== "intransitive" && past ? "object" : "subject"}
|
||||
</strong>
|
||||
{transitivity === "transitive" && past && objNP ? " noun" : ""}
|
||||
</div>
|
||||
{transitivity === "transitive" && past && objNP && (
|
||||
<div>
|
||||
<InlinePs opts={opts}>{objNP.selection.ps[0]}</InlinePs>
|
||||
{` `}({printGenNum(personToGenNum(objNP.selection.person))})
|
||||
</div>
|
||||
)}
|
||||
{transitivity === "grammatically transitive" && past && (
|
||||
<div>(implied 3rd pers. m. pl.)</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function lengthsMakeADiff(v: T.LengthOptions<T.RenderVerbOutput[]>): boolean {
|
||||
if (v.long.length > 1) {
|
||||
return true;
|
||||
}
|
||||
const longSample = combineIntoText([[makeBlock(v.long[0].vbs[1][0])]], 0);
|
||||
const shortSample = combineIntoText([[makeBlock(v.short[0].vbs[1][0])]], 0);
|
||||
return !eqPsStringWVars.equals(longSample, shortSample);
|
||||
}
|
||||
|
||||
export default VerbChartDisplay;
|
||||
|
|
|
@ -3,6 +3,8 @@ import * as T from "../../../types";
|
|||
import { buildVerbChart } from "./chart-builder";
|
||||
import { isPastTense } from "../../library";
|
||||
|
||||
// TODO - combine this with NewVerbFormDisplay
|
||||
|
||||
function ChartDisplay({
|
||||
verb,
|
||||
tense,
|
||||
|
@ -11,6 +13,7 @@ function ChartDisplay({
|
|||
imperative,
|
||||
negative,
|
||||
transitivity,
|
||||
objectNP,
|
||||
}: {
|
||||
verb: T.VerbEntry;
|
||||
tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense;
|
||||
|
@ -19,6 +22,7 @@ function ChartDisplay({
|
|||
imperative: boolean;
|
||||
negative: boolean;
|
||||
transitivity: T.Transitivity;
|
||||
objectNP: T.NPSelection | undefined;
|
||||
}) {
|
||||
const verbChart = buildVerbChart({
|
||||
verb,
|
||||
|
@ -27,10 +31,13 @@ function ChartDisplay({
|
|||
negative,
|
||||
transitivity,
|
||||
imperative,
|
||||
objectNP,
|
||||
});
|
||||
return (
|
||||
<div className="mb-4">
|
||||
<NewVerbFormDisplay
|
||||
imperative={imperative}
|
||||
negative={negative}
|
||||
chart={verbChart}
|
||||
opts={opts}
|
||||
transitivity={transitivity}
|
||||
|
|
|
@ -28,28 +28,28 @@ export const vpPhraseURLParam = "vp";
|
|||
// TODO: error handling on error with rendering etc
|
||||
|
||||
function VPExplorer(props: {
|
||||
loaded?: T.VPSelectionState,
|
||||
verb: T.VerbEntry,
|
||||
opts: T.TextOptions,
|
||||
handleLinkClick: ((ts: number) => void) | "none",
|
||||
entryFeeder: T.EntryFeeder,
|
||||
onlyPhrases?: boolean,
|
||||
loaded?: T.VPSelectionState;
|
||||
verb: T.VerbEntry;
|
||||
opts: T.TextOptions;
|
||||
handleLinkClick: ((ts: number) => void) | "none";
|
||||
entryFeeder: T.EntryFeeder;
|
||||
onlyPhrases?: boolean;
|
||||
}) {
|
||||
const [vps, adjustVps] = useStickyReducer(
|
||||
vpsReducer,
|
||||
props.loaded
|
||||
? props.loaded
|
||||
: savedVps => makeVPSelectionState(props.verb, savedVps),
|
||||
: (savedVps) => makeVPSelectionState(props.verb, savedVps),
|
||||
"vpsState16",
|
||||
flashMessage,
|
||||
flashMessage
|
||||
);
|
||||
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">(
|
||||
savedMode => {
|
||||
(savedMode) => {
|
||||
if (!savedMode) return props.onlyPhrases ? "phrases" : "charts";
|
||||
if (savedMode === "quiz") return "phrases";
|
||||
return savedMode;
|
||||
},
|
||||
"verbExplorerMode2",
|
||||
"verbExplorerMode2"
|
||||
);
|
||||
const [showClipped, setShowClipped] = useState<string>("");
|
||||
const [
|
||||
|
@ -87,7 +87,7 @@ function VPExplorer(props: {
|
|||
setMode("phrases");
|
||||
adjustVps({
|
||||
type: "load vps",
|
||||
payload: VPSFromUrl
|
||||
payload: VPSFromUrl,
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
|
@ -130,16 +130,17 @@ function VPExplorer(props: {
|
|||
const object = getObjectSelection(vps.blocks).selection;
|
||||
const VPS = completeVPSelection(vps);
|
||||
const phraseIsComplete = !!VPS;
|
||||
return <div className="mt-3" style={{ maxWidth: "950px"}}>
|
||||
return (
|
||||
<div className="mt-3" style={{ maxWidth: "950px" }}>
|
||||
<VerbPicker
|
||||
vps={vps}
|
||||
onChange={quizLock(adjustVps)}
|
||||
opts={props.opts}
|
||||
handleLinkClick={props.handleLinkClick}
|
||||
/>
|
||||
{!props.onlyPhrases && <div className="mt-2 mb-3 d-flex flex-row justify-content-between align-items-center">
|
||||
<div style={{ width: "1rem" }}>
|
||||
</div>
|
||||
{!props.onlyPhrases && (
|
||||
<div className="mt-2 mb-3 d-flex flex-row justify-content-between align-items-center">
|
||||
<div style={{ width: "1rem" }}></div>
|
||||
<ButtonSelect
|
||||
value={mode}
|
||||
options={[
|
||||
|
@ -155,7 +156,11 @@ function VPExplorer(props: {
|
|||
onClick={mode === "phrases" ? handleCopyCode : undefined}
|
||||
style={{ width: "1rem" }}
|
||||
>
|
||||
{(mode === "phrases" && phraseIsComplete) ? <i className="fas fa-code" /> : ""}
|
||||
{mode === "phrases" && phraseIsComplete ? (
|
||||
<i className="fas fa-code" />
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="clickable"
|
||||
|
@ -165,52 +170,79 @@ function VPExplorer(props: {
|
|||
{mode === "phrases" ? <i className="fas fa-share-alt" /> : ""}
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
{(vps.verb && (typeof object === "object") && (vps.verb.isCompound !== "dynamic") && (vps.verb.tenseCategory !== "imperative") &&(mode === "phrases")) &&
|
||||
</div>
|
||||
)}
|
||||
{vps.verb &&
|
||||
typeof object === "object" &&
|
||||
vps.verb.isCompound !== "dynamic" &&
|
||||
vps.verb.tenseCategory !== "imperative" &&
|
||||
mode === "phrases" && (
|
||||
<div className="text-center my-2">
|
||||
<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
|
||||
</button>
|
||||
</div>}
|
||||
{mode === "phrases" && <VPPicker
|
||||
</div>
|
||||
)}
|
||||
{mode === "phrases" && (
|
||||
<VPPicker
|
||||
opts={props.opts}
|
||||
entryFeeder={props.entryFeeder}
|
||||
onChange={(payload) => adjustVps({ type: "load vps", payload })}
|
||||
vps={vps}
|
||||
/>}
|
||||
{mode !== "phrases" && <div className="my-2">
|
||||
<TensePicker
|
||||
vps={vps}
|
||||
onChange={adjustVps}
|
||||
mode={mode}
|
||||
/>
|
||||
</div>}
|
||||
{mode === "phrases" && <VPDisplay
|
||||
VPS={vps}
|
||||
opts={props.opts}
|
||||
setForm={handleSetForm}
|
||||
/>}
|
||||
{mode === "charts" && <AllTensesDisplay VS={vps.verb} opts={props.opts} />}
|
||||
{mode === "quiz" && <VPExplorerQuiz opts={props.opts} vps={vps} />}
|
||||
{showClipped && <div className="alert alert-primary text-center" role="alert" style={{
|
||||
position: "fixed",
|
||||
top: "30%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
zIndex: 9999999999999,
|
||||
}}>
|
||||
{showClipped}
|
||||
</div>}
|
||||
{alertMsg && <div className="alert alert-warning text-center" role="alert" style={{
|
||||
position: "fixed",
|
||||
top: "30%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
zIndex: 9999999999999,
|
||||
}}>
|
||||
{alertMsg}
|
||||
</div>}
|
||||
)}
|
||||
{mode !== "phrases" && (
|
||||
<div className="my-2">
|
||||
<TensePicker vps={vps} onChange={adjustVps} mode={mode} />
|
||||
</div>
|
||||
)}
|
||||
{mode === "phrases" && (
|
||||
<VPDisplay VPS={vps} opts={props.opts} setForm={handleSetForm} />
|
||||
)}
|
||||
{mode === "charts" && (
|
||||
<AllTensesDisplay
|
||||
object={object}
|
||||
VS={vps.verb}
|
||||
opts={props.opts}
|
||||
onChange={adjustVps}
|
||||
/>
|
||||
)}
|
||||
{mode === "quiz" && <VPExplorerQuiz opts={props.opts} vps={vps} />}
|
||||
{showClipped && (
|
||||
<div
|
||||
className="alert alert-primary text-center"
|
||||
role="alert"
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: "30%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
zIndex: 9999999999999,
|
||||
}}
|
||||
>
|
||||
{showClipped}
|
||||
</div>
|
||||
)}
|
||||
{alertMsg && (
|
||||
<div
|
||||
className="alert alert-warning text-center"
|
||||
role="alert"
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: "30%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
zIndex: 9999999999999,
|
||||
}}
|
||||
>
|
||||
{alertMsg}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default VPExplorer;
|
||||
|
@ -237,4 +269,3 @@ function getVPSFromUrl(): T.VPSelectionState | undefined {
|
|||
const decoded = LZString.decompressFromEncodedURIComponent(fromParams);
|
||||
return JSON.parse(decoded) as T.VPSelectionState;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,17 @@ import {
|
|||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { getKingAndServant, renderVP } from "../../../lib/src/phrase-building/render-vp";
|
||||
import { completeVPSelection, isPastTense } from "../../../lib/src/phrase-building/vp-tools";
|
||||
import VPExplorerExplanationModal, { roleIcon } from "./VPExplorerExplanationModal";
|
||||
import {
|
||||
getKingAndServant,
|
||||
renderVP,
|
||||
} from "../../../lib/src/phrase-building/render-vp";
|
||||
import {
|
||||
completeVPSelection,
|
||||
isPastTense,
|
||||
} from "../../../lib/src/phrase-building/vp-tools";
|
||||
import VPExplorerExplanationModal, {
|
||||
roleIcon,
|
||||
} from "./VPExplorerExplanationModal";
|
||||
import APPicker from "../../src/ap-picker/APPicker";
|
||||
// import autoAnimate from "@formkit/auto-animate";
|
||||
import {
|
||||
|
@ -18,23 +26,37 @@ import {
|
|||
isNoObject,
|
||||
} from "../../../lib/src/phrase-building/blocks-utils";
|
||||
import ComplementPicker from "../ComplementPicker";
|
||||
import { vpsReducer, VpsReducerAction } from "../../../lib/src/phrase-building/vps-reducer";
|
||||
import {
|
||||
vpsReducer,
|
||||
VpsReducerAction,
|
||||
} from "../../../lib/src/phrase-building/vps-reducer";
|
||||
|
||||
function VPPicker({ opts, vps, onChange, entryFeeder }: {
|
||||
opts: T.TextOptions,
|
||||
vps: T.VPSelectionState,
|
||||
onChange: (vps: T.VPSelectionState) => void,
|
||||
entryFeeder: T.EntryFeeder,
|
||||
function VPPicker({
|
||||
opts,
|
||||
vps,
|
||||
onChange,
|
||||
entryFeeder,
|
||||
}: {
|
||||
opts: T.TextOptions;
|
||||
vps: T.VPSelectionState;
|
||||
onChange: (vps: T.VPSelectionState) => void;
|
||||
entryFeeder: T.EntryFeeder;
|
||||
}) {
|
||||
const parent = useRef<HTMLDivElement>(null);
|
||||
// useEffect(() => {
|
||||
// parent.current && autoAnimate(parent.current);
|
||||
// }, [parent]);
|
||||
const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false);
|
||||
const [showingExplanation, setShowingExplanation] =
|
||||
useState<{ role: "servant" | "king"; item: "subject" | "object" } | false>(
|
||||
false
|
||||
);
|
||||
function adjustVps(action: VpsReducerAction) {
|
||||
onChange(vpsReducer(vps, action));
|
||||
}
|
||||
function handleSubjectChange(subject: T.NPSelection | undefined, skipPronounConflictCheck?: boolean) {
|
||||
function handleSubjectChange(
|
||||
subject: T.NPSelection | undefined,
|
||||
skipPronounConflictCheck?: boolean
|
||||
) {
|
||||
adjustVps({
|
||||
type: "set subject",
|
||||
payload: { subject, skipPronounConflictCheck },
|
||||
|
@ -52,174 +74,333 @@ function VPPicker({ opts, vps, onChange, entryFeeder }: {
|
|||
const phraseIsComplete = !!VPS;
|
||||
const rendered = VPS ? renderVP(VPS) : undefined;
|
||||
const servantIsShrunk = includesShrunkenServant(rendered?.kids);
|
||||
const isPast = isPastTense(vps.verb.tenseCategory === "perfect" ? vps.verb.perfectTense : vps.verb.verbTense);
|
||||
const isPast = isPastTense(
|
||||
vps.verb.tenseCategory === "perfect"
|
||||
? vps.verb.perfectTense
|
||||
: vps.verb.verbTense
|
||||
);
|
||||
const roles = getKingAndServant(
|
||||
isPast,
|
||||
vps.verb.transitivity !== "intransitive",
|
||||
vps.verb.transitivity !== "intransitive"
|
||||
);
|
||||
return <div>
|
||||
<div className="clickable h5" onClick={() => adjustVps({ type: "insert new AP" })}>+ AP</div>
|
||||
<div ref={parent} className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}>
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className="clickable h5"
|
||||
onClick={() => adjustVps({ type: "insert new AP" })}
|
||||
>
|
||||
+ AP
|
||||
</div>
|
||||
<div
|
||||
ref={parent}
|
||||
className="d-flex flex-row justify-content-around flex-wrap"
|
||||
style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}
|
||||
>
|
||||
{vps.blocks.map(({ block, key }, i, blocks) => {
|
||||
if (isNoObject(block)) return null;
|
||||
return <div className="my-2 card block-card p-1 mx-1" key={key} style={{
|
||||
background: (servantIsShrunk && (
|
||||
(roles.servant === "subject" && block?.type === "subjectSelection")
|
||||
||
|
||||
(roles.servant === "object" && block?.type === "objectSelection")
|
||||
)) ? shrunkenBackground : "inherit",
|
||||
}}>
|
||||
<div className="d-flex flex-row justify-content-between mb-1" style={{ height: "1rem" }}>
|
||||
{(i > 0 && !isNoObject(blocks[i - 1].block)) ? <div
|
||||
return (
|
||||
<div
|
||||
className="my-2 card block-card p-1 mx-1"
|
||||
key={key}
|
||||
style={{
|
||||
background:
|
||||
servantIsShrunk &&
|
||||
((roles.servant === "subject" &&
|
||||
block?.type === "subjectSelection") ||
|
||||
(roles.servant === "object" &&
|
||||
block?.type === "objectSelection"))
|
||||
? shrunkenBackground
|
||||
: "inherit",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="d-flex flex-row justify-content-between mb-1"
|
||||
style={{ height: "1rem" }}
|
||||
>
|
||||
{i > 0 &&
|
||||
!isNoObject(blocks[i - 1].block) &&
|
||||
!isGenStatCompNoun(block) ? (
|
||||
<div
|
||||
className="small clickable ml-1"
|
||||
onClick={() => adjustVps({ type: "shift block", payload: { index: i, direction: "back" }})}
|
||||
onClick={() =>
|
||||
adjustVps({
|
||||
type: "shift block",
|
||||
payload: { index: i, direction: "back" },
|
||||
})
|
||||
}
|
||||
>
|
||||
<i className="fas fa-chevron-left" />
|
||||
</div> : <div/>}
|
||||
{(i < vps.blocks.length - 1 && !isNoObject(blocks[i + 1].block)) ? <div
|
||||
</div>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
{i < vps.blocks.length - 1 &&
|
||||
!isNoObject(blocks[i + 1].block) &&
|
||||
!isGenStatCompNoun(block) ? (
|
||||
<div
|
||||
className="small clickable mr-1"
|
||||
onClick={() => adjustVps({ type: "shift block", payload: { index: i, direction: "forward" }})}
|
||||
onClick={() =>
|
||||
adjustVps({
|
||||
type: "shift block",
|
||||
payload: { index: i, direction: "forward" },
|
||||
})
|
||||
}
|
||||
>
|
||||
<i className="fas fa-chevron-right" />
|
||||
</div> : <div/>}
|
||||
</div>
|
||||
{(!block || block.type === "AP")
|
||||
? <APPicker
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
</div>
|
||||
{!block || block.type === "AP" ? (
|
||||
<APPicker
|
||||
phraseIsComplete={phraseIsComplete}
|
||||
heading="AP"
|
||||
entryFeeder={entryFeeder}
|
||||
AP={block}
|
||||
opts={opts}
|
||||
onChange={AP => adjustVps({ type: "set AP", payload: { index: i, AP } })}
|
||||
onChange={(AP) =>
|
||||
adjustVps({ type: "set AP", payload: { index: i, AP } })
|
||||
}
|
||||
onRemove={() => adjustVps({ type: "remove AP", payload: i })}
|
||||
/>
|
||||
: (block?.type === "subjectSelection")
|
||||
? <NPPicker
|
||||
) : block?.type === "subjectSelection" ? (
|
||||
<NPPicker
|
||||
phraseIsComplete={phraseIsComplete}
|
||||
heading={roles.king === "subject"
|
||||
? <div className="h5 text-center">
|
||||
Subj. <span onClick={() => setShowingExplanation({ role: "king", item: "subject" })}>{roleIcon.king}</span>
|
||||
{(rendered && rendered.whatsAdjustable !== "servant") &&
|
||||
heading={
|
||||
roles.king === "subject" ? (
|
||||
<div className="h5 text-center">
|
||||
Subj.{" "}
|
||||
<span
|
||||
onClick={() =>
|
||||
setShowingExplanation({
|
||||
role: "king",
|
||||
item: "subject",
|
||||
})
|
||||
}
|
||||
>
|
||||
{roleIcon.king}
|
||||
</span>
|
||||
{rendered && rendered.whatsAdjustable !== "servant" && (
|
||||
<KingRemover
|
||||
onChange={() => adjustVps({ type: "toggle king remove" })}
|
||||
onChange={() =>
|
||||
adjustVps({ type: "toggle king remove" })
|
||||
}
|
||||
showKing={!VPS?.form.removeKing}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
: <div className="h5 text-center">
|
||||
) : (
|
||||
<div className="h5 text-center">
|
||||
Subj.
|
||||
{` `}
|
||||
<span className="clickable" onClick={() => setShowingExplanation({ role: "servant", item: "subject" })}>{roleIcon.servant}</span>
|
||||
<span
|
||||
className="clickable"
|
||||
onClick={() =>
|
||||
setShowingExplanation({
|
||||
role: "servant",
|
||||
item: "subject",
|
||||
})
|
||||
}
|
||||
>
|
||||
{roleIcon.servant}
|
||||
</span>
|
||||
{` `}
|
||||
{(rendered && rendered.whatsAdjustable !== "king") &&
|
||||
{rendered && rendered.whatsAdjustable !== "king" && (
|
||||
<ServantShrinker
|
||||
shrunk={servantIsShrunk}
|
||||
onClick={() => adjustVps({ type: "toggle servant shrink" })}
|
||||
/>
|
||||
onClick={() =>
|
||||
adjustVps({ type: "toggle servant shrink" })
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>}
|
||||
entryFeeder={entryFeeder}
|
||||
np={block.selection}
|
||||
counterPart={vps.verb ? object : undefined}
|
||||
role={(isPast && vps.verb.transitivity !== "intransitive")
|
||||
role={
|
||||
isPast && vps.verb.transitivity !== "intransitive"
|
||||
? "ergative"
|
||||
: "subject"
|
||||
}
|
||||
onChange={handleSubjectChange}
|
||||
opts={opts}
|
||||
isShrunk={(servantIsShrunk && roles.servant === "subject")}
|
||||
isShrunk={servantIsShrunk && roles.servant === "subject"}
|
||||
isRemoved={roles.king === "subject" && VPS?.form.removeKing}
|
||||
/>
|
||||
: (vps.verb && block?.type === "objectSelection" && block.selection !== "none")
|
||||
? <div className="my-2" style={{ background: (servantIsShrunk && roles.servant === "object") ? shrunkenBackground : "inherit" }}>
|
||||
{(typeof block.selection === "number")
|
||||
? <div>
|
||||
{roles.king === "object"
|
||||
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "king", item: "object" })}>Object {roleIcon.king}</div>
|
||||
: roles.servant === "object"
|
||||
? <div className="h5 text-center clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>Object {roleIcon.servant}</div>
|
||||
: <div className="h5 text-center">Object</div>}
|
||||
) : vps.verb &&
|
||||
block?.type === "objectSelection" &&
|
||||
block.selection !== "none" ? (
|
||||
<div
|
||||
className="my-2"
|
||||
style={{
|
||||
background:
|
||||
servantIsShrunk && roles.servant === "object"
|
||||
? shrunkenBackground
|
||||
: "inherit",
|
||||
}}
|
||||
>
|
||||
{typeof block.selection === "number" ? (
|
||||
<div>
|
||||
{roles.king === "object" ? (
|
||||
<div
|
||||
className="h5 text-center clickable"
|
||||
onClick={() =>
|
||||
setShowingExplanation({
|
||||
role: "king",
|
||||
item: "object",
|
||||
})
|
||||
}
|
||||
>
|
||||
Object {roleIcon.king}
|
||||
</div>
|
||||
) : roles.servant === "object" ? (
|
||||
<div
|
||||
className="h5 text-center clickable"
|
||||
onClick={() =>
|
||||
setShowingExplanation({
|
||||
role: "servant",
|
||||
item: "object",
|
||||
})
|
||||
}
|
||||
>
|
||||
Object {roleIcon.servant}
|
||||
</div>
|
||||
) : (
|
||||
<div className="h5 text-center">Object</div>
|
||||
)}
|
||||
<div className="text-muted text-center">
|
||||
<div className="mt-3 mb-1">Unspoken</div>
|
||||
<div>3rd Pers. Masc. Plur.</div>
|
||||
</div>
|
||||
</div>
|
||||
: <NPPicker
|
||||
) : (
|
||||
<NPPicker
|
||||
phraseIsComplete={phraseIsComplete}
|
||||
heading={roles.king === "object"
|
||||
? <div className="h5 text-center">
|
||||
Obj. <span onClick={() => setShowingExplanation({ role: "king", item: "object" })}>{roleIcon.king}</span>
|
||||
{(rendered && rendered.whatsAdjustable !== "servant") &&
|
||||
heading={
|
||||
roles.king === "object" ? (
|
||||
<div className="h5 text-center">
|
||||
Obj.{" "}
|
||||
<span
|
||||
onClick={() =>
|
||||
setShowingExplanation({
|
||||
role: "king",
|
||||
item: "object",
|
||||
})
|
||||
}
|
||||
>
|
||||
{roleIcon.king}
|
||||
</span>
|
||||
{rendered &&
|
||||
rendered.whatsAdjustable !== "servant" && (
|
||||
<KingRemover
|
||||
onChange={() => adjustVps({ type: "toggle king remove" })}
|
||||
onChange={() =>
|
||||
adjustVps({ type: "toggle king remove" })
|
||||
}
|
||||
showKing={!VPS?.form.removeKing}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
: <div className="h5 text-center">
|
||||
) : (
|
||||
<div className="h5 text-center">
|
||||
Obj.
|
||||
{` `}
|
||||
<span className="clickable" onClick={() => setShowingExplanation({ role: "servant", item: "object" })}>{roleIcon.servant}</span>
|
||||
{` `}
|
||||
{(rendered && rendered.whatsAdjustable !== "king") &&
|
||||
<ServantShrinker shrunk={servantIsShrunk} onClick={() => adjustVps({ type: "toggle servant shrink" })} />
|
||||
<span
|
||||
className="clickable"
|
||||
onClick={() =>
|
||||
setShowingExplanation({
|
||||
role: "servant",
|
||||
item: "object",
|
||||
})
|
||||
}
|
||||
>
|
||||
{roleIcon.servant}
|
||||
</span>
|
||||
{` `}
|
||||
{rendered &&
|
||||
rendered.whatsAdjustable !== "king" && (
|
||||
<ServantShrinker
|
||||
shrunk={servantIsShrunk}
|
||||
onClick={() =>
|
||||
adjustVps({ type: "toggle servant shrink" })
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>}
|
||||
entryFeeder={entryFeeder}
|
||||
role="object"
|
||||
np={block.selection}
|
||||
counterPart={subject}
|
||||
onChange={handleObjectChange}
|
||||
opts={opts}
|
||||
isShrunk={(servantIsShrunk && roles.servant === "object")}
|
||||
isRemoved={roles.king === "object" && VPS?.form.removeKing}
|
||||
/>}
|
||||
isShrunk={servantIsShrunk && roles.servant === "object"}
|
||||
isRemoved={
|
||||
roles.king === "object" && VPS?.form.removeKing
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
: null}
|
||||
</div>;
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{vps.externalComplement && <div className="my-2 card block-card p-1 mr-1" key="complementPicker">
|
||||
{vps.externalComplement && (
|
||||
<div className="my-2 card block-card p-1 mr-1" key="complementPicker">
|
||||
<div className="h5 text-center">Complement</div>
|
||||
<ComplementPicker
|
||||
phraseIsComplete={phraseIsComplete}
|
||||
comp={vps.externalComplement.selection.type === "unselected"
|
||||
comp={
|
||||
vps.externalComplement.selection.type === "unselected"
|
||||
? undefined
|
||||
: vps.externalComplement as T.ComplementSelection // TODO: just typescript being dumb? - looks like it
|
||||
: (vps.externalComplement as T.ComplementSelection) // TODO: just typescript being dumb? - looks like it
|
||||
}
|
||||
onChange={(payload) =>
|
||||
adjustVps({ type: "set externalComplement", payload })
|
||||
}
|
||||
onChange={payload => adjustVps({ type: "set externalComplement", payload })}
|
||||
opts={opts}
|
||||
entryFeeder={entryFeeder}
|
||||
/>
|
||||
</div>}
|
||||
</div>
|
||||
)}
|
||||
<div className="my-2">
|
||||
<TensePicker
|
||||
vps={vps}
|
||||
onChange={adjustVps}
|
||||
mode="phrases"
|
||||
/>
|
||||
<TensePicker vps={vps} onChange={adjustVps} mode="phrases" />
|
||||
</div>
|
||||
</div>
|
||||
<VPExplorerExplanationModal
|
||||
showing={showingExplanation}
|
||||
setShowing={setShowingExplanation}
|
||||
/>
|
||||
</div>;
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ServantShrinker({ shrunk, onClick }: {
|
||||
function ServantShrinker({
|
||||
shrunk,
|
||||
onClick,
|
||||
}: {
|
||||
shrunk: boolean;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
return <span className="mx-2 clickable" onClick={onClick}>
|
||||
return (
|
||||
<span className="mx-2 clickable" onClick={onClick}>
|
||||
{!shrunk ? "🪄" : "👶"}
|
||||
</span>;
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function KingRemover({ showKing, onChange }: {
|
||||
function KingRemover({
|
||||
showKing,
|
||||
onChange,
|
||||
}: {
|
||||
showKing: boolean;
|
||||
onChange: () => void;
|
||||
}) {
|
||||
return <span className="form-check form-check-inline ml-3">
|
||||
return (
|
||||
<span className="form-check form-check-inline ml-3">
|
||||
<input
|
||||
checked={showKing}
|
||||
onChange={onChange}
|
||||
|
@ -227,7 +408,29 @@ function KingRemover({ showKing, onChange }: {
|
|||
type="checkbox"
|
||||
id="showKingCheck"
|
||||
/>
|
||||
</span>;
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function isGenStatCompNoun(
|
||||
block:
|
||||
| T.APSelection
|
||||
| T.ComplementSelection
|
||||
| T.SubjectSelection
|
||||
| T.ObjectSelection
|
||||
| undefined
|
||||
) {
|
||||
if (!block) return false;
|
||||
console.log({ block });
|
||||
if (
|
||||
block.type === "objectSelection" &&
|
||||
typeof block.selection === "object" &&
|
||||
block.selection.selection.type === "noun" &&
|
||||
block.selection.selection.genStativeComplement
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export default VPPicker;
|
|
@ -1,31 +1,48 @@
|
|||
import * as T from "../../../types";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
import { RootsAndStems } from "../verb-info/VerbInfo";
|
||||
import { getAbilityRootsAndStems, getPassiveRootsAndStems, getVerbInfo } from "../../../lib/src/verb-info";
|
||||
import {
|
||||
getAbilityRootsAndStems,
|
||||
getPassiveRootsAndStems,
|
||||
getVerbInfo,
|
||||
} from "../../../lib/src/verb-info";
|
||||
import Hider from "../Hider";
|
||||
import useStickyState from "../useStickyState";
|
||||
import CompoundDisplay from "./CompoundDisplay";
|
||||
import {
|
||||
VpsReducerAction
|
||||
} from "../../../lib/src/phrase-building/vps-reducer";
|
||||
import { VpsReducerAction } from "../../../lib/src/phrase-building/vps-reducer";
|
||||
import { ensureNonComboVerbInfo } from "../../../lib/src/misc-helpers";
|
||||
|
||||
// TODO: dark on past tense selecitons
|
||||
|
||||
function VerbPicker(props: {
|
||||
vps: T.VPSelectionState,
|
||||
onChange: (a: VpsReducerAction) => void,
|
||||
opts: T.TextOptions,
|
||||
handleLinkClick: ((ts: number) => void) | "none",
|
||||
vps: T.VPSelectionState;
|
||||
onChange: (a: VpsReducerAction) => void;
|
||||
opts: T.TextOptions;
|
||||
handleLinkClick: ((ts: number) => void) | "none";
|
||||
}) {
|
||||
const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(false, "showRootsAndStems");
|
||||
const infoRaw = props.vps.verb ? getVerbInfo(props.vps.verb.verb.entry, props.vps.verb.verb.complement) : undefined;
|
||||
const info = (!infoRaw || !props.vps.verb)
|
||||
const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(
|
||||
false,
|
||||
"showRootsAndStems"
|
||||
);
|
||||
const infoRaw = props.vps.verb
|
||||
? getVerbInfo(props.vps.verb.verb.entry, props.vps.verb.verb.complement)
|
||||
: undefined;
|
||||
const info =
|
||||
!infoRaw || !props.vps.verb
|
||||
? undefined
|
||||
: ("stative" in infoRaw)
|
||||
? infoRaw[props.vps.verb.isCompound === "stative" ? "stative" : "dynamic"]
|
||||
: ("transitive" in infoRaw)
|
||||
? infoRaw[props.vps.verb.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
|
||||
: "stative" in infoRaw
|
||||
? infoRaw[
|
||||
props.vps.verb.isCompound === "stative" ||
|
||||
props.vps.verb.isCompound === "generative stative"
|
||||
? "stative"
|
||||
: "dynamic"
|
||||
]
|
||||
: "transitive" in infoRaw
|
||||
? infoRaw[
|
||||
props.vps.verb.transitivity === "grammatically transitive"
|
||||
? "grammaticallyTransitive"
|
||||
: "transitive"
|
||||
]
|
||||
: infoRaw;
|
||||
if (info && ("stative" in info || "transitive" in info)) {
|
||||
return <div>ERROR: Verb version should be select first</div>;
|
||||
|
@ -36,10 +53,14 @@ function VerbPicker(props: {
|
|||
payload: value,
|
||||
});
|
||||
}
|
||||
function notInstransitive(t: "transitive" | "intransitive" | "grammatically transitive"): "transitive" | "grammatically transitive" {
|
||||
function notInstransitive(
|
||||
t: "transitive" | "intransitive" | "grammatically transitive"
|
||||
): "transitive" | "grammatically transitive" {
|
||||
return t === "intransitive" ? "transitive" : t;
|
||||
}
|
||||
function handleChangeTransitivity(payload: "transitive" | "grammatically transitive") {
|
||||
function handleChangeTransitivity(
|
||||
payload: "transitive" | "grammatically transitive"
|
||||
) {
|
||||
props.onChange({
|
||||
type: "set transitivity",
|
||||
payload,
|
||||
|
@ -51,91 +72,142 @@ function VerbPicker(props: {
|
|||
payload,
|
||||
});
|
||||
}
|
||||
const passiveRootsAndStems = (info && props.vps.verb.voice === "passive") ? getPassiveRootsAndStems(info) : undefined;
|
||||
const passiveRootsAndStems =
|
||||
info && props.vps.verb.voice === "passive"
|
||||
? getPassiveRootsAndStems(info)
|
||||
: undefined;
|
||||
const abilityRootsAndStems = (() => {
|
||||
try {
|
||||
return (info && props.vps.verb.tenseCategory === "modal") ? getAbilityRootsAndStems(info) : undefined;
|
||||
return info && props.vps.verb.tenseCategory === "modal"
|
||||
? getAbilityRootsAndStems(info)
|
||||
: undefined;
|
||||
} catch (e) {
|
||||
console.log("error making ability roots and stems", e);
|
||||
return undefined;
|
||||
}
|
||||
})();
|
||||
return <div className="mb-3">
|
||||
{info && <CompoundDisplay
|
||||
return (
|
||||
<div className="mb-3">
|
||||
{info && (
|
||||
<CompoundDisplay
|
||||
info={info}
|
||||
opts={props.opts}
|
||||
handleLinkClick={props.handleLinkClick}
|
||||
/>}
|
||||
{info && <div className="mt-3 mb-1 text-center">
|
||||
/>
|
||||
)}
|
||||
{info && (
|
||||
<div className="mt-3 mb-1 text-center">
|
||||
<Hider
|
||||
showing={showRootsAndStems}
|
||||
label={`🌳 ${passiveRootsAndStems ? "Passive" : abilityRootsAndStems ? "Ability" : ""} Roots and Stems${info.type === "dynamic compound" ? " for Aux. Verb" : ""}`}
|
||||
handleChange={() => setShowRootsAndStems(p => !p)}
|
||||
label={`🌳 ${
|
||||
passiveRootsAndStems
|
||||
? "Passive"
|
||||
: abilityRootsAndStems
|
||||
? "Ability"
|
||||
: ""
|
||||
} Roots and Stems${
|
||||
info.type === "dynamic compound" ? " for Aux. Verb" : ""
|
||||
}`}
|
||||
handleChange={() => setShowRootsAndStems((p) => !p)}
|
||||
hLevel={5}
|
||||
>
|
||||
<RootsAndStems
|
||||
textOptions={props.opts}
|
||||
info={passiveRootsAndStems
|
||||
info={
|
||||
passiveRootsAndStems
|
||||
? passiveRootsAndStems
|
||||
: abilityRootsAndStems
|
||||
? abilityRootsAndStems
|
||||
: info.type === "dynamic compound"
|
||||
? ensureNonComboVerbInfo(getVerbInfo(info.auxVerb))
|
||||
: info}
|
||||
: info
|
||||
}
|
||||
/>
|
||||
</Hider>
|
||||
</div>}
|
||||
<div className="d-flex flex-row justify-content-around flex-wrap" style={{ maxWidth: "400px", margin: "0 auto" }}>
|
||||
{props.vps.verb && props.vps.verb.canChangeTransitivity && <div className="text-center my-2">
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="d-flex flex-row justify-content-around flex-wrap"
|
||||
style={{ maxWidth: "400px", margin: "0 auto" }}
|
||||
>
|
||||
{props.vps.verb && props.vps.verb.canChangeTransitivity && (
|
||||
<div className="text-center my-2">
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[{
|
||||
options={[
|
||||
{
|
||||
label: "gramm. trans.",
|
||||
value: "grammatically transitive",
|
||||
}, {
|
||||
},
|
||||
{
|
||||
label: "trans.",
|
||||
value: "transitive",
|
||||
}]}
|
||||
},
|
||||
]}
|
||||
value={notInstransitive(props.vps.verb.transitivity)}
|
||||
handleChange={handleChangeTransitivity}
|
||||
/>
|
||||
</div>}
|
||||
{props.vps.verb && props.vps.verb.canChangeVoice && <div className="text-center my-2">
|
||||
</div>
|
||||
)}
|
||||
{props.vps.verb && props.vps.verb.canChangeVoice && (
|
||||
<div className="text-center my-2">
|
||||
<ButtonSelect
|
||||
small
|
||||
value={props.vps.verb.voice}
|
||||
options={(props.vps.verb.tenseCategory === "imperative") // || props.vps.verb.tenseCategory === "modal")
|
||||
? [{
|
||||
options={
|
||||
props.vps.verb.tenseCategory === "imperative" // || props.vps.verb.tenseCategory === "modal")
|
||||
? [
|
||||
{
|
||||
label: "Active",
|
||||
value: "active",
|
||||
}]
|
||||
: [{
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
label: "Active",
|
||||
value: "active",
|
||||
}, {
|
||||
},
|
||||
{
|
||||
label: "Passive",
|
||||
value: "passive",
|
||||
}]}
|
||||
},
|
||||
]
|
||||
}
|
||||
handleChange={onVoiceSelect}
|
||||
/>
|
||||
</div>}
|
||||
{props.vps.verb && props.vps.verb.canChangeStatDyn && <div className="text-center my-2">
|
||||
</div>
|
||||
)}
|
||||
{props.vps.verb && props.vps.verb.canChangeStatDyn && (
|
||||
<div className="text-center my-2">
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[{
|
||||
label: "stative",
|
||||
options={[
|
||||
{
|
||||
label:
|
||||
infoRaw?.type === "dynamic or generative stative compound"
|
||||
? "gen. stative"
|
||||
: "stative",
|
||||
value: "stative",
|
||||
}, {
|
||||
},
|
||||
{
|
||||
label: "dynamic",
|
||||
value: "dynamic",
|
||||
}]}
|
||||
value={props.vps.verb.isCompound ? props.vps.verb.isCompound : "stative"}
|
||||
},
|
||||
]}
|
||||
value={
|
||||
props.vps.verb.isCompound === "generative stative"
|
||||
? "stative"
|
||||
: props.vps.verb.isCompound
|
||||
? props.vps.verb.isCompound
|
||||
: "stative"
|
||||
}
|
||||
handleChange={handleChangeStatDyn}
|
||||
/>
|
||||
</div>}
|
||||
</div>
|
||||
</div>;
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default VerbPicker;
|
|
@ -1,7 +1,8 @@
|
|||
import { renderVerb } from "../../../lib/src/new-verb-engine/render-verb";
|
||||
import * as T from "../../../types";
|
||||
import { equals } from "rambda";
|
||||
import { isPastTense } from "../../library";
|
||||
import { isPastTense, renderNPSelection } from "../../library";
|
||||
import { getPersonFromNP } from "../../../lib/src/phrase-building/vp-tools";
|
||||
|
||||
export function buildVerbChart({
|
||||
verb,
|
||||
|
@ -10,6 +11,7 @@ export function buildVerbChart({
|
|||
voice,
|
||||
imperative,
|
||||
negative,
|
||||
objectNP,
|
||||
}: {
|
||||
verb: T.VerbEntry;
|
||||
tense: T.VerbTense | T.PerfectTense | T.AbilityTense | T.ImperativeTense;
|
||||
|
@ -17,7 +19,11 @@ export function buildVerbChart({
|
|||
imperative: boolean;
|
||||
voice: T.VerbSelection["voice"];
|
||||
negative: boolean;
|
||||
}): T.OptionalPersonInflections<T.SingleOrLengthOpts<T.RenderVerbOutput[]>> {
|
||||
objectNP: T.NPSelection | undefined;
|
||||
}): {
|
||||
objNP: T.Rendered<T.NPSelection> | undefined;
|
||||
vbs: T.OptionalPersonInflections<T.SingleOrLengthOpts<T.RenderVerbOutput[]>>;
|
||||
} {
|
||||
const allPersons = imperative
|
||||
? [
|
||||
T.Person.SecondSingMale,
|
||||
|
@ -27,6 +33,9 @@ export function buildVerbChart({
|
|||
]
|
||||
: ([...Array(12).keys()] as T.Person[]);
|
||||
const isPast = isPastTense(tense);
|
||||
const objNP: T.Rendered<T.NPSelection> | undefined = objectNP
|
||||
? renderNPSelection(objectNP, false, false, "object", "none", false)
|
||||
: undefined;
|
||||
function conjugateAllPers(
|
||||
p?: T.Person
|
||||
): T.SingleOrLengthOpts<T.RenderVerbOutput[]> {
|
||||
|
@ -46,19 +55,51 @@ export function buildVerbChart({
|
|||
negative,
|
||||
});
|
||||
});
|
||||
const hasLengths = vIsLength("long")(ps[0]);
|
||||
const hasMini = vIsLength("mini")(ps[0]);
|
||||
return pullOutLengths(hasLengths, hasMini, ps);
|
||||
return pullOutLengths(ps);
|
||||
}
|
||||
if (transitivity === "transitive" && !isPast) {
|
||||
return conflateIfNoCompGenNumDiff({
|
||||
return {
|
||||
objNP,
|
||||
vbs: conflateIfNoCompGenNumDiff({
|
||||
mascSing: conjugateAllPers(T.Person.FirstSingMale),
|
||||
mascPlur: conjugateAllPers(T.Person.FirstPlurMale),
|
||||
femSing: conjugateAllPers(T.Person.FirstSingFemale),
|
||||
femPlur: conjugateAllPers(T.Person.FirstPlurFemale),
|
||||
});
|
||||
}),
|
||||
};
|
||||
} else if (objNP && isPast) {
|
||||
return {
|
||||
objNP,
|
||||
vbs: pullOutLengths([
|
||||
renderVerb({
|
||||
verb,
|
||||
tense,
|
||||
subject: 0,
|
||||
object: getPersonFromNP(objNP),
|
||||
voice,
|
||||
negative,
|
||||
}),
|
||||
]),
|
||||
};
|
||||
} else if (isPast && transitivity === "grammatically transitive") {
|
||||
return {
|
||||
objNP,
|
||||
vbs: pullOutLengths([
|
||||
renderVerb({
|
||||
verb,
|
||||
tense,
|
||||
subject: 0,
|
||||
object: T.Person.ThirdPlurMale,
|
||||
voice,
|
||||
negative,
|
||||
}),
|
||||
]),
|
||||
};
|
||||
} else {
|
||||
return conjugateAllPers();
|
||||
return {
|
||||
objNP: undefined,
|
||||
vbs: conjugateAllPers(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,23 +147,21 @@ function grabLength(
|
|||
if (v.length === 2) {
|
||||
const [vb, vbe] = v;
|
||||
return {
|
||||
objComp: undefined,
|
||||
hasBa,
|
||||
vbs: [ph, [grabVBLength(vb), vbe]],
|
||||
};
|
||||
}
|
||||
return {
|
||||
objComp: undefined,
|
||||
hasBa,
|
||||
vbs: [ph, [grabVBLength(v[0])]],
|
||||
};
|
||||
}
|
||||
|
||||
function pullOutLengths(
|
||||
hasLengths: boolean,
|
||||
hasMini: boolean,
|
||||
ps: T.RenderVerbOutput[]
|
||||
): T.SingleOrLengthOpts<T.RenderVerbOutput[]> {
|
||||
const hasLengths = vIsLength("long")(ps[0]);
|
||||
const hasMini = vIsLength("mini")(ps[0]);
|
||||
if (!hasLengths) {
|
||||
return ps;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
@media screen and (max-width: 600px) {
|
||||
.hide-on-mobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,85 +0,0 @@
|
|||
import * as T from "../../types";
|
||||
|
||||
export function fmapSingleOrLengthOpts<A extends object, B extends object>(f: (x: A) => B, x: T.SingleOrLengthOpts<A>): T.SingleOrLengthOpts<B> {
|
||||
if ("long" in x) {
|
||||
return {
|
||||
long: f(x.long),
|
||||
short: f(x.short),
|
||||
..."mini" in x && x.mini ? {
|
||||
mini: f(x.mini),
|
||||
} : {},
|
||||
};
|
||||
} else {
|
||||
return f(x);
|
||||
}
|
||||
}
|
||||
|
||||
export function mapInflections(f: (x: T.PsString) => T.PsString, inf: T.UnisexInflections): T.UnisexInflections {
|
||||
function handleSide(inf: T.InflectionSet): T.InflectionSet {
|
||||
return inf.map(x => x.map(f)) as T.ArrayFixed<T.ArrayOneOrMore<T.PsString>, 3>;
|
||||
}
|
||||
return {
|
||||
masc: handleSide(inf.masc),
|
||||
fem: handleSide(inf.fem),
|
||||
};
|
||||
}
|
||||
|
||||
export function mapVerbRenderedOutput(f: (a: T.PsString) => T.PsString, [a, b]: T.VerbRenderedOutput): T.VerbRenderedOutput {
|
||||
return [
|
||||
fmapVHead(a),
|
||||
fmapV(b),
|
||||
];
|
||||
function fmapVHead([v]: [T.VHead] | []): [T.VHead] | [] {
|
||||
if (v === undefined) {
|
||||
return [];
|
||||
}
|
||||
if (v.type === "PH") {
|
||||
return [{
|
||||
...v,
|
||||
ps: f(v.ps),
|
||||
}];
|
||||
}
|
||||
return [{
|
||||
...v,
|
||||
comp: fmapComp(v.comp),
|
||||
}];
|
||||
}
|
||||
function fmapComp(comp: T.Comp): T.Comp {
|
||||
return {
|
||||
...comp,
|
||||
ps: f(comp.ps),
|
||||
};
|
||||
}
|
||||
function fmapV(v: [T.VB, T.VBE] | [T.VBE]): [T.VB, T.VBE]| [T.VBE] {
|
||||
return v.map(fmapVB) as [T.VB, T.VBE]| [T.VBE];
|
||||
}
|
||||
function fmapVB<V extends T.VB | T.VBE>(v: V): V {
|
||||
if (v.type === "welded") {
|
||||
return {
|
||||
...v,
|
||||
left: fmapWeldedLeft(v.left),
|
||||
right: fmapVB(v.right),
|
||||
};
|
||||
}
|
||||
return {
|
||||
...v,
|
||||
ps: fmapSingleOrLengthOpts((x) => x.map(f), v.ps),
|
||||
};
|
||||
}
|
||||
function fmapWeldedLeft(v: T.NComp | T.VBBasic | T.Welded) {
|
||||
if (v.type === "NComp") {
|
||||
return {
|
||||
...v,
|
||||
comp: fmapComp(v.comp),
|
||||
};
|
||||
}
|
||||
return fmapVB(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -41,3 +41,95 @@ export const monoidPsStringWVars: Monoid<T.PsString[]> = {
|
|||
concat: semigroupPsStringWVars.concat,
|
||||
empty: [monoidPsString.empty],
|
||||
};
|
||||
|
||||
export function fmapSingleOrLengthOpts<A extends object, B extends object>(
|
||||
f: (x: A) => B,
|
||||
x: T.SingleOrLengthOpts<A>
|
||||
): T.SingleOrLengthOpts<B> {
|
||||
if ("long" in x) {
|
||||
return {
|
||||
long: f(x.long),
|
||||
short: f(x.short),
|
||||
...("mini" in x && x.mini
|
||||
? {
|
||||
mini: f(x.mini),
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
} else {
|
||||
return f(x);
|
||||
}
|
||||
}
|
||||
|
||||
export function mapInflections(
|
||||
f: (x: T.PsString) => T.PsString,
|
||||
inf: T.UnisexInflections
|
||||
): T.UnisexInflections {
|
||||
function handleSide(inf: T.InflectionSet): T.InflectionSet {
|
||||
return inf.map((x) => x.map(f)) as T.ArrayFixed<
|
||||
T.ArrayOneOrMore<T.PsString>,
|
||||
3
|
||||
>;
|
||||
}
|
||||
return {
|
||||
masc: handleSide(inf.masc),
|
||||
fem: handleSide(inf.fem),
|
||||
};
|
||||
}
|
||||
|
||||
export function mapVerbRenderedOutput(
|
||||
f: (a: T.PsString) => T.PsString,
|
||||
[a, b]: T.VerbRenderedOutput
|
||||
): T.VerbRenderedOutput {
|
||||
return [fmapVHead(a), fmapV(b)];
|
||||
function fmapVHead([v]: [T.VHead] | []): [T.VHead] | [] {
|
||||
if (v === undefined) {
|
||||
return [];
|
||||
}
|
||||
if (v.type === "PH") {
|
||||
return [
|
||||
{
|
||||
...v,
|
||||
ps: f(v.ps),
|
||||
},
|
||||
];
|
||||
}
|
||||
return [
|
||||
{
|
||||
...v,
|
||||
comp: fmapComp(v.comp),
|
||||
},
|
||||
];
|
||||
}
|
||||
function fmapComp(comp: T.Comp): T.Comp {
|
||||
return {
|
||||
...comp,
|
||||
ps: f(comp.ps),
|
||||
};
|
||||
}
|
||||
function fmapV(v: [T.VB, T.VBE] | [T.VBE]): [T.VB, T.VBE] | [T.VBE] {
|
||||
return v.map(fmapVB) as [T.VB, T.VBE] | [T.VBE];
|
||||
}
|
||||
function fmapVB<V extends T.VB | T.VBE>(v: V): V {
|
||||
if (v.type === "welded") {
|
||||
return {
|
||||
...v,
|
||||
left: fmapWeldedLeft(v.left),
|
||||
right: fmapVB(v.right),
|
||||
};
|
||||
}
|
||||
return {
|
||||
...v,
|
||||
ps: fmapSingleOrLengthOpts((x) => x.map(f), v.ps),
|
||||
};
|
||||
}
|
||||
function fmapWeldedLeft(v: T.NComp | T.VBBasic | T.Welded) {
|
||||
if (v.type === "NComp") {
|
||||
return {
|
||||
...v,
|
||||
comp: fmapComp(v.comp),
|
||||
};
|
||||
}
|
||||
return fmapVB(v);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import * as T from "../../types";
|
||||
import { fmapSingleOrLengthOpts } from "./fmaps";
|
||||
import { fmapSingleOrLengthOpts } from "./fp-ps";
|
||||
|
||||
export const blank: T.PsString = {
|
||||
p: "_____",
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
personNumber,
|
||||
personToGenNum,
|
||||
} from "../misc-helpers";
|
||||
import { fmapSingleOrLengthOpts } from "../fmaps";
|
||||
import { fmapSingleOrLengthOpts } from "../fp-ps";
|
||||
import { concatPsString, getLength } from "../p-text-helpers";
|
||||
import {
|
||||
presentEndings,
|
||||
|
@ -18,6 +18,7 @@ import {
|
|||
isAbilityTense,
|
||||
isPerfectTense,
|
||||
isTlulVerb,
|
||||
isImperativeTense,
|
||||
} from "../type-predicates";
|
||||
import { perfectTenseHasBa } from "../phrase-building/vp-tools";
|
||||
import { makePsString, removeFVarients } from "../accent-and-ps-utils";
|
||||
|
@ -100,6 +101,7 @@ export function renderVerb({
|
|||
subject,
|
||||
object,
|
||||
voice,
|
||||
negative,
|
||||
}: {
|
||||
verb: T.VerbEntry;
|
||||
negative: boolean;
|
||||
|
@ -126,7 +128,7 @@ export function renderVerb({
|
|||
const [vHead, rest] = getRootStem({
|
||||
verb,
|
||||
rs: isPast ? "root" : "stem",
|
||||
aspect,
|
||||
aspect: negative && isImperativeTense(tense) ? "imperfective" : aspect,
|
||||
voice,
|
||||
type,
|
||||
genderNumber: personToGenNum(transitive ? object : subject),
|
||||
|
@ -136,7 +138,6 @@ export function renderVerb({
|
|||
const ending = getEnding(king, tenseC, aspect);
|
||||
return {
|
||||
hasBa,
|
||||
objComp: undefined,
|
||||
vbs: [
|
||||
vHead,
|
||||
addEnding({
|
||||
|
|
|
@ -31,9 +31,9 @@ import {
|
|||
isKedul,
|
||||
} from "./rs-helpers";
|
||||
import { inflectPattern3 } from "./new-inflectors";
|
||||
import { fmapSingleOrLengthOpts } from "../fmaps";
|
||||
import { fmapSingleOrLengthOpts } from "../fp-ps";
|
||||
|
||||
const statVerb = {
|
||||
export const statVerb = {
|
||||
intransitive: vEntry({
|
||||
ts: 1581086654898,
|
||||
i: 11100,
|
||||
|
|
|
@ -30,7 +30,7 @@ import {
|
|||
splitUpSyllables,
|
||||
} from "./accent-helpers";
|
||||
import * as T from "../../types";
|
||||
import { fmapSingleOrLengthOpts } from "./fmaps";
|
||||
import { fmapSingleOrLengthOpts } from "./fp-ps";
|
||||
|
||||
const endingInSingleARegex = /[^a]'?’?[aá]'?’?$/;
|
||||
const endingInHeyOrAynRegex = /[^ا][هع]$/;
|
||||
|
@ -42,24 +42,29 @@ export function inflectWord(word: T.DictionaryEntry): T.InflectorOutput {
|
|||
const w = removeFVarients(word);
|
||||
if (w.c?.includes("doub.")) {
|
||||
const words = splitDoubleWord(w);
|
||||
const inflected = words.map((x) => ensureUnisexInflections(inflectWord(x), x));
|
||||
const inflected = words.map((x) =>
|
||||
ensureUnisexInflections(inflectWord(x), x)
|
||||
);
|
||||
return {
|
||||
inflections: concatInflections(
|
||||
inflected[0].inflections,
|
||||
inflected[1].inflections,
|
||||
inflected[1].inflections
|
||||
) as T.UnisexInflections,
|
||||
};
|
||||
}
|
||||
if (w.c && w.c.includes("pl.")) {
|
||||
return handlePluralNounOrAdj(w);
|
||||
}
|
||||
if (w.c && (w.c.includes("adj.") || w.c.includes("unisex") || w.c.includes("num"))) {
|
||||
if (
|
||||
w.c &&
|
||||
(w.c.includes("adj.") || w.c.includes("unisex") || w.c.includes("num"))
|
||||
) {
|
||||
return handleUnisexWord(w);
|
||||
}
|
||||
if (w.c && (w.c.includes("n. m."))) {
|
||||
if (w.c && w.c.includes("n. m.")) {
|
||||
return handleMascNoun(w);
|
||||
}
|
||||
if (w.c && (w.c.includes("n. f."))) {
|
||||
if (w.c && w.c.includes("n. f.")) {
|
||||
return handleFemNoun(w);
|
||||
}
|
||||
// It's not a noun/adj
|
||||
|
@ -88,10 +93,16 @@ function handleUnisexWord(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
|||
return { inflections: inflectRegularYeyUnisex(word.p, word.f), ...plurals };
|
||||
}
|
||||
if (pEnd === "ه" && word.g.slice(-1) === "u") {
|
||||
return { inflections: inflectRegularShwaEndingUnisex(word.p, word.f), ...plurals };
|
||||
return {
|
||||
inflections: inflectRegularShwaEndingUnisex(word.p, word.f),
|
||||
...plurals,
|
||||
};
|
||||
}
|
||||
if (pEnd === "ی" && word.f.slice(-2) === "éy") {
|
||||
return { inflections: inflectEmphasizedYeyUnisex(word.p, word.f), ...plurals };
|
||||
return {
|
||||
inflections: inflectEmphasizedYeyUnisex(word.p, word.f),
|
||||
...plurals,
|
||||
};
|
||||
}
|
||||
if (
|
||||
pashtoConsonants.includes(pEnd) ||
|
||||
|
@ -100,7 +111,10 @@ function handleUnisexWord(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
|||
word.f.slice(-1) === "w" ||
|
||||
(word.p.slice(-1) === "ه" && word.f.slice(-1) === "h")
|
||||
) {
|
||||
return { inflections: inflectConsonantEndingUnisex(word.p, word.f), ...plurals };
|
||||
return {
|
||||
inflections: inflectConsonantEndingUnisex(word.p, word.f),
|
||||
...plurals,
|
||||
};
|
||||
}
|
||||
if (plurals) return plurals;
|
||||
return false;
|
||||
|
@ -134,7 +148,10 @@ function handleMascNoun(w: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
|||
...plurals,
|
||||
};
|
||||
}
|
||||
const isTobEnding = (w.p.slice(-3) === "توب" && ["tób", "tob"].includes(w.f.slice(-3)) && w.p.length > 3);
|
||||
const isTobEnding =
|
||||
w.p.slice(-3) === "توب" &&
|
||||
["tób", "tob"].includes(w.f.slice(-3)) &&
|
||||
w.p.length > 3;
|
||||
if (isTobEnding) {
|
||||
return { inflections: inflectTobMasc(w.p, w.f), ...plurals };
|
||||
}
|
||||
|
@ -142,9 +159,12 @@ function handleMascNoun(w: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
|||
return { inflections: inflectRegularYeyMasc(w.p, w.f), ...plurals };
|
||||
}
|
||||
if (pEnd === "ی" && fEnd === "éy") {
|
||||
return { inflections: inflectRegularEmphasizedYeyMasc(w.p, w.f), ...plurals };
|
||||
return {
|
||||
inflections: inflectRegularEmphasizedYeyMasc(w.p, w.f),
|
||||
...plurals,
|
||||
};
|
||||
}
|
||||
return plurals ? { ...plurals } : false
|
||||
return plurals ? { ...plurals } : false;
|
||||
}
|
||||
|
||||
function handleFemNoun(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
||||
|
@ -163,13 +183,22 @@ function handleFemNoun(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
|||
return { inflections: inflectRegularAFem(word.p, word.f), ...plurals };
|
||||
}
|
||||
if (word.p.slice(-1) === "ح" && endingInSingleARegex.test(word.f)) {
|
||||
return { inflections: inflectRegularAWithHimPEnding(word.p, word.f), ...plurals };
|
||||
return {
|
||||
inflections: inflectRegularAWithHimPEnding(word.p, word.f),
|
||||
...plurals,
|
||||
};
|
||||
}
|
||||
// TODO: better reusable function to check if something ends with a consonant
|
||||
if ((pashtoConsonants.includes(pEnd) || word.f.slice(-1) === "w") && !animate) {
|
||||
return { inflections: inflectRegularInanMissingAFem(word.p, word.f), ...plurals };
|
||||
if (
|
||||
(pashtoConsonants.includes(pEnd) || word.f.slice(-1) === "w") &&
|
||||
!animate
|
||||
) {
|
||||
return {
|
||||
inflections: inflectRegularInanMissingAFem(word.p, word.f),
|
||||
...plurals,
|
||||
};
|
||||
}
|
||||
if (pEnd === "ي" && (!animate)) {
|
||||
if (pEnd === "ي" && !animate) {
|
||||
return { inflections: inflectRegularInanEeFem(word.p, word.f), ...plurals };
|
||||
}
|
||||
if (pEnd === "ۍ") {
|
||||
|
@ -182,14 +211,23 @@ function handleFemNoun(word: T.DictionaryEntryNoFVars): T.InflectorOutput {
|
|||
}
|
||||
|
||||
// LEVEL 3 FUNCTIONS
|
||||
function inflectIrregularUnisex(p: string, f: string, inflections: Array<{p: string, f: string}>): T.Inflections {
|
||||
function inflectIrregularUnisex(
|
||||
p: string,
|
||||
f: string,
|
||||
inflections: Array<{ p: string; f: string }>
|
||||
): T.Inflections {
|
||||
const inf1 = removeAccents(inflections[1]);
|
||||
const inf0 = removeAccents(inflections[0]);
|
||||
const inf0fSyls = splitUpSyllables(inf0.f).length;
|
||||
return {
|
||||
masc: [
|
||||
[{ p, f }],
|
||||
[{p: inflections[0].p, f: `${inf0.f.slice(0, -1)}${inf0fSyls === 1 ? "u" : "ú"}` }],
|
||||
[
|
||||
{
|
||||
p: inflections[0].p,
|
||||
f: `${inf0.f.slice(0, -1)}${inf0fSyls === 1 ? "u" : "ú"}`,
|
||||
},
|
||||
],
|
||||
[{ p: `${inf1.p}و`, f: `${inf1.f}${inf0fSyls === 1 ? "o" : "ó"}` }],
|
||||
],
|
||||
fem: [
|
||||
|
@ -200,7 +238,10 @@ function inflectIrregularUnisex(p: string, f: string, inflections: Array<{p: str
|
|||
};
|
||||
}
|
||||
|
||||
export function inflectRegularYeyUnisex(p: string, f: string): T.UnisexInflections {
|
||||
export function inflectRegularYeyUnisex(
|
||||
p: string,
|
||||
f: string
|
||||
): T.UnisexInflections {
|
||||
const baseP = p.slice(0, -1);
|
||||
const baseF = f.slice(0, -2);
|
||||
return {
|
||||
|
@ -220,7 +261,10 @@ export function inflectRegularYeyUnisex(p: string, f: string): T.UnisexInflectio
|
|||
};
|
||||
}
|
||||
|
||||
export function inflectRegularShwaEndingUnisex(pr: string, fr: string): T.UnisexInflections {
|
||||
export function inflectRegularShwaEndingUnisex(
|
||||
pr: string,
|
||||
fr: string
|
||||
): T.UnisexInflections {
|
||||
const { p, f } = removeAccents(makePsString(pr, fr));
|
||||
const accented = fr.slice(-1) === "ú";
|
||||
const baseP = p.slice(0, -1);
|
||||
|
@ -256,23 +300,23 @@ function inflectEmphasizedYeyUnisex(p: string, f: string): T.UnisexInflections {
|
|||
[{ p: `${baseP}ۍ`, f: `${baseF}úy` }],
|
||||
[
|
||||
{ p: `${baseP}یو`, f: `${baseF}úyo` },
|
||||
{ p: `${baseP}و`, f: `${baseF}ó`, },
|
||||
{ p: `${baseP}و`, f: `${baseF}ó` },
|
||||
],
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function inflectConsonantEndingUnisex(p: string, f: string): T.UnisexInflections {
|
||||
function inflectConsonantEndingUnisex(
|
||||
p: string,
|
||||
f: string
|
||||
): T.UnisexInflections {
|
||||
const fSyls = splitUpSyllables(removeAccents(f));
|
||||
const iBase = fSyls.length === 1
|
||||
const iBase =
|
||||
fSyls.length === 1
|
||||
? makePsString(p, accentFSylsOnNFromEnd(fSyls, 0))
|
||||
: makePsString(p, f);
|
||||
return {
|
||||
masc: [
|
||||
[{p, f}],
|
||||
[{p, f}],
|
||||
[{p: `${iBase.p}و`, f: `${iBase.f}o`}],
|
||||
],
|
||||
masc: [[{ p, f }], [{ p, f }], [{ p: `${iBase.p}و`, f: `${iBase.f}o` }]],
|
||||
fem: [
|
||||
[{ p: `${iBase.p}ه`, f: `${iBase.f}a` }],
|
||||
[{ p: `${iBase.p}ې`, f: `${iBase.f}e` }],
|
||||
|
@ -323,21 +367,37 @@ function inflectRegularEmphasizedYeyMasc(p: string, f: string): T.Inflections {
|
|||
};
|
||||
}
|
||||
|
||||
function inflectIrregularMasc(p: string, f: string, inflections: Array<{p: string, f: string}>): T.Inflections {
|
||||
function inflectIrregularMasc(
|
||||
p: string,
|
||||
f: string,
|
||||
inflections: Array<{ p: string; f: string }>
|
||||
): T.Inflections {
|
||||
let inf0f = removeAccents(inflections[0].f);
|
||||
const inf0syls = splitUpSyllables(f).length;
|
||||
const inf1f = removeAccents(inflections[1].f);
|
||||
return {
|
||||
masc: [
|
||||
[{ p, f }],
|
||||
[{p: inflections[0].p, f: `${inf0f.slice(0, -1)}${inf0syls === 1 ? "u" : "ú"}`}],
|
||||
[{p: `${inflections[1].p}و`, f: `${inf1f}${inf0syls === 1 ? "o" : "ó"}`}],
|
||||
[
|
||||
{
|
||||
p: inflections[0].p,
|
||||
f: `${inf0f.slice(0, -1)}${inf0syls === 1 ? "u" : "ú"}`,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
p: `${inflections[1].p}و`,
|
||||
f: `${inf1f}${inf0syls === 1 ? "o" : "ó"}`,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function inflectRegularAFem(p: string, f: string): T.Inflections {
|
||||
const withoutTrailingComma = ["'", "’"].includes(f.slice(-1)) ? f.slice(0, -1) : f;
|
||||
const withoutTrailingComma = ["'", "’"].includes(f.slice(-1))
|
||||
? f.slice(0, -1)
|
||||
: f;
|
||||
const accentLast = hasAccents(withoutTrailingComma.slice(-1));
|
||||
const baseF = withoutTrailingComma.slice(0, -1);
|
||||
const baseP = p.slice(-1) === "ع" ? p : p.slice(0, -1);
|
||||
|
@ -362,9 +422,8 @@ function inflectRegularAWithHimPEnding(p: string, f: string): T.Inflections {
|
|||
}
|
||||
|
||||
function inflectRegularInanMissingAFem(p: string, f: string): T.Inflections {
|
||||
const fBase = splitUpSyllables(f).length === 1
|
||||
? accentFSylsOnNFromEnd(f, 0)
|
||||
: f;
|
||||
const fBase =
|
||||
splitUpSyllables(f).length === 1 ? accentFSylsOnNFromEnd(f, 0) : f;
|
||||
return {
|
||||
fem: [
|
||||
[{ p, f }],
|
||||
|
@ -401,16 +460,13 @@ function inflectRegularUyFem(p: string, f: string): T.Inflections {
|
|||
};
|
||||
}
|
||||
|
||||
function makePashtoPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections | undefined {
|
||||
function makePashtoPlural(
|
||||
word: T.DictionaryEntryNoFVars
|
||||
): T.PluralInflections | undefined {
|
||||
if (!(word.ppp && word.ppf)) return undefined;
|
||||
const base = splitPsByVarients(
|
||||
makePsString(word.ppp, word.ppf)
|
||||
);
|
||||
const base = splitPsByVarients(makePsString(word.ppp, word.ppf));
|
||||
function getBaseAndO(): T.PluralInflectionSet {
|
||||
return [
|
||||
base,
|
||||
base.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>,
|
||||
];
|
||||
return [base, base.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>];
|
||||
}
|
||||
if (word.c?.includes("n. m.")) {
|
||||
return { masc: getBaseAndO() };
|
||||
|
@ -422,14 +478,14 @@ function makePashtoPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections |
|
|||
return undefined;
|
||||
}
|
||||
|
||||
function makeBundledPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections | undefined {
|
||||
function makeBundledPlural(
|
||||
word: T.DictionaryEntryNoFVars
|
||||
): T.PluralInflections | undefined {
|
||||
if (!endsInConsonant(word) || !word.c?.includes("n.")) {
|
||||
return undefined;
|
||||
}
|
||||
const w = makePsString(word.p, word.f);
|
||||
const base = countSyllables(w) === 1
|
||||
? accentOnNFromEnd(w, 0)
|
||||
: w;
|
||||
const base = countSyllables(w) === 1 ? accentOnNFromEnd(w, 0) : w;
|
||||
return {
|
||||
masc: [
|
||||
[concatPsString(base, { p: "ه", f: "a" })],
|
||||
|
@ -438,7 +494,9 @@ function makeBundledPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections
|
|||
};
|
||||
}
|
||||
|
||||
function makeArabicPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections | undefined {
|
||||
function makeArabicPlural(
|
||||
word: T.DictionaryEntryNoFVars
|
||||
): T.PluralInflections | undefined {
|
||||
if (!(word.apf && word.app)) return undefined;
|
||||
const w = makePsString(word.app, word.apf);
|
||||
const plural = splitPsByVarients(w);
|
||||
|
@ -456,15 +514,19 @@ function makeArabicPlural(word: T.DictionaryEntryNoFVars): T.PluralInflections |
|
|||
return { masc: value };
|
||||
}
|
||||
|
||||
function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections, bundledPlural?: T.PluralInflections } | { arabicPlural: T.PluralInflections, bundledPlural?: T.PluralInflections } | undefined {
|
||||
function addSecondInf(plur: T.ArrayOneOrMore<T.PsString> | T.PsString): T.PluralInflectionSet {
|
||||
function makePlural(
|
||||
w: T.DictionaryEntryNoFVars
|
||||
):
|
||||
| { plural: T.PluralInflections; bundledPlural?: T.PluralInflections }
|
||||
| { arabicPlural: T.PluralInflections; bundledPlural?: T.PluralInflections }
|
||||
| undefined {
|
||||
function addSecondInf(
|
||||
plur: T.ArrayOneOrMore<T.PsString> | T.PsString
|
||||
): T.PluralInflectionSet {
|
||||
if (!Array.isArray(plur)) {
|
||||
return addSecondInf([plur]);
|
||||
}
|
||||
return [
|
||||
plur,
|
||||
plur.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>,
|
||||
];
|
||||
return [plur, plur.flatMap(addOEnding) as T.ArrayOneOrMore<T.PsString>];
|
||||
}
|
||||
if (w.c && w.c.includes("pl.")) {
|
||||
const plural = addSecondInf(makePsString(w.p, w.f));
|
||||
|
@ -476,19 +538,31 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
|||
const arabicPlural = makeArabicPlural(w);
|
||||
const pashtoPlural = makePashtoPlural(w);
|
||||
const bundledPlural = makeBundledPlural(w);
|
||||
function addMascPluralSuffix(animate?: boolean, shortSquish?: boolean): T.PluralInflectionSet {
|
||||
function addMascPluralSuffix(
|
||||
animate?: boolean,
|
||||
shortSquish?: boolean
|
||||
): T.PluralInflectionSet {
|
||||
if (shortSquish && (w.infap === undefined || w.infaf === undefined)) {
|
||||
throw new Error(`no irregular inflection info for ${w.p} - ${w.ts}`);
|
||||
}
|
||||
const b = removeAccents(shortSquish
|
||||
? makePsString((w.infap as string).slice(0, -1), (w.infaf as string).slice(0, -1))
|
||||
const b = removeAccents(
|
||||
shortSquish
|
||||
? makePsString(
|
||||
(w.infap as string).slice(0, -1),
|
||||
(w.infaf as string).slice(0, -1)
|
||||
)
|
||||
: w
|
||||
);
|
||||
const base = endsInShwa(b)
|
||||
? makePsString(b.p.slice(0, -1), b.f.slice(0, -1))
|
||||
: b;
|
||||
return addSecondInf(
|
||||
concatPsString(base, (animate && !shortSquish) ? { p: "ان", f: "áan" } : { p: "ونه", f: "óona" }),
|
||||
concatPsString(
|
||||
base,
|
||||
animate && !shortSquish
|
||||
? { p: "ان", f: "áan" }
|
||||
: { p: "ونه", f: "óona" }
|
||||
)
|
||||
);
|
||||
}
|
||||
function addAnimUnisexPluralSuffix(): T.UnisexSet<T.PluralInflectionSet> {
|
||||
|
@ -505,10 +579,14 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
|||
f: b.f.slice(0, -2),
|
||||
};
|
||||
const firstInf: T.ArrayOneOrMore<T.PsString> = [
|
||||
concatPsString(base, { p: "یان", f: "iyáan" }, gender === "fem" ? { p: "ې", f: "e" } : ""),
|
||||
...gender === "fem"
|
||||
concatPsString(
|
||||
base,
|
||||
{ p: "یان", f: "iyáan" },
|
||||
gender === "fem" ? { p: "ې", f: "e" } : ""
|
||||
),
|
||||
...(gender === "fem"
|
||||
? [concatPsString(base, { p: "یګانې", f: "eegáane" })]
|
||||
: [],
|
||||
: []),
|
||||
];
|
||||
return [
|
||||
firstInf,
|
||||
|
@ -537,11 +615,12 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
|||
function addLongVowelSuffix(gender: "masc" | "fem"): T.PluralInflectionSet {
|
||||
const base = removeEndTick(makePsString(w.p, w.f));
|
||||
const baseWOutAccents = removeAccents(base);
|
||||
const space = (w.p.slice(-1) === "ع" || w.p.slice(-1) === "ه") ? { p: " ", f: " " } : "";
|
||||
const space =
|
||||
w.p.slice(-1) === "ع" || w.p.slice(-1) === "ه" ? { p: " ", f: " " } : "";
|
||||
if (gender === "fem") {
|
||||
return addSecondInf([
|
||||
concatPsString(base, space, { p: "وې", f: "we" }),
|
||||
concatPsString(baseWOutAccents, space, { p: "ګانې", f: "gáane" })
|
||||
concatPsString(baseWOutAccents, space, { p: "ګانې", f: "gáane" }),
|
||||
]);
|
||||
} else {
|
||||
return addSecondInf([
|
||||
|
@ -571,24 +650,32 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
|||
|
||||
const shortSquish = !!w.infap && !w.infap.includes("ا");
|
||||
const anim = w.c?.includes("anim.");
|
||||
const type = (w.c?.includes("unisex"))
|
||||
const type = w.c?.includes("unisex")
|
||||
? "unisex noun"
|
||||
: (w.c?.includes("n. m."))
|
||||
: w.c?.includes("n. m.")
|
||||
? "masc noun"
|
||||
: (w.c?.includes("n. f."))
|
||||
: w.c?.includes("n. f.")
|
||||
? "fem noun"
|
||||
: "other";
|
||||
if (pashtoPlural) return {
|
||||
if (pashtoPlural)
|
||||
return {
|
||||
plural: pashtoPlural,
|
||||
arabicPlural,
|
||||
};
|
||||
if (type === "unisex noun") {
|
||||
// doesn't need to be labelled anim - because it's only with animate nouns that you get the unisex - I THINK
|
||||
if (endsInConsonant(w) && (!w.infap)) {
|
||||
return { arabicPlural, bundledPlural, plural: addAnimUnisexPluralSuffix() };
|
||||
if (endsInConsonant(w) && !w.infap) {
|
||||
return {
|
||||
arabicPlural,
|
||||
bundledPlural,
|
||||
plural: addAnimUnisexPluralSuffix(),
|
||||
};
|
||||
}
|
||||
if (shortSquish && !anim) {
|
||||
return { arabicPlural, plural: { masc: addMascPluralSuffix(anim, shortSquish) }};
|
||||
return {
|
||||
arabicPlural,
|
||||
plural: { masc: addMascPluralSuffix(anim, shortSquish) },
|
||||
};
|
||||
}
|
||||
if (endsWith([{ p: "ی", f: "éy" }, { p: "ي" }], w, true)) {
|
||||
return { arabicPlural, plural: addAnimN3UnisexPluralSuffix() };
|
||||
|
@ -598,8 +685,8 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
|||
}
|
||||
if (
|
||||
type === "masc noun" &&
|
||||
(shortSquish || ((endsInConsonant(w) || endsInShwa(w)) && (!w.infap))) &&
|
||||
(w.p.slice(-3) !== "توب")
|
||||
(shortSquish || ((endsInConsonant(w) || endsInShwa(w)) && !w.infap)) &&
|
||||
w.p.slice(-3) !== "توب"
|
||||
) {
|
||||
return {
|
||||
arabicPlural,
|
||||
|
@ -609,11 +696,7 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
|||
},
|
||||
};
|
||||
}
|
||||
if (
|
||||
type === "masc noun" &&
|
||||
endsWith({ p: "ی", f: "éy" }, w, true) &&
|
||||
anim
|
||||
) {
|
||||
if (type === "masc noun" && endsWith({ p: "ی", f: "éy" }, w, true) && anim) {
|
||||
const { masc } = addAnimN3UnisexPluralSuffix();
|
||||
return {
|
||||
arabicPlural,
|
||||
|
@ -630,7 +713,7 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
|||
};
|
||||
}
|
||||
// TODO: What about endings in long ee / animate at inanimate
|
||||
if (type === "masc noun" && endsInAaOrOo(w) && (!w.infap)) {
|
||||
if (type === "masc noun" && endsInAaOrOo(w) && !w.infap) {
|
||||
return {
|
||||
arabicPlural,
|
||||
plural: {
|
||||
|
@ -639,7 +722,7 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
|||
};
|
||||
}
|
||||
// TODO: What about endings in long ee / animate at inanimate
|
||||
if (type === "fem noun" && endsInAaOrOo(w) && (!w.infap)) {
|
||||
if (type === "fem noun" && endsInAaOrOo(w) && !w.infap) {
|
||||
return {
|
||||
arabicPlural,
|
||||
plural: {
|
||||
|
@ -661,6 +744,8 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections,
|
|||
return undefined;
|
||||
}
|
||||
|
||||
export function inflectYey(ps: T.SingleOrLengthOpts<T.PsString>): T.SingleOrLengthOpts<T.UnisexInflections> {
|
||||
export function inflectYey(
|
||||
ps: T.SingleOrLengthOpts<T.PsString>
|
||||
): T.SingleOrLengthOpts<T.UnisexInflections> {
|
||||
return fmapSingleOrLengthOpts((x) => inflectRegularYeyUnisex(x.p, x.f), ps);
|
||||
}
|
||||
|
|
|
@ -15,31 +15,53 @@ export function makeKid(kid: T.Kid["kid"], key?: number): T.Kid {
|
|||
};
|
||||
}
|
||||
|
||||
export function getSubjectSelection(blocks: T.EPSBlockComplete[] | T.VPSBlockComplete[]): T.SubjectSelectionComplete;
|
||||
export function getSubjectSelection(blocks: T.EPSBlock[] | T.VPSBlock[]): T.SubjectSelection;
|
||||
export function getSubjectSelection(blocks: T.EPSBlock[] | T.EPSBlockComplete[] | T.VPSBlockComplete[] | T.VPSBlock[]): T.SubjectSelection | T.SubjectSelectionComplete {
|
||||
const b = blocks.find(f => f.block?.type === "subjectSelection");
|
||||
export function getSubjectSelection(
|
||||
blocks: T.EPSBlockComplete[] | T.VPSBlockComplete[]
|
||||
): T.SubjectSelectionComplete;
|
||||
export function getSubjectSelection(
|
||||
blocks: T.EPSBlock[] | T.VPSBlock[]
|
||||
): T.SubjectSelection;
|
||||
export function getSubjectSelection(
|
||||
blocks:
|
||||
| T.EPSBlock[]
|
||||
| T.EPSBlockComplete[]
|
||||
| T.VPSBlockComplete[]
|
||||
| T.VPSBlock[]
|
||||
): T.SubjectSelection | T.SubjectSelectionComplete {
|
||||
const b = blocks.find((f) => f.block?.type === "subjectSelection");
|
||||
if (!b || !b.block || b.block.type !== "subjectSelection") {
|
||||
throw new Error("subjectSelection not found in blocks");
|
||||
}
|
||||
return b.block;
|
||||
}
|
||||
|
||||
export function getComplementFromBlocks(blocks: T.Block[][]): T.Rendered<T.ComplementSelection> | T.UnselectedComplementSelection | undefined {
|
||||
const b = blocks[0].find(f => f.block.type === "complement");
|
||||
return b?.block as T.Rendered<T.ComplementSelection> | T.UnselectedComplementSelection | undefined;
|
||||
export function getComplementFromBlocks(
|
||||
blocks: T.Block[][]
|
||||
):
|
||||
| T.Rendered<T.ComplementSelection>
|
||||
| T.UnselectedComplementSelection
|
||||
| undefined {
|
||||
const b = blocks[0].find((f) => f.block.type === "complement");
|
||||
return b?.block as
|
||||
| T.Rendered<T.ComplementSelection>
|
||||
| T.UnselectedComplementSelection
|
||||
| undefined;
|
||||
}
|
||||
|
||||
export function getSubjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.SubjectSelectionComplete> {
|
||||
const b = blocks[0].find(f => f.block.type === "subjectSelection");
|
||||
export function getSubjectSelectionFromBlocks(
|
||||
blocks: T.Block[][]
|
||||
): T.Rendered<T.SubjectSelectionComplete> {
|
||||
const b = blocks[0].find((f) => f.block.type === "subjectSelection");
|
||||
if (!b || b.block.type !== "subjectSelection") {
|
||||
throw new Error("subjectSelection not found in blocks");
|
||||
}
|
||||
return b.block;
|
||||
}
|
||||
|
||||
export function getObjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.ObjectSelectionComplete> {
|
||||
const b = blocks[0].find(f => f.block.type === "objectSelection");
|
||||
export function getObjectSelectionFromBlocks(
|
||||
blocks: T.Block[][]
|
||||
): T.Rendered<T.ObjectSelectionComplete> {
|
||||
const b = blocks[0].find((f) => f.block.type === "objectSelection");
|
||||
if (!b || b.block.type !== "objectSelection") {
|
||||
throw new Error("objectSelection not found in blocks");
|
||||
}
|
||||
|
@ -48,27 +70,37 @@ export function getObjectSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.
|
|||
|
||||
export function includesShrunkenServant(kids?: T.Kid[]): boolean {
|
||||
if (!kids) return false;
|
||||
return kids.some(k => (
|
||||
k.kid.type === "mini-pronoun" && k.kid.source === "servant"
|
||||
));
|
||||
return kids.some(
|
||||
(k) => k.kid.type === "mini-pronoun" && k.kid.source === "servant"
|
||||
);
|
||||
}
|
||||
|
||||
export function getPredicateSelectionFromBlocks(blocks: T.Block[][]): T.Rendered<T.PredicateSelectionComplete> {
|
||||
const b = blocks[0].find(f => f.block.type === "predicateSelection");
|
||||
export function getPredicateSelectionFromBlocks(
|
||||
blocks: T.Block[][]
|
||||
): T.Rendered<T.PredicateSelectionComplete> {
|
||||
const b = blocks[0].find((f) => f.block.type === "predicateSelection");
|
||||
if (!b || b.block.type !== "predicateSelection") {
|
||||
throw new Error("predicateSelection not found in blocks");
|
||||
}
|
||||
return b.block;
|
||||
}
|
||||
|
||||
export function getAPsFromBlocks(blocks: T.Block[][]): T.Rendered<T.APSelection>[] {
|
||||
return blocks[0].filter(b => b.block.type === "AP").map(b => b.block) as T.Rendered<T.APSelection>[];
|
||||
export function getAPsFromBlocks(
|
||||
blocks: T.Block[][]
|
||||
): T.Rendered<T.APSelection>[] {
|
||||
return blocks[0]
|
||||
.filter((b) => b.block.type === "AP")
|
||||
.map((b) => b.block) as T.Rendered<T.APSelection>[];
|
||||
}
|
||||
|
||||
export function getObjectSelection(blocks: T.VPSBlockComplete[]): T.ObjectSelectionComplete;
|
||||
export function getObjectSelection(
|
||||
blocks: T.VPSBlockComplete[]
|
||||
): T.ObjectSelectionComplete;
|
||||
export function getObjectSelection(blocks: T.VPSBlock[]): T.ObjectSelection;
|
||||
export function getObjectSelection(blocks: T.VPSBlock[] | T.VPSBlockComplete[]): T.ObjectSelection | T.ObjectSelectionComplete {
|
||||
const b = blocks.find(f => f.block?.type === "objectSelection");
|
||||
export function getObjectSelection(
|
||||
blocks: T.VPSBlock[] | T.VPSBlockComplete[]
|
||||
): T.ObjectSelection | T.ObjectSelectionComplete {
|
||||
const b = blocks.find((f) => f.block?.type === "objectSelection");
|
||||
if (!b || !b.block || b.block.type !== "objectSelection") {
|
||||
throw new Error("objectSelection not found in blocks");
|
||||
}
|
||||
|
@ -83,18 +115,24 @@ export function makeEPSBlocks(): T.EPSBlock[] {
|
|||
type: "subjectSelection",
|
||||
selection: undefined,
|
||||
},
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function makeAPBlock(): { key: number, block: undefined } {
|
||||
export function makeAPBlock(): { key: number; block: undefined } {
|
||||
return {
|
||||
key: Math.random(),
|
||||
block: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export function makeSubjectSelection(selection: T.SubjectSelection | T.NPSelection | T.NPSelection["selection"] | undefined): T.SubjectSelection {
|
||||
export function makeSubjectSelection(
|
||||
selection:
|
||||
| T.SubjectSelection
|
||||
| T.NPSelection
|
||||
| T.NPSelection["selection"]
|
||||
| undefined
|
||||
): T.SubjectSelection {
|
||||
if (!selection) {
|
||||
return {
|
||||
type: "subjectSelection",
|
||||
|
@ -115,16 +153,23 @@ export function makeSubjectSelection(selection: T.SubjectSelection | T.NPSelecti
|
|||
selection: {
|
||||
type: "NP",
|
||||
selection,
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function makeObjectSelection(selection: T.ObjectSelection | T.ObjectNP | T.NPSelection | T.NPSelection["selection"] | undefined): T.ObjectSelection {
|
||||
export function makeObjectSelection(
|
||||
selection:
|
||||
| T.ObjectSelection
|
||||
| T.ObjectNP
|
||||
| T.NPSelection
|
||||
| T.NPSelection["selection"]
|
||||
| undefined
|
||||
): T.ObjectSelection {
|
||||
if (!selection) {
|
||||
return {
|
||||
type: "objectSelection",
|
||||
selection: undefined,
|
||||
}
|
||||
};
|
||||
}
|
||||
if (typeof selection !== "object") {
|
||||
return {
|
||||
|
@ -150,16 +195,20 @@ export function makeObjectSelection(selection: T.ObjectSelection | T.ObjectNP |
|
|||
};
|
||||
}
|
||||
|
||||
export function EPSBlocksAreComplete(blocks: T.EPSBlock[]): blocks is T.EPSBlockComplete[] {
|
||||
if (blocks.some(block => block.block === undefined)) {
|
||||
export function EPSBlocksAreComplete(
|
||||
blocks: T.EPSBlock[]
|
||||
): blocks is T.EPSBlockComplete[] {
|
||||
if (blocks.some((block) => block.block === undefined)) {
|
||||
return false;
|
||||
}
|
||||
const subject = getSubjectSelection(blocks);
|
||||
return !!subject.selection;
|
||||
}
|
||||
|
||||
export function VPSBlocksAreComplete(blocks: T.VPSBlock[]): blocks is T.VPSBlockComplete[] {
|
||||
if (blocks.some(block => block.block === undefined)) {
|
||||
export function VPSBlocksAreComplete(
|
||||
blocks: T.VPSBlock[]
|
||||
): blocks is T.VPSBlockComplete[] {
|
||||
if (blocks.some((block) => block.block === undefined)) {
|
||||
return false;
|
||||
}
|
||||
const subject = getSubjectSelection(blocks);
|
||||
|
@ -169,70 +218,137 @@ export function VPSBlocksAreComplete(blocks: T.VPSBlock[]): blocks is T.VPSBlock
|
|||
return true;
|
||||
}
|
||||
|
||||
export function adjustSubjectSelection(blocks: T.EPSBlock[], subject: T.SubjectSelection | T.NPSelection | undefined): T.EPSBlock[];
|
||||
export function adjustSubjectSelection(blocks: T.VPSBlock[], subject: T.SubjectSelection | T.NPSelection | undefined): T.VPSBlock[];
|
||||
export function adjustSubjectSelection(blocks: T.VPSBlock[] | T.EPSBlock[], subject: T.SubjectSelection | T.NPSelection | undefined): T.VPSBlock[] | T.EPSBlock[] {
|
||||
export function adjustSubjectSelection(
|
||||
blocks: T.EPSBlock[],
|
||||
subject: T.SubjectSelection | T.NPSelection | undefined
|
||||
): T.EPSBlock[];
|
||||
export function adjustSubjectSelection(
|
||||
blocks: T.VPSBlock[],
|
||||
subject: T.SubjectSelection | T.NPSelection | undefined
|
||||
): T.VPSBlock[];
|
||||
export function adjustSubjectSelection(
|
||||
blocks: T.VPSBlock[] | T.EPSBlock[],
|
||||
subject: T.SubjectSelection | T.NPSelection | undefined
|
||||
): T.VPSBlock[] | T.EPSBlock[] {
|
||||
const nb = [...blocks];
|
||||
const i = nb.findIndex(b => b.block && b.block.type === "subjectSelection");
|
||||
const i = nb.findIndex((b) => b.block && b.block.type === "subjectSelection");
|
||||
if (i === -1) {
|
||||
throw new Error("couldn't find subjectSelection to modify");
|
||||
}
|
||||
nb[i].block = subject?.type === "subjectSelection" ? subject : makeSubjectSelection(subject);
|
||||
nb[i].block =
|
||||
subject?.type === "subjectSelection"
|
||||
? subject
|
||||
: makeSubjectSelection(subject);
|
||||
return nb;
|
||||
}
|
||||
|
||||
export function adjustObjectSelection(blocks: Readonly<T.VPSBlock[]>, object: T.ObjectSelectionComplete | T.NPSelection | T.VerbObject | T.ObjectSelectionComplete): T.VPSBlockComplete[];
|
||||
export function adjustObjectSelection(blocks: Readonly<T.VPSBlock[]>, object: T.ObjectSelection | T.NPSelection | T.VerbObject | T.ObjectSelection | undefined): T.EPSBlock[];
|
||||
export function adjustObjectSelection(blocks: Readonly<T.VPSBlock[]>, object: T.ObjectSelection | T.ObjectSelectionComplete | T.VerbObject | T.NPSelection | undefined): T.VPSBlock[] | T.VPSBlockComplete[] {
|
||||
export function adjustObjectSelection(
|
||||
blocks: Readonly<T.VPSBlock[]>,
|
||||
object:
|
||||
| T.ObjectSelectionComplete
|
||||
| T.NPSelection
|
||||
| T.VerbObject
|
||||
| T.ObjectSelectionComplete
|
||||
): T.VPSBlockComplete[];
|
||||
export function adjustObjectSelection(
|
||||
blocks: Readonly<T.VPSBlock[]>,
|
||||
object:
|
||||
| T.ObjectSelection
|
||||
| T.NPSelection
|
||||
| T.VerbObject
|
||||
| T.ObjectSelection
|
||||
| undefined
|
||||
): T.EPSBlock[];
|
||||
export function adjustObjectSelection(
|
||||
blocks: Readonly<T.VPSBlock[]>,
|
||||
object:
|
||||
| T.ObjectSelection
|
||||
| T.ObjectSelectionComplete
|
||||
| T.VerbObject
|
||||
| T.NPSelection
|
||||
| undefined
|
||||
): T.VPSBlock[] | T.VPSBlockComplete[] {
|
||||
const nb = [...blocks];
|
||||
const i = nb.findIndex(b => b.block && b.block.type === "objectSelection");
|
||||
const i = nb.findIndex((b) => b.block && b.block.type === "objectSelection");
|
||||
if (i === -1) {
|
||||
throw new Error("couldn't find objectSelection to modify");
|
||||
}
|
||||
nb[i].block = typeof object === "object" && object?.type === "objectSelection"
|
||||
nb[i].block =
|
||||
typeof object === "object" && object?.type === "objectSelection"
|
||||
? object
|
||||
: makeObjectSelection(object);
|
||||
return nb;
|
||||
}
|
||||
|
||||
export function shiftBlock<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B, index: number, direction: "back" | "forward"): B {
|
||||
const newIndex = index + (direction === "forward"
|
||||
? 1 // (isNoObject(blocks[index + 1].block) ? 2 : 1)
|
||||
: -1 // (isNoObject(blocks[index - 1].block) ? -2 : -2)
|
||||
export function moveObjectToEnd(
|
||||
blocks: T.VPSBlockComplete[]
|
||||
): T.VPSBlockComplete[] {
|
||||
const i = blocks.findIndex(
|
||||
(b) => b.block && b.block.type === "objectSelection"
|
||||
);
|
||||
if (i === -1) {
|
||||
throw new Error("couldn't find objectSelection to move");
|
||||
}
|
||||
if (i === blocks.length - 1) {
|
||||
return blocks;
|
||||
}
|
||||
return arrayMove(blocks, i, blocks.length - 1);
|
||||
}
|
||||
|
||||
export function shiftBlock<B extends T.VPSBlock[] | T.EPSBlock[]>(
|
||||
blocks: B,
|
||||
index: number,
|
||||
direction: "back" | "forward"
|
||||
): B {
|
||||
const newIndex =
|
||||
index +
|
||||
(direction === "forward"
|
||||
? 1 // (isNoObject(blocks[index + 1].block) ? 2 : 1)
|
||||
: -1); // (isNoObject(blocks[index - 1].block) ? -2 : -2)
|
||||
return arrayMove(blocks, index, newIndex) as B;
|
||||
}
|
||||
|
||||
export function insertNewAP<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B): B {
|
||||
export function insertNewAP<B extends T.VPSBlock[] | T.EPSBlock[]>(
|
||||
blocks: B
|
||||
): B {
|
||||
return [makeAPBlock(), ...blocks] as B;
|
||||
}
|
||||
|
||||
export function setAP<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B, index: number, AP: T.APSelection | undefined): B {
|
||||
export function setAP<B extends T.VPSBlock[] | T.EPSBlock[]>(
|
||||
blocks: B,
|
||||
index: number,
|
||||
AP: T.APSelection | undefined
|
||||
): B {
|
||||
const nBlocks = [...blocks] as B;
|
||||
nBlocks[index].block = AP;
|
||||
return nBlocks;
|
||||
}
|
||||
|
||||
export function removeAP<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B, index: number): B {
|
||||
export function removeAP<B extends T.VPSBlock[] | T.EPSBlock[]>(
|
||||
blocks: B,
|
||||
index: number
|
||||
): B {
|
||||
const nBlocks = [...blocks] as B;
|
||||
nBlocks.splice(index, 1);
|
||||
return nBlocks;
|
||||
}
|
||||
|
||||
export function isNoObject(b: T.VPSBlock["block"] | T.EPSBlock["block"]): b is { type: "objectSelection", selection: "none" } {
|
||||
return !!(
|
||||
b
|
||||
&&
|
||||
(b.type === "objectSelection" && b.selection === "none")
|
||||
);
|
||||
export function isNoObject(
|
||||
b: T.VPSBlock["block"] | T.EPSBlock["block"]
|
||||
): b is { type: "objectSelection"; selection: "none" } {
|
||||
return !!(b && b.type === "objectSelection" && b.selection === "none");
|
||||
}
|
||||
|
||||
export function specifyEquativeLength(blocksWVars: T.Block[][], length: "long" | "short"): T.Block[][] {
|
||||
export function specifyEquativeLength(
|
||||
blocksWVars: T.Block[][],
|
||||
length: "long" | "short"
|
||||
): T.Block[][] {
|
||||
function specify(blocks: T.Block[]): T.Block[] {
|
||||
const i = blocks.findIndex(b => b.block.type === "equative");
|
||||
const i = blocks.findIndex((b) => b.block.type === "equative");
|
||||
if (i === -1) throw new Error("equative block not found in EPRendered");
|
||||
const eq = blocks[i];
|
||||
if (eq.block.type !== "equative") throw new Error("error searching for equative block");
|
||||
if (eq.block.type !== "equative")
|
||||
throw new Error("error searching for equative block");
|
||||
const adjusted = [...blocks];
|
||||
adjusted[i] = {
|
||||
...eq,
|
||||
|
@ -268,23 +384,21 @@ export function isRenderedVerbB({ block }: T.Block): boolean {
|
|||
if (block.type === "complement") {
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
export function hasEquativeWithLengths(blocks: T.Block[][]): boolean {
|
||||
const equative = blocks[0].find(x => x.block.type === "equative");
|
||||
const equative = blocks[0].find((x) => x.block.type === "equative");
|
||||
if (!equative) throw new Error("equative not found in blocks");
|
||||
if (equative.block.type !== "equative") throw new Error("error finding equative in blocks");
|
||||
if (equative.block.type !== "equative")
|
||||
throw new Error("error finding equative in blocks");
|
||||
return "long" in equative.block.equative.ps;
|
||||
}
|
||||
|
||||
function arrayMove<X>(ar: X[], old_index: number, new_index: number): X[] {
|
||||
const arr = [...ar];
|
||||
const new_i = (new_index >= arr.length)
|
||||
? (arr.length - 1)
|
||||
: (new_index < 0)
|
||||
? 0
|
||||
: new_index;
|
||||
const new_i =
|
||||
new_index >= arr.length ? arr.length - 1 : new_index < 0 ? 0 : new_index;
|
||||
arr.splice(new_i, 0, arr.splice(old_index, 1)[0]);
|
||||
return arr;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import {
|
|||
specifyEquativeLength,
|
||||
} from "./blocks-utils";
|
||||
import { blank, kidsBlank } from "../misc-helpers";
|
||||
import { monoidPsStringWVars } from "../fp-ps";
|
||||
import { concatAll } from "fp-ts/lib/Monoid";
|
||||
|
||||
type BlankoutOptions = {
|
||||
equative?: boolean;
|
||||
|
@ -215,64 +217,66 @@ export function combineIntoText(
|
|||
subjectPerson: T.Person,
|
||||
blankOut?: BlankoutOptions
|
||||
): T.PsString[] {
|
||||
function removeDoubleBlanks(x: T.PsString): T.PsString {
|
||||
return {
|
||||
p: x.p.replace(blank.p + blank.p, blank.p),
|
||||
f: x.f.replace(blank.f + blank.f, blank.f),
|
||||
};
|
||||
return piecesWVars
|
||||
.map((pieces) => {
|
||||
const psVarsBlocks = getPsVarsBlocks(
|
||||
applyBlankOut(pieces, blankOut),
|
||||
subjectPerson
|
||||
);
|
||||
return concatAll(monoidPsStringWVars)(psVarsBlocks);
|
||||
})
|
||||
.flat();
|
||||
}
|
||||
function combine(pieces: (T.Block | T.Kid | T.PsString)[]): T.PsString[] {
|
||||
const first = pieces[0];
|
||||
const next = pieces[1];
|
||||
const rest = pieces.slice(1);
|
||||
// better to do map-reduce
|
||||
// map the blocks into monoids [T.PsString] (with appropriate space blocks) and then concat them all together
|
||||
const firstPs =
|
||||
"p" in first
|
||||
? [first]
|
||||
: (blankOut?.equative &&
|
||||
"block" in first &&
|
||||
first.block.type === "equative") ||
|
||||
(blankOut?.verb && "block" in first && isRenderedVerbB(first)) ||
|
||||
|
||||
function getPsVarsBlocks(
|
||||
pieces: (T.Block | T.Kid | T.PsString)[],
|
||||
subjectPerson: T.Person
|
||||
): T.PsString[][] {
|
||||
const space = [{ p: " ", f: " " }];
|
||||
const phToCliticNegSpace = [{ p: "", f: "-" }];
|
||||
const endIndex = pieces.length - 1;
|
||||
return pieces.reduce<T.PsString[][]>((acc, x, i) => {
|
||||
const next = pieces[i + 1];
|
||||
if ("p" in x) {
|
||||
return [...acc, [x]];
|
||||
}
|
||||
const ps = getPsFromPiece(x, subjectPerson);
|
||||
return [
|
||||
...acc,
|
||||
ps,
|
||||
...(i === endIndex
|
||||
? []
|
||||
: "block" in x && x.block.type === "PH"
|
||||
? "kid" in next || ("block" in next && next.block.type === "negative")
|
||||
? [phToCliticNegSpace]
|
||||
: []
|
||||
: [space]),
|
||||
];
|
||||
}, []);
|
||||
}
|
||||
function applyBlankOut(
|
||||
pieces: (T.Block | T.Kid | T.PsString)[],
|
||||
blankOut: BlankoutOptions | undefined
|
||||
): (T.Block | T.Kid | T.PsString)[] {
|
||||
if (!blankOut) return pieces;
|
||||
return pieces.map((x) => {
|
||||
if (
|
||||
(blankOut.equative && "block" in x && x.block.type === "equative") ||
|
||||
(blankOut.verb && "block" in x && isRenderedVerbB(x)) ||
|
||||
(blankOut?.predicate &&
|
||||
"block" in first &&
|
||||
first.block.type === "predicateSelection")
|
||||
? [blank]
|
||||
: blankOut?.ba && "kid" in first && first.kid.type === "ba"
|
||||
? [kidsBlank]
|
||||
: blankOut?.negative &&
|
||||
"block" in first &&
|
||||
first.block.type === "negative"
|
||||
? [{ p: "", f: "" }]
|
||||
: getPsFromPiece(first, subjectPerson);
|
||||
if (!rest.length) {
|
||||
return firstPs;
|
||||
"block" in x &&
|
||||
x.block.type === "predicateSelection")
|
||||
) {
|
||||
return blank;
|
||||
}
|
||||
return combine(rest)
|
||||
.flatMap((r) =>
|
||||
firstPs.map((fPs) =>
|
||||
concatPsString(
|
||||
fPs,
|
||||
// TODO: this spacing is a mess and not accurate
|
||||
!("p" in first) &&
|
||||
"block" in first &&
|
||||
first.block.type === "PH" &&
|
||||
!("p" in next) &&
|
||||
(("block" in next &&
|
||||
(isRenderedVerbB(next) || next.block.type === "negative")) ||
|
||||
("kid" in next && next.kid.type === "mini-pronoun"))
|
||||
? ("block" in next && next.block.type === "negative") ||
|
||||
("kid" in next && next.kid.type === "mini-pronoun")
|
||||
? { p: "", f: " " }
|
||||
: ""
|
||||
: " ",
|
||||
r
|
||||
)
|
||||
)
|
||||
)
|
||||
.map(removeDoubleBlanks);
|
||||
if (blankOut?.ba && "kid" in x && x.kid.type === "ba") {
|
||||
return kidsBlank;
|
||||
}
|
||||
return piecesWVars.flatMap(combine);
|
||||
if (blankOut?.negative && "block" in x && x.block.type === "negative") {
|
||||
return { p: "", f: "" };
|
||||
}
|
||||
return x;
|
||||
});
|
||||
}
|
||||
|
||||
function getPsFromPiece(
|
||||
|
|
|
@ -12,14 +12,18 @@ export function makeAdverbSelection(entry: T.AdverbEntry): T.AdverbSelection {
|
|||
};
|
||||
}
|
||||
|
||||
export function makeLocativeAdverbSelection(entry: T.LocativeAdverbEntry): T.LocativeAdverbSelection {
|
||||
export function makeLocativeAdverbSelection(
|
||||
entry: T.LocativeAdverbEntry
|
||||
): T.LocativeAdverbSelection {
|
||||
return {
|
||||
type: "loc. adv.",
|
||||
entry: entry,
|
||||
};
|
||||
}
|
||||
|
||||
export function makeAdjectiveSelection(entry: T.AdjectiveEntry): T.AdjectiveSelection {
|
||||
export function makeAdjectiveSelection(
|
||||
entry: T.AdjectiveEntry
|
||||
): T.AdjectiveSelection {
|
||||
return {
|
||||
type: "adjective",
|
||||
entry: entry,
|
||||
|
@ -27,7 +31,9 @@ export function makeAdjectiveSelection(entry: T.AdjectiveEntry): T.AdjectiveSele
|
|||
};
|
||||
}
|
||||
|
||||
export function makeParticipleSelection(verb: T.VerbEntry): T.ParticipleSelection {
|
||||
export function makeParticipleSelection(
|
||||
verb: T.VerbEntry
|
||||
): T.ParticipleSelection {
|
||||
return {
|
||||
type: "participle",
|
||||
verb,
|
||||
|
@ -35,7 +41,11 @@ export function makeParticipleSelection(verb: T.VerbEntry): T.ParticipleSelectio
|
|||
};
|
||||
}
|
||||
|
||||
export function makeNounSelection(entry: T.NounEntry, old: T.NounSelection | undefined, dynamicComplement?: true): T.NounSelection {
|
||||
export function makeNounSelection(
|
||||
entry: T.NounEntry,
|
||||
old: T.NounSelection | undefined,
|
||||
complementType?: "dynamic" | "generative stative"
|
||||
): T.NounSelection {
|
||||
const number = isPluralNounEntry(entry) ? "plural" : "singular";
|
||||
return {
|
||||
type: "noun",
|
||||
|
@ -44,9 +54,10 @@ export function makeNounSelection(entry: T.NounEntry, old: T.NounSelection | und
|
|||
genderCanChange: isUnisexNounEntry(entry),
|
||||
number,
|
||||
numberCanChange: number === "singular",
|
||||
adjectives: (!dynamicComplement && old) ? old.adjectives : [],
|
||||
possesor: !dynamicComplement ? old?.possesor : undefined,
|
||||
dynamicComplement,
|
||||
adjectives: !complementType && old ? old.adjectives : [],
|
||||
possesor: !complementType ? old?.possesor : undefined,
|
||||
dynamicComplement: complementType === "dynamic",
|
||||
genStativeComplement: complementType === "generative stative",
|
||||
demonstrative: undefined,
|
||||
};
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import * as T from "../../../types";
|
||||
import { mapVerbRenderedOutput } from "../fmaps";
|
||||
import { mapVerbRenderedOutput } from "../fp-ps";
|
||||
import { removeAccents } from "../accent-helpers";
|
||||
import { getPersonFromNP, isPastTense } from "./vp-tools";
|
||||
import { isImperativeTense, isPattern4Entry } from "../type-predicates";
|
||||
|
@ -19,6 +19,7 @@ import {
|
|||
getMiniPronounPs,
|
||||
} from "./render-common";
|
||||
import { renderComplementSelection } from "./render-complement";
|
||||
import { statVerb } from "../new-verb-engine/roots-and-stems";
|
||||
|
||||
export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
|
||||
const subject = getSubjectSelection(VP.blocks).selection;
|
||||
|
@ -45,8 +46,18 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
|
|||
king,
|
||||
complementPerson,
|
||||
});
|
||||
// TODO: for dynamic -
|
||||
const { vbs, hasBa } = renderVerb({
|
||||
verb: VP.verb.verb,
|
||||
verb:
|
||||
VP.verb.isCompound === "generative stative"
|
||||
? statVerb[
|
||||
VP.verb.transitivity === "intransitive"
|
||||
? "intransitive"
|
||||
: "transitive"
|
||||
]
|
||||
: VP.verb.dynAuxVerb
|
||||
? VP.verb.dynAuxVerb
|
||||
: VP.verb.verb,
|
||||
tense: VP.verb.tense,
|
||||
subject: subjectPerson,
|
||||
object: objectPerson,
|
||||
|
@ -128,7 +139,6 @@ export function insertNegative(
|
|||
if (!negative) {
|
||||
return [blocks.flat().map(makeBlock)];
|
||||
}
|
||||
const blocksA = blocks.flat().map(makeBlock);
|
||||
const blocksNoAccentA = mapVerbRenderedOutput(removeAccents, blocks)
|
||||
.flat()
|
||||
.map(makeBlock);
|
||||
|
@ -138,13 +148,13 @@ export function insertNegative(
|
|||
// swapped ending with negative for ability and perfect verb forms
|
||||
if (nonStandPerfectiveSplit) {
|
||||
return [
|
||||
insertFromEnd(swapEndingBlocks(blocksA), neg, 2),
|
||||
insertFromEnd(swapEndingBlocks(blocksA, 2), neg, 3),
|
||||
insertFromEnd(swapEndingBlocks(blocksNoAccentA), neg, 2),
|
||||
insertFromEnd(swapEndingBlocks(blocksNoAccentA, 2), neg, 3),
|
||||
insertFromEnd(blocksNoAccentA, neg, 1),
|
||||
];
|
||||
}
|
||||
return [
|
||||
insertFromEnd(swapEndingBlocks(blocksA), neg, 2),
|
||||
insertFromEnd(swapEndingBlocks(blocksNoAccentA), neg, 2),
|
||||
insertFromEnd(blocksNoAccentA, neg, 1),
|
||||
];
|
||||
}
|
||||
|
@ -280,8 +290,9 @@ function whatsAdjustable(
|
|||
VP: T.VPSelectionComplete
|
||||
): "both" | "king" | "servant" {
|
||||
// TODO: intransitive dynamic compounds?
|
||||
return VP.verb.isCompound === "dynamic" &&
|
||||
VP.verb.transitivity === "transitive"
|
||||
return VP.verb.isCompound === "dynamic" ||
|
||||
(VP.verb.isCompound === "generative stative" &&
|
||||
VP.verb.transitivity === "transitive")
|
||||
? isPastTense(VP.verb.tense)
|
||||
? "servant"
|
||||
: "king"
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import {
|
||||
makeNounSelection,
|
||||
} from "./make-selections";
|
||||
import { makeNounSelection } from "./make-selections";
|
||||
import * as T from "../../../types";
|
||||
import { getVerbInfo } from "../verb-info";
|
||||
import {
|
||||
|
@ -9,16 +7,24 @@ import {
|
|||
getSubjectSelection,
|
||||
makeObjectSelection,
|
||||
makeSubjectSelection,
|
||||
moveObjectToEnd,
|
||||
} from "./blocks-utils";
|
||||
|
||||
export function makeVPSelectionState(
|
||||
verb: T.VerbEntry,
|
||||
os?: T.VPSelectionState,
|
||||
os?: T.VPSelectionState
|
||||
): T.VPSelectionState {
|
||||
const info = getVerbInfo(verb.entry, verb.complement);
|
||||
const subject = (os?.verb.voice === "passive" && info.type === "dynamic compound")
|
||||
? makeNounSelection(info.objComplement.entry as T.NounEntry, undefined, true)
|
||||
: (os?.blocks ? getSubjectSelection(os.blocks).selection : undefined);
|
||||
const subject =
|
||||
os?.verb.voice === "passive" && info.type === "dynamic compound"
|
||||
? makeNounSelection(
|
||||
info.objComplement.entry as T.NounEntry,
|
||||
undefined,
|
||||
"dynamic"
|
||||
)
|
||||
: os?.blocks
|
||||
? getSubjectSelection(os.blocks).selection
|
||||
: undefined;
|
||||
function getTransObjFromos() {
|
||||
const osObj = os ? getObjectSelection(os.blocks).selection : undefined;
|
||||
if (
|
||||
|
@ -26,32 +32,52 @@ export function makeVPSelectionState(
|
|||
osObj === "none" ||
|
||||
typeof osObj === "number" ||
|
||||
os.verb.isCompound === "dynamic" ||
|
||||
(osObj?.selection.type === "noun" && osObj.selection.dynamicComplement)
|
||||
) return undefined;
|
||||
(osObj?.selection.type === "noun" &&
|
||||
(osObj.selection.dynamicComplement ||
|
||||
osObj.selection.genStativeComplement))
|
||||
)
|
||||
return undefined;
|
||||
return osObj;
|
||||
}
|
||||
const transitivity: T.Transitivity = "grammaticallyTransitive" in info
|
||||
? "transitive"
|
||||
: info.transitivity;
|
||||
const object = (transitivity === "grammatically transitive")
|
||||
const transitivity: T.Transitivity =
|
||||
"grammaticallyTransitive" in info ? "transitive" : info.transitivity;
|
||||
const object =
|
||||
transitivity === "grammatically transitive"
|
||||
? T.Person.ThirdPlurMale
|
||||
: (info.type === "dynamic compound" && os?.verb.voice !== "passive")
|
||||
? makeNounSelection(info.objComplement.entry as T.NounEntry, undefined, true)
|
||||
: (transitivity === "transitive" && os?.verb.voice !== "passive")
|
||||
: (info.type === "dynamic compound" ||
|
||||
info.type === "generative stative compound") &&
|
||||
os?.verb.voice !== "passive"
|
||||
? makeNounSelection(
|
||||
info.objComplement.entry as T.NounEntry,
|
||||
undefined,
|
||||
info.type === "dynamic compound" ? "dynamic" : "generative stative"
|
||||
)
|
||||
: info.type === "dynamic or generative stative compound" &&
|
||||
os?.verb.voice !== "passive"
|
||||
? makeNounSelection(
|
||||
info.dynamic.objComplement.entry as T.NounEntry,
|
||||
undefined,
|
||||
"generative stative"
|
||||
)
|
||||
: transitivity === "transitive" && os?.verb.voice !== "passive"
|
||||
? getTransObjFromos()
|
||||
: "none";
|
||||
const isCompound = ("stative" in info || info.type === "stative compound")
|
||||
const isCompound =
|
||||
"stative" in info && info.type === "dynamic or generative stative compound"
|
||||
? "generative stative"
|
||||
: "stative" in info || info.type === "stative compound"
|
||||
? "stative"
|
||||
: info.type === "dynamic compound"
|
||||
? "dynamic"
|
||||
: false;
|
||||
// TODO: here and below in the changeStatDyn function ... allow for entries with complement
|
||||
const dynAuxVerb: T.VerbEntry | undefined = isCompound !== "dynamic"
|
||||
const dynAuxVerb: T.VerbEntry | undefined =
|
||||
isCompound !== "dynamic"
|
||||
? undefined
|
||||
: info.type === "dynamic compound"
|
||||
? { entry: info.auxVerb } as T.VerbEntry
|
||||
? ({ entry: info.auxVerb } as T.VerbEntry)
|
||||
: "dynamic" in info
|
||||
? { entry: info.dynamic.auxVerb } as T.VerbEntry
|
||||
? ({ entry: info.dynamic.auxVerb } as T.VerbEntry)
|
||||
: undefined;
|
||||
const blocks = [
|
||||
{ key: Math.random(), block: makeSubjectSelection(subject) },
|
||||
|
@ -69,9 +95,8 @@ export function makeVPSelectionState(
|
|||
tenseCategory: os ? os.verb.tenseCategory : "basic",
|
||||
transitivity,
|
||||
isCompound,
|
||||
voice: transitivity === "transitive"
|
||||
? (os?.verb.voice || "active")
|
||||
: "active",
|
||||
voice:
|
||||
transitivity === "transitive" ? os?.verb.voice || "active" : "active",
|
||||
negative: os ? os.verb.negative : false,
|
||||
canChangeTransitivity: "grammaticallyTransitive" in info,
|
||||
canChangeVoice: transitivity === "transitive",
|
||||
|
@ -80,7 +105,8 @@ export function makeVPSelectionState(
|
|||
externalComplement: takesExternalComplement(verb)
|
||||
? { type: "complement", selection: { type: "unselected" } }
|
||||
: undefined,
|
||||
form: (os && info.type !== "dynamic compound")
|
||||
form:
|
||||
os && info.type !== "dynamic compound"
|
||||
? os.form
|
||||
: { removeKing: false, shrinkServant: false },
|
||||
};
|
||||
|
@ -96,33 +122,62 @@ function takesExternalComplement(v: T.VerbEntry): boolean {
|
|||
return false;
|
||||
}
|
||||
|
||||
export function changeStatDyn(v: T.VPSelectionState, s: "dynamic" | "stative"): T.VPSelectionState {
|
||||
export function changeStatDyn(
|
||||
v: T.VPSelectionState,
|
||||
s: "dynamic" | "stative"
|
||||
): T.VPSelectionState {
|
||||
const info = getVerbInfo(v.verb.verb.entry, v.verb.verb.complement);
|
||||
if (!("stative" in info)) {
|
||||
return v;
|
||||
}
|
||||
const newBlocks = adjustObjectSelection(
|
||||
v.blocks,
|
||||
s === "dynamic" ||
|
||||
(s === "stative" &&
|
||||
info.type === "dynamic or generative stative compound")
|
||||
? {
|
||||
type: "NP",
|
||||
selection: makeNounSelection(
|
||||
info.dynamic.objComplement.entry as T.NounEntry,
|
||||
undefined,
|
||||
s === "dynamic" ? "dynamic" : "generative stative"
|
||||
),
|
||||
}
|
||||
: undefined
|
||||
);
|
||||
return {
|
||||
...v,
|
||||
blocks: adjustObjectSelection(
|
||||
v.blocks,
|
||||
s === "dynamic"
|
||||
? { type: "NP", selection: makeNounSelection(info.dynamic.objComplement.entry as T.NounEntry, undefined, true) }
|
||||
: undefined,
|
||||
),
|
||||
blocks:
|
||||
s === "stative" && info.type === "dynamic or generative stative compound"
|
||||
? moveObjectToEnd(newBlocks)
|
||||
: newBlocks,
|
||||
verb: {
|
||||
...v.verb,
|
||||
isCompound: s,
|
||||
dynAuxVerb: s === "dynamic"
|
||||
? { entry: info.dynamic.auxVerb } as T.VerbEntry
|
||||
isCompound:
|
||||
info.type === "dynamic or generative stative compound" &&
|
||||
s === "stative"
|
||||
? "generative stative"
|
||||
: s,
|
||||
dynAuxVerb:
|
||||
s === "dynamic"
|
||||
? ({ entry: info.dynamic.auxVerb } as T.VerbEntry)
|
||||
: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function changeTransitivity(v: T.VPSelectionState, transitivity: "transitive" | "grammatically transitive"): T.VPSelectionState {
|
||||
export function changeTransitivity(
|
||||
v: T.VPSelectionState,
|
||||
transitivity: "transitive" | "grammatically transitive"
|
||||
): T.VPSelectionState {
|
||||
return {
|
||||
...v,
|
||||
blocks: adjustObjectSelection(v.blocks, transitivity === "grammatically transitive" ? T.Person.ThirdPlurMale : undefined),
|
||||
blocks: adjustObjectSelection(
|
||||
v.blocks,
|
||||
transitivity === "grammatically transitive"
|
||||
? T.Person.ThirdPlurMale
|
||||
: undefined
|
||||
),
|
||||
verb: {
|
||||
...v.verb,
|
||||
transitivity,
|
||||
|
|
|
@ -132,12 +132,14 @@ export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
|||
// throw new Error("unknown tense");
|
||||
// }
|
||||
|
||||
export function getPersonFromNP(np: T.NPSelection): T.Person;
|
||||
export function getPersonFromNP(
|
||||
np: T.NPSelection | T.ObjectNP
|
||||
np: T.NPSelection | T.Rendered<T.NPSelection>
|
||||
): T.Person;
|
||||
export function getPersonFromNP(
|
||||
np: T.NPSelection | T.Rendered<T.NPSelection> | T.ObjectNP
|
||||
): T.Person | undefined;
|
||||
export function getPersonFromNP(
|
||||
np: T.NPSelection | T.ObjectNP
|
||||
np: T.NPSelection | T.Rendered<T.NPSelection> | T.ObjectNP
|
||||
): T.Person | undefined {
|
||||
if (np === "none") {
|
||||
return undefined;
|
||||
|
|
|
@ -28,15 +28,9 @@ import {
|
|||
psStringEquals,
|
||||
} from "./p-text-helpers";
|
||||
import { makePsString } from "./accent-and-ps-utils";
|
||||
import {
|
||||
inflectYey,
|
||||
} from "./pashto-inflector";
|
||||
import {
|
||||
accentOnNFromEnd, removeAccents,
|
||||
} from "./accent-helpers";
|
||||
import {
|
||||
mapInflections,
|
||||
} from "./fmaps";
|
||||
import { inflectYey } from "./pashto-inflector";
|
||||
import { accentOnNFromEnd, removeAccents } from "./accent-helpers";
|
||||
import { mapInflections } from "./fp-ps";
|
||||
import { pashtoConsonants } from "./pashto-consonants";
|
||||
import {
|
||||
checkForIrregularConjugation,
|
||||
|
@ -49,14 +43,29 @@ import {
|
|||
} from "./misc-helpers";
|
||||
import * as T from "../../types";
|
||||
|
||||
const dummyEntry: T.DictionaryEntry = { i: 0, p: "", f: "", g: "", e: "", c: "", ts: 0 };
|
||||
const dummyEntry: T.DictionaryEntry = {
|
||||
i: 0,
|
||||
p: "",
|
||||
f: "",
|
||||
g: "",
|
||||
e: "",
|
||||
c: "",
|
||||
ts: 0,
|
||||
};
|
||||
|
||||
const aayTail = [{p: "ای", f: "aay" }, { p: "ی", f: "ey" }];
|
||||
const aayTail = [
|
||||
{ p: "ای", f: "aay" },
|
||||
{ p: "ی", f: "ey" },
|
||||
];
|
||||
|
||||
export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.DictionaryEntry, verbInfo?: T.NonComboVerbInfo): T.VerbOutput {
|
||||
export function conjugateVerb(
|
||||
entry: T.DictionaryEntry,
|
||||
complement?: T.DictionaryEntry,
|
||||
verbInfo?: T.NonComboVerbInfo
|
||||
): T.VerbOutput {
|
||||
if (!(entry.c && entry.c.slice(0, 2) === "v.")) {
|
||||
throw new Error("not a verb");
|
||||
};
|
||||
}
|
||||
const irregularConj = checkForIrregularConjugation(entry);
|
||||
if (irregularConj) {
|
||||
return irregularConj;
|
||||
|
@ -65,16 +74,35 @@ export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.Dictionar
|
|||
if (info.type === "transitive or grammatically transitive simple") {
|
||||
return {
|
||||
info,
|
||||
transitive: conjugateVerb({ ...entry, c: entry.c ? entry.c.replace("/gramm. trans.", "") : "" }, dummyEntry, info.transitive) as T.VerbConjugation,
|
||||
grammaticallyTransitive: conjugateVerb({ ...entry, c: entry.c ? entry.c?.replace("trans./", "") : "" }, dummyEntry, info.grammaticallyTransitive) as T.VerbConjugation,
|
||||
transitive: conjugateVerb(
|
||||
{ ...entry, c: entry.c ? entry.c.replace("/gramm. trans.", "") : "" },
|
||||
dummyEntry,
|
||||
info.transitive
|
||||
) as T.VerbConjugation,
|
||||
grammaticallyTransitive: conjugateVerb(
|
||||
{ ...entry, c: entry.c ? entry.c?.replace("trans./", "") : "" },
|
||||
dummyEntry,
|
||||
info.grammaticallyTransitive
|
||||
) as T.VerbConjugation,
|
||||
};
|
||||
}
|
||||
|
||||
if (info.type === "dynamic or stative compound" || info.type === "dynamic or generative stative compound") {
|
||||
if (
|
||||
info.type === "dynamic or stative compound" ||
|
||||
info.type === "dynamic or generative stative compound"
|
||||
) {
|
||||
return {
|
||||
info,
|
||||
stative: conjugateVerb({ ...entry, c: entry.c ? entry.c.replace("dyn./", "") : "" }, dummyEntry, info.stative) as T.VerbConjugation,
|
||||
dynamic: conjugateVerb({ ...entry, c: entry.c ? entry.c.replace("/stat.", "") : "" }, dummyEntry, info.dynamic) as T.VerbConjugation,
|
||||
stative: conjugateVerb(
|
||||
{ ...entry, c: entry.c ? entry.c.replace("dyn./", "") : "" },
|
||||
dummyEntry,
|
||||
info.stative
|
||||
) as T.VerbConjugation,
|
||||
dynamic: conjugateVerb(
|
||||
{ ...entry, c: entry.c ? entry.c.replace("/stat.", "") : "" },
|
||||
dummyEntry,
|
||||
info.dynamic
|
||||
) as T.VerbConjugation,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -91,14 +119,22 @@ export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.Dictionar
|
|||
hypothetical: makeHypotheticalContent(nonComboInfo),
|
||||
participle: makeParticipleContent(nonComboInfo),
|
||||
perfect: makePerfectContent(nonComboInfo),
|
||||
..."singularForm" in info ? {
|
||||
singularForm: conjugateVerb(entry, complement, info.singularForm) as T.VerbConjugation,
|
||||
} : {},
|
||||
...("singularForm" in info
|
||||
? {
|
||||
singularForm: conjugateVerb(
|
||||
entry,
|
||||
complement,
|
||||
info.singularForm
|
||||
) as T.VerbConjugation,
|
||||
}
|
||||
: {}),
|
||||
// if transitive include passive voice
|
||||
...info.transitivity !== "intransitive" ? {
|
||||
...(info.transitivity !== "intransitive"
|
||||
? {
|
||||
// TODO: STATIVE COMPOUND VERSION OF THIS
|
||||
passive: makePassiveContent(nonComboInfo),
|
||||
} : {},
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
|
||||
return nonComboInfo.transitivity === "grammatically transitive"
|
||||
|
@ -108,7 +144,9 @@ export function conjugateVerb(entry: T.DictionaryEntry, complement?: T.Dictionar
|
|||
: conjugation;
|
||||
}
|
||||
|
||||
function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjugation {
|
||||
function conjugateDynamicCompound(
|
||||
info: T.DynamicCompoundVerbInfo
|
||||
): T.VerbConjugation {
|
||||
// const willUseImperative = !(
|
||||
// info.type === "dynamic compound"
|
||||
// && info.transitivity === "intransitive"
|
||||
|
@ -116,18 +154,24 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
|||
// );
|
||||
const auxConj = enforceObject(
|
||||
conjugateVerb(info.auxVerb, info.auxVerbComplement) as T.VerbConjugation,
|
||||
info.objComplement.person,
|
||||
info.objComplement.person
|
||||
);
|
||||
const complement = info.objComplement.plural
|
||||
? info.objComplement.plural
|
||||
: makePsString(info.objComplement.entry.p, info.objComplement.entry.f);
|
||||
const makeAspectContent = (aspect: T.Aspect): T.AspectContent => {
|
||||
const makeDynamicModalContent = (): T.ModalContent => {
|
||||
const nonImperative = addToForm([complement, " "], auxConj[aspect].modal.nonImperative);
|
||||
const nonImperative = addToForm(
|
||||
[complement, " "],
|
||||
auxConj[aspect].modal.nonImperative
|
||||
);
|
||||
const future = addToForm([baParticle, " "], nonImperative);
|
||||
const past = addToForm([complement, " "], auxConj[aspect].modal.past);
|
||||
const habitualPast = addToForm([baParticle, " "], past);
|
||||
const hypotheticalPast = addToForm([complement, " "], auxConj[aspect].modal.hypotheticalPast);
|
||||
const hypotheticalPast = addToForm(
|
||||
[complement, " "],
|
||||
auxConj[aspect].modal.hypotheticalPast
|
||||
);
|
||||
return {
|
||||
nonImperative,
|
||||
future,
|
||||
|
@ -151,20 +195,18 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
|||
habitualPast,
|
||||
modal,
|
||||
};
|
||||
}
|
||||
};
|
||||
const hypothetical = addToForm([complement, " "], auxConj.hypothetical);
|
||||
const auxPPart = auxConj.participle.past;
|
||||
const participle = {
|
||||
present: concatInflections(complement, auxConj.participle.present),
|
||||
past: (
|
||||
(("long" in auxPPart) && ("masc" in auxPPart.long)) ||
|
||||
("masc" in auxPPart)
|
||||
)
|
||||
// @ts-ignore
|
||||
? concatInflections(complement, auxPPart)
|
||||
// @ts-ignore
|
||||
: concatPsString(complement, " ", auxPPart)
|
||||
}
|
||||
past:
|
||||
("long" in auxPPart && "masc" in auxPPart.long) || "masc" in auxPPart
|
||||
? // @ts-ignore
|
||||
concatInflections(complement, auxPPart)
|
||||
: // @ts-ignore
|
||||
concatPsString(complement, " ", auxPPart),
|
||||
};
|
||||
const makePerfect = (pset: T.PerfectContent): T.PerfectContent => ({
|
||||
halfPerfect: addToForm([complement, " "], pset.halfPerfect),
|
||||
past: addToForm([complement, " "], pset.past),
|
||||
|
@ -176,12 +218,21 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
|||
pastSubjunctive: addToForm([complement, " "], pset.pastSubjunctive),
|
||||
wouldHaveBeen: addToForm([complement, " "], pset.wouldHaveBeen),
|
||||
});
|
||||
const makePassiveAspectContent = (aspect: T.Aspect, passive: T.PassiveContent): T.AspectContentPassive => {
|
||||
const nonImperative = addToForm([complement, " "], passive[aspect].nonImperative);
|
||||
const makePassiveAspectContent = (
|
||||
aspect: T.Aspect,
|
||||
passive: T.PassiveContent
|
||||
): T.AspectContentPassive => {
|
||||
const nonImperative = addToForm(
|
||||
[complement, " "],
|
||||
passive[aspect].nonImperative
|
||||
);
|
||||
const future = addToForm([baParticle, " "], nonImperative);
|
||||
const past = addToForm([complement, " "], passive[aspect].past);
|
||||
const habitualPast = addToForm([baParticle, " "], past);
|
||||
const modal = makePassiveModalSection([complement, " "], stativeAux.intransitive.imperfective.modal);
|
||||
const modal = makePassiveModalSection(
|
||||
[complement, " "],
|
||||
stativeAux.intransitive.imperfective.modal
|
||||
);
|
||||
return {
|
||||
imperative: undefined,
|
||||
nonImperative,
|
||||
|
@ -189,8 +240,8 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
|||
past,
|
||||
habitualPast,
|
||||
modal,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
return {
|
||||
info,
|
||||
imperfective: makeAspectContent("imperfective"),
|
||||
|
@ -198,24 +249,36 @@ function conjugateDynamicCompound(info: T.DynamicCompoundVerbInfo): T.VerbConjug
|
|||
hypothetical,
|
||||
participle,
|
||||
perfect: makePerfect(auxConj.perfect),
|
||||
...auxConj.passive ? {
|
||||
...(auxConj.passive
|
||||
? {
|
||||
passive: {
|
||||
imperfective: makePassiveAspectContent("imperfective", auxConj.passive),
|
||||
imperfective: makePassiveAspectContent(
|
||||
"imperfective",
|
||||
auxConj.passive
|
||||
),
|
||||
perfective: makePassiveAspectContent("perfective", auxConj.passive),
|
||||
perfect: makePerfect(auxConj.passive.perfect),
|
||||
},
|
||||
} : {},
|
||||
...info.singularForm ? {
|
||||
singularForm: conjugateDynamicCompound(info.singularForm)
|
||||
} : {},
|
||||
...info.intransitiveForm ? {
|
||||
intransitiveForm: conjugateDynamicCompound(info.intransitiveForm)
|
||||
} : {},
|
||||
}
|
||||
: {}),
|
||||
...(info.singularForm
|
||||
? {
|
||||
singularForm: conjugateDynamicCompound(info.singularForm),
|
||||
}
|
||||
: {}),
|
||||
...(info.intransitiveForm
|
||||
? {
|
||||
intransitiveForm: conjugateDynamicCompound(info.intransitiveForm),
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
function makeAspectContent(info: T.NonComboVerbInfo, aspect: T.Aspect): T.AspectContent {
|
||||
if ((info.type === "stative compound") && spaceInForm(info.root[aspect])) {
|
||||
function makeAspectContent(
|
||||
info: T.NonComboVerbInfo,
|
||||
aspect: T.Aspect
|
||||
): T.AspectContent {
|
||||
if (info.type === "stative compound" && spaceInForm(info.root[aspect])) {
|
||||
return makeStativeCompoundSeperatedAspectContent(info, aspect);
|
||||
}
|
||||
const stem = noPersInfs(info.stem[aspect]);
|
||||
|
@ -223,7 +286,10 @@ function makeAspectContent(info: T.NonComboVerbInfo, aspect: T.Aspect): T.Aspect
|
|||
const nonImperative = addToForm([stem], presentEndings);
|
||||
const future = addToForm([baParticle, " "], nonImperative);
|
||||
const imperative = addToForm([stem], imperativeEndings);
|
||||
const roughPast = addToForm([root], pastEndings) as T.LengthOptions<T.VerbBlock>;
|
||||
const roughPast = addToForm(
|
||||
[root],
|
||||
pastEndings
|
||||
) as T.LengthOptions<T.VerbBlock>;
|
||||
// add accents and idiosyncratic third person sing masc forms
|
||||
const past = finishSimpleVerbPast(info, aspect, roughPast);
|
||||
const habitualPast = addToForm([baParticle, " "], past);
|
||||
|
@ -237,14 +303,26 @@ function makeAspectContent(info: T.NonComboVerbInfo, aspect: T.Aspect): T.Aspect
|
|||
};
|
||||
}
|
||||
|
||||
function makeJoinedModalContent(info: T.NonComboVerbInfo, aspectIn: T.Aspect): T.ModalContent {
|
||||
function makeJoinedModalContent(
|
||||
info: T.NonComboVerbInfo,
|
||||
aspectIn: T.Aspect
|
||||
): T.ModalContent {
|
||||
const aspect: T.Aspect = noPerfectiveModal(info) ? "imperfective" : aspectIn;
|
||||
const aux = stativeAux.intransitive.perfective;
|
||||
const rAndT = info.yulEnding
|
||||
? [concatPsString(noPersInfs(info.root[aspect]).long, aayTail[1]), concatPsString(noPersInfs(info.root[aspect]).long, aayTail[0])]
|
||||
: [concatPsString(noPersInfs(info.root[aspect]), aayTail[1]), concatPsString(noPersInfs(info.root[aspect]), aayTail[0])]
|
||||
const rootAndTail = aspect === "imperfective"
|
||||
? rAndT.map((x: T.PsString | T.LengthOptions<T.PsString>) => accentImperfectiveModalRootAndTail(info, x))
|
||||
? [
|
||||
concatPsString(noPersInfs(info.root[aspect]).long, aayTail[1]),
|
||||
concatPsString(noPersInfs(info.root[aspect]).long, aayTail[0]),
|
||||
]
|
||||
: [
|
||||
concatPsString(noPersInfs(info.root[aspect]), aayTail[1]),
|
||||
concatPsString(noPersInfs(info.root[aspect]), aayTail[0]),
|
||||
];
|
||||
const rootAndTail =
|
||||
aspect === "imperfective"
|
||||
? rAndT.map((x: T.PsString | T.LengthOptions<T.PsString>) =>
|
||||
accentImperfectiveModalRootAndTail(info, x)
|
||||
)
|
||||
: rAndT;
|
||||
|
||||
const nonImperative = addToForm([rootAndTail, " "], aux.nonImperative);
|
||||
|
@ -252,7 +330,7 @@ function makeJoinedModalContent(info: T.NonComboVerbInfo, aspectIn: T.Aspect): T
|
|||
const past = addToForm(
|
||||
[rootAndTail, " "],
|
||||
// @ts-ignore
|
||||
aux.past.short,
|
||||
aux.past.short
|
||||
);
|
||||
const habitualPast = addToForm([baParticle, " "], past);
|
||||
function mhp(rt: T.PsString[]): T.VerbBlock {
|
||||
|
@ -270,11 +348,13 @@ function makeJoinedModalContent(info: T.NonComboVerbInfo, aspectIn: T.Aspect): T
|
|||
[form, form],
|
||||
];
|
||||
}
|
||||
const hypotheticalPast = "short" in rootAndTail[0]
|
||||
const hypotheticalPast =
|
||||
"short" in rootAndTail[0]
|
||||
? {
|
||||
short: mhp(rootAndTail.map((rt) => "short" in rt ? rt.short : rt)),
|
||||
long: mhp(rootAndTail.map((rt) => "short" in rt ? rt.long : rt)),
|
||||
} : mhp(rootAndTail.map((rt) => "short" in rt ? rt.long : rt));
|
||||
short: mhp(rootAndTail.map((rt) => ("short" in rt ? rt.short : rt))),
|
||||
long: mhp(rootAndTail.map((rt) => ("short" in rt ? rt.long : rt))),
|
||||
}
|
||||
: mhp(rootAndTail.map((rt) => ("short" in rt ? rt.long : rt)));
|
||||
|
||||
// const hypotheticalPast = [
|
||||
// [concatPsString(rootAndTail[0], " ", { p: "سو", f: "shw" }, aayTail[0])]
|
||||
|
@ -289,18 +369,26 @@ function makeJoinedModalContent(info: T.NonComboVerbInfo, aspectIn: T.Aspect): T
|
|||
};
|
||||
}
|
||||
|
||||
function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbInfo, aspect: T.Aspect): T.AspectContent {
|
||||
function makeStativeCompoundSeperatedAspectContent(
|
||||
info: T.StativeCompoundVerbInfo,
|
||||
aspect: T.Aspect
|
||||
): T.AspectContent {
|
||||
const transitivity = getTransitivity(info);
|
||||
const complement: T.UnisexInflections = aspect === "imperfective"
|
||||
const complement: T.UnisexInflections =
|
||||
aspect === "imperfective"
|
||||
? mapInflections(removeAccents, info.complement)
|
||||
: info.complement;
|
||||
const presentComplement = (transitivity === "transitive" && complementInflects(complement))
|
||||
const presentComplement =
|
||||
transitivity === "transitive" && complementInflects(complement)
|
||||
? unisexInfToObjectMatrix(complement) // transitive verb requires an object matrix for the complex
|
||||
: complement; // intransitive verb doesn't require that because the complement matches the subject
|
||||
|
||||
function makeTransitiveStativeModalContent() {
|
||||
const aux = stativeAux[transitivity][aspect].modal;
|
||||
const nonImperative = addToForm([presentComplement, " "], aux.nonImperative);
|
||||
const nonImperative = addToForm(
|
||||
[presentComplement, " "],
|
||||
aux.nonImperative
|
||||
);
|
||||
const future = addToForm([baParticle, " "], nonImperative);
|
||||
const past = addToForm([complement, " "], aux.past);
|
||||
const habitualPast = addToForm([baParticle, " "], past);
|
||||
|
@ -318,7 +406,7 @@ function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbIn
|
|||
// CHECK, does this work with transitive and intransitive??
|
||||
const nonImperative = addToForm(
|
||||
[presentComplement, " "],
|
||||
stativeAux[transitivity][aspect].nonImperative,
|
||||
stativeAux[transitivity][aspect].nonImperative
|
||||
);
|
||||
const future = addToForm([baParticle, " "], nonImperative);
|
||||
const imperative = addToForm([presentComplement, " "], aux.imperative);
|
||||
|
@ -330,27 +418,38 @@ function makeStativeCompoundSeperatedAspectContent(info: T.StativeCompoundVerbIn
|
|||
past,
|
||||
habitualPast,
|
||||
imperative,
|
||||
modal: info.transitivity === "transitive"
|
||||
modal:
|
||||
info.transitivity === "transitive"
|
||||
? makeTransitiveStativeModalContent()
|
||||
: makeJoinedModalContent(info, "imperfective"),
|
||||
};
|
||||
}
|
||||
|
||||
function makeHypotheticalContent(info: T.NonComboVerbInfo): T.VerbForm {
|
||||
function makeStativeCompoundSepHypotheticalContent(info: T.StativeCompoundVerbInfo): T.VerbForm {
|
||||
function makeStativeCompoundSepHypotheticalContent(
|
||||
info: T.StativeCompoundVerbInfo
|
||||
): T.VerbForm {
|
||||
const transitivity = getTransitivity(info);
|
||||
const aux = stativeAux[transitivity].hypothetical;
|
||||
return addToForm([
|
||||
(transitivity === "transitive" && complementInflects(info.complement))
|
||||
return addToForm(
|
||||
[
|
||||
transitivity === "transitive" && complementInflects(info.complement)
|
||||
? unisexInfToObjectMatrix(info.complement)
|
||||
: info.complement,
|
||||
" ",
|
||||
], aux);
|
||||
],
|
||||
aux
|
||||
);
|
||||
}
|
||||
if (("complement" in info) && spaceInForm(info.root.imperfective)) {
|
||||
return makeStativeCompoundSepHypotheticalContent(info as T.StativeCompoundVerbInfo);
|
||||
if ("complement" in info && spaceInForm(info.root.imperfective)) {
|
||||
return makeStativeCompoundSepHypotheticalContent(
|
||||
info as T.StativeCompoundVerbInfo
|
||||
);
|
||||
}
|
||||
const makeHypothetical = (root: T.OptionalPersonInflections<T.LengthOptions<T.PsString>>, length: "short" | "long"): T.PsString[] => {
|
||||
const makeHypothetical = (
|
||||
root: T.OptionalPersonInflections<T.LengthOptions<T.PsString>>,
|
||||
length: "short" | "long"
|
||||
): T.PsString[] => {
|
||||
if ("mascSing" in root) {
|
||||
// BIG TODO: SHOULD THERE BE PERS INFS HERE?? IGNORING THEM NOW IF THEY EXIST
|
||||
return makeHypothetical(root.mascSing, length) as T.PsString[];
|
||||
|
@ -358,16 +457,22 @@ function makeHypotheticalContent(info: T.NonComboVerbInfo): T.VerbForm {
|
|||
return [
|
||||
accentOnNFromEnd(
|
||||
concatPsString(root[length], aayTail[0]),
|
||||
(length === "long" ? 1 : 0) + (info.yulEnding ? 1 : 0),
|
||||
(length === "long" ? 1 : 0) + (info.yulEnding ? 1 : 0)
|
||||
),
|
||||
accentOnNFromEnd(
|
||||
concatPsString(root[length], aayTail[1]),
|
||||
(length === "long" ? 1 : 0) + (info.yulEnding ? 1 : 0),
|
||||
(length === "long" ? 1 : 0) + (info.yulEnding ? 1 : 0)
|
||||
),
|
||||
];
|
||||
};
|
||||
const short = makeHypothetical(info.root.imperfective, "short") as T.ArrayOneOrMore<T.PsString>;
|
||||
const long = makeHypothetical(info.root.imperfective, "long") as T.ArrayOneOrMore<T.PsString>;
|
||||
const short = makeHypothetical(
|
||||
info.root.imperfective,
|
||||
"short"
|
||||
) as T.ArrayOneOrMore<T.PsString>;
|
||||
const long = makeHypothetical(
|
||||
info.root.imperfective,
|
||||
"long"
|
||||
) as T.ArrayOneOrMore<T.PsString>;
|
||||
return {
|
||||
short: [
|
||||
[short, short],
|
||||
|
@ -390,13 +495,26 @@ function makeHypotheticalContent(info: T.NonComboVerbInfo): T.VerbForm {
|
|||
|
||||
function makeParticipleContent(info: T.NonComboVerbInfo): T.ParticipleContent {
|
||||
const transitivity = getTransitivity(info);
|
||||
const past = ("complement" in info)
|
||||
? concatInflections(info.complement, stativeAux[transitivity].participle.past as T.UnisexInflections)
|
||||
: ("objComplement" in info)
|
||||
? concatInflections(info.objComplement.plural ? info.objComplement.plural : info.objComplement.entry, stativeAux[transitivity].participle.past as T.UnisexInflections)
|
||||
const past =
|
||||
"complement" in info
|
||||
? concatInflections(
|
||||
info.complement,
|
||||
stativeAux[transitivity].participle.past as T.UnisexInflections
|
||||
)
|
||||
: "objComplement" in info
|
||||
? concatInflections(
|
||||
info.objComplement.plural
|
||||
? info.objComplement.plural
|
||||
: info.objComplement.entry,
|
||||
stativeAux[transitivity].participle.past as T.UnisexInflections
|
||||
)
|
||||
: inflectYey(noPersInfs(info.participle.past));
|
||||
const present = ("complement" in info && spaceInForm(info.root.imperfective))
|
||||
? concatInflections(info.complement, stativeAux[transitivity].participle.present as T.UnisexInflections)
|
||||
const present =
|
||||
"complement" in info && spaceInForm(info.root.imperfective)
|
||||
? concatInflections(
|
||||
info.complement,
|
||||
stativeAux[transitivity].participle.present as T.UnisexInflections
|
||||
)
|
||||
: inflectYey(noPersInfs(info.participle.present));
|
||||
return {
|
||||
present, // PRESENT PARTICIPLE inflected
|
||||
|
@ -406,22 +524,45 @@ function makeParticipleContent(info: T.NonComboVerbInfo): T.ParticipleContent {
|
|||
|
||||
function makePerfectContent(info: T.NonComboVerbInfo): T.PerfectContent {
|
||||
const transitivity = getTransitivity(info);
|
||||
const pastPart: (" " | T.SingleOrLengthOpts<T.UnisexInflections> | T.SingleOrLengthOpts<T.PsString>)[] =
|
||||
(info.type === "stative compound")
|
||||
// for stative compounds
|
||||
? [mapInflections(removeAccents, info.complement), " ", stativeAux[transitivity].participle.past]
|
||||
// for regular compounds
|
||||
: [inflectYey(noPersInfs(info.participle.past))]
|
||||
const pastPart: (
|
||||
| " "
|
||||
| T.SingleOrLengthOpts<T.UnisexInflections>
|
||||
| T.SingleOrLengthOpts<T.PsString>
|
||||
)[] =
|
||||
info.type === "stative compound"
|
||||
? // for stative compounds
|
||||
[
|
||||
mapInflections(removeAccents, info.complement),
|
||||
" ",
|
||||
stativeAux[transitivity].participle.past,
|
||||
]
|
||||
: // for regular compounds
|
||||
[inflectYey(noPersInfs(info.participle.past))];
|
||||
|
||||
const halfPerfect = addToForm([...pastPart], emptyVerbBlock);
|
||||
const past = addToForm([...pastPart, " "], equativeEndings.past.short);
|
||||
const present = addToForm([...pastPart, " "], equativeEndings.present);
|
||||
const habitual = addToForm([...pastPart, " "], equativeEndings.habitual);
|
||||
const subjunctive = addToForm([...pastPart, " "], equativeEndings.subjunctive);
|
||||
const future = addToForm([baParticle, " ", ...pastPart, " "], equativeEndings.habitual);
|
||||
const wouldBe = addToForm([baParticle, " ", ...pastPart, " "], equativeEndings.past.short);
|
||||
const pastSubjunctive = addToForm([...pastPart, " "], equativeEndings.pastSubjunctive);
|
||||
const wouldHaveBeen = addToForm([baParticle, " ", ...pastPart, " "], equativeEndings.pastSubjunctive);
|
||||
const subjunctive = addToForm(
|
||||
[...pastPart, " "],
|
||||
equativeEndings.subjunctive
|
||||
);
|
||||
const future = addToForm(
|
||||
[baParticle, " ", ...pastPart, " "],
|
||||
equativeEndings.habitual
|
||||
);
|
||||
const wouldBe = addToForm(
|
||||
[baParticle, " ", ...pastPart, " "],
|
||||
equativeEndings.past.short
|
||||
);
|
||||
const pastSubjunctive = addToForm(
|
||||
[...pastPart, " "],
|
||||
equativeEndings.pastSubjunctive
|
||||
);
|
||||
const wouldHaveBeen = addToForm(
|
||||
[baParticle, " ", ...pastPart, " "],
|
||||
equativeEndings.pastSubjunctive
|
||||
);
|
||||
return {
|
||||
halfPerfect, // Past Participle
|
||||
past, // Past Participle + Past Equative
|
||||
|
@ -436,29 +577,31 @@ function makePerfectContent(info: T.NonComboVerbInfo): T.PerfectContent {
|
|||
}
|
||||
|
||||
function makePassiveContent(info: T.NonComboVerbInfo): {
|
||||
imperfective: T.AspectContentPassive // --╖ ASPECT = "imperfective"
|
||||
perfective: T.AspectContentPassive // --╜ ASPECT = "perfective"
|
||||
imperfective: T.AspectContentPassive; // --╖ ASPECT = "imperfective"
|
||||
perfective: T.AspectContentPassive; // --╜ ASPECT = "perfective"
|
||||
perfect: T.PerfectContent;
|
||||
} {
|
||||
function makePassiveAspectContent(aspect: T.Aspect): T.AspectContentPassive {
|
||||
if ("complement" in info && spaceInForm(info.root[aspect])) {
|
||||
// seperated stative compound verb
|
||||
const bridge = aspect === "imperfective"
|
||||
const bridge =
|
||||
aspect === "imperfective"
|
||||
? noPersInfs(stativeAux.transitive.info.root.imperfective).long
|
||||
: passiveStativeBridge;
|
||||
const nonImperative = addToForm(
|
||||
[info.complement, " ", bridge, " "],
|
||||
stativeAux.intransitive[aspect].nonImperative,
|
||||
stativeAux.intransitive[aspect].nonImperative
|
||||
);
|
||||
const future = addToForm([baParticle, " "], nonImperative);
|
||||
const past = addToForm(
|
||||
[info.complement, " ", bridge, " "],
|
||||
stativeAux.intransitive[aspect].past,
|
||||
stativeAux.intransitive[aspect].past
|
||||
);
|
||||
const habitualPast = addToForm([baParticle, " "], past);
|
||||
const modal = makePassiveModalSection([
|
||||
noPersInfs(info.root.imperfective).long, " ",
|
||||
], stativeAux.intransitive.imperfective.modal);
|
||||
const modal = makePassiveModalSection(
|
||||
[noPersInfs(info.root.imperfective).long, " "],
|
||||
stativeAux.intransitive.imperfective.modal
|
||||
);
|
||||
return {
|
||||
imperative: undefined,
|
||||
nonImperative,
|
||||
|
@ -468,7 +611,8 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
|
|||
modal,
|
||||
};
|
||||
}
|
||||
const root = (aspect === "imperfective")
|
||||
const root =
|
||||
aspect === "imperfective"
|
||||
? removeAccents(noPersInfs(info.root[aspect]).long)
|
||||
: noPersInfs(info.root[aspect]).long;
|
||||
const aux = stativeAux.intransitive[aspect];
|
||||
|
@ -477,7 +621,10 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
|
|||
const past = addToForm([root, " "], aux.past);
|
||||
const habitualPast = addToForm([baParticle, " "], past);
|
||||
const auxModal = aux.modal;
|
||||
const modal = makePassiveModalSection([noPersInfs(info.root.imperfective).long, " "], auxModal);
|
||||
const modal = makePassiveModalSection(
|
||||
[noPersInfs(info.root.imperfective).long, " "],
|
||||
auxModal
|
||||
);
|
||||
return {
|
||||
imperative: undefined,
|
||||
nonImperative, // ROOT LONG + kedulStat[aspect].nonImperative
|
||||
|
@ -491,11 +638,12 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
|
|||
past: concatPsString(
|
||||
removeAccents(noPersInfs(info.root.imperfective).long),
|
||||
" ",
|
||||
stativeAux.intransitive.info.participle.past as T.PsString,
|
||||
stativeAux.intransitive.info.participle.past as T.PsString
|
||||
),
|
||||
present: { p: "ن ا", f: "n / a" },
|
||||
};
|
||||
const perfect = (info.type === "stative compound")
|
||||
const perfect =
|
||||
info.type === "stative compound"
|
||||
? makePassivePerfectContent(info)
|
||||
: makePerfectContent({ ...info, participle: simpleVerbParticiple });
|
||||
return {
|
||||
|
@ -505,7 +653,18 @@ function makePassiveContent(info: T.NonComboVerbInfo): {
|
|||
};
|
||||
}
|
||||
|
||||
function makePassiveModalSection(base: Array<" " | T.SingleOrLengthOpts<T.PsString> | T.SingleOrLengthOpts<T.UnisexInflections> | T.SingleOrLengthOpts<T.PsString>[] | T.SingleOrLengthOpts<T.PsString[]> | T.OptionalPersonInflections<T.PsString> | T.VerbBlock>, auxModal: T.ModalContent): T.ModalContent {
|
||||
function makePassiveModalSection(
|
||||
base: Array<
|
||||
| " "
|
||||
| T.SingleOrLengthOpts<T.PsString>
|
||||
| T.SingleOrLengthOpts<T.UnisexInflections>
|
||||
| T.SingleOrLengthOpts<T.PsString>[]
|
||||
| T.SingleOrLengthOpts<T.PsString[]>
|
||||
| T.OptionalPersonInflections<T.PsString>
|
||||
| T.VerbBlock
|
||||
>,
|
||||
auxModal: T.ModalContent
|
||||
): T.ModalContent {
|
||||
return {
|
||||
nonImperative: addToForm(base, auxModal.nonImperative),
|
||||
future: addToForm(base, auxModal.future),
|
||||
|
@ -515,44 +674,73 @@ function makePassiveModalSection(base: Array<" " | T.SingleOrLengthOpts<T.PsStri
|
|||
};
|
||||
}
|
||||
|
||||
function makePassivePerfectContent(info: T.StativeCompoundVerbInfo): T.PerfectContent {
|
||||
function makePassivePerfectContent(
|
||||
info: T.StativeCompoundVerbInfo
|
||||
): T.PerfectContent {
|
||||
const pPart = stativeAux.intransitive.participle.past;
|
||||
// will always be transitive
|
||||
const halfPerfect = addToForm(
|
||||
[info.complement, " ", passiveStativeBridge, " ", pPart],
|
||||
emptyVerbBlock,
|
||||
emptyVerbBlock
|
||||
);
|
||||
const past = addToForm(
|
||||
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||
equativeEndings.past.short,
|
||||
equativeEndings.past.short
|
||||
);
|
||||
const present = addToForm(
|
||||
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||
equativeEndings.present,
|
||||
equativeEndings.present
|
||||
);
|
||||
const habitual = addToForm(
|
||||
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||
equativeEndings.habitual,
|
||||
equativeEndings.habitual
|
||||
);
|
||||
const subjunctive = addToForm(
|
||||
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||
equativeEndings.subjunctive,
|
||||
equativeEndings.subjunctive
|
||||
);
|
||||
const future = addToForm(
|
||||
[baParticle, " ", info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||
equativeEndings.habitual,
|
||||
[
|
||||
baParticle,
|
||||
" ",
|
||||
info.complement,
|
||||
" ",
|
||||
passiveStativeBridge,
|
||||
" ",
|
||||
pPart,
|
||||
" ",
|
||||
],
|
||||
equativeEndings.habitual
|
||||
);
|
||||
const wouldBe = addToForm(
|
||||
[baParticle, " ", info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||
equativeEndings.past.short,
|
||||
[
|
||||
baParticle,
|
||||
" ",
|
||||
info.complement,
|
||||
" ",
|
||||
passiveStativeBridge,
|
||||
" ",
|
||||
pPart,
|
||||
" ",
|
||||
],
|
||||
equativeEndings.past.short
|
||||
);
|
||||
const pastSubjunctive = addToForm(
|
||||
[info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||
equativeEndings.pastSubjunctive,
|
||||
equativeEndings.pastSubjunctive
|
||||
);
|
||||
const wouldHaveBeen = addToForm(
|
||||
[baParticle, " ", info.complement, " ", passiveStativeBridge, " ", pPart, " "],
|
||||
equativeEndings.pastSubjunctive,
|
||||
[
|
||||
baParticle,
|
||||
" ",
|
||||
info.complement,
|
||||
" ",
|
||||
passiveStativeBridge,
|
||||
" ",
|
||||
pPart,
|
||||
" ",
|
||||
],
|
||||
equativeEndings.pastSubjunctive
|
||||
);
|
||||
return {
|
||||
halfPerfect,
|
||||
|
@ -567,7 +755,10 @@ function makePassivePerfectContent(info: T.StativeCompoundVerbInfo): T.PerfectCo
|
|||
};
|
||||
}
|
||||
|
||||
function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjugation {
|
||||
function enforceObject(
|
||||
conj: T.VerbConjugation,
|
||||
person: T.Person
|
||||
): T.VerbConjugation {
|
||||
const modifyPastInAspect = (as: T.AspectContent): T.AspectContent => ({
|
||||
// WATCH OUT FOR DIFFERENCES WITH allOnePersonInflection (for the object w/ present tense)
|
||||
// AND allOnePersonVerbForm (for the object w/ past tense object)
|
||||
|
@ -584,7 +775,9 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
|
|||
hypotheticalPast: allOnePersonVerbForm(as.modal.hypotheticalPast, person),
|
||||
},
|
||||
});
|
||||
const modifyParticiple = (part: T.ParticipleContent): T.ParticipleContent => ({
|
||||
const modifyParticiple = (
|
||||
part: T.ParticipleContent
|
||||
): T.ParticipleContent => ({
|
||||
// TODO: What to do with this!
|
||||
present: allOnePersonInflection(part.present, person),
|
||||
past: chooseParticipleInflection(part.past, person),
|
||||
|
@ -600,7 +793,9 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
|
|||
pastSubjunctive: allOnePersonVerbForm(perf.pastSubjunctive, person),
|
||||
wouldHaveBeen: allOnePersonVerbForm(perf.wouldHaveBeen, person),
|
||||
});
|
||||
const modifyPassiveAspect = (as: T.AspectContentPassive): T.AspectContentPassive => ({
|
||||
const modifyPassiveAspect = (
|
||||
as: T.AspectContentPassive
|
||||
): T.AspectContentPassive => ({
|
||||
imperative: undefined,
|
||||
nonImperative: allOnePersonVerbForm(as.nonImperative, person),
|
||||
future: allOnePersonVerbForm(as.future, person),
|
||||
|
@ -620,13 +815,15 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
|
|||
perfective: modifyPastInAspect(conj.perfective),
|
||||
participle: modifyParticiple(conj.participle),
|
||||
perfect: modifyPerfect(conj.perfect),
|
||||
...conj.passive ? {
|
||||
...(conj.passive
|
||||
? {
|
||||
passive: {
|
||||
imperfective: modifyPassiveAspect(conj.passive.imperfective),
|
||||
perfective: modifyPassiveAspect(conj.passive.perfective),
|
||||
perfect: modifyPerfect(conj.passive.perfect),
|
||||
},
|
||||
}
|
||||
} : {},
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -635,18 +832,29 @@ function enforceObject(conj: T.VerbConjugation, person: T.Person): T.VerbConjuga
|
|||
function finishSimpleVerbPast(
|
||||
info: T.NonComboVerbInfo,
|
||||
aspect: T.Aspect,
|
||||
roughPast: T.LengthOptions<T.VerbBlock>,
|
||||
roughPast: T.LengthOptions<T.VerbBlock>
|
||||
): T.VerbForm {
|
||||
const applyAccent = (block: T.VerbBlock, form: "short" | "long"): T.VerbBlock => (
|
||||
mapVerbBlock((item: T.PsString, rowNum: number | undefined, colNum: number | undefined) => {
|
||||
const nonRedundantLEnding = (
|
||||
(rowNum === 4 && colNum === 1) &&
|
||||
const applyAccent = (
|
||||
block: T.VerbBlock,
|
||||
form: "short" | "long"
|
||||
): T.VerbBlock =>
|
||||
mapVerbBlock(
|
||||
(
|
||||
item: T.PsString,
|
||||
rowNum: number | undefined,
|
||||
colNum: number | undefined
|
||||
) => {
|
||||
const nonRedundantLEnding =
|
||||
rowNum === 4 &&
|
||||
colNum === 1 &&
|
||||
item.p.slice(-1) === "ل" &&
|
||||
["ul", "úl"].includes(item.f.slice(-2))
|
||||
)
|
||||
const n = (((form === "short") || nonRedundantLEnding) ? 0 : 1) + (info.yulEnding ? 1 : 0);
|
||||
["ul", "úl"].includes(item.f.slice(-2));
|
||||
const n =
|
||||
(form === "short" || nonRedundantLEnding ? 0 : 1) +
|
||||
(info.yulEnding ? 1 : 0);
|
||||
return accentOnNFromEnd(item, n);
|
||||
}, block)
|
||||
},
|
||||
block
|
||||
);
|
||||
const short = ensureShort3rdPersMascSing(info, aspect, roughPast.short);
|
||||
if (aspect === "imperfective") {
|
||||
|
@ -663,29 +871,24 @@ function finishSimpleVerbPast(
|
|||
function ensureShort3rdPersMascSing(
|
||||
info: T.NonComboVerbInfo,
|
||||
aspect: T.Aspect,
|
||||
block: T.VerbBlock,
|
||||
block: T.VerbBlock
|
||||
): T.VerbBlock {
|
||||
const replace3rdPersMascSing = (
|
||||
replacement: T.ArrayOneOrMore<T.PsString>,
|
||||
block: T.VerbBlock,
|
||||
): T.VerbBlock => ([
|
||||
...block.slice(0, 4),
|
||||
[replacement, block[4][1]],
|
||||
block[5],
|
||||
] as T.VerbBlock);
|
||||
block: T.VerbBlock
|
||||
): T.VerbBlock =>
|
||||
[...block.slice(0, 4), [replacement, block[4][1]], block[5]] as T.VerbBlock;
|
||||
const makeAawuForm = (root: T.PsString): T.PsString => {
|
||||
const base = {
|
||||
p: root.p.slice(0, -1),
|
||||
f: root.f.slice(0, -2),
|
||||
};
|
||||
return concatPsString(base, { p: "اوه", f: "aawu" });
|
||||
}
|
||||
};
|
||||
const infinitive = noPersInfs(info.root.imperfective).long;
|
||||
const endsInAwul = (
|
||||
(["awul", "awúl"].includes(infinitive.f.slice(-4)))
|
||||
&&
|
||||
(infinitive.p.slice(-2) === "ول")
|
||||
);
|
||||
const endsInAwul =
|
||||
["awul", "awúl"].includes(infinitive.f.slice(-4)) &&
|
||||
infinitive.p.slice(-2) === "ول";
|
||||
if (endsInAwul) {
|
||||
const root = noPersInfs(info.root[aspect]).short;
|
||||
return replace3rdPersMascSing([makeAawuForm(root)], block);
|
||||
|
@ -694,7 +897,8 @@ function ensureShort3rdPersMascSing(
|
|||
const form = info.idiosyncraticThirdMascSing[aspect];
|
||||
// if it ends in a consonant, the special form will also have another
|
||||
// variation ending with a ه - u
|
||||
const endsInAConsonant = (pashtoConsonants.includes(form.p.slice(-1)) || form.f.slice(-1) === "w");
|
||||
const endsInAConsonant =
|
||||
pashtoConsonants.includes(form.p.slice(-1)) || form.f.slice(-1) === "w";
|
||||
const replacement: T.ArrayOneOrMore<T.PsString> = endsInAConsonant
|
||||
? [
|
||||
form,
|
||||
|
@ -711,24 +915,28 @@ function ensureShort3rdPersMascSing(
|
|||
function accentImperfectiveModalRootAndTail(
|
||||
info: T.NonComboVerbInfo,
|
||||
rt: T.SingleOrLengthOpts<T.PsString>,
|
||||
length?: "long" | "short",
|
||||
length?: "long" | "short"
|
||||
): T.SingleOrLengthOpts<T.PsString> {
|
||||
if ("long" in rt) {
|
||||
return {
|
||||
short: accentImperfectiveModalRootAndTail(info, rt.short, "short") as T.PsString,
|
||||
long: accentImperfectiveModalRootAndTail(info, rt.long, "long") as T.PsString,
|
||||
short: accentImperfectiveModalRootAndTail(
|
||||
info,
|
||||
rt.short,
|
||||
"short"
|
||||
) as T.PsString,
|
||||
long: accentImperfectiveModalRootAndTail(
|
||||
info,
|
||||
rt.long,
|
||||
"long"
|
||||
) as T.PsString,
|
||||
};
|
||||
}
|
||||
}
|
||||
const n = info.yulEnding
|
||||
? 2
|
||||
: length === "short"
|
||||
? 0
|
||||
: 1;
|
||||
const n = info.yulEnding ? 2 : length === "short" ? 0 : 1;
|
||||
return accentOnNFromEnd(rt, n);
|
||||
}
|
||||
|
||||
function getTransitivity(info: T.VerbInfo): "transitive" | "intransitive" {
|
||||
return ("transitivity" in info && info.transitivity === "intransitive")
|
||||
return "transitivity" in info && info.transitivity === "intransitive"
|
||||
? "intransitive"
|
||||
: "transitive";
|
||||
}
|
||||
|
|
|
@ -693,7 +693,7 @@ export type VPRendered = {
|
|||
servant: "subject" | "object" | undefined;
|
||||
isPast: boolean;
|
||||
isTransitive: boolean;
|
||||
isCompound: "stative" | "dynamic" | false;
|
||||
isCompound: "stative" | "dynamic" | "generative stative" | false;
|
||||
blocks: Block[][];
|
||||
kids: Kid[];
|
||||
englishBase?: string[];
|
||||
|
@ -811,7 +811,7 @@ export type VerbSelection = {
|
|||
transitivity: Transitivity;
|
||||
canChangeTransitivity: boolean;
|
||||
canChangeStatDyn: boolean;
|
||||
isCompound: "stative" | "dynamic" | false;
|
||||
isCompound: "stative" | "dynamic" | "generative stative" | false;
|
||||
voice: Voice;
|
||||
canChangeVoice: boolean;
|
||||
negative: boolean;
|
||||
|
@ -867,6 +867,7 @@ export type NounSelection = {
|
|||
number: NounNumber;
|
||||
numberCanChange: boolean;
|
||||
dynamicComplement?: boolean;
|
||||
genStativeComplement?: boolean;
|
||||
adjectives: AdjectiveSelection[];
|
||||
possesor: undefined | PossesorSelection;
|
||||
demonstrative: undefined | DemonstrativeSelection;
|
||||
|
@ -1199,7 +1200,6 @@ export type MiniPronoun = {
|
|||
export type RenderVerbOutput = {
|
||||
hasBa: boolean;
|
||||
vbs: VerbRenderedOutput;
|
||||
objComp: Rendered<NPSelection> | undefined;
|
||||
};
|
||||
export type VerbRenderedOutput = [[VHead] | [], [VB, VBE] | [VBE]];
|
||||
export type RootsStemsOutput = [[VHead] | [], [VB, VBA] | [VBA]]; // or perfect / equative
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
*/
|
||||
|
||||
module.exports = [
|
||||
1527818320, // جارو کول - to sweep
|
||||
1658796089458, // استري کول - to iron
|
||||
1527816643, // استعفا کول - to resign, to quit (a job or position)
|
||||
1527817823, // اصرار کول - to insist, persist, demand
|
||||
1591002320547, // امر کول - to order, command
|
||||
|
@ -139,4 +141,4 @@ module.exports = [
|
|||
1609599425410, // دعا کول - to pray
|
||||
1527812939, // منډې وهل - to run
|
||||
1614602054303, // بدله اخیستل - to take revenge
|
||||
]
|
||||
];
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
module.exports = [
|
||||
1608137130992, // چیغه کول
|
||||
1658537998960, // لېونی کول
|
||||
1527812403, // بچ کول - to save, protect, guard, spare, rescue, economize
|
||||
1577299232429, // بدلول - to change, to adapt, exchange, replace
|
||||
|
@ -83,4 +84,4 @@ module.exports = [
|
|||
1527816559, // یادول - to remember, to recall, to think on, to call
|
||||
1527813556, // یو ځای کول - to gather, bring together
|
||||
1527815444, // زده کول - to learn, to teach
|
||||
]
|
||||
];
|
||||
|
|
|
@ -5427,7 +5427,7 @@ forwarded@0.2.0:
|
|||
|
||||
fp-ts@^2.16.0:
|
||||
version "2.16.0"
|
||||
resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.16.0.tgz#64e03314dfc1c7ce5e975d3496ac14bc3eb7f92e"
|
||||
resolved "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.0.tgz"
|
||||
integrity sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ==
|
||||
|
||||
fragment-cache@^0.2.1:
|
||||
|
@ -9544,11 +9544,6 @@ react-lifecycles-compat@^3.0.4:
|
|||
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz"
|
||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||
|
||||
react-media-hook@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/react-media-hook/-/react-media-hook-0.5.0.tgz#f830231f31ea80049f8cbaf8058da90ab71e7150"
|
||||
integrity sha512-OupDgOSCjUUWPiXq3HMoRwpsQry4cGf4vKzh2E984Xtm4I01ZFbq8JwCG/RPqXB9h0qxgzoYLbABC+LIZH8deQ==
|
||||
|
||||
react-overlays@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.npmjs.org/react-overlays/-/react-overlays-5.1.1.tgz"
|
||||
|
|
Loading…
Reference in New Issue