Ability to use complements in the phrase builder with kawul/kedul stative! This is still a bit messy, and I should somehow get the "verbComplement" types deprecated

This commit is contained in:
lingdocs 2022-07-10 16:29:23 -05:00
parent 66fd580411
commit c3170f65f5
22 changed files with 359 additions and 136 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@lingdocs/pashto-inflector", "name": "@lingdocs/pashto-inflector",
"version": "3.3.1", "version": "3.3.2",
"author": "lingdocs.com", "author": "lingdocs.com",
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations", "description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
"homepage": "https://verbs.lingdocs.com", "homepage": "https://verbs.lingdocs.com",

View File

@ -1,32 +1,37 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import * as T from "../../../types"; import * as T from "../types";
import AdjectivePicker from "../../np-picker/AdjectivePicker"; import AdjectivePicker from "./np-picker/AdjectivePicker";
import LocativeAdverbPicker from "./LocativeAdverbPicker"; import LocativeAdverbPicker from "./ep-explorer/eq-comp-picker/LocativeAdverbPicker";
import SandwichPicker from "../../np-picker/SandwichPicker"; import SandwichPicker from "./np-picker/SandwichPicker";
const compTypes: T.EqCompType[] = ["adjective", "loc. adv.", "sandwich"]; const compTypes: T.ComplementType[] = ["adjective", "loc. adv.", "sandwich", "comp. noun"];
function EqCompPicker(props: { function selectionTypeToCompType(s: Exclude<T.ComplementType, "comp. noun"> | "noun"): T.ComplementType {
if (s === "noun") return "comp. noun";
return s;
}
function ComplementPicker(props: {
phraseIsComplete: boolean, phraseIsComplete: boolean,
onChange: (comp: T.EqCompSelection | undefined) => void, onChange: (comp: T.ComplementSelection | undefined) => void,
comp: T.EqCompSelection | undefined, comp: T.ComplementSelection | undefined,
opts: T.TextOptions, opts: T.TextOptions,
cantClear?: boolean, cantClear?: boolean,
heading?: JSX.Element | string, heading?: JSX.Element | string,
entryFeeder: T.EntryFeeder, entryFeeder: T.EntryFeeder,
}) { }) {
const [compType, setCompType] = useState<T.EqCompType | undefined>(props.comp const [compType, setCompType] = useState<T.ComplementType | undefined>(props.comp
? props.comp.selection.type ? selectionTypeToCompType(props.comp.selection.type)
: undefined); : undefined);
useEffect(() => { useEffect(() => {
setCompType(props.comp setCompType(props.comp
? props.comp.selection.type ? selectionTypeToCompType(props.comp.selection.type)
: undefined); : undefined);
}, [props.comp]); }, [props.comp]);
function handleClear() { function handleClear() {
setCompType(undefined); setCompType(undefined);
props.onChange(undefined); props.onChange(undefined);
} }
function handleCompTypeChange(ctp: T.EqCompType) { function handleCompTypeChange(ctp: T.ComplementType) {
props.onChange(undefined); props.onChange(undefined);
setCompType(ctp); setCompType(ctp);
} }
@ -70,7 +75,7 @@ function EqCompPicker(props: {
entryFeeder={props.entryFeeder} entryFeeder={props.entryFeeder}
adjective={props.comp?.selection.type === "adjective" ? props.comp.selection : undefined} adjective={props.comp?.selection.type === "adjective" ? props.comp.selection : undefined}
opts={props.opts} opts={props.opts}
onChange={(a) => props.onChange(a ? { type: "EQComp", selection: a } : undefined)} onChange={(a) => props.onChange(a ? { type: "complement", selection: a } : undefined)}
phraseIsComplete={props.phraseIsComplete} phraseIsComplete={props.phraseIsComplete}
/> />
: compType === "loc. adv." : compType === "loc. adv."
@ -78,11 +83,11 @@ function EqCompPicker(props: {
entryFeeder={props.entryFeeder.locativeAdverbs} entryFeeder={props.entryFeeder.locativeAdverbs}
adjective={props.comp?.selection.type === "loc. adv." ? props.comp.selection : undefined} adjective={props.comp?.selection.type === "loc. adv." ? props.comp.selection : undefined}
opts={props.opts} opts={props.opts}
onChange={(a) => props.onChange(a ? { type: "EQComp", selection: a } : undefined)} onChange={(a) => props.onChange(a ? { type: "complement", selection: a } : undefined)}
/> />
: compType === "sandwich" : compType === "sandwich"
? <SandwichPicker ? <SandwichPicker
onChange={(a) => props.onChange(a ? { type: "EQComp", selection: a } : undefined)} onChange={(a) => props.onChange(a ? { type: "complement", selection: a } : undefined)}
opts={props.opts} opts={props.opts}
sandwich={props.comp?.selection.type === "sandwich" ? props.comp.selection : undefined} sandwich={props.comp?.selection.type === "sandwich" ? props.comp.selection : undefined}
entryFeeder={props.entryFeeder} entryFeeder={props.entryFeeder}
@ -90,9 +95,13 @@ function EqCompPicker(props: {
// TODO: get phraseIsComplete working here // TODO: get phraseIsComplete working here
phraseIsComplete={props.phraseIsComplete} phraseIsComplete={props.phraseIsComplete}
/> />
: compType === "comp. noun"
? <div style={{ maxWidth: "9rem" }}>
Sorry, can't choose complement nouns yet 🚧
</div>
: null} : null}
</div> </div>
</>; </>;
} }
export default EqCompPicker; export default ComplementPicker;

View File

@ -30,8 +30,8 @@ function Block({ opts, block, king, script }: {
const english = getEnglishFromRendered(block.block.selection); const english = getEnglishFromRendered(block.block.selection);
return <div className="text-center"> return <div className="text-center">
<div><strong>Predicate</strong></div> <div><strong>Predicate</strong></div>
{block.block.selection.type === "EQComp" {block.block.selection.type === "complement"
? <EqCompBlock opts={opts} comp={block.block.selection.selection} script={script} /> ? <ComplementBlock opts={opts} comp={block.block.selection.selection} script={script} />
: <NPBlock opts={opts} english={english} script={script}>{block.block.selection}</NPBlock>} : <NPBlock opts={opts} english={english} script={script}>{block.block.selection}</NPBlock>}
</div> </div>
} }
@ -63,6 +63,9 @@ function Block({ opts, block, king, script }: {
if (block.block.type === "modalVerbKedulPart") { if (block.block.type === "modalVerbKedulPart") {
return <ModalAuxBlock opts={opts} aux={block.block} script={script} /> return <ModalAuxBlock opts={opts} aux={block.block} script={script} />
} }
if (block.block.type === "complement") {
return <ComplementBlock opts={opts} comp={block.block.selection} script={script} />;
}
return null; return null;
} }
@ -99,7 +102,12 @@ function VerbSBlock({ opts, v, script }: {
return <div className="text-center"> return <div className="text-center">
{"long" in v.ps && <div className="clickable small mb-1" onClick={changeLength}>{length}</div>} {"long" in v.ps && <div className="clickable small mb-1" onClick={changeLength}>{length}</div>}
<Border> <Border>
<>
{v.type === "verb" && v.complement && <span className="mx-2">
<ComplementBlock opts={opts} comp={v.complement.selection} script={script} inside />
</span>}
{getLength(v.ps, length)[0][script]} {getLength(v.ps, length)[0][script]}
</>
</Border> </Border>
<div>{v.type === "perfectParticipleBlock" ? "Past Partic." : "Verb"}</div> <div>{v.type === "perfectParticipleBlock" ? "Past Partic." : "Verb"}</div>
<EnglishBelow>{((v.type === "perfectParticipleBlock" ? "Past Partic." : "Verb") <EnglishBelow>{((v.type === "perfectParticipleBlock" ? "Past Partic." : "Verb")
@ -244,10 +252,11 @@ function ObjectBlock({ opts, obj, role, script }: {
</div>; </div>;
} }
function EqCompBlock({ opts, comp, script }: { function ComplementBlock({ opts, comp, script, inside }: {
script: "p" | "f", script: "p" | "f",
opts: T.TextOptions, opts: T.TextOptions,
comp: T.Rendered<T.EqCompSelection["selection"]>, comp: T.Rendered<T.ComplementSelection["selection"]> | T.Rendered<T.UnselectedComplementSelection>["selection"],
inside?: boolean,
}) { }) {
function AdjectiveBlock({ opts, adj }: { function AdjectiveBlock({ opts, adj }: {
opts: T.TextOptions, opts: T.TextOptions,
@ -274,18 +283,31 @@ function EqCompBlock({ opts, comp, script }: {
<EnglishBelow>{adv.e}</EnglishBelow> <EnglishBelow>{adv.e}</EnglishBelow>
</div>; </div>;
} }
return <div className="text-center"> return <div className="text-center">
<div>Comp.</div> <div>Comp.</div>
{comp.type === "adjective" {comp.type === "adjective"
? <AdjectiveBlock opts={opts} adj={comp} /> ? <AdjectiveBlock opts={opts} adj={comp} />
: comp.type === "loc. adv." : comp.type === "loc. adv."
? <LocAdvBlock opts={opts} adv={comp} /> ? <LocAdvBlock opts={opts} adv={comp} />
: <div> : comp.type === "noun"
<Sandwich opts={opts} sandwich={comp} script={script} /> ? <Border>
<div>Sandwich</div> NOT DONE YET
</Border>
: comp.type === "unselected"
? <div>
<Border>
____
</Border>
{!inside && <>
<div>&nbsp;</div>
<EnglishBelow>{comp.e}</EnglishBelow> <EnglishBelow>{comp.e}</EnglishBelow>
</div>} </>}
</div>
: <div>
<Sandwich opts={opts} sandwich={comp} script={script} />
<div>Sandwich</div>
<EnglishBelow>{comp.e}</EnglishBelow>
</div>}
</div>; </div>;
} }

View File

@ -2,7 +2,7 @@ import * as T from "../../types";
import NPPicker from "../np-picker/NPPicker"; import NPPicker from "../np-picker/NPPicker";
import EquativePicker from "./EquativePicker"; import EquativePicker from "./EquativePicker";
import ButtonSelect from "../ButtonSelect"; import ButtonSelect from "../ButtonSelect";
import EqCompPicker from "./eq-comp-picker/EqCompPicker"; import ComplementPicker from "../ComplementPicker";
import epsReducer, { EpsReducerAction } from "./eps-reducer"; import epsReducer, { EpsReducerAction } from "./eps-reducer";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { completeEPSelection } from "../../lib/phrase-building/render-ep"; import { completeEPSelection } from "../../lib/phrase-building/render-ep";
@ -92,10 +92,10 @@ function EPPicker({ opts, eps, onChange, entryFeeder }: {
role="subject" role="subject"
onChange={payload => adjustEps({ type: "set predicate NP", payload })} onChange={payload => adjustEps({ type: "set predicate NP", payload })}
opts={opts} opts={opts}
/> : <EqCompPicker /> : <ComplementPicker
phraseIsComplete={phraseIsComplete} phraseIsComplete={phraseIsComplete}
comp={eps.predicate.type === "Complement" ? eps.predicate.Complement : undefined} comp={eps.predicate.type === "Complement" ? eps.predicate.Complement : undefined}
onChange={payload => adjustEps({ type: "set predicate comp", payload })} onChange={payload => adjustEps({ type: "set predicate complement", payload })}
opts={opts} opts={opts}
entryFeeder={entryFeeder} entryFeeder={entryFeeder}
/>} />}

View File

@ -17,8 +17,8 @@ export type EpsReducerAction = {
type: "set predicate NP", type: "set predicate NP",
payload: T.NPSelection | undefined, payload: T.NPSelection | undefined,
} | { } | {
type: "set predicate comp", type: "set predicate complement",
payload: T.EqCompSelection | undefined, payload: T.ComplementSelection | undefined,
} | { } | {
type: "set omitSubject", type: "set omitSubject",
payload: "true" | "false", payload: "true" | "false",
@ -134,7 +134,7 @@ export default function epsReducer(eps: T.EPSelectionState, action: EpsReducerAc
}; };
return selection ? ensureMiniPronounsOk(eps, n, sendAlert) : n; return selection ? ensureMiniPronounsOk(eps, n, sendAlert) : n;
} }
if (action.type === "set predicate comp") { if (action.type === "set predicate complement") {
return { return {
...eps, ...eps,
predicate: { predicate: {

View File

@ -486,6 +486,7 @@ function getRandomVPSelection(mix: MixType = "both") {
)), )),
verb: randomizeTense(verb, true), verb: randomizeTense(verb, true),
form: { removeKing: false, shrinkServant: false }, form: { removeKing: false, shrinkServant: false },
externalComplement: undefined,
} }
} }
return { return {
@ -501,6 +502,7 @@ function getRandomVPSelection(mix: MixType = "both") {
)), )),
verb: randomizeTense(verb, true), verb: randomizeTense(verb, true),
form: { removeKing: false, shrinkServant: false }, form: { removeKing: false, shrinkServant: false },
externalComplement: undefined,
}; };
}; };
}; };

View File

@ -8,7 +8,13 @@ import VPExplorerExplanationModal, { roleIcon } from "./VPExplorerExplanationMod
import { vpsReducer, VpsReducerAction } from "./vps-reducer"; import { vpsReducer, VpsReducerAction } from "./vps-reducer";
import APPicker from "../ap-picker/APPicker"; import APPicker from "../ap-picker/APPicker";
import autoAnimate from "@formkit/auto-animate"; import autoAnimate from "@formkit/auto-animate";
import { getObjectSelection, getSubjectSelection, includesShrunkenServant, isNoObject } from "../../lib/phrase-building/blocks-utils"; import {
getObjectSelection,
getSubjectSelection,
includesShrunkenServant,
isNoObject,
} from "../../lib/phrase-building/blocks-utils";
import ComplementPicker from "../ComplementPicker";
function VPPicker({ opts, vps, onChange, entryFeeder }: { function VPPicker({ opts, vps, onChange, entryFeeder }: {
opts: T.TextOptions, opts: T.TextOptions,
@ -156,11 +162,6 @@ function VPPicker({ opts, vps, onChange, entryFeeder }: {
{!servantIsShrunk ? "🪄" : "👶"} {!servantIsShrunk ? "🪄" : "👶"}
</span> </span>
} }
{(rendered && rendered.whatsAdjustable !== "servant") &&
<span onClick={() => adjustVps({ type: "toggle king remove" })} className="mx-2 clickable">
{!VPS?.form.removeKing ? "🚫" : "🙈"}
</span>
}
</div>} </div>}
entryFeeder={entryFeeder} entryFeeder={entryFeeder}
role="object" role="object"
@ -175,6 +176,19 @@ function VPPicker({ opts, vps, onChange, entryFeeder }: {
: null} : null}
</div>; </div>;
})} })}
{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"
? undefined
: vps.externalComplement as T.ComplementSelection // TODO: just typescript being dumb? - looks like it
}
onChange={payload => adjustVps({ type: "set externalComplement", payload })}
opts={opts}
entryFeeder={entryFeeder}
/>
</div>}
<div className="my-2"> <div className="my-2">
<TensePicker <TensePicker
vps={vps} vps={vps}

View File

@ -71,10 +71,23 @@ export function makeVPSelectionState(
canChangeVoice: transitivity === "transitive", canChangeVoice: transitivity === "transitive",
canChangeStatDyn: "stative" in info, canChangeStatDyn: "stative" in info,
}, },
externalComplement: takesExternalComplement(verb)
? { type: "complement", selection: { type: "unselected" }}
: undefined,
form: os ? os.form : { removeKing: false, shrinkServant: false }, form: os ? os.form : { removeKing: false, shrinkServant: false },
}; };
} }
function takesExternalComplement(v: T.VerbEntry): boolean {
if (v.entry.p === "کول" && v.entry.e.includes("to make")) {
return true;
}
if (v.entry.p === "کېدل" && v.entry.e.includes("to become")) {
return true;
}
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); const info = getVerbInfo(v.verb.verb.entry, v.verb.verb.complement);
if (!("stative" in info)) { if (!("stative" in info)) {

View File

@ -74,7 +74,10 @@ export type VpsReducerAction = {
index: number, index: number,
direction: "back" | "forward", direction: "back" | "forward",
}, },
}; } | {
type: "set externalComplement",
payload: T.ComplementSelection | undefined,
}
export function vpsReducer(vps: T.VPSelectionState, action: VpsReducerAction, sendAlert?: (msg: string) => void): T.VPSelectionState { export function vpsReducer(vps: T.VPSelectionState, action: VpsReducerAction, sendAlert?: (msg: string) => void): T.VPSelectionState {
return ensureMiniPronounsOk(vps, doReduce()); return ensureMiniPronounsOk(vps, doReduce());
@ -291,6 +294,18 @@ export function vpsReducer(vps: T.VPSelectionState, action: VpsReducerAction, se
blocks: shiftBlock(vps.blocks, index, direction), blocks: shiftBlock(vps.blocks, index, direction),
}; };
} }
if (action.type === "set externalComplement") {
const selection = action.payload;
return {
...vps,
externalComplement: selection === undefined
// TODO: this is a bit messy
// when using the ComplementPicker with an EP - undefined means it hasn't been selected
// when using the ComplementPicker with a VP - undefined means there can be no complement
? { type: "complement", selection: { type: "unselected" }}
: selection,
}
}
throw new Error("unknown vpsReducer state"); throw new Error("unknown vpsReducer state");
} }
} }

View File

@ -99,7 +99,18 @@ export function getPredicateSelectionFromBlocks(blocks: T.Block[][]): T.Rendered
export function getAPsFromBlocks(blocks: T.Block[][]): 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>[]; return blocks[0].filter(b => b.block.type === "AP").map(b => b.block) as T.Rendered<T.APSelection>[];
} }
export function getComplementFromBlocks(blocks: T.Block[][]): T.Rendered<T.ComplementSelection> | T.Rendered<T.UnselectedComplementSelection> | undefined {
const complement = blocks[0].find(b => b.block.type === "complement");
if (!complement) {
return undefined;
}
if (complement.block.type !== "complement") {
throw new Error("error finding complement - other kind of block retrieved");
}
return complement.block;
}
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.ObjectSelection;
@ -256,7 +267,11 @@ export function removeAP<B extends T.VPSBlock[] | T.EPSBlock[]>(blocks: B, index
} }
export function isNoObject(b: T.VPSBlock["block"] | T.EPSBlock["block"]): b is { type: "objectSelection", 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"); 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[][] {

View File

@ -14,12 +14,12 @@ import { completeVPSelection } from "./vp-tools";
import { renderVP } from "./render-vp"; import { renderVP } from "./render-vp";
import { import {
getAPsFromBlocks, getAPsFromBlocks,
getComplementFromBlocks,
getObjectSelectionFromBlocks, getObjectSelectionFromBlocks,
getPredicateSelectionFromBlocks, getPredicateSelectionFromBlocks,
getSubjectSelectionFromBlocks, getSubjectSelectionFromBlocks,
getVerbFromBlocks, getVerbFromBlocks,
hasEquativeWithLengths, hasEquativeWithLengths,
hasVerbWithLengths,
specifyEquativeLength, specifyEquativeLength,
specifyVerbLength, specifyVerbLength,
} from "./blocks-utils"; } from "./blocks-utils";
@ -81,10 +81,14 @@ export function compileVP(VP: T.VPRendered, form: T.FormVersion, combineLengths?
} }
function compileVPPs(blocks: T.Block[][], kids: T.Kid[], form: T.FormVersion, king: "subject" | "object"): T.SingleOrLengthOpts<T.PsString[]> { function compileVPPs(blocks: T.Block[][], kids: T.Kid[], form: T.FormVersion, king: "subject" | "object"): T.SingleOrLengthOpts<T.PsString[]> {
if (hasVerbWithLengths(blocks)) { const verbBlock = getVerbFromBlocks(blocks);
if ("long" in verbBlock.block.ps) {
return { return {
long: compileVPPs(specifyVerbLength(blocks, "long"), kids, form, king) as T.PsString[], long: compileVPPs(specifyVerbLength(blocks, "long"), kids, form, king) as T.PsString[],
short: compileVPPs(specifyVerbLength(blocks, "short"), kids, form, king) as T.PsString[], short: compileVPPs(specifyVerbLength(blocks, "short"), kids, form, king) as T.PsString[],
..."mini" in verbBlock.block.ps ? {
mini: compileVPPs(specifyVerbLength(blocks, "mini"), kids, form, king) as T.PsString[],
} : {},
}; };
} }
const subjectPerson = getSubjectSelectionFromBlocks(blocks) const subjectPerson = getSubjectSelectionFromBlocks(blocks)
@ -94,6 +98,7 @@ function compileVPPs(blocks: T.Block[][], kids: T.Kid[], form: T.FormVersion, ki
kids, kids,
false, false,
); );
console.log({ blocksWKids });
return removeDuplicates(combineIntoText(blocksWKids, subjectPerson, {})); return removeDuplicates(combineIntoText(blocksWKids, subjectPerson, {}));
} }
@ -198,7 +203,7 @@ function getPsFromPiece(piece: T.Block | T.Kid, subjectPerson: T.Person): T.PsSt
return [piece.block.ps]; return [piece.block.ps];
} }
if (piece.block.type === "verbComplement") { if (piece.block.type === "verbComplement") {
return [{ p: "---", f: "---"}]; //getPashtoFromRendered(piece.block.complement); return [{ p: "____", f: "____"}]; //getPashtoFromRendered(piece.block.complement);
} }
if (piece.block.type === "objectSelection") { if (piece.block.type === "objectSelection") {
if (typeof piece.block.selection !== "object") { if (typeof piece.block.selection !== "object") {
@ -208,7 +213,11 @@ function getPsFromPiece(piece: T.Block | T.Kid, subjectPerson: T.Person): T.PsSt
} }
if (piece.block.type === "verb") { if (piece.block.type === "verb") {
// getLong is just for type safety - we will have split up the length options earlier in compileVPPs // getLong is just for type safety - we will have split up the length options earlier in compileVPPs
return getLong(piece.block.block.ps); const verbPs = getLong(piece.block.block.ps);
if (piece.block.block.complement) {
return combineComplementWVerbPs(piece.block.block.complement, verbPs);
}
return verbPs;
} }
if (piece.block.type === "perfectParticipleBlock") { if (piece.block.type === "perfectParticipleBlock") {
// getLong is just for type safety - we will have split up the length options earlier in compileVPPs // getLong is just for type safety - we will have split up the length options earlier in compileVPPs
@ -226,6 +235,13 @@ function getPsFromPiece(piece: T.Block | T.Kid, subjectPerson: T.Person): T.PsSt
// just using the short one for now - it will only be short anyways // just using the short one for now - it will only be short anyways
return getShort(piece.block.ps); return getShort(piece.block.ps);
} }
if (piece.block.type === "complement") {
if (piece.block.selection.type === "sandwich") {
// TODO: Kinda cheating
return getPashtoFromRendered({ type: "AP", selection: piece.block.selection }, false);
}
return piece.block.selection.ps;
}
} }
if ("kid" in piece) { if ("kid" in piece) {
if (piece.kid.type === "ba") { if (piece.kid.type === "ba") {
@ -235,10 +251,18 @@ function getPsFromPiece(piece: T.Block | T.Kid, subjectPerson: T.Person): T.PsSt
return [piece.kid.ps]; return [piece.kid.ps];
} }
} }
throw new Error("unrecognized piece type"); throw new Error("unrecognized piece type");
} }
function combineComplementWVerbPs(comp: T.Rendered<T.ComplementSelection | T.UnselectedComplementSelection>, v: T.PsString[]): T.PsString[] {
const compPs = comp.selection.type === "sandwich"
? getPashtoFromRendered({ type: "AP", selection: comp.selection }, false)
: comp.selection.ps;
return compPs.flatMap((c) => (
v.map((p) => concatPsString(c, " ", p))
));
}
function getEngAPs(blocks: T.Block[][]): string { function getEngAPs(blocks: T.Block[][]): string {
return getAPsFromBlocks(blocks).reduce((accum, curr) => { return getAPsFromBlocks(blocks).reduce((accum, curr) => {
const e = getEnglishFromRendered(curr); const e = getEnglishFromRendered(curr);
@ -247,6 +271,17 @@ function getEngAPs(blocks: T.Block[][]): string {
}, ""); }, "");
} }
function getEngComplement(blocks: T.Block[][]): string | undefined {
const comp = getComplementFromBlocks(blocks);
if (!comp) return undefined;
if (comp.selection === undefined) {
return "____";
}
if (comp.selection.type === "sandwich") {
return getEnglishFromRendered({ type: "AP", selection: comp.selection });
}
}
function putKidsInKidsSection(blocksWVars: T.Block[][], kids: T.Kid[], enforceKidsSectionBlankout: boolean): (T.Block | T.Kid | T.PsString)[][] { function putKidsInKidsSection(blocksWVars: T.Block[][], kids: T.Kid[], enforceKidsSectionBlankout: boolean): (T.Block | T.Kid | T.PsString)[][] {
function insert(blocks: T.Block[]): (T.Block | T.Kid | T.PsString)[] { function insert(blocks: T.Block[]): (T.Block | T.Kid | T.PsString)[] {
const first = blocks[0]; const first = blocks[0];
@ -261,8 +296,13 @@ function putKidsInKidsSection(blocksWVars: T.Block[][], kids: T.Kid[], enforceKi
} }
function compileEnglishVP(VP: T.VPRendered): string[] | undefined { function compileEnglishVP(VP: T.VPRendered): string[] | undefined {
function insertEWords(e: string, { subject, object, APs }: { subject: string, object?: string, APs: string }): string { function insertEWords(e: string, { subject, object, APs, complement }: { subject: string, object?: string, APs: string, complement: string | undefined }): string {
return e.replace("$SUBJ", subject).replace("$OBJ", object || "") + APs; return e
.replace("$SUBJ", subject)
.replace("$OBJ", object || "")
// TODO: check if this always works
+ (complement ? ` ${complement}` : "")
+ APs;
} }
const engSubj = getSubjectSelectionFromBlocks(VP.blocks).selection; const engSubj = getSubjectSelectionFromBlocks(VP.blocks).selection;
const obj = getObjectSelectionFromBlocks(VP.blocks).selection; const obj = getObjectSelectionFromBlocks(VP.blocks).selection;
@ -272,6 +312,7 @@ function compileEnglishVP(VP: T.VPRendered): string[] | undefined {
? "" ? ""
: undefined; : undefined;
const engAPs = getEngAPs(VP.blocks); const engAPs = getEngAPs(VP.blocks);
const engComplement = getEngComplement(VP.blocks);
// require all English parts for making the English phrase // require all English parts for making the English phrase
return (VP.englishBase && engSubj && engObj !== undefined) return (VP.englishBase && engSubj && engObj !== undefined)
? VP.englishBase.map(e => insertEWords(e, { ? VP.englishBase.map(e => insertEWords(e, {
@ -279,6 +320,7 @@ function compileEnglishVP(VP: T.VPRendered): string[] | undefined {
subject: getEnglishFromRendered(engSubj) || "", subject: getEnglishFromRendered(engSubj) || "",
object: engObj ? getEnglishFromRendered(engObj) : "", object: engObj ? getEnglishFromRendered(engObj) : "",
APs: engAPs, APs: engAPs,
complement: engComplement,
})).map(capitalizeFirstLetter) })).map(capitalizeFirstLetter)
: undefined; : undefined;
} }

View File

@ -41,9 +41,6 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
function isToBe(v: T.EnglishVerbConjugationEc): boolean { function isToBe(v: T.EnglishVerbConjugationEc): boolean {
return (v[2] === "being"); return (v[2] === "being");
} }
const futureEngBuilder: T.EnglishBuilder = (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
]);
// TODO: Pull these out to a seperate entity and import it // TODO: Pull these out to a seperate entity and import it
const basicBuilders: Record< const basicBuilders: Record<
T.VerbTense, T.VerbTense,
@ -59,8 +56,13 @@ export function renderEnglishVPBase({ subjectPerson, object, vs }: {
`that $SUBJ ${n ? " won't" : " will"} ${isToBe(ec) ? "be" : ec[0]}`, `that $SUBJ ${n ? " won't" : " will"} ${isToBe(ec) ? "be" : ec[0]}`,
`$SUBJ ${n ? " not" : ""} should ${isToBe(ec) ? "be" : ec[0]}`, `$SUBJ ${n ? " not" : ""} should ${isToBe(ec) ? "be" : ec[0]}`,
]), ]),
imperfectiveFuture: futureEngBuilder, imperfectiveFuture: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
perfectiveFuture: futureEngBuilder, `$SUBJ will${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
`$SUBJ will${n ? " not" : ""} be ${isToBe(ec) ? "be" : ec[2]}`,
]),
perfectiveFuture: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
`$SUBJ will${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
]),
imperfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([ imperfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
// - subj pastEquative (N && "not") ec.2 obj // - subj pastEquative (N && "not") ec.2 obj
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} ${ec[2]}`, `$SUBJ ${engEquative("past", s)}${n ? " not" : ""} ${ec[2]}`,

View File

@ -5,7 +5,7 @@ import {
import * as T from "../../types"; import * as T from "../../types";
import { concatPsString } from "../p-text-helpers"; import { concatPsString } from "../p-text-helpers";
function getBaseAndAdjectives({ selection }: T.Rendered<T.NPSelection | T.EqCompSelection | T.APSelection>): T.PsString[] { function getBaseAndAdjectives({ selection }: T.Rendered<T.NPSelection | T.ComplementSelection | T.APSelection>): T.PsString[] {
if (selection.type === "sandwich") { if (selection.type === "sandwich") {
return getSandwichPsBaseAndAdjectives(selection); return getSandwichPsBaseAndAdjectives(selection);
} }
@ -79,7 +79,7 @@ function trimOffShrunkenPossesive(p: T.Rendered<T.NPSelection>): T.Rendered<T.NP
}; };
} }
export function getPashtoFromRendered(b: T.Rendered<T.NPSelection> | T.Rendered<T.EqCompSelection> | T.Rendered<T.APSelection>, subjectsPerson: false | T.Person): T.PsString[] { export function getPashtoFromRendered(b: T.Rendered<T.NPSelection> | T.Rendered<T.ComplementSelection> | T.Rendered<T.APSelection>, subjectsPerson: false | T.Person): T.PsString[] {
const base = getBaseAndAdjectives(b); const base = getBaseAndAdjectives(b);
if (b.selection.type === "loc. adv." || b.selection.type === "adverb") { if (b.selection.type === "loc. adv." || b.selection.type === "adverb") {
return base; return base;
@ -88,6 +88,7 @@ export function getPashtoFromRendered(b: T.Rendered<T.NPSelection> | T.Rendered<
if (!b.selection.sandwich) { if (!b.selection.sandwich) {
return base return base
} }
// TODO: Kinda cheating
const sandwichPs = getPashtoFromRendered({ type: "AP", selection: b.selection.sandwich }, false); const sandwichPs = getPashtoFromRendered({ type: "AP", selection: b.selection.sandwich }, false);
return base.flatMap(p => ( return base.flatMap(p => (
sandwichPs.flatMap(s => ( sandwichPs.flatMap(s => (
@ -199,7 +200,10 @@ function pronounPossEng(p: T.Person): string {
return "their"; return "their";
} }
export function getEnglishFromRendered(r: T.Rendered<T.NPSelection | T.EqCompSelection | T.APSelection>): string | undefined { export function getEnglishFromRendered(r: T.Rendered<T.NPSelection | T.ComplementSelection | T.APSelection | T.SandwichSelection<T.Sandwich>>): string | undefined {
if (r.type === "sandwich") {
return getEnglishFromRenderedSandwich(r);
}
if (r.selection.type === "sandwich") { if (r.selection.type === "sandwich") {
return getEnglishFromRenderedSandwich(r.selection); return getEnglishFromRenderedSandwich(r.selection);
} }

View File

@ -18,30 +18,29 @@ function chooseInflection(inflections: T.UnisexSet<T.InflectionSet>, pers: T.Per
return inflections[gender][infNumber]; return inflections[gender][infNumber];
} }
export function renderAdjectiveSelection(a: T.AdjectiveSelection, person: T.Person, inflected: boolean, role: "king" | "servant" | "none"): T.Rendered<T.AdjectiveSelection> { export function inflectAdjective(a: T.AdjectiveSelection, person: T.Person, inflected: boolean): T.ArrayOneOrMore<T.PsString> {
const infs = inflectWord(a.entry); const infs = inflectWord(a.entry);
if (!infs) {
return [psStringFromEntry(a.entry)];
}
if (!infs.inflections || !isUnisexSet(infs.inflections)) {
throw new Error("error getting inflections for adjective, looks like a noun's inflections");
}
return chooseInflection(infs.inflections, person, inflected);
}
export function renderAdjectiveSelection(a: T.AdjectiveSelection, person: T.Person, inflected: boolean): T.Rendered<T.AdjectiveSelection> {
const eWord = getEnglishWord(a.entry); const eWord = getEnglishWord(a.entry);
const e = !eWord const e = !eWord
? undefined ? undefined
: typeof eWord === "string" : typeof eWord === "string"
? eWord ? eWord
: (eWord.singular || undefined); : (eWord.singular || undefined);
if (!infs) return { const ps = inflectAdjective(a, person, inflected);
type: "adjective",
entry: a.entry,
ps: [psStringFromEntry(a.entry)],
e,
inflected,
sandwich: a.sandwich ? renderSandwich(a.sandwich) : undefined,
person,
}
if (!infs.inflections || !isUnisexSet(infs.inflections)) {
throw new Error("error getting inflections for adjective, looks like a noun's inflections");
}
return { return {
type: "adjective", type: "adjective",
entry: a.entry, entry: a.entry,
ps: chooseInflection(infs.inflections, person, inflected), ps,
e, e,
inflected, inflected,
person, person,

View File

@ -32,7 +32,7 @@ export function findPossesivesToShrink(
]; ];
} }
if (block.type === "predicateSelection") { if (block.type === "predicateSelection") {
if (block.selection.type === "EQComp") { if (block.selection.type === "complement") {
if (block.selection.selection.type === "sandwich") { if (block.selection.selection.type === "sandwich") {
return [ return [
...kids, ...kids,

View File

@ -0,0 +1,55 @@
import * as T from "../../types";
import { renderNounSelection } from "./render-np";
import { getEnglishWord } from "../get-english-word";
import { psStringFromEntry } from "../p-text-helpers";
import { renderAdjectiveSelection } from "./render-adj";
import { renderSandwich } from "./render-sandwich";
export function renderComplementSelection(s: T.ComplementSelection | T.UnselectedComplementSelection, person: T.Person): T.Rendered<T.ComplementSelection | T.UnselectedComplementSelection> {
if (s.selection.type === "unselected") {
return {
type: "complement",
selection: {
type: "unselected",
ps: [{ p: "____", f: "____" }],
e: "____",
},
};
}
if (s.selection.type === "sandwich") {
return {
type: "complement",
selection: renderSandwich(s.selection),
};
}
const e = getEnglishWord(s.selection.entry);
if (!e || typeof e !== "string") {
throw new Error("error getting english for compliment");
}
if (s.selection.type === "loc. adv.") {
return {
type: "complement",
selection: {
type: "loc. adv.",
entry: s.selection.entry,
ps: [psStringFromEntry(s.selection.entry)],
e,
inflected: false,
// TODO: don't use persons for these
person,
role: "none",
},
};
}
if (s.selection.type === "adjective") {
return {
type: "complement",
selection: renderAdjectiveSelection(s.selection, person, false),
};
}
// if (s.selection.type === "noun") {
return {
type: "complement",
selection: renderNounSelection(s.selection, false, "none"),
};
}

View File

@ -8,12 +8,11 @@ import { getPersonFromVerbForm } from "../../lib/misc-helpers";
import { getVerbBlockPosFromPerson } from "../misc-helpers"; import { getVerbBlockPosFromPerson } from "../misc-helpers";
import { getEnglishWord } from "../get-english-word"; import { getEnglishWord } from "../get-english-word";
import { psStringFromEntry } from "../p-text-helpers"; import { psStringFromEntry } from "../p-text-helpers";
import { isLocativeAdverbEntry } from "../type-predicates";
import { renderAdjectiveSelection } from "./render-adj";
import { renderSandwich } from "./render-sandwich"; import { renderSandwich } from "./render-sandwich";
import { EPSBlocksAreComplete, getSubjectSelection, makeBlock, makeKid } from "./blocks-utils"; import { EPSBlocksAreComplete, getSubjectSelection, makeBlock, makeKid } from "./blocks-utils";
import { removeAccentsWLength } from "../accent-helpers"; import { removeAccentsWLength } from "../accent-helpers";
import { findPossesivesToShrink, orderKids } from "./render-common"; import { findPossesivesToShrink, orderKids } from "./render-common";
import { renderComplementSelection } from "./render-complement";
export function renderEP(EP: T.EPSelectionComplete): T.EPRendered { export function renderEP(EP: T.EPSelectionComplete): T.EPRendered {
const { kids, blocks, englishEquativePerson } = getEPSBlocksAndKids(EP); const { kids, blocks, englishEquativePerson } = getEPSBlocksAndKids(EP);
@ -45,7 +44,8 @@ function getEPSBlocksAndKids(EP: T.EPSelectionComplete): { kids: T.Kid[], blocks
type: "predicateSelection", type: "predicateSelection",
selection: EP.predicate.selection.type === "NP" selection: EP.predicate.selection.type === "NP"
? renderNPSelection(EP.predicate.selection, false, false, "subject", "king") ? renderNPSelection(EP.predicate.selection, false, false, "subject", "king")
: renderEqCompSelection(EP.predicate.selection, commandingPerson), // we won't have an unselected complement in the EP - TODO: make safer?
: renderComplementSelection(EP.predicate.selection, commandingPerson) as T.Rendered<T.ComplementSelection>,
}), }),
makeBlock(equative), makeBlock(equative),
], EP.equative.negative); ], EP.equative.negative);
@ -150,40 +150,6 @@ export function renderAdverbSelection(a: T.AdverbSelection): T.Rendered<T.Adverb
}; };
} }
function renderEqCompSelection(s: T.EqCompSelection, person: T.Person): T.Rendered<T.EqCompSelection> {
if (s.selection.type === "sandwich") {
return {
type: "EQComp",
selection: renderSandwich(s.selection),
};
}
const e = getEnglishWord(s.selection.entry);
if (!e || typeof e !== "string") {
throw new Error("error getting english for compliment");
}
if (isLocativeAdverbEntry(s.selection.entry)) {
return {
type: "EQComp",
selection: {
type: "loc. adv.",
entry: s.selection.entry,
ps: [psStringFromEntry(s.selection.entry)],
e,
inflected: false,
person,
role: "none",
},
};
}
if (s.selection.type === "adjective") {
return {
type: "EQComp",
selection: renderAdjectiveSelection(s.selection, person, false, "none"),
};
}
throw new Error("invalid EqCompSelection");
}
const equativeBuilders: Record<T.EquativeTense, (p: T.Person, n: boolean) => string[]> = { const equativeBuilders: Record<T.EquativeTense, (p: T.Person, n: boolean) => string[]> = {
present: (p, n) => { present: (p, n) => {
return [ return [

View File

@ -46,7 +46,7 @@ export function renderNPSelection(NP: T.NPSelection, inflected: boolean, inflect
throw new Error("unknown NP type"); throw new Error("unknown NP type");
}; };
function renderNounSelection(n: T.NounSelection, inflected: boolean, role: "servant" | "king" | "none"): T.Rendered<T.NounSelection> { export function renderNounSelection(n: T.NounSelection, inflected: boolean, role: "servant" | "king" | "none"): T.Rendered<T.NounSelection> {
const english = getEnglishFromNoun(n.entry, n.number); const english = getEnglishFromNoun(n.entry, n.number);
const pashto = ((): T.PsString[] => { const pashto = ((): T.PsString[] => {
const infs = inflectWord(n.entry); const infs = inflectWord(n.entry);
@ -64,7 +64,7 @@ function renderNounSelection(n: T.NounSelection, inflected: boolean, role: "serv
const person = getPersonNumber(n.gender, n.number); const person = getPersonNumber(n.gender, n.number);
return { return {
...n, ...n,
adjectives: n.adjectives.map(a => renderAdjectiveSelection(a, person, inflected, role)), adjectives: n.adjectives.map(a => renderAdjectiveSelection(a, person, inflected)),
person, person,
inflected, inflected,
role, role,

View File

@ -29,6 +29,7 @@ import { renderNPSelection } from "./render-np";
import { findPerfectiveHead, getObjectSelection, getSubjectSelection, makeBlock, makeKid } from "./blocks-utils"; import { findPerfectiveHead, getObjectSelection, getSubjectSelection, makeBlock, makeKid } from "./blocks-utils";
import { renderAPSelection } from "./render-ap"; import { renderAPSelection } from "./render-ap";
import { findPossesivesToShrink, orderKids, getMiniPronounPs } from "./render-common"; import { findPossesivesToShrink, orderKids, getMiniPronounPs } from "./render-common";
import { renderComplementSelection } from "./render-complement";
// TODO: ISSUE GETTING SPLIT HEAD NOT MATCHING WITH FUTURE VERBS // TODO: ISSUE GETTING SPLIT HEAD NOT MATCHING WITH FUTURE VERBS
@ -42,6 +43,7 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
const kingPerson = getPersonFromNP( const kingPerson = getPersonFromNP(
king === "subject" ? subject : object, king === "subject" ? subject : object,
); );
const complementPerson = getPersonFromNP(object ? object : subject)
// TODO: more elegant way of handling this type safety // TODO: more elegant way of handling this type safety
if (kingPerson === undefined) { if (kingPerson === undefined) {
throw new Error("king of sentance does not exist"); throw new Error("king of sentance does not exist");
@ -56,8 +58,9 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
inflectSubject, inflectSubject,
inflectObject, inflectObject,
king, king,
complementPerson,
}); });
const { verbBlocks, hasBa } = renderVerbSelection(VP.verb, kingPerson, objectPerson); const { verbBlocks, hasBa } = renderVerbSelection(VP.verb, kingPerson, objectPerson, VP.externalComplement);
const b: T.VPRendered = { const b: T.VPRendered = {
type: "VPRendered", type: "VPRendered",
king, king,
@ -332,6 +335,7 @@ function renderVPBlocks(blocks: T.VPSBlockComplete[], config: {
inflectSubject: boolean, inflectSubject: boolean,
inflectObject: boolean, inflectObject: boolean,
king: "subject" | "object", king: "subject" | "object",
complementPerson: T.Person | undefined,
}): T.Block[] { }): T.Block[] {
return blocks.reduce((blocks, { block }): T.Block[] => { return blocks.reduce((blocks, { block }): T.Block[] => {
if (block.type === "subjectSelection") { if (block.type === "subjectSelection") {
@ -363,9 +367,20 @@ function renderVPBlocks(blocks: T.VPSBlockComplete[], config: {
}), }),
]; ];
} }
if (block.type === "AP") {
return [
...blocks,
makeBlock(renderAPSelection(block)),
];
}
return [ return [
...blocks, ...blocks,
makeBlock(renderAPSelection(block)), makeBlock(
renderComplementSelection(
block,
// just for typesafety // TODO: only include the person if we're doing an adjective
config.complementPerson || T.Person.FirstSingMale,
)),
]; ];
}, [] as T.Block[]); }, [] as T.Block[]);
} }
@ -390,7 +405,7 @@ type VerbBlocks =
| [T.PerfectParticipleBlock, T.PerfectEquativeBlock] // perfect verb | [T.PerfectParticipleBlock, T.PerfectEquativeBlock] // perfect verb
| [T.ModalVerbBlock, T.ModalVerbKedulPart] // modal verb | [T.ModalVerbBlock, T.ModalVerbKedulPart] // modal verb
function renderVerbSelection(vs: T.VerbSelectionComplete, person: T.Person, objectPerson: T.Person | undefined): { function renderVerbSelection(vs: T.VerbSelectionComplete, person: T.Person, complementPerson: T.Person | undefined, externalComplement: T.ComplementSelection | T.UnselectedComplementSelection | undefined): {
verbBlocks: VerbBlocks verbBlocks: VerbBlocks
hasBa: boolean, hasBa: boolean,
} { } {
@ -404,7 +419,9 @@ function renderVerbSelection(vs: T.VerbSelectionComplete, person: T.Person, obje
: "stative" in conjugations : "stative" in conjugations
? conjugations.stative ? conjugations.stative
: conjugations; : conjugations;
const { ps: { head, rest }, hasBa } = getPsVerbConjugation(conj, vs, person, objectPerson); const { ps: { head, rest }, hasBa } = getPsVerbConjugation(conj, vs, person, complementPerson);
const perfective = isPerfective(vs.tense);
const stativeHelper = isStativeHelper(vs.verb)
const vrb: T.VerbRenderedBlock = { const vrb: T.VerbRenderedBlock = {
type: "verb", type: "verb",
block: { block: {
@ -412,11 +429,14 @@ function renderVerbSelection(vs: T.VerbSelectionComplete, person: T.Person, obje
ps: rest, ps: rest,
person, person,
hasBa, hasBa,
complement: (!perfective && stativeHelper && externalComplement)
? renderComplementSelection(externalComplement, complementPerson || T.Person.FirstSingMale)
: undefined,
}, },
}; };
const verbBlocks = [ const verbBlocks = [
...(head ? ( ...(head ? (
vs.isCompound === "stative" ? [{ (vs.isCompound === "stative" && !vrb.block.complement) ? [{
type: "verbComplement", type: "verbComplement",
complement: head, complement: head,
} as T.VerbComplementBlock] : [{ } as T.VerbComplementBlock] : [{
@ -424,6 +444,9 @@ function renderVerbSelection(vs: T.VerbSelectionComplete, person: T.Person, obje
ps: head, ps: head,
} as T.PerfectiveHeadBlock] } as T.PerfectiveHeadBlock]
) : [] as [T.VerbComplementBlock] | [T.PerfectiveHeadBlock] | []), ) : [] as [T.VerbComplementBlock] | [T.PerfectiveHeadBlock] | []),
...(externalComplement && perfective && stativeHelper)
? [renderComplementSelection(externalComplement, complementPerson || T.Person.FirstSingMale)]
: [],
...splitUpIfModal(vrb), ...splitUpIfModal(vrb),
] as VerbBlocks; ] as VerbBlocks;
const perfectStuff = isPerfectTense(vrb.block.tense) ? getPerfectStuff(rest, vrb) : undefined; const perfectStuff = isPerfectTense(vrb.block.tense) ? getPerfectStuff(rest, vrb) : undefined;
@ -433,6 +456,12 @@ function renderVerbSelection(vs: T.VerbSelectionComplete, person: T.Person, obje
}; };
} }
function isStativeHelper(v: T.VerbEntry): boolean {
if (v.entry.p === "کول" && v.entry.e.includes("make")) return true;
if (v.entry.p === "کېدل" && v.entry.e.includes("become")) return true;
return false;
}
function splitUpIfModal(v: T.VerbRenderedBlock): [T.VerbRenderedBlock] | [T.ModalVerbBlock, T.ModalVerbKedulPart] { function splitUpIfModal(v: T.VerbRenderedBlock): [T.VerbRenderedBlock] | [T.ModalVerbBlock, T.ModalVerbKedulPart] {
if (!isModalTense(v.block.tense)) { if (!isModalTense(v.block.tense)) {
return [v]; return [v];
@ -489,7 +518,7 @@ function getPsVerbConjugation(conj: T.VerbConjugation, vs: T.VerbSelectionComple
if (perfective) { if (perfective) {
const past = isPastTense(vs.tense); const past = isPastTense(vs.tense);
const splitInfo = conj.info[(past || isModalTense(vs.tense)) ? "root" : "stem"].perfectiveSplit; const splitInfo = conj.info[(past || isModalTense(vs.tense)) ? "root" : "stem"].perfectiveSplit;
if (!splitInfo) return { ps: { head: undefined, rest: verbForm }, hasBa }; if (!splitInfo) return { ps: { head: undefined, rest: removeBaFromForm(verbForm) }, hasBa };
// TODO: Either solve this in the inflector or here, it seems silly (or redundant) // TODO: Either solve this in the inflector or here, it seems silly (or redundant)
// to have a length option in the perfective split stem?? // to have a length option in the perfective split stem??
const [splitHead] = getLong(getMatrixBlock(splitInfo, objectPerson, person)); const [splitHead] = getLong(getMatrixBlock(splitInfo, objectPerson, person));

View File

@ -554,7 +554,7 @@ export type SubjectSelectionComplete = {
export type PredicateSelectionComplete = { export type PredicateSelectionComplete = {
type: "predicateSelection", type: "predicateSelection",
selection: EqCompSelection | NPSelection, selection: ComplementSelection | NPSelection,
}; };
export type ObjectSelectionComplete = { export type ObjectSelectionComplete = {
@ -565,12 +565,14 @@ export type ObjectSelectionComplete = {
export type VPSelectionState = { export type VPSelectionState = {
blocks: VPSBlock[] blocks: VPSBlock[]
verb: VerbSelection, verb: VerbSelection,
externalComplement: undefined | UnselectedComplementSelection | ComplementSelection,
form: FormVersion, form: FormVersion,
}; };
export type VPSelectionComplete = { export type VPSelectionComplete = {
blocks: VPSBlockComplete[] blocks: VPSBlockComplete[]
verb: VerbSelectionComplete, verb: VerbSelectionComplete,
externalComplement: VPSelectionState["externalComplement"],
form: FormVersion, form: FormVersion,
}; };
@ -690,19 +692,23 @@ export type RenderedPossesorSelection = {
shrunken: boolean, shrunken: boolean,
}; };
export type UnselectedComplementSelection = { type: "complement", selection: { type: "unselected" }};
export type Rendered< export type Rendered<
T extends T extends
| NPSelection | NPSelection
| NPSelection["selection"] | NPSelection["selection"]
| APSelection | APSelection
| APSelection["selection"] | APSelection["selection"]
| EqCompSelection
| EqCompSelection["selection"]
| SubjectSelectionComplete | SubjectSelectionComplete
| ObjectSelectionComplete | ObjectSelectionComplete
| PredicateSelectionComplete | PredicateSelectionComplete
| AdjectiveSelection | AdjectiveSelection
| SandwichSelection<Sandwich> | SandwichSelection<Sandwich>
| ComplementSelection
| ComplementSelection["selection"]
| UnselectedComplementSelection
| undefined
> = > =
T extends NPSelection T extends NPSelection
? { ? {
@ -714,10 +720,19 @@ export type Rendered<
type: "AP", type: "AP",
selection: Rendered<APSelection["selection"]> selection: Rendered<APSelection["selection"]>
} }
: T extends EqCompSelection : T extends ComplementSelection
? { ? {
type: "EQComp", type: "complement",
selection: Rendered<EqCompSelection["selection"]> selection: Rendered<ComplementSelection["selection"]>
}
: T extends UnselectedComplementSelection
? {
type: "complement",
selection: {
type: "unselected",
ps: PsString[],
e: string,
},
} }
: T extends SandwichSelection<Sandwich> : T extends SandwichSelection<Sandwich>
? Omit<SandwichSelection<Sandwich>, "inside"> & { ? Omit<SandwichSelection<Sandwich>, "inside"> & {
@ -740,6 +755,11 @@ export type Rendered<
inflected: boolean, inflected: boolean,
person: Person, person: Person,
} }
: T extends ComplementSelection
? {
type: "complement",
selection: Rendered<ComplementSelection["selection"]>,
}
: T extends SubjectSelectionComplete : T extends SubjectSelectionComplete
? { ? {
type: "subjectSelection", type: "subjectSelection",
@ -753,8 +773,13 @@ export type Rendered<
: T extends PredicateSelectionComplete : T extends PredicateSelectionComplete
? { ? {
type: "predicateSelection", type: "predicateSelection",
selection: Rendered<EqCompSelection> | Rendered<NPSelection>, selection: Rendered<ComplementSelection> | Rendered<NPSelection>,
} : ReplaceKey< } : T extends undefined
? {
type: "undefined",
ps: PsString,
}
: ReplaceKey<
Omit<T, "changeGender" | "changeNumber" | "changeDistance" | "adjectives" | "possesor">, Omit<T, "changeGender" | "changeNumber" | "changeDistance" | "adjectives" | "possesor">,
"e", "e",
string string
@ -777,7 +802,7 @@ export type EPSelectionState = {
predicate: { predicate: {
type: "NP" | "Complement", type: "NP" | "Complement",
NP: NPSelection | undefined, NP: NPSelection | undefined,
Complement: EqCompSelection | undefined, Complement: ComplementSelection | undefined,
}, },
equative: EquativeSelection, equative: EquativeSelection,
omitSubject: boolean, omitSubject: boolean,
@ -795,11 +820,11 @@ export type EPSBlockComplete = {
export type VPSBlock = { export type VPSBlock = {
key: number, key: number,
// TODO: confusing use of APSelection / should be like APSelection s APSelection complete like the others // TODO: confusing use of APSelection / should be like APSelection s APSelection complete like the others
block: SubjectSelection | ObjectSelection | (APSelection | undefined), block: SubjectSelection | ObjectSelection | (APSelection | undefined) | ComplementSelection,
}; };
export type VPSBlockComplete = { export type VPSBlockComplete = {
key: number, key: number,
block: SubjectSelectionComplete | ObjectSelectionComplete | APSelection, block: SubjectSelectionComplete | ObjectSelectionComplete | APSelection | ComplementSelection,
}; };
export type EPSelectionComplete = Omit<EPSelectionState, "predicate" | "blocks"> & { export type EPSelectionComplete = Omit<EPSelectionState, "predicate" | "blocks"> & {
@ -808,16 +833,20 @@ export type EPSelectionComplete = Omit<EPSelectionState, "predicate" | "blocks">
omitSubject: boolean, omitSubject: boolean,
}; };
export type EqCompType = "adjective" | "loc. adv." | "sandwich" export type ComplementType = "adjective" | "loc. adv." | "sandwich" | "comp. noun";
export type EqCompSelection = {
type: "EQComp",
selection: AdjectiveSelection | LocativeAdverbSelection | SandwichSelection<Sandwich>,
};
export type SandwichSelection<S extends Sandwich> = S & { export type SandwichSelection<S extends Sandwich> = S & {
inside: NPSelection, inside: NPSelection,
}; };
export type ComplementSelection = {
type: "complement",
selection: AdjectiveSelection
| LocativeAdverbSelection
| SandwichSelection<Sandwich>
| NounSelection,
};
export type Sandwich = { export type Sandwich = {
type: "sandwich", type: "sandwich",
before: PsString | undefined, before: PsString | undefined,
@ -898,6 +927,7 @@ export type VerbRenderedBlock = {
hasBa: boolean, hasBa: boolean,
ps: SingleOrLengthOpts<PsString[]>, ps: SingleOrLengthOpts<PsString[]>,
person: Person, person: Person,
complement: undefined | Rendered<ComplementSelection> | Rendered<UnselectedComplementSelection>,
}, },
}; };
@ -907,6 +937,8 @@ export type Block = {
| Rendered<ObjectSelectionComplete> | Rendered<ObjectSelectionComplete>
| Rendered<APSelection> | Rendered<APSelection>
| Rendered<PredicateSelectionComplete> | Rendered<PredicateSelectionComplete>
| Rendered<ComplementSelection>
| Rendered<UnselectedComplementSelection>
| PerfectParticipleBlock | PerfectParticipleBlock
| PerfectEquativeBlock | PerfectEquativeBlock
| ModalVerbBlock | ModalVerbBlock

View File

@ -46,4 +46,6 @@ module.exports = [
1527815348, // تلل - to go 1527815348, // تلل - to go
1527815216, // راتلل - to come 1527815216, // راتلل - to come
1527819674, // څملاستل - to lie down 1527819674, // څملاستل - to lie down
] 1581086654898, // کېدل - to become
1527812754, // کېدل - to happen
];

View File

@ -87,4 +87,6 @@ module.exports = [
1527815214, // راوړل - to bring 1527815214, // راوړل - to bring
1527819827, // راوستل - to bring 1527819827, // راوستل - to bring
1527812275, // لیدل - to see 1527812275, // لیدل - to see
] 1579015359582, // کول - to make
1527812752, // کول - to do
];