working - quiz is broken
This commit is contained in:
parent
4e5075ca19
commit
0f720e3be1
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@lingdocs/pashto-inflector",
|
||||
"version": "2.8.0",
|
||||
"version": "2.8.1",
|
||||
"author": "lingdocs.com",
|
||||
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
|
||||
"homepage": "https://verbs.lingdocs.com",
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
import * as T from "../../types";
|
||||
import classNames from "classnames";
|
||||
import {
|
||||
getEnglishFromRendered,
|
||||
} from "../../lib/phrase-building/np-tools";
|
||||
|
||||
function Block({ opts, block }: {
|
||||
opts: T.TextOptions,
|
||||
block: T.Block,
|
||||
}) {
|
||||
if ("equative" in block) {
|
||||
return <EquativeBlock opts={opts} eq={block.equative} />;
|
||||
}
|
||||
if (block.type === "AP") {
|
||||
const english = getEnglishFromRendered(block);
|
||||
return <AP opts={opts} english={english}>{block}</AP>
|
||||
}
|
||||
if (block.type === "subjectSelection") {
|
||||
return <SubjectBlock opts={opts} np={block.selection} />
|
||||
}
|
||||
if (block.type === "predicateSelection") {
|
||||
const english = getEnglishFromRendered(block.selection);
|
||||
return <div className="text-center">
|
||||
<div>Pred</div>
|
||||
{block.selection.type === "EQComp"
|
||||
? <EqCompBlock opts={opts} comp={block.selection.selection} />
|
||||
: <NP opts={opts} english={english}>{block.selection}</NP>}
|
||||
</div>
|
||||
}
|
||||
if (block.type === "nu") {
|
||||
return <NUBlock opts={opts} />
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default Block;
|
||||
|
||||
function NUBlock({ opts }: {
|
||||
opts: T.TextOptions,
|
||||
}) {
|
||||
return <div>
|
||||
<div
|
||||
className={classNames("d-flex flex-row justify-content-center align-items-center")}
|
||||
style={{
|
||||
border: "2px solid black",
|
||||
padding: "1rem",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
nu
|
||||
</div>
|
||||
<div className="small text-muted text-center" style={{
|
||||
// TODO: find a better way to keep this limited to the width of the div above
|
||||
// don't let this make the div above expand
|
||||
margin: "0 auto",
|
||||
maxWidth: "300px",
|
||||
}}>not</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function EquativeBlock({ opts, eq }: {
|
||||
opts: T.TextOptions,
|
||||
eq: T.EquativeRendered,
|
||||
}) {
|
||||
return <div>
|
||||
<div
|
||||
className={classNames("d-flex flex-row justify-content-center align-items-center")}
|
||||
style={{
|
||||
border: "2px solid black",
|
||||
padding: "1rem",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{"short" in eq.ps ? eq.ps.short[0].f : eq.ps[0].f}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function SubjectBlock({ opts, np }: {
|
||||
opts: T.TextOptions,
|
||||
np: T.Rendered<T.NPSelection>,
|
||||
}) {
|
||||
const english = getEnglishFromRendered(np);
|
||||
return <div className="text-center">
|
||||
<div>Subject</div>
|
||||
<NP opts={opts} english={english}>{np}</NP>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function EqCompBlock({ opts, comp }: {
|
||||
opts: T.TextOptions,
|
||||
comp: T.Rendered<T.EqCompSelection["selection"]>,
|
||||
}) {
|
||||
function AdjectiveBlock({ opts, adj }: {
|
||||
opts: T.TextOptions,
|
||||
adj: T.Rendered<T.AdjectiveSelection>,
|
||||
}) {
|
||||
return <div>
|
||||
<div
|
||||
className={classNames("d-flex flex-row justify-content-center align-items-center")}
|
||||
style={{
|
||||
border: "2px solid black",
|
||||
padding: "1rem",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{adj.ps[0].f}
|
||||
</div>
|
||||
<div>Adj.</div>
|
||||
{adj.e && <div className="small text-muted text-center" style={{
|
||||
// TODO: find a better way to keep this limited to the width of the div above
|
||||
// don't let this make the div above expand
|
||||
margin: "0 auto",
|
||||
maxWidth: "300px",
|
||||
}}>{adj.e}</div>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
function LocAdvBlock({ opts, adv }: {
|
||||
opts: T.TextOptions,
|
||||
adv: T.Rendered<T.LocativeAdverbSelection>,
|
||||
}) {
|
||||
return <div>
|
||||
<div
|
||||
className={classNames("d-flex flex-row justify-content-center align-items-center")}
|
||||
style={{
|
||||
border: "2px solid black",
|
||||
padding: "1rem",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{adv.ps[0].f}
|
||||
</div>
|
||||
<div>Loc. Adv.</div>
|
||||
{adv.e && <div className="small text-muted text-center" style={{
|
||||
// TODO: find a better way to keep this limited to the width of the div above
|
||||
// don't let this make the div above expand
|
||||
margin: "0 auto",
|
||||
maxWidth: "300px",
|
||||
}}>{adv.e}</div>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
return <div className="text-center mb-2">
|
||||
<div>Comp.</div>
|
||||
{comp.type === "adjective"
|
||||
? <AdjectiveBlock opts={opts} adj={comp} />
|
||||
: comp.type === "loc. adv."
|
||||
? <LocAdvBlock opts={opts} adv={comp} />
|
||||
: <div>
|
||||
<Sandwich opts={opts} sandwich={comp} />
|
||||
<div>Sandwich</div>
|
||||
</div>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
function AP({ opts, children, english }: {
|
||||
opts: T.TextOptions,
|
||||
children: T.Rendered<T.APSelection>,
|
||||
english?: string,
|
||||
}) {
|
||||
const ap = children;
|
||||
if (ap.selection.type === "adverb") {
|
||||
return <div>
|
||||
<div
|
||||
className={classNames("d-flex flex-row justify-content-center align-items-center")}
|
||||
style={{
|
||||
border: "2px solid black",
|
||||
padding: "1rem",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{ap.selection.ps[0].f}
|
||||
</div>
|
||||
<div>AP</div>
|
||||
{english && <div className="small text-muted text-center" style={{
|
||||
// TODO: find a better way to keep this limited to the width of the div above
|
||||
// don't let this make the div above expand
|
||||
margin: "0 auto",
|
||||
maxWidth: "300px",
|
||||
}}>{english}</div>}
|
||||
</div>;
|
||||
}
|
||||
return <div>
|
||||
<Sandwich opts={opts} sandwich={ap.selection} />
|
||||
<div>AP</div>
|
||||
{english && <div className="small text-muted text-center" style={{
|
||||
// TODO: find a better way to keep this limited to the width of the div above
|
||||
// don't let this make the div above expand
|
||||
margin: "0 auto",
|
||||
maxWidth: "300px",
|
||||
}}>{english}</div>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
function Sandwich({ opts, sandwich }: {
|
||||
opts: T.TextOptions,
|
||||
sandwich: T.Rendered<T.SandwichSelection<T.Sandwich>>,
|
||||
}) {
|
||||
return <div>
|
||||
<div className="text-center">Sandwich 🥪</div>
|
||||
<div
|
||||
className={classNames("d-flex flex-row justify-content-center align-items-center")}
|
||||
style={{
|
||||
border: "2px solid black",
|
||||
padding: "0.75rem 0.5rem 0.25rem 0.5rem",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
<div className="d-flex flex-row justify-content-between align-items-end">
|
||||
<Possesors opts={opts}>{sandwich.inside.selection.type !== "pronoun" ? sandwich.inside.selection.possesor : undefined}</Possesors>
|
||||
<div className="mr-2 ml-1 mb-1"><strong>{sandwich.before ? sandwich.before.f : ""}</strong></div>
|
||||
<div>
|
||||
<NP opts={opts} inside>{sandwich.inside}</NP>
|
||||
</div>
|
||||
<div className="ml-2 mr-1 mb-1"><strong>{sandwich.after ? sandwich.after.f : ""}</strong></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function NP({ opts, children, inside, english }: {
|
||||
opts: T.TextOptions,
|
||||
children: T.Rendered<T.NPSelection>,
|
||||
inside?: boolean,
|
||||
english?: string,
|
||||
}) {
|
||||
const np = children;
|
||||
const hasPossesor = !!(np.selection.type !== "pronoun" && np.selection.possesor);
|
||||
return <div>
|
||||
<div
|
||||
className={classNames("d-flex flex-row justify-content-center align-items-center", { "pt-2": !inside && hasPossesor })}
|
||||
style={{
|
||||
border: "2px solid black",
|
||||
padding: inside ? "0.3rem" : hasPossesor ? "0.5rem 1rem 0.25rem 1rem" : "1rem",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{!inside && <Possesors opts={opts}>{np.selection.type !== "pronoun" ? np.selection.possesor : undefined}</Possesors>}
|
||||
<Adjectives opts={opts}>{np.selection.adjectives}</Adjectives>
|
||||
<div> {np.selection.ps[0].f}</div>
|
||||
</div>
|
||||
<div className={inside ? "small" : ""}>NP</div>
|
||||
{english && <div className="small text-muted text-center" style={{
|
||||
// TODO: find a better way to keep this limited to the width of the div above
|
||||
// don't let this make the div above expand
|
||||
margin: "0 auto",
|
||||
maxWidth: "300px",
|
||||
}}>{english}</div>}
|
||||
</div>
|
||||
}
|
||||
|
||||
function Possesors({ opts, children }: {
|
||||
opts: T.TextOptions,
|
||||
children: { shrunken: boolean, np: T.Rendered<T.NPSelection> } | undefined,
|
||||
}) {
|
||||
if (!children) {
|
||||
return null;
|
||||
}
|
||||
const contraction = checkForContraction(children.np);
|
||||
return <div className="d-flex flex-row mr-1 align-items-end" style={{
|
||||
marginBottom: "0.5rem",
|
||||
borderBottom: "1px solid grey",
|
||||
}}>
|
||||
{children.np.selection.type !== "pronoun" && <Possesors opts={opts}>{children.np.selection.possesor}</Possesors>}
|
||||
<div>
|
||||
{contraction && <div className="mb-1">({contraction})</div>}
|
||||
<div className={classNames("d-flex", "flex-row", "align-items-center", { "text-muted": contraction })}>
|
||||
<div className="mr-1 pb-2">du</div>
|
||||
<div>
|
||||
<NP opts={opts} inside>{children.np}</NP>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
function checkForContraction(np: T.Rendered<T.NPSelection>): string | undefined {
|
||||
if (np.selection.type !== "pronoun") return undefined;
|
||||
if (np.selection.person === T.Person.FirstSingMale || np.selection.person === T.Person.FirstSingFemale) {
|
||||
return "zmaa"
|
||||
}
|
||||
if (np.selection.person === T.Person.SecondSingMale || np.selection.person === T.Person.SecondSingFemale) {
|
||||
return "staa"
|
||||
}
|
||||
if (np.selection.person === T.Person.FirstPlurMale || np.selection.person === T.Person.FirstPlurFemale) {
|
||||
return "zmoonG"
|
||||
}
|
||||
if (np.selection.person === T.Person.SecondPlurMale || np.selection.person === T.Person.SecondPlurFemale) {
|
||||
return "staaso"
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function Adjectives({ opts, children }: {
|
||||
opts: T.TextOptions,
|
||||
children: T.Rendered<T.AdjectiveSelection>[] | undefined,
|
||||
}) {
|
||||
if (!children) {
|
||||
return null;
|
||||
}
|
||||
return <em className="mr-1">
|
||||
{children.map(a => a.ps[0].f).join(" ")}{` `}
|
||||
</em>
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import * as T from "../../types";
|
||||
import Block from "../blocks/Block";
|
||||
|
||||
function EPBlocksDisplay({ opts, rendered }: { opts: T.TextOptions, rendered: T.EPRendered }) {
|
||||
const blocks = rendered.omitSubject
|
||||
? rendered.blocks.filter(b => b.type !== "subjectSelection")
|
||||
: rendered.blocks;
|
||||
|
||||
return <div className="d-flex flex-row justify-content-center align-items-end mt-3">
|
||||
{blocks.map((block, i) => (
|
||||
<div key={Math.random()} className="mr-2">
|
||||
<Block opts={opts} block={block} />
|
||||
</div>
|
||||
))}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default EPBlocksDisplay;
|
|
@ -1,17 +1,22 @@
|
|||
import * as T from "../../types";
|
||||
import { completeEPSelection, renderEP } from "../../lib/phrase-building/render-ep";
|
||||
import { compileEP } from "../../lib/phrase-building/compile";
|
||||
import Examples from "../Examples";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
import { getRenderedSubjectSelection, getSubjectSelection } from "../../lib/phrase-building/blocks-utils";
|
||||
import { getPredicateSelectionFromBlocks, getSubjectSelection, getSubjectSelectionFromBlocks } from "../../lib/phrase-building/blocks-utils";
|
||||
import { useState } from "react";
|
||||
import EPTextDisplay from "./EPTextDisplay";
|
||||
import EPBlocksDisplay from "./EPBlocksDisplay";
|
||||
type Mode = "text" | "blocks";
|
||||
|
||||
function EPDisplay({ eps, opts, setOmitSubject }: {
|
||||
eps: T.EPSelectionState,
|
||||
opts: T.TextOptions,
|
||||
setOmitSubject: (value: "true" | "false") => void,
|
||||
}) {
|
||||
const [mode] = useState<Mode>("text");
|
||||
const EP = completeEPSelection(eps);
|
||||
const subject = getSubjectSelection(eps.blocks);
|
||||
|
||||
if (!EP) {
|
||||
return <div className="lead text-center my-4">
|
||||
{(!subject && !eps.predicate[eps.predicate.type])
|
||||
|
@ -25,9 +30,11 @@ function EPDisplay({ eps, opts, setOmitSubject }: {
|
|||
}
|
||||
const rendered = renderEP(EP);
|
||||
const result = compileEP(rendered);
|
||||
const renderedSubject = getRenderedSubjectSelection(rendered.blocks).selection;
|
||||
const renderedSubject = getSubjectSelectionFromBlocks(rendered.blocks).selection;
|
||||
const renderedPredicate = getPredicateSelectionFromBlocks(rendered.blocks).selection;
|
||||
return <div className="text-center pt-3">
|
||||
<div className="mb-2">
|
||||
<div className="mb-2 d-flex flex-row justify-content-between align-items-center">
|
||||
{/* <ModeSelect value={mode} onChange={setMode} /> */}
|
||||
<ButtonSelect
|
||||
small
|
||||
value={(eps.omitSubject ? "true" : "false") as "true" | "false"}
|
||||
|
@ -37,31 +44,28 @@ function EPDisplay({ eps, opts, setOmitSubject }: {
|
|||
]}
|
||||
handleChange={setOmitSubject}
|
||||
/>
|
||||
<div />
|
||||
</div>
|
||||
{"long" in result.ps ?
|
||||
<div>
|
||||
<VariationLayer vs={result.ps.long} opts={opts} />
|
||||
<VariationLayer vs={result.ps.short} opts={opts} />
|
||||
{result.ps.mini && <VariationLayer vs={result.ps.mini} opts={opts} />}
|
||||
</div>
|
||||
: <VariationLayer vs={result.ps} opts={opts} />
|
||||
}
|
||||
{result.e && <div className="text-muted mt-3">
|
||||
{result.e.map((e, i) => <div key={i}>{e}</div>)}
|
||||
</div>}
|
||||
{mode === "text"
|
||||
? <EPTextDisplay opts={opts} compiled={result} />
|
||||
: <EPBlocksDisplay opts={opts} rendered={rendered} />}
|
||||
{EP.predicate.selection.selection.type === "participle" && <div style={{ maxWidth: "6 00px", margin: "0 auto" }} className="alert alert-warning mt-3 pt-4">
|
||||
<p>⚠️ NOTE: This means that the subject {renderedSubject.selection.e ? `(${renderedSubject.selection.e})` : ""} is <strong>the action/idea</strong> of
|
||||
{` `}
|
||||
"{rendered.predicate.selection.e ? rendered.predicate.selection.e : "the particple"}".</p>
|
||||
"{renderedPredicate.selection.e ? renderedPredicate.selection.e : "the particple"}".</p>
|
||||
<p>It <strong>does not</strong> mean that the subject is doing the action, which is what the transaltion sounds like in English.</p>
|
||||
</div>}
|
||||
</div>
|
||||
}
|
||||
|
||||
function VariationLayer({ vs, opts }: { vs: T.PsString[], opts: T.TextOptions }) {
|
||||
return <div className="mb-2">
|
||||
<Examples opts={opts} lineHeight={0}>{vs}</Examples>
|
||||
</div>;
|
||||
}
|
||||
// function ModeSelect({ value, onChange }: { value: Mode, onChange: (m: Mode) => void }) {
|
||||
// return <div style={{ fontSize: "larger" }}>
|
||||
// {value === "text" ? <div className="clickable" onClick={() => onChange("blocks")}>
|
||||
// <i className="fas fa-cubes" />
|
||||
// </div> : <div className="clickable" onClick={() => onChange("text")}>
|
||||
// <i className="fas fa-align-left" />
|
||||
// </div>}
|
||||
// </div>;
|
||||
// }
|
||||
|
||||
export default EPDisplay;
|
|
@ -38,7 +38,7 @@ function EPExplorer(props: {
|
|||
entryFeeder: T.EntryFeeder,
|
||||
}) {
|
||||
const [mode, setMode] = useStickyState<"charts" | "phrases">("charts", "EPExplorerMode");
|
||||
const [eps, adjustEps] = useStickyReducer(epsReducer, blankEps, "EPState5", flashMessage);
|
||||
const [eps, adjustEps] = useStickyReducer(epsReducer, blankEps, "EPState6", flashMessage);
|
||||
const [alert, setAlert] = useState<string | undefined>(undefined);
|
||||
const [showClipped, setShowClipped] = useState<string>("");
|
||||
const parent = useRef<HTMLDivElement>(null);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import * as T from "../../types";
|
||||
import Examples from "../Examples";
|
||||
|
||||
function EPTextDisplay({ compiled, opts }: { compiled: {
|
||||
ps: T.SingleOrLengthOpts<T.PsString[]>;
|
||||
e?: string[] | undefined;
|
||||
}, opts: T.TextOptions }) {
|
||||
function VariationLayer({ vs }: { vs: T.PsString[] }) {
|
||||
return <div className="mb-2">
|
||||
<Examples opts={opts} lineHeight={0}>{vs}</Examples>
|
||||
</div>;
|
||||
}
|
||||
return <div>
|
||||
{"long" in compiled.ps ?
|
||||
<div>
|
||||
<VariationLayer vs={compiled.ps.long} />
|
||||
<VariationLayer vs={compiled.ps.short} />
|
||||
{compiled.ps.mini && <VariationLayer vs={compiled.ps.mini} />}
|
||||
</div>
|
||||
: <VariationLayer vs={compiled.ps} />
|
||||
}
|
||||
{compiled.e && <div className="text-muted mt-3">
|
||||
{compiled.e.map((e, i) => <div key={i}>{e}</div>)}
|
||||
</div>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default EPTextDisplay;
|
|
@ -4,7 +4,7 @@ import {
|
|||
personNumber,
|
||||
} from "../../lib/misc-helpers";
|
||||
import { isUnisexNounEntry } from "../../lib/type-predicates";
|
||||
import { checkForMiniPronounsError } from "../../lib/phrase-building/compile";
|
||||
import { checkEPForMiniPronounsError } from "../../lib/phrase-building/compile";
|
||||
import { adjustSubjectSelection, getSubjectSelection, insertNewAP, removeAP, setAP, shiftBlock } from "../../lib/phrase-building/blocks-utils";
|
||||
|
||||
type EpsReducerAction = {
|
||||
|
@ -189,7 +189,7 @@ export default function epsReducer(eps: T.EPSelectionState, action: EpsReducerAc
|
|||
}
|
||||
|
||||
function ensureMiniPronounsOk(old: T.EPSelectionState, eps: T.EPSelectionState, sendAlert?: (msg: string) => void): T.EPSelectionState {
|
||||
const error = checkForMiniPronounsError(eps);
|
||||
const error = checkEPForMiniPronounsError(eps);
|
||||
if (error) {
|
||||
if (sendAlert) sendAlert(error);
|
||||
return old;
|
||||
|
|
|
@ -106,6 +106,12 @@ function VPExplorerQuiz(props: {
|
|||
setAnswerBlank("");
|
||||
setQuizState(tickQuizState(quizState.vps));
|
||||
}
|
||||
if (1 < 3) {
|
||||
return <div className="text-center my-4">
|
||||
<h3>The quiz is broken 😭</h3>
|
||||
<p>It will be fixed in like a week or two... hopefully.</p>
|
||||
</div>
|
||||
}
|
||||
return <div className="mt-4">
|
||||
<ProgressBar quizState={quizState} />
|
||||
<div className="d-flex flex-row justify-content-around flex-wrap">
|
||||
|
@ -322,6 +328,7 @@ function tickQuizState(startingWith: T.VPSelectionComplete | QuizState): QuizSta
|
|||
}
|
||||
const answer = makeRes(newVps);
|
||||
const wrongAnswers = wrongVpsS.map(makeRes);
|
||||
console.log({ newVps, answer, wrongAnswers });
|
||||
const allAnswers = shuffleArray([...wrongAnswers, answer]);
|
||||
const options = allAnswers.map(getOptionFromResult);
|
||||
return {
|
||||
|
|
|
@ -108,6 +108,20 @@ function accentSyllable(s: string): string {
|
|||
});
|
||||
}
|
||||
|
||||
export function removeAccentsWLength(s: T.SingleOrLengthOpts<T.PsString[]>): T.SingleOrLengthOpts<T.PsString[]> {
|
||||
if ("long" in s) {
|
||||
return {
|
||||
long: removeAccentsWLength(s.long) as T.PsString[],
|
||||
short: removeAccentsWLength(s.short) as T.PsString[],
|
||||
...s.mini ? {
|
||||
mini: removeAccentsWLength(s.mini) as T.PsString[],
|
||||
} : {},
|
||||
};
|
||||
}
|
||||
return removeAccents(s);
|
||||
}
|
||||
|
||||
|
||||
export function removeAccents(s: T.PsString): T.PsString;
|
||||
export function removeAccents(s: string): string;
|
||||
export function removeAccents(s: T.PsString[]): T.PsString[];
|
||||
|
|
|
@ -28,6 +28,12 @@ export function pickPersInf<T>(s: T.OptionalPersonInflections<T>, persInf: T.Per
|
|||
return s;
|
||||
}
|
||||
|
||||
export function getFirstSecThird(p: T.Person): 1 | 2 | 3 {
|
||||
if ([0, 1, 6, 7].includes(p)) return 1;
|
||||
if ([2, 3, 8, 9].includes(p)) return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
// export function pickPersInf(
|
||||
// s: T.OptionalPersonInflections<T.LengthOptions<T.PsString>>,
|
||||
// persInf: T.PersonInflectionsField,
|
||||
|
|
|
@ -984,6 +984,10 @@ export function psStringFromEntry(entry: T.PsString): T.PsString {
|
|||
};
|
||||
}
|
||||
|
||||
export function getLength<U>(x: T.SingleOrLengthOpts<U>, length: "long" | "short"): U {
|
||||
return ("long" in x) ? x[length] : x;
|
||||
}
|
||||
|
||||
export function getLong<U>(x: T.SingleOrLengthOpts<U>): U {
|
||||
if ("long" in x) {
|
||||
return x.long;
|
||||
|
@ -991,6 +995,13 @@ export function getLong<U>(x: T.SingleOrLengthOpts<U>): U {
|
|||
return x;
|
||||
}
|
||||
|
||||
export function getShort<U>(a: T.SingleOrLengthOpts<U>): U {
|
||||
if ("long" in a) {
|
||||
return a.short;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
export function capitalizeFirstLetter(string: string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import * as T from "../../types";
|
||||
import { getLength } from "../p-text-helpers";
|
||||
|
||||
export function getSubjectSelection(blocks: T.EPSBlockComplete[] | T.VPSBlockComplete[]): T.SubjectSelectionComplete;
|
||||
export function getSubjectSelection(blocks: T.EPSBlock[] | T.VPSBlock[]): T.SubjectSelection;
|
||||
|
@ -10,6 +11,26 @@ export function getSubjectSelection(blocks: T.EPSBlock[] | T.EPSBlockComplete[]
|
|||
return b.block;
|
||||
}
|
||||
|
||||
export function getSubjectSelectionFromBlocks(blocks: T.Block[]): T.Rendered<T.SubjectSelectionComplete> {
|
||||
const b = blocks.find(f => f.type === "subjectSelection");
|
||||
if (!b || b.type !== "subjectSelection") {
|
||||
throw new Error("subjectSelection not found in blocks");
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
export function getPredicateSelectionFromBlocks(blocks: T.Block[]): T.Rendered<T.PredicateSelectionComplete> {
|
||||
const b = blocks.find(f => f.type === "predicateSelection");
|
||||
if (!b || b.type !== "predicateSelection") {
|
||||
throw new Error("predicateSelection not found in blocks");
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
export function getAPsFromBlocks(blocks: T.Block[]): T.Rendered<T.APSelection>[] {
|
||||
return blocks.filter(b => b.type === "AP") as T.Rendered<T.APSelection>[];
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -185,6 +206,29 @@ export function isNoObject(b: T.VPSBlock["block"] | T.EPSBlock["block"]): b is {
|
|||
return !!(b && b.type === "objectSelection" && b.selection === "none");
|
||||
}
|
||||
|
||||
export function specifyEquativeLength(blocks: T.Block[], length: "long" | "short"): T.Block[] {
|
||||
const i = blocks.findIndex(b => b.type === "equative");
|
||||
if (i === -1) throw new Error("equative block not found in EPRendered");
|
||||
const eq = blocks[i];
|
||||
if (eq.type !== "equative") throw new Error("error searching for equative block");
|
||||
const adjusted = [...blocks];
|
||||
adjusted[i] = {
|
||||
...eq,
|
||||
equative: {
|
||||
...eq.equative,
|
||||
ps: getLength(eq.equative.ps, length),
|
||||
},
|
||||
};
|
||||
return adjusted;
|
||||
}
|
||||
|
||||
export function hasEquativeWithLengths(blocks: T.Block[]): boolean {
|
||||
const equative = blocks.find(x => x.type === "equative");
|
||||
if (!equative) throw new Error("equative not found in blocks");
|
||||
if (equative.type !== "equative") throw new Error("error finding equative in blocks");
|
||||
return "long" in equative.equative.ps;
|
||||
}
|
||||
|
||||
function arrayMove<X>(ar: X[], old_index: number, new_index: number): X[] {
|
||||
const arr = [...ar];
|
||||
const new_i = (new_index >= arr.length)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as T from "../../types";
|
||||
import {
|
||||
concatPsString,
|
||||
concatPsString, getLong,
|
||||
} from "../p-text-helpers";
|
||||
import {
|
||||
Segment,
|
||||
|
@ -8,7 +8,7 @@ import {
|
|||
flattenLengths,
|
||||
combineSegments,
|
||||
splitOffLeapfrogWord,
|
||||
putKidsInKidsSection,
|
||||
putKidsInKidsSection as oldPutKidsInKidsSection,
|
||||
} from "./segment";
|
||||
import {
|
||||
removeAccents,
|
||||
|
@ -25,15 +25,17 @@ import { pronouns } from "../grammar-units";
|
|||
import { completeEPSelection, renderEP } from "./render-ep";
|
||||
import { completeVPSelection } from "./vp-tools";
|
||||
import { renderVP } from "./render-vp";
|
||||
import { getRenderedObjectSelection, getRenderedSubjectSelection } from "./blocks-utils";
|
||||
import { getAPsFromBlocks, getPredicateSelectionFromBlocks, getRenderedObjectSelection, getRenderedSubjectSelection, getSubjectSelectionFromBlocks, hasEquativeWithLengths, specifyEquativeLength } from "./blocks-utils";
|
||||
|
||||
const blank: T.PsString = {
|
||||
p: "______",
|
||||
f: "______",
|
||||
};
|
||||
// TODO: GET BLANKING WORKING!
|
||||
|
||||
// const blank: T.PsString = {
|
||||
// p: "______",
|
||||
// f: "______",
|
||||
// };
|
||||
type BlankoutOptions = { equative?: boolean, ba?: boolean, kidsSection?: boolean };
|
||||
|
||||
const kidsBlank = makeSegment({ p: "___", f: "___" }, ["isKid"]);
|
||||
// const kidsBlank = makeSegment({ p: "___", f: "___" }, ["isKid"]);
|
||||
|
||||
export function compileVP(VP: T.VPRendered, form: T.FormVersion): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] };
|
||||
export function compileVP(VP: T.VPRendered, form: T.FormVersion, combineLengths: true): { ps: T.PsString[], e?: string [] };
|
||||
|
@ -80,7 +82,7 @@ function compilePs({ blocks, kids, verb: { head, rest }, VP }: CompilePsInput):
|
|||
return removeDuplicates(verbWNegativeVersions.flatMap((verbSegments) => {
|
||||
// for each permutation of the possible ordering of NPs and Verb + nu
|
||||
// 1. put in kids in the kids section
|
||||
const segments = putKidsInKidsSection([...blocks, ...verbSegments], kids);
|
||||
const segments = oldPutKidsInKidsSection([...blocks, ...verbSegments], kids);
|
||||
// 2. space out the words properly
|
||||
const withProperSpaces = addSpacesBetweenSegments(segments);
|
||||
// 3. throw it all together into a PsString for each permutation
|
||||
|
@ -145,37 +147,6 @@ export function getVPSegmentsAndKids(VP: T.VPRendered, form?: T.FormVersion): {
|
|||
};
|
||||
}
|
||||
|
||||
export function getEPSegmentsAndKids(EP: T.EPRendered, blankOut?: BlankoutOptions): { kids: Segment[], blocks: Segment[] } {
|
||||
const possToShrink = findPossesivesToShrinkInEP(EP);
|
||||
const blocks = EP.blocks.reduce((accum, block) => {
|
||||
if (block.type === "subjectSelection") {
|
||||
if (EP.omitSubject) return accum;
|
||||
return [
|
||||
...accum,
|
||||
makeSegment(getPashtoFromRendered(block.selection, false)),
|
||||
];
|
||||
}
|
||||
return [
|
||||
...accum,
|
||||
makeSegment(getPashtoFromRendered(block, false)),
|
||||
];
|
||||
}, [] as Segment[]);
|
||||
const predicate = makeSegment(getPashtoFromRendered(EP.predicate, false));
|
||||
return {
|
||||
kids: blankOut?.kidsSection ? [kidsBlank] : orderKidsSection([
|
||||
...EP.equative.hasBa
|
||||
? (
|
||||
blankOut?.ba ? [kidsBlank] : [makeSegment(grammarUnits.baParticle, ["isBa", "isKid"])])
|
||||
: [],
|
||||
...possToShrink.map(a => shrinkNP(a.np)),
|
||||
]),
|
||||
blocks: [
|
||||
...blocks,
|
||||
predicate
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function arrangeVerbWNegative(head: T.PsString | undefined, restRaw: T.PsString[], V: T.VerbRendered): Segment[][] {
|
||||
const hasLeapfrog = isPerfectTense(V.tense) || isModalTense(V.tense);
|
||||
const rest = (() => {
|
||||
|
@ -292,42 +263,67 @@ function arrangeVerbWNegative(head: T.PsString | undefined, restRaw: T.PsString[
|
|||
export function compileEP(EP: T.EPRendered): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string[] };
|
||||
export function compileEP(EP: T.EPRendered, combineLengths: true, blankOut?: BlankoutOptions): { ps: T.PsString[], e?: string[] };
|
||||
export function compileEP(EP: T.EPRendered, combineLengths?: boolean, blankOut?: BlankoutOptions): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string[] } {
|
||||
const { kids, blocks } = getEPSegmentsAndKids(EP, blankOut);
|
||||
const equative = EP.equative.ps;
|
||||
const psResult = compileEPPs({
|
||||
blocks,
|
||||
kids,
|
||||
equative: blankOut?.equative ? [blank] : equative,
|
||||
negative: EP.equative.negative,
|
||||
});
|
||||
const psResult = compileEPPs(EP.blocks, EP.kids, blankOut);
|
||||
return {
|
||||
ps: combineLengths ? flattenLengths(psResult) : psResult,
|
||||
e: compileEnglishEP(EP),
|
||||
};
|
||||
}
|
||||
|
||||
function compileEPPs({ blocks, kids, equative, negative }: {
|
||||
blocks: Segment[],
|
||||
kids: Segment[],
|
||||
equative: T.SingleOrLengthOpts<T.PsString[]>,
|
||||
negative: boolean,
|
||||
}): T.SingleOrLengthOpts<T.PsString[]> {
|
||||
if ("long" in equative) {
|
||||
function compileEPPs(blocks: T.Block[], kids: T.Kid[], blankOut?: BlankoutOptions): T.SingleOrLengthOpts<T.PsString[]> {
|
||||
if (hasEquativeWithLengths(blocks)) {
|
||||
return {
|
||||
long: compileEPPs({ blocks, kids, equative: equative.long, negative }) as T.PsString[],
|
||||
short: compileEPPs({ blocks, kids, equative: equative.short, negative }) as T.PsString[],
|
||||
long: compileEPPs(specifyEquativeLength(blocks, "long"), kids, blankOut) as T.PsString[],
|
||||
short: compileEPPs(specifyEquativeLength(blocks, "short"), kids, blankOut) as T.PsString[],
|
||||
};
|
||||
}
|
||||
const allSegments = putKidsInKidsSection([
|
||||
...blocks,
|
||||
...negative ? [
|
||||
makeSegment({ p: "نه", f: "nú" }),
|
||||
makeSegment(removeAccents(equative))
|
||||
] : [
|
||||
makeSegment(equative),
|
||||
],
|
||||
], kids);
|
||||
return removeDuplicates(combineSegments(allSegments, "spaces"));
|
||||
const subjectPerson = getSubjectSelectionFromBlocks(blocks)
|
||||
.selection.selection.person;
|
||||
const blocksWKids = putKidsInKidsSection(blocks, kids);
|
||||
return removeDuplicates(combineIntoText(blocksWKids, subjectPerson));
|
||||
}
|
||||
|
||||
function combineIntoText(pieces: (T.Block | T.Kid)[], subjectPerson: T.Person): T.PsString[] {
|
||||
const first = pieces[0];
|
||||
const rest = pieces.slice(1);
|
||||
const firstPs = getPsFromPiece(first, subjectPerson);
|
||||
if (!rest.length) {
|
||||
return firstPs;
|
||||
}
|
||||
return combineIntoText(rest, subjectPerson).flatMap(r => (
|
||||
firstPs.map(fPs => concatPsString(fPs, " ", r))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getPsFromPiece(piece: T.Block | T.Kid, subjectPerson: T.Person): T.PsString[] {
|
||||
if (piece.type === "ba") {
|
||||
return [grammarUnits.baParticle];
|
||||
}
|
||||
if (piece.type === "mini-pronoun") {
|
||||
return [piece.ps];
|
||||
}
|
||||
if (piece.type === "nu") {
|
||||
return [{ p: "نه", f: "nú" }];
|
||||
}
|
||||
if (piece.type === "equative") {
|
||||
// length will already be specified in compileEPPs - this is just for type safety
|
||||
return getLong(piece.equative.ps);
|
||||
}
|
||||
if (piece.type === "subjectSelection" || piece.type === "predicateSelection") {
|
||||
return getPashtoFromRendered(piece.selection, subjectPerson);
|
||||
}
|
||||
// if (piece.type === "AP") {
|
||||
return getPashtoFromRendered(piece, subjectPerson);
|
||||
// }
|
||||
}
|
||||
|
||||
function getEngAPs(blocks: T.Block[]): string {
|
||||
return getAPsFromBlocks(blocks).reduce((accum, curr) => {
|
||||
const e = getEnglishFromRendered(curr);
|
||||
if (!e) return accum;
|
||||
return `${accum} ${e}`;
|
||||
}, "");
|
||||
}
|
||||
|
||||
function getEnglishAPs(blocks: (T.Rendered<T.SubjectSelectionComplete> | T.Rendered<T.APSelection> | T.RenderedVPSBlock)[]) {
|
||||
|
@ -339,6 +335,16 @@ function getEnglishAPs(blocks: (T.Rendered<T.SubjectSelectionComplete> | T.Rende
|
|||
}, "");
|
||||
}
|
||||
|
||||
function putKidsInKidsSection(blocks: T.Block[], kids: T.Kid[]): (T.Block | T.Kid)[] {
|
||||
const first = blocks[0];
|
||||
const rest = blocks.slice(1);
|
||||
return [
|
||||
first,
|
||||
...kids,
|
||||
...rest,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
function mergeSegments(s1: Segment, s2: Segment, noSpace?: "no space"): Segment {
|
||||
if (noSpace) {
|
||||
|
@ -405,10 +411,11 @@ function compileEnglishEP(EP: T.EPRendered): string[] | undefined {
|
|||
function insertEWords(e: string, { subject, predicate, APs }: { subject: string, predicate: string, APs: string }): string {
|
||||
return e.replace("$SUBJ", subject).replace("$PRED", predicate || "") + APs;
|
||||
}
|
||||
const engSubjR = getRenderedSubjectSelection(EP.blocks).selection;
|
||||
const engSubjR = getSubjectSelectionFromBlocks(EP.blocks).selection;
|
||||
const engPredR = getPredicateSelectionFromBlocks(EP.blocks).selection;
|
||||
const engSubj = getEnglishFromRendered(engSubjR);
|
||||
const engPred = getEnglishFromRendered(EP.predicate);
|
||||
const engAPs = getEnglishAPs(EP.blocks);
|
||||
const engPred = getEnglishFromRendered(engPredR);
|
||||
const engAPs = getEngAPs(EP.blocks);
|
||||
// require all English parts for making the English phrase
|
||||
const b = (EP.englishBase && engSubj && engPred)
|
||||
? EP.englishBase.map(e => insertEWords(e, {
|
||||
|
@ -440,7 +447,33 @@ export function orderKidsSection(kids: Segment[]): Segment[] {
|
|||
});
|
||||
}
|
||||
|
||||
export function checkForMiniPronounsError(s: T.EPSelectionState | T.VPSelectionState): undefined | string {
|
||||
export function checkEPForMiniPronounsError(s: T.EPSelectionState): undefined | string {
|
||||
function findDuplicateMiniP(mp: T.MiniPronoun[]): T.MiniPronoun | undefined {
|
||||
const duplicates = mp.filter((item, index) => (
|
||||
mp.findIndex(m => item.ps.p === m.ps.p) !== index
|
||||
));
|
||||
if (duplicates.length === 0) return undefined;
|
||||
return duplicates[0];
|
||||
}
|
||||
const kids = (() => {
|
||||
const EPS = completeEPSelection(s);
|
||||
if (!EPS) return undefined;
|
||||
const { kids } = renderEP(EPS);
|
||||
return kids;
|
||||
})();
|
||||
if (!kids) return undefined;
|
||||
const miniPronouns = kids.filter(x => x.type === "mini-pronoun") as T.MiniPronoun[];
|
||||
if (miniPronouns.length > 2) {
|
||||
return "can't add another mini-pronoun, there are alread two";
|
||||
}
|
||||
const duplicateMiniPronoun = findDuplicateMiniP(miniPronouns);
|
||||
if (duplicateMiniPronoun) {
|
||||
return `there's already a ${duplicateMiniPronoun.ps.p} - ${duplicateMiniPronoun.ps.f} mini-pronoun in use, can't have two of those`;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function checkForMiniPronounsError(s: T.VPSelectionState): undefined | string {
|
||||
function findDuplicateMiniPronoun(mp: Segment[]): Segment | undefined {
|
||||
const duplicates = mp.filter((item, index) => (
|
||||
mp.findIndex(m => item.ps[0].p === m.ps[0].p) !== index
|
||||
|
@ -449,12 +482,6 @@ export function checkForMiniPronounsError(s: T.EPSelectionState | T.VPSelectionS
|
|||
return duplicates[0];
|
||||
}
|
||||
const kids = (() => {
|
||||
if ("predicate" in s) {
|
||||
const EPS = completeEPSelection(s);
|
||||
if (!EPS) return undefined;
|
||||
const { kids } = getEPSegmentsAndKids(renderEP(EPS));
|
||||
return kids;
|
||||
}
|
||||
const VPS = completeVPSelection(s);
|
||||
if (!VPS) return undefined;
|
||||
const { kids } = getVPSegmentsAndKids(renderVP(VPS));
|
||||
|
@ -536,44 +563,6 @@ function findPossesivesInAdjective(a: T.Rendered<T.AdjectiveSelection>): T.Rende
|
|||
return findPossesivesInNP(a.sandwich.inside);
|
||||
}
|
||||
|
||||
type FoundNP = {
|
||||
np: T.Rendered<T.NPSelection>,
|
||||
from: "subject" | "predicate" | "AP",
|
||||
};
|
||||
|
||||
export function findPossesivesToShrinkInEP(EP: T.EPRendered): FoundNP[] {
|
||||
const inBlocks: FoundNP[] = EP.blocks.reduce((accum, block): FoundNP[] => {
|
||||
if (block.type === "subjectSelection") {
|
||||
if (EP.omitSubject) return accum;
|
||||
const found: FoundNP[] = findPossesivesInNP(block.selection).map(np => ({ np, from: "subject" }));
|
||||
return [
|
||||
...accum,
|
||||
...found,
|
||||
];
|
||||
}
|
||||
if (block.selection.type === "sandwich") {
|
||||
const found: FoundNP[] = findPossesivesInNP(block.selection.inside).map(np => ({ np, from: "AP" }));
|
||||
return [
|
||||
...accum,
|
||||
...found,
|
||||
];
|
||||
}
|
||||
return accum;
|
||||
}, [] as FoundNP[]);
|
||||
const inPredicate: FoundNP[] = ((EP.predicate.selection.type === "loc. adv.")
|
||||
? []
|
||||
: (EP.predicate.selection.type === "adjective")
|
||||
? findPossesivesInAdjective(EP.predicate.selection)
|
||||
: EP.predicate.selection.type === "sandwich"
|
||||
? findPossesivesInNP(EP.predicate.selection.inside)
|
||||
: EP.predicate.selection.type === "pronoun"
|
||||
? []
|
||||
: findPossesivesInNP({ type: "NP", selection: EP.predicate.selection })).map(np => ({ np, from: "predicate" }));
|
||||
return [
|
||||
...inBlocks,
|
||||
...inPredicate,
|
||||
];
|
||||
}
|
||||
|
||||
// export function findPossesiveToShrinkInVP(VP: T.VPRendered): T.Rendered<T.NPSelection>[] {
|
||||
// const obj: T.Rendered<T.NPSelection> | undefined = ("object" in VP && typeof VP.object === "object")
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
getPersonFromNP,
|
||||
} from "./vp-tools";
|
||||
import { renderNPSelection } from "./render-np";
|
||||
import { getPersonFromVerbForm } from "../../lib/misc-helpers";
|
||||
import { getFirstSecThird, getPersonFromVerbForm } from "../../lib/misc-helpers";
|
||||
import { getVerbBlockPosFromPerson } from "../misc-helpers";
|
||||
import { getEnglishWord } from "../get-english-word";
|
||||
import { psStringFromEntry } from "../p-text-helpers";
|
||||
|
@ -12,39 +12,143 @@ import { isLocativeAdverbEntry } from "../type-predicates";
|
|||
import { renderAdjectiveSelection } from "./render-adj";
|
||||
import { renderSandwich } from "./render-sandwich";
|
||||
import { EPSBlocksAreComplete, getSubjectSelection } from "./blocks-utils";
|
||||
import { removeAccentsWLength } from "../accent-helpers";
|
||||
import { pronouns } from "../grammar-units";
|
||||
|
||||
export function renderEP(EP: T.EPSelectionComplete): T.EPRendered {
|
||||
const subject = getSubjectSelection(EP.blocks).selection;
|
||||
const king = (subject.selection.type === "pronoun")
|
||||
? "subject"
|
||||
: EP.predicate.type === "NP"
|
||||
? "predicate"
|
||||
: "subject";
|
||||
// TODO: less repetative logic
|
||||
const kingPerson = king === "subject"
|
||||
? getPersonFromNP(subject)
|
||||
: EP.predicate.type === "NP"
|
||||
? getPersonFromNP(EP.predicate.selection)
|
||||
: getPersonFromNP(subject);
|
||||
const kingIsParticiple = king === "subject"
|
||||
? (subject.selection.type === "participle")
|
||||
: (EP.predicate.type === "NP" && EP.predicate.selection.selection.type === "participle");
|
||||
const { kids, blocks, englishEquativePerson } = getEPSBlocksAndKids(EP);
|
||||
return {
|
||||
type: "EPRendered",
|
||||
king: EP.predicate.type === "Complement" ? "subject" : "predicate",
|
||||
blocks: renderEPSBlocks(EP.blocks, king),
|
||||
predicate: EP.predicate.type === "NP"
|
||||
? renderNPSelection(EP.predicate.selection, false, true, "subject", "king")
|
||||
: renderEqCompSelection(EP.predicate.selection, kingPerson),
|
||||
equative: renderEquative(EP.equative, kingPerson),
|
||||
blocks,
|
||||
kids,
|
||||
englishBase: equativeBuilders[EP.equative.tense](
|
||||
kingIsParticiple ? T.Person.ThirdSingMale : kingPerson,
|
||||
englishEquativePerson,
|
||||
EP.equative.negative,
|
||||
),
|
||||
omitSubject: EP.omitSubject,
|
||||
};
|
||||
}
|
||||
|
||||
function getEPSBlocksAndKids(EP: T.EPSelectionComplete): { kids: T.Kid[], blocks: T.Block[], englishEquativePerson: T.Person } {
|
||||
const subject = getSubjectSelection(EP.blocks).selection;
|
||||
const commandingNP: T.NPSelection = subject.selection.type === "pronoun"
|
||||
? subject
|
||||
: EP.predicate.selection.type === "NP"
|
||||
? EP.predicate.selection
|
||||
: subject;
|
||||
const commandingPerson = getPersonFromNP(commandingNP);
|
||||
const equative: T.EquativeBlock = { type: "equative", equative: renderEquative(EP.equative, commandingPerson) };
|
||||
const blocks: T.Block[] = [
|
||||
...renderEPSBlocks(EP.omitSubject ? EP.blocks.filter(b => b.block.type !== "subjectSelection") : EP.blocks),
|
||||
{
|
||||
type: "predicateSelection",
|
||||
selection: EP.predicate.selection.type === "NP"
|
||||
? renderNPSelection(EP.predicate.selection, false, false, "subject", "king")
|
||||
: renderEqCompSelection(EP.predicate.selection, commandingPerson),
|
||||
},
|
||||
...EP.equative.negative ? [{ type: "nu" } as T.Block] : [],
|
||||
EP.equative.negative ? removeAccontsFromEq(equative) : equative,
|
||||
];
|
||||
const miniPronouns = findPossesivesToShrink([...EP.blocks, EP.predicate], EP.omitSubject);
|
||||
const kids: T.Kid[] = orderKids([
|
||||
...equative.equative.hasBa ? [{ type: "ba" } as T.Kid] : [],
|
||||
...miniPronouns,
|
||||
]);
|
||||
return {
|
||||
blocks,
|
||||
kids,
|
||||
englishEquativePerson: commandingNP.selection.type === "participle" ? T.Person.ThirdSingMale : commandingPerson,
|
||||
};
|
||||
}
|
||||
|
||||
function orderKids(kids: T.Kid[]): T.Kid[] {
|
||||
const sorted = [...kids].sort((a, b) => {
|
||||
// ba first
|
||||
if (a.type === "ba") return -1;
|
||||
// kinds lined up 1st 2nd 3rd person
|
||||
if (a.type === "mini-pronoun" && b.type === "mini-pronoun") {
|
||||
const aPers = getFirstSecThird(a.person);
|
||||
const bPers = getFirstSecThird(b.person);
|
||||
if (aPers < bPers) {
|
||||
return -1;
|
||||
}
|
||||
if (aPers > bPers) {
|
||||
return 1;
|
||||
}
|
||||
// TODO: is this enough?
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return sorted;
|
||||
}
|
||||
|
||||
function findPossesivesToShrink(blocks: (T.EPSBlockComplete | T.SubjectSelectionComplete | T.PredicateSelectionComplete | T.APSelection)[], omitSubject: boolean): T.MiniPronoun[] {
|
||||
return blocks.reduce((kids, item) => {
|
||||
const block = "block" in item ? item.block : item;
|
||||
if (block.type === "subjectSelection") {
|
||||
if (omitSubject) return kids;
|
||||
return [
|
||||
...kids,
|
||||
...findShrunkenPossInNP(block.selection),
|
||||
];
|
||||
}
|
||||
if (block.type === "AP") {
|
||||
if (block.selection.type === "adverb") return kids;
|
||||
return [
|
||||
...kids,
|
||||
...findShrunkenPossInNP(block.selection.inside),
|
||||
];
|
||||
}
|
||||
if (block.type === "predicateSelection") {
|
||||
if (block.selection.type === "EQComp") {
|
||||
if (block.selection.selection.type === "sandwich") {
|
||||
return [
|
||||
...kids,
|
||||
...findShrunkenPossInNP(block.selection.selection.inside),
|
||||
];
|
||||
}
|
||||
return kids;
|
||||
}
|
||||
return [
|
||||
...kids,
|
||||
...findShrunkenPossInNP(block.selection),
|
||||
];
|
||||
}
|
||||
return kids;
|
||||
}, [] as T.MiniPronoun[]);
|
||||
}
|
||||
|
||||
function findShrunkenPossInNP(NP: T.NPSelection): T.MiniPronoun[] {
|
||||
if (NP.selection.type === "pronoun") return [];
|
||||
if (!NP.selection.possesor) return [];
|
||||
if (NP.selection.type === "noun") {
|
||||
if (NP.selection.adjectives) {
|
||||
const { adjectives, ...rest } = NP.selection;
|
||||
return [
|
||||
// TODO: ability to find possesives shrinkage in sandwiches in adjectives
|
||||
// ...findShrunkenPossInAdjectives(adjectives),
|
||||
...findShrunkenPossInNP({ type: "NP", selection: {
|
||||
...rest,
|
||||
adjectives: [],
|
||||
}}),
|
||||
];
|
||||
}
|
||||
}
|
||||
if (NP.selection.possesor.shrunken) {
|
||||
const person = getPersonFromNP(NP.selection.possesor.np);
|
||||
const miniP: T.MiniPronoun = {
|
||||
type: "mini-pronoun",
|
||||
person,
|
||||
ps: getMiniPronounPs(person),
|
||||
source: "possesive",
|
||||
np: NP.selection.possesor.np,
|
||||
};
|
||||
return [miniP];
|
||||
}
|
||||
return findShrunkenPossInNP(NP.selection.possesor.np);
|
||||
}
|
||||
|
||||
export function getEquativeForm(tense: T.EquativeTense): { hasBa: boolean, form: T.SingleOrLengthOpts<T.VerbBlock> } {
|
||||
const hasBa = (tense === "future" || tense === "wouldBe");
|
||||
const baseTense = (tense === "future")
|
||||
|
@ -58,7 +162,7 @@ export function getEquativeForm(tense: T.EquativeTense): { hasBa: boolean, form:
|
|||
}
|
||||
}
|
||||
|
||||
function renderEPSBlocks(blocks: T.EPSBlockComplete[], king: "subject" | "predicate"): (T.Rendered<T.SubjectSelectionComplete> | T.Rendered<T.APSelection>)[] {
|
||||
function renderEPSBlocks(blocks: T.EPSBlockComplete[]): T.Block[] {
|
||||
return blocks.map(({ block }): (T.Rendered<T.SubjectSelectionComplete> | T.Rendered<T.APSelection>) => {
|
||||
if (block.type === "AP") {
|
||||
if (block.selection.type === "adverb") {
|
||||
|
@ -76,7 +180,7 @@ function renderEPSBlocks(blocks: T.EPSBlockComplete[], king: "subject" | "predic
|
|||
}
|
||||
return {
|
||||
type: "subjectSelection",
|
||||
selection: renderNPSelection(block.selection, false, false, "subject", king === "subject" ? "king" : "none")
|
||||
selection: renderNPSelection(block.selection, false, false, "subject", "none")
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -218,7 +322,7 @@ export function completeEPSelection(eps: T.EPSelectionState): T.EPSelectionCompl
|
|||
...eps,
|
||||
blocks: eps.blocks,
|
||||
predicate: {
|
||||
type: "Complement",
|
||||
type: "predicateSelection",
|
||||
selection,
|
||||
},
|
||||
};
|
||||
|
@ -230,8 +334,23 @@ export function completeEPSelection(eps: T.EPSelectionState): T.EPSelectionCompl
|
|||
...eps,
|
||||
blocks: eps.blocks,
|
||||
predicate: {
|
||||
type: "NP",
|
||||
type: "predicateSelection",
|
||||
selection,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getMiniPronounPs(person: T.Person): T.PsString {
|
||||
const [row, col] = getVerbBlockPosFromPerson(person);
|
||||
return pronouns.mini[row][col][0];
|
||||
}
|
||||
|
||||
function removeAccontsFromEq(equ: T.EquativeBlock): T.EquativeBlock {
|
||||
return {
|
||||
...equ,
|
||||
equative: {
|
||||
...equ.equative,
|
||||
ps: removeAccentsWLength(equ.equative.ps),
|
||||
},
|
||||
};
|
||||
}
|
|
@ -5,8 +5,6 @@ import {
|
|||
import {
|
||||
concatPsString,
|
||||
} from "../p-text-helpers";
|
||||
// SEGMENT TOOLS
|
||||
// TODO: PULL OUT FOR SHARING ACROSS COMPILE EP ETC?
|
||||
|
||||
type SegmentDescriptions = {
|
||||
isVerbHead?: boolean,
|
||||
|
|
47
src/types.ts
47
src/types.ts
|
@ -552,6 +552,11 @@ export type SubjectSelectionComplete = {
|
|||
selection: NPSelection,
|
||||
};
|
||||
|
||||
export type PredicateSelectionComplete = {
|
||||
type: "predicateSelection",
|
||||
selection: EqCompSelection | NPSelection,
|
||||
};
|
||||
|
||||
export type ObjectSelectionComplete = {
|
||||
type: "objectSelection",
|
||||
selection: NPSelection | ObjectNP,
|
||||
|
@ -695,6 +700,7 @@ export type Rendered<
|
|||
| EqCompSelection["selection"]
|
||||
| SubjectSelectionComplete
|
||||
| ObjectSelectionComplete
|
||||
| PredicateSelectionComplete
|
||||
| AdjectiveSelection
|
||||
| SandwichSelection<Sandwich>
|
||||
> =
|
||||
|
@ -744,7 +750,11 @@ export type Rendered<
|
|||
type: "objectSelection",
|
||||
selection: Rendered<NPSelection> | Person.ThirdPlurMale | "none",
|
||||
}
|
||||
: ReplaceKey<
|
||||
: T extends PredicateSelectionComplete
|
||||
? {
|
||||
type: "predicateSelection",
|
||||
selection: Rendered<EqCompSelection> | Rendered<NPSelection>,
|
||||
} : ReplaceKey<
|
||||
Omit<T, "changeGender" | "changeNumber" | "changeDistance" | "adjectives" | "possesor">,
|
||||
"e",
|
||||
string
|
||||
|
@ -794,13 +804,7 @@ export type VPSBlockComplete = {
|
|||
|
||||
export type EPSelectionComplete = Omit<EPSelectionState, "predicate" | "blocks"> & {
|
||||
blocks: EPSBlockComplete[],
|
||||
predicate: {
|
||||
type: "NP",
|
||||
selection: NPSelection,
|
||||
} | {
|
||||
type: "Complement",
|
||||
selection: EqCompSelection,
|
||||
},
|
||||
predicate: PredicateSelectionComplete,
|
||||
omitSubject: boolean,
|
||||
};
|
||||
|
||||
|
@ -834,10 +838,8 @@ export type EquativeRendered = EquativeSelection & {
|
|||
|
||||
export type EPRendered = {
|
||||
type: "EPRendered",
|
||||
king: "subject" | "predicate",
|
||||
blocks: (Rendered<SubjectSelectionComplete> | Rendered<APSelection>)[],
|
||||
predicate: Rendered<NPSelection> | Rendered<EqCompSelection>,
|
||||
equative: EquativeRendered,
|
||||
blocks: Block[],
|
||||
kids: Kid[],
|
||||
englishBase?: string[],
|
||||
omitSubject: boolean,
|
||||
}
|
||||
|
@ -863,3 +865,24 @@ export type EntryLookupPortal<X extends VerbEntry | DictionaryEntry> = {
|
|||
getByTs: (ts: number) => (X | undefined),
|
||||
}
|
||||
|
||||
export type EquativeBlock = { type: "equative", equative: EquativeRendered };
|
||||
|
||||
export type Block =
|
||||
| Rendered<SubjectSelectionComplete>
|
||||
| Rendered<APSelection>
|
||||
| Rendered<PredicateSelectionComplete>
|
||||
| { type: "nu" }
|
||||
| EquativeBlock;
|
||||
|
||||
export type Kid =
|
||||
| { type: "ba" }
|
||||
| MiniPronoun;
|
||||
|
||||
export type MiniPronoun = {
|
||||
type: "mini-pronoun",
|
||||
person: Person,
|
||||
ps: PsString,
|
||||
source: "servant" | "possesive",
|
||||
np: NPSelection,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue