diff --git a/src/App.tsx b/src/App.tsx index 18179fb..24d70ba 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -21,6 +21,7 @@ import { entryFeeder } from "./demo-components/entryFeeder"; import { Hider } from "./components/library"; import InflectionDemo from "./demo-components/InflectionDemo"; import SpellingDemo from "./demo-components/SpellingDemo"; +import { renderVerb } from "./lib/src/render-verb"; function App() { const [showingTextOptions, setShowingTextOptions] = useStickyState(false, "showTextOpts1"); @@ -35,8 +36,17 @@ function App() { useEffect(() => { document.documentElement.setAttribute("data-theme", theme); }, [theme]); + const rv = renderVerb({ + verb: { entry: {"ts":1527815399,"i":15035,"p":"وهل","f":"wahul","g":"wahul","e":"to hit","r":4,"c":"v. trans.","tppp":"واهه","tppf":"waahu","ec":"hit,hits,hitting,hit,hit"} as T.VerbDictionaryEntry}, + aspect: "imperfective", + tense: "habitualPast", + person: 9, + }); return <>
+
+                {JSON.stringify(rv, null, "  ")}
+            
>): T.LengthOptions; -export function noPersInfs(s: T.FullForm): T.SingleOrLengthOpts; -export function noPersInfs(s: - T.OptionalPersonInflections> | T.FullForm -): T.SingleOrLengthOpts | T.LengthOptions { +export function noPersInfs(s: T.OptionalPersonInflections): S { if ("mascSing" in s) { // this path shouldn't be used, just for type safety return s.mascSing; diff --git a/src/lib/src/render-verb.ts b/src/lib/src/render-verb.ts new file mode 100644 index 0000000..6041786 --- /dev/null +++ b/src/lib/src/render-verb.ts @@ -0,0 +1,142 @@ +import { + getVerbBlockPosFromPerson, + noPersInfs, +} from "./misc-helpers"; +import * as T from "../../types"; +import { concatPsString, getVerbInfo } from "../library"; +import { + presentEndings, + pastEndings, +} from "./grammar-units"; + +// export type RenderedVerbB = VerbRenderedBlock +// | PerfectiveHeadBlock +// | ModalVerbBlock +// | ModalVerbKedulPart +// | PerfectEquativeBlock +// | PerfectParticipleBlock; + +// export type PerfectiveHeadBlock = { type: "perfectiveHead", ps: PsString }; +// export type VerbRenderedBlock = { +// type: "verb", +// block: Omit & { +// hasBa: boolean, +// ps: SingleOrLengthOpts, +// person: Person, +// complementWelded: undefined | Rendered | Rendered, +// }, +// }; + +type PerfectiveHeadBlock = { + type: "perfectiveHead", + ps: T.PsString, +}; + +type VerbBlock = { + type: "verb", + hasBa: boolean, + ps: T.SingleOrLengthOpts, + person: T.Person, + aspect: T.Aspect, + tense: keyof T.AspectContent, +}; + +export function renderVerb({ verb, aspect, tense, person }: { + verb: T.VerbEntry, + aspect: T.Aspect, + tense: keyof T.AspectContent, + person: T.Person, +}): { + hasBa: boolean, + verbBlocks: [PerfectiveHeadBlock, VerbBlock] | [VerbBlock] +} { + // WARNING: this only works with simple verbs + const isPast = tense === "past" || tense === "habitualPast"; + const hasBa = tense === "future" || tense === "habitualPast"; + const { perfectiveHead, rootStem } = getRootStem(verb, aspect, isPast); + const ending = getEnding(person, isPast); + const verbPs = addEnding(rootStem, ending); + const verbBlock: VerbBlock = { + type: "verb", + hasBa, + ps: verbPs, + person, + aspect, + tense, + }; + const perfectiveHeadBlock: PerfectiveHeadBlock | undefined = perfectiveHead ? { + type: "perfectiveHead", + ps: noPersInfs(perfectiveHead), + } : undefined; + return { + hasBa, + verbBlocks: perfectiveHeadBlock ? [ + perfectiveHeadBlock, verbBlock, + ] : [verbBlock], + } +} + +function addEnding(rootStem: T.FullForm, ending: T.SingleOrLengthOpts): T.SingleOrLengthOpts { + const rs = noPersInfs(rootStem); + const end = noPersInfs(ending); + if ("long" in rs) { + if ("long" in end) { + return { + long: end.long.map((e) => concatPsString(rs.long, e)), + short: end.short.map((e) => concatPsString(rs.short, e)), + }; + } else { + return { + long: end.map((e) => concatPsString(rs.long, e)), + short: end.map((e) => concatPsString(rs.short, e)), + }; + } + } + if ("long" in end) { + throw new Error("should not be using verb stems with long and short endings"); + } + return end.map((e) => concatPsString(rs, e)); +} + +function getRootStem(verb: T.VerbEntry, aspect: T.Aspect, isPast: boolean): { + perfectiveHead: undefined | T.OptionalPersonInflections, + rootStem: T.OptionalPersonInflections>, +} { + const vInfo = getVerbInfo(verb.entry) as T.SimpleVerbInfo; + const rs = vInfo[isPast ? "root" : "stem"]; + if (aspect === "perfective" && rs.perfectiveSplit) { + return extractPerfectiveSplit(rs.perfectiveSplit); + } + return { + perfectiveHead: undefined, + rootStem: rs[aspect], + } + + function extractPerfectiveSplit(splitInfo: T.SplitInfo): ReturnType { + // TODO: allow for infs + const si = noPersInfs(splitInfo); + if ("long" in si) { + return { + perfectiveHead: si.long[0], + rootStem: { + long: si.long[1], + short: si.short[1], + } + } + } else { + return { + perfectiveHead: si[0], + rootStem: si[1], + } + } + } +} + +function getEnding(person: T.Person, isPast: boolean) { + const [row, col] = getVerbBlockPosFromPerson(person); + return isPast ? { + long: pastEndings.long[row][col], + short: pastEndings.short[row][col], + } : presentEndings[row][col]; +} +