From 773ae85002af128465275e7131c116e6bc00f7d9 Mon Sep 17 00:00:00 2001 From: adueck Date: Fri, 18 Aug 2023 19:42:58 +0400 Subject: [PATCH] more for vps --- src/lib/src/parsing/compare.ts | 554 ----------------- src/lib/src/parsing/parse-block.ts | 61 -- src/lib/src/parsing/parse-blocks.ts | 132 ++--- src/lib/src/parsing/parse-np.ts | 3 +- src/lib/src/parsing/parse-ph.ts | 51 ++ src/lib/src/parsing/parse-vp.test.ts | 851 ++++++++++++++++++--------- src/lib/src/parsing/parse-vp.ts | 125 +++- src/lib/src/parsing/utils.test.ts | 19 + src/lib/src/parsing/utils.ts | 13 + src/types.ts | 16 +- 10 files changed, 846 insertions(+), 979 deletions(-) delete mode 100644 src/lib/src/parsing/parse-block.ts create mode 100644 src/lib/src/parsing/parse-ph.ts create mode 100644 src/lib/src/parsing/utils.test.ts diff --git a/src/lib/src/parsing/compare.ts b/src/lib/src/parsing/compare.ts index 6db1022..e69de29 100644 --- a/src/lib/src/parsing/compare.ts +++ b/src/lib/src/parsing/compare.ts @@ -1,554 +0,0 @@ -const b = [ - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to come", - ec: "come,comes,coming,came,come", - f: "raatlúl", - g: "raatlul", - noOo: true, - p: "راتلل", - pprtf: "raaghúlay", - pprtp: "راغلی", - prf: "ráaghlul", - prp: "راغلل", - psf: "raadz", - psp: "راځ", - r: 4, - separationAtF: 3, - separationAtP: 2, - ssf: "ráash", - ssp: "راش", - tppf: "ráaghay", - tppp: "راغی", - ts: 1527815216, - }, - }, - }, - person: 4, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to come", - ec: "come,comes,coming,came,come", - f: "raatlúl", - g: "raatlul", - noOo: true, - p: "راتلل", - pprtf: "raaghúlay", - pprtp: "راغلی", - prf: "ráaghlul", - prp: "راغلل", - psf: "raadz", - psp: "راځ", - r: 4, - separationAtF: 3, - separationAtP: 2, - ssf: "ráash", - ssp: "راش", - tppf: "ráaghay", - tppp: "راغی", - ts: 1527815216, - }, - }, - }, - person: 5, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to come", - ec: "come,comes,coming,came,come", - f: "raatlúl", - g: "raatlul", - noOo: true, - p: "راتلل", - pprtf: "raaghúlay", - pprtp: "راغلی", - prf: "ráaghlul", - prp: "راغلل", - psf: "raadz", - psp: "راځ", - r: 4, - separationAtF: 3, - separationAtP: 2, - ssf: "ráash", - ssp: "راش", - tppf: "ráaghay", - tppp: "راغی", - ts: 1527815216, - }, - }, - }, - person: 10, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to come", - ec: "come,comes,coming,came,come", - f: "raatlúl", - g: "raatlul", - noOo: true, - p: "راتلل", - pprtf: "raaghúlay", - pprtp: "راغلی", - prf: "ráaghlul", - prp: "راغلل", - psf: "raadz", - psp: "راځ", - r: 4, - separationAtF: 3, - separationAtP: 2, - ssf: "ráash", - ssp: "راش", - tppf: "ráaghay", - tppp: "راغی", - ts: 1527815216, - }, - }, - }, - person: 11, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to become _____", - ec: "become", - f: "kedul", - g: "kedul", - noOo: true, - p: "کېدل", - pprtf: "shúway", - pprtp: "شوی", - prf: "shwul", - prp: "شول", - r: 2, - ssf: "sh", - ssp: "ش", - ts: 1581086654898, - }, - }, - }, - person: 4, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to become _____", - ec: "become", - f: "kedul", - g: "kedul", - noOo: true, - p: "کېدل", - pprtf: "shúway", - pprtp: "شوی", - prf: "shwul", - prp: "شول", - r: 2, - ssf: "sh", - ssp: "ش", - ts: 1581086654898, - }, - }, - }, - person: 5, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to become _____", - ec: "become", - f: "kedul", - g: "kedul", - noOo: true, - p: "کېدل", - pprtf: "shúway", - pprtp: "شوی", - prf: "shwul", - prp: "شول", - r: 2, - ssf: "sh", - ssp: "ش", - ts: 1581086654898, - }, - }, - }, - person: 10, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to become _____", - ec: "become", - f: "kedul", - g: "kedul", - noOo: true, - p: "کېدل", - pprtf: "shúway", - pprtp: "شوی", - prf: "shwul", - prp: "شول", - r: 2, - ssf: "sh", - ssp: "ش", - ts: 1581086654898, - }, - }, - }, - person: 11, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - diacExcept: true, - e: "to happen, occur", - ec: "happen", - f: "kedul", - g: "kedul", - p: "کېدل", - pprtf: "shúway", - pprtp: "شوی", - prf: "óoshwul", - prp: "وشول", - r: 2, - separationAtF: 2, - separationAtP: 1, - ssf: "óosh", - ssp: "وش", - ts: 1527812754, - }, - }, - }, - person: 4, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - diacExcept: true, - e: "to happen, occur", - ec: "happen", - f: "kedul", - g: "kedul", - p: "کېدل", - pprtf: "shúway", - pprtp: "شوی", - prf: "óoshwul", - prp: "وشول", - r: 2, - separationAtF: 2, - separationAtP: 1, - ssf: "óosh", - ssp: "وش", - ts: 1527812754, - }, - }, - }, - person: 5, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - diacExcept: true, - e: "to happen, occur", - ec: "happen", - f: "kedul", - g: "kedul", - p: "کېدل", - pprtf: "shúway", - pprtp: "شوی", - prf: "óoshwul", - prp: "وشول", - r: 2, - separationAtF: 2, - separationAtP: 1, - ssf: "óosh", - ssp: "وش", - ts: 1527812754, - }, - }, - }, - person: 10, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - diacExcept: true, - e: "to happen, occur", - ec: "happen", - f: "kedul", - g: "kedul", - p: "کېدل", - pprtf: "shúway", - pprtp: "شوی", - prf: "óoshwul", - prp: "وشول", - r: 2, - separationAtF: 2, - separationAtP: 1, - ssf: "óosh", - ssp: "وش", - ts: 1527812754, - }, - }, - }, - person: 11, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to come / go over to (third person or place)", - ec: "come,comes,coming,came,come", - f: "wărtlul", - g: "wartlul", - noOo: true, - p: "ورتلل", - pprtf: "wărghúlay", - pprtp: "ورغلی", - prf: "wárghlul", - prp: "ورغلل", - psf: "wărdz", - psp: "ورځ", - r: 4, - separationAtF: 3, - separationAtP: 2, - ssf: "wársh", - ssp: "ورش", - tppf: "wărghay", - tppp: "ورغی", - ts: 1585228579997, - }, - }, - }, - person: 4, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to come / go over to (third person or place)", - ec: "come,comes,coming,came,come", - f: "wărtlul", - g: "wartlul", - noOo: true, - p: "ورتلل", - pprtf: "wărghúlay", - pprtp: "ورغلی", - prf: "wárghlul", - prp: "ورغلل", - psf: "wărdz", - psp: "ورځ", - r: 4, - separationAtF: 3, - separationAtP: 2, - ssf: "wársh", - ssp: "ورش", - tppf: "wărghay", - tppp: "ورغی", - ts: 1585228579997, - }, - }, - }, - person: 5, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to come / go over to (third person or place)", - ec: "come,comes,coming,came,come", - f: "wărtlul", - g: "wartlul", - noOo: true, - p: "ورتلل", - pprtf: "wărghúlay", - pprtp: "ورغلی", - prf: "wárghlul", - prp: "ورغلل", - psf: "wărdz", - psp: "ورځ", - r: 4, - separationAtF: 3, - separationAtP: 2, - ssf: "wársh", - ssp: "ورش", - tppf: "wărghay", - tppp: "ورغی", - ts: 1585228579997, - }, - }, - }, - person: 10, - type: "VB", - }, - ], - [ - null, - { - info: { - aspect: "perfective", - base: "stem", - type: "verb", - verb: { - entry: { - c: "v. intrans.", - e: "to come / go over to (third person or place)", - ec: "come,comes,coming,came,come", - f: "wărtlul", - g: "wartlul", - noOo: true, - p: "ورتلل", - pprtf: "wărghúlay", - pprtp: "ورغلی", - prf: "wárghlul", - prp: "ورغلل", - psf: "wărdz", - psp: "ورځ", - r: 4, - separationAtF: 3, - separationAtP: 2, - ssf: "wársh", - ssp: "ورش", - tppf: "wărghay", - tppp: "ورغی", - ts: 1585228579997, - }, - }, - }, - person: 11, - type: "VB", - }, - ], -]; diff --git a/src/lib/src/parsing/parse-block.ts b/src/lib/src/parsing/parse-block.ts deleted file mode 100644 index 8a67ec0..0000000 --- a/src/lib/src/parsing/parse-block.ts +++ /dev/null @@ -1,61 +0,0 @@ -import * as T from "../../../types"; -import { fmapParseResult } from "../fp-ps"; -import { parseNP } from "./parse-np"; -import { parseVerb } from "./parse-verb"; - -export function parseBlock( - tokens: Readonly, - lookup: (s: Partial) => T.DictionaryEntry[], - verbLookup: (s: string) => T.VerbEntry[] -): T.ParseResult< - | [ - { - inflected: boolean; - selection: T.NPSelection; - } - ] - | [ - ( - | { - type: "PH"; - s: string; - } - | undefined - ), - Omit - ] - | [] ->[] { - if (tokens.length === 0) { - return [ - { - tokens: [], - body: [], - errors: [], - }, - ]; - } - - return [ - ...(fmapParseResult((x) => [x], parseNP(tokens, lookup)) as T.ParseResult< - [ - { - inflected: boolean; - selection: T.NPSelection; - } - ] - >[]), - ...(parseVerb(tokens, verbLookup) as T.ParseResult< - [ - ( - | { - type: "PH"; - s: string; - } - | undefined - ), - Omit - ] - >[]), - ]; -} diff --git a/src/lib/src/parsing/parse-blocks.ts b/src/lib/src/parsing/parse-blocks.ts index 1ffebf3..212e00a 100644 --- a/src/lib/src/parsing/parse-blocks.ts +++ b/src/lib/src/parsing/parse-blocks.ts @@ -1,96 +1,94 @@ import * as T from "../../../types"; -import { parseBlock } from "./parse-block"; +import { fmapParseResult } from "../fp-ps"; import { parseKidsSection } from "./parse-kids-section"; +import { parseNP } from "./parse-np"; +import { parsePH } from "./parse-ph"; +import { parseVerb } from "./parse-verb"; import { bindParseResult, returnParseResult } from "./utils"; export function parseBlocks( tokens: Readonly, lookup: (s: Partial) => T.DictionaryEntry[], verbLookup: (s: string) => T.VerbEntry[], - prevBlocks: ( - | { - inflected: boolean; - selection: T.NPSelection; - } - | { - type: "PH"; - s: string; - } - | Omit - )[], + blocks: T.ParsedBlock[], kids: T.ParsedKid[] ): T.ParseResult<{ kids: T.ParsedKid[]; - blocks: ( - | { - inflected: boolean; - selection: T.NPSelection; - } - | { - type: "PH"; - s: string; - } - | Omit - )[]; + blocks: T.ParsedBlock[]; }>[] { if (tokens.length === 0) { - // console.log("at end", { prevBlocks, kids }); - return returnParseResult(tokens, { blocks: prevBlocks, kids }); + return returnParseResult(tokens, { blocks, kids }); } - - const block = parseBlock(tokens, lookup, verbLookup); + const prevPh: T.ParsedPH | undefined = blocks.find( + (b): b is T.ParsedPH => "type" in b && b.type === "PH" + ); + const vbExists = blocks.some((b) => "type" in b && b.type === "VB"); + const np = prevPh ? [] : fmapParseResult((x) => [x], parseNP(tokens, lookup)); + // UHOH... This could cause double paths ... maybe don't parse the PH in the parse VB! + const ph = + vbExists || prevPh ? [] : fmapParseResult((x) => [x], parsePH(tokens)); + const vb = fmapParseResult( + ([ph, v]) => (ph ? [ph, v] : [v]), + parseVerb(tokens, verbLookup) + ); const kidsR = parseKidsSection(tokens, []); - const allResults = [...block, ...kidsR] as T.ParseResult< - | [ - { - inflected: boolean; - selection: T.NPSelection; - } - ] - | [ - ( - | { - type: "PH"; - s: string; - } - | undefined - ), - Omit - ] - | [] - | { kids: T.ParsedKid[] } + const allResults = [...np, ...ph, ...vb, ...kidsR] as T.ParseResult< + T.ParsedBlock[] | { kids: T.ParsedKid[] } >[]; - if (!allResults.length) { - return [ - { - tokens: [], - body: { blocks: prevBlocks, kids }, - errors: [], - }, - ]; - } + // TODO: is this necessary? + // if (!allResults.length) { + // return [ + // { + // tokens, + // body: { blocks, kids }, + // errors: [], + // }, + // ]; + // } return bindParseResult(allResults, (tokens, r) => { if ("kids" in r) { return { - next: parseBlocks(tokens, lookup, verbLookup, prevBlocks, [ + next: parseBlocks(tokens, lookup, verbLookup, blocks, [ ...kids, ...r.kids, ]), errors: - prevBlocks.length !== 1 + blocks.length !== 1 ? [{ message: "kids' section out of place" }] : [], }; } - // filter out the empty PH pieces - // for some reason ts won't let me do filter here - const newBlocks = r.flatMap((x) => (x ? [x] : [])); - return parseBlocks( - tokens, - lookup, - verbLookup, - [...prevBlocks, ...newBlocks], - kids - ); + if (prevPh && r.some((x) => "type" in x && x.type === "PH")) { + return []; + } + const vb = r.find((x): x is T.ParsedVBE => "type" in x && x.type === "VB"); + if (!phMatches(prevPh, vb)) { + return []; + } + return parseBlocks(tokens, lookup, verbLookup, [...blocks, ...r], kids); }); } + +function phMatches(ph: T.ParsedPH | undefined, vb: T.ParsedVBE | undefined) { + if (!ph) { + return true; + } + const v = vb && vb.type === "VB" && vb.info.type === "verb" && vb.info.verb; + if (!v) { + return true; + } + const verbPh = getPhFromVerb(v); + return verbPh === ph.s; +} + +function getPhFromVerb(v: T.VerbEntry): string { + // TODO!! what to do about yo / bo ??? + if (v.entry.separationAtP) { + return v.entry.p.slice(0, v.entry.separationAtP); + } + // TODO or آ + if (v.entry.p.startsWith("ا")) { + return "وا"; + } + return "و"; +} diff --git a/src/lib/src/parsing/parse-np.ts b/src/lib/src/parsing/parse-np.ts index a9097e3..67978be 100644 --- a/src/lib/src/parsing/parse-np.ts +++ b/src/lib/src/parsing/parse-np.ts @@ -6,7 +6,7 @@ import { fmapParseResult } from "../fp-ps"; export function parseNP( s: Readonly, lookup: (s: Partial) => T.DictionaryEntry[] -): T.ParseResult<{ inflected: boolean; selection: T.NPSelection }>[] { +): T.ParseResult[] { if (s.length === 0) { return []; } @@ -34,7 +34,6 @@ export function parseNP( }; } - // @ts-ignore grrr webpack is having trouble with this return fmapParseResult(makeNPSl, [ ...parsePronoun(s), ...parseNoun(s, lookup), diff --git a/src/lib/src/parsing/parse-ph.ts b/src/lib/src/parsing/parse-ph.ts new file mode 100644 index 0000000..8d7422a --- /dev/null +++ b/src/lib/src/parsing/parse-ph.ts @@ -0,0 +1,51 @@ +import * as T from "../../../types"; +import { returnParseResult } from "./utils"; + +const phs = [ + "و", + "وا", + "کې", + "یو", + "بو", + "څم", + "پرې", + "کښې", + "در", + "را", + "ور", + "پرا", +]; + +export function parsePH( + tokens: Readonly +): T.ParseResult<{ type: "PH"; s: string }>[] { + if (tokens.length === 0) { + return []; + } + const [first, ...rest] = tokens; + if (phs.includes(first.s)) { + return returnParseResult(rest, { + type: "PH", + s: first.s, + }); + } + // TODO: maybe it would be better to only do this splitting off of the perfect head + // if the next thing could be a kids section + return phs + .filter((p) => first.s.startsWith(p)) + .flatMap((ph) => + returnParseResult( + [ + { + ...first, + s: first.s.slice(ph.length), + }, + ...rest, + ], + { + type: "PH", + s: ph, + } as const + ) + ); +} diff --git a/src/lib/src/parsing/parse-vp.test.ts b/src/lib/src/parsing/parse-vp.test.ts index 1fbe380..374fc1e 100644 --- a/src/lib/src/parsing/parse-vp.test.ts +++ b/src/lib/src/parsing/parse-vp.test.ts @@ -14,7 +14,7 @@ import { lookup, verbLookup, wordQuery } from "./lookup"; import { parseVP } from "./parse-vp"; import { tokenizer } from "./tokenizer"; import { tlul } from "./irreg-verbs"; -import { removeKeys } from "./utils"; +import { getPeople, removeKeys } from "./utils"; const sarey = wordQuery("سړی", "noun"); const rasedul = wordQuery("رسېدل", "verb"); @@ -71,79 +71,79 @@ const tests: { cases: [ { input: "زه ځم", - output: [ - { - blocks: [ - { - key: 1, - block: makeSubjectSelectionComplete({ - type: "NP", - selection: makePronounSelection(T.Person.FirstSingMale), - }), - }, - { - key: 2, - block: { - type: "objectSelection", - selection: "none", - }, - }, - ], - verb: { - type: "verb", - verb: tlul, - transitivity: "transitive", - canChangeTransitivity: false, - canChangeStatDyn: false, - negative: false, - tense: "presentVerb", - canChangeVoice: true, - isCompound: false, - voice: "active", + output: getPeople(1, "sing").map((person) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(person), + }), }, - externalComplement: undefined, - form: { - removeKing: false, - shrinkServant: false, + { + key: 2, + block: { + type: "objectSelection", + selection: "none", + }, }, + ], + verb: { + type: "verb", + verb: tlul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "presentVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", }, - { - blocks: [ - { - key: 1, - block: makeSubjectSelectionComplete({ - type: "NP", - - selection: makePronounSelection(T.Person.FirstSingFemale), - }), - }, - { - key: 2, - block: { - type: "objectSelection", - selection: "none", - }, - }, - ], - verb: { - type: "verb", - verb: tlul, - transitivity: "transitive", - canChangeTransitivity: false, - canChangeStatDyn: false, - negative: false, - tense: "presentVerb", - canChangeVoice: true, - isCompound: false, - voice: "active", - }, - externalComplement: undefined, - form: { - removeKing: false, - shrinkServant: false, - }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: false, }, - ], + })), + }, + { + input: "زه به ځم", + output: getPeople(1, "sing").map((person) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(person), + }), + }, + { + key: 2, + block: { + type: "objectSelection", + selection: "none", + }, + }, + ], + verb: { + type: "verb", + verb: tlul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "imperfectiveFuture", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: false, + }, + })), }, { input: "سړی رسېږي", @@ -232,79 +232,41 @@ const tests: { cases: [ { input: "ځم", - output: [ - { - blocks: [ - { - key: 1, - block: makeSubjectSelectionComplete({ - type: "NP", - selection: makePronounSelection(T.Person.FirstSingMale), - }), - }, - { - key: 2, - block: { - type: "objectSelection", - selection: "none", - }, - }, - ], - verb: { - type: "verb", - verb: tlul, - transitivity: "transitive", - canChangeTransitivity: false, - canChangeStatDyn: false, - negative: false, - tense: "presentVerb", - canChangeVoice: true, - isCompound: false, - voice: "active", + output: getPeople(1, "sing").map((subj) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(subj), + }), }, - externalComplement: undefined, - form: { - removeKing: true, - shrinkServant: false, + { + key: 2, + block: { + type: "objectSelection", + selection: "none", + }, }, + ], + verb: { + type: "verb", + verb: tlul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "presentVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", }, - { - blocks: [ - { - key: 1, - block: makeSubjectSelectionComplete({ - type: "NP", - - selection: makePronounSelection(T.Person.FirstSingFemale), - }), - }, - { - key: 2, - block: { - type: "objectSelection", - selection: "none", - }, - }, - ], - verb: { - type: "verb", - verb: tlul, - transitivity: "transitive", - canChangeTransitivity: false, - canChangeStatDyn: false, - negative: false, - tense: "presentVerb", - canChangeVoice: true, - isCompound: false, - voice: "active", - }, - externalComplement: undefined, - form: { - removeKing: true, - shrinkServant: false, - }, + externalComplement: undefined, + form: { + removeKing: true, + shrinkServant: false, }, - ], + })), }, ], }, @@ -354,6 +316,92 @@ const tests: { }, ], }, + { + input: "سړي به ماشومه ولیده", + output: [ + { + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makeNounSelection(sarey, undefined), + }), + }, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: { + ...makeNounSelection(maashoom, undefined), + gender: "fem", + }, + }), + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "habitualPerfectivePast", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: false, + }, + }, + ], + }, + { + input: "سړي به ماشومه لیده", + output: [ + { + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makeNounSelection(sarey, undefined), + }), + }, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: { + ...makeNounSelection(maashoom, undefined), + gender: "fem", + }, + }), + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "habitualImperfectivePast", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: false, + }, + }, + ], + }, ], }, { @@ -442,84 +490,92 @@ const tests: { }, { input: "سړی ما ویني", - output: [ - { - blocks: [ - { - key: 1, - block: makeSubjectSelectionComplete({ - type: "NP", - selection: makeNounSelection(sarey, undefined), - }), - }, - { - key: 2, - block: makeObjectSelectionComplete({ - type: "NP", - selection: makePronounSelection(T.Person.FirstSingMale), - }), - }, - ], - verb: { - type: "verb", - verb: leedul, - transitivity: "transitive", - canChangeTransitivity: false, - canChangeStatDyn: false, - negative: false, - tense: "presentVerb", - canChangeVoice: true, - isCompound: false, - voice: "active", + output: getPeople(1, "sing").map((objPerson) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makeNounSelection(sarey, undefined), + }), }, - externalComplement: undefined, - form: { - removeKing: false, - shrinkServant: false, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(objPerson), + }), }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "presentVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", }, - { - blocks: [ - { - key: 1, - block: makeSubjectSelectionComplete({ - type: "NP", - selection: makeNounSelection(sarey, undefined), - }), - }, - { - key: 2, - block: makeObjectSelectionComplete({ - type: "NP", - selection: makePronounSelection(T.Person.FirstSingFemale), - }), - }, - ], - verb: { - type: "verb", - verb: leedul, - transitivity: "transitive", - canChangeTransitivity: false, - canChangeStatDyn: false, - negative: false, - tense: "presentVerb", - canChangeVoice: true, - isCompound: false, - voice: "active", - }, - externalComplement: undefined, - form: { - removeKing: false, - shrinkServant: false, - }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: false, }, - ], + })), }, ], }, { label: "transitive no king", cases: [ + { + input: "ما وینې", + output: getPeople(1, "sing").flatMap((objectPerson) => + getPeople(2, "sing").map((subjPerson) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(subjPerson), + }), + }, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(objectPerson), + }), + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "presentVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: true, + shrinkServant: false, + }, + })) + ), + }, + { + input: "زه وینې", + output: [], + error: true, + }, { input: "سړي ولیدله", output: [ @@ -562,84 +618,327 @@ const tests: { }, { input: "سړی وینم", - output: [ - { - blocks: [ - { - key: 1, - block: makeSubjectSelectionComplete({ - type: "NP", - selection: makePronounSelection(T.Person.FirstSingMale), - }), - }, - { - key: 2, - block: makeObjectSelectionComplete({ - type: "NP", - selection: makeNounSelection(sarey, undefined), - }), - }, - ], - verb: { - type: "verb", - verb: leedul, - transitivity: "transitive", - canChangeTransitivity: false, - canChangeStatDyn: false, - negative: false, - tense: "presentVerb", - canChangeVoice: true, - isCompound: false, - voice: "active", + output: getPeople(1, "sing").map((subjPerson) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(subjPerson), + }), }, - externalComplement: undefined, - form: { - removeKing: true, - shrinkServant: false, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makeNounSelection(sarey, undefined), + }), }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "presentVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", }, - { - blocks: [ - { - key: 1, - block: makeSubjectSelectionComplete({ - type: "NP", - selection: makePronounSelection(T.Person.FirstSingFemale), - }), - }, - { - key: 2, - block: makeObjectSelectionComplete({ - type: "NP", - selection: makeNounSelection(sarey, undefined), - }), - }, - ], - verb: { - type: "verb", - verb: leedul, - transitivity: "transitive", - canChangeTransitivity: false, - canChangeStatDyn: false, - negative: false, - tense: "presentVerb", - canChangeVoice: true, - isCompound: false, - voice: "active", - }, - externalComplement: undefined, - form: { - removeKing: true, - shrinkServant: false, - }, + externalComplement: undefined, + form: { + removeKing: true, + shrinkServant: false, }, - ], + })), }, ], }, { label: "transitive shrunken servant", - cases: [], + cases: [ + { + input: "زه دې وینم", + output: getPeople(1, "sing").flatMap((subjectPerson) => + getPeople(2, "sing").map((objectPerson) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(subjectPerson), + }), + }, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(objectPerson), + }), + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "presentVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: true, + }, + })) + ), + }, + { + input: "سړی مې ولید", + output: getPeople(1, "sing").map((subjPerson) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(subjPerson), + }), + }, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makeNounSelection(sarey, undefined), + }), + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "perfectivePast", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: true, + }, + })), + }, + { + input: "سړی دې لید", + output: [ + { + blocks: [ + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makeNounSelection(sarey, undefined), + }), + }, + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: { + ...makePronounSelection(T.Person.ThirdSingFemale), + distance: "near", + }, + }), + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "imperfectivePast", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: false, + }, + }, + ...getPeople(2, "sing").map((subj) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(subj), + }), + }, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makeNounSelection(sarey, undefined), + }), + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "imperfectivePast", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: true, + }, + })), + ], + }, + { + input: "سړی یې وویني", + output: getPeople(3, "both").map((person) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makeNounSelection(sarey, undefined), + }), + }, + { + key: 1, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(person), + }), + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "subjunctiveVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: true, + }, + })), + }, + { + input: "سړی مو ویني", + output: [...getPeople(1, "pl"), ...getPeople(2, "pl")].map( + (person) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makeNounSelection(sarey, undefined), + }), + }, + { + key: 1, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(person), + }), + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "presentVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: true, + }, + }) + ), + }, + ], + }, + { + label: "transitive no king shrunken servant", + cases: [ + { + input: "ودې لیدم", + output: getPeople(2, "sing").flatMap((subjPerson) => + getPeople(1, "sing").map((objPerson) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(subjPerson), + }), + }, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(objPerson), + }), + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "perfectivePast", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: true, + shrinkServant: true, + }, + })) + ), + }, + ], }, ]; diff --git a/src/lib/src/parsing/parse-vp.ts b/src/lib/src/parsing/parse-vp.ts index 19a2b21..cf9acaa 100644 --- a/src/lib/src/parsing/parse-vp.ts +++ b/src/lib/src/parsing/parse-vp.ts @@ -15,8 +15,12 @@ import { isFirstOrSecondPersPronoun } from "../phrase-building/render-vp"; // ماشومان سړي ولیدل // ماشومانو سړي ولیدل +// map over transitivities, to give transitive / gramm. transitive optionns + // make impossible subjects like I saw me, error +// کې به ناست not working! + // TODO: transitivity options export function parseVP( @@ -30,13 +34,10 @@ export function parseVP( const blocks = parseBlocks(tokens, lookup, verbLookup, [], []); return bindParseResult(blocks, (tokens, { blocks, kids }) => { const ph = blocks.find((x) => "type" in x && x.type === "PH") as - | { - type: "PH"; - s: string; - } + | T.ParsedPH | undefined; const verb = blocks.find((x) => "type" in x && x.type === "VB") as - | Omit + | T.ParsedVBE | undefined; const ba = !!kids.find((k) => k === "ba"); if (!verb || verb.type !== "VB" || verb.info.type !== "verb") { @@ -47,6 +48,10 @@ export function parseVP( if (!ph) { return []; } + } else { + if (ph) { + return []; + } } const tense = getTenseFromRootsStems(ba, verb.info.base, verb.info.aspect); const isPast = isPastTense(tense); @@ -70,6 +75,12 @@ export function parseVP( ); // TODO: check that verb and PH match if (verb.info.verb.entry.c.includes("intrans")) { + const errors: T.ParseError[] = []; + if (getMiniPronouns(kids).length) { + errors.push({ + message: "unknown mini-pronoun", + }); + } if (nps.length > 1) { return []; } @@ -90,17 +101,20 @@ export function parseVP( }, }, ]; - return returnParseResult(tokens, { - blocks, - verb: v, - externalComplement: undefined, - form: { - removeKing: true, - shrinkServant: false, - }, - } as T.VPSelectionComplete); + return returnParseResult( + tokens, + { + blocks, + verb: v, + externalComplement: undefined, + form: { + removeKing: true, + shrinkServant: false, + }, + } as T.VPSelectionComplete, + errors + ); } - const errors: T.ParseError[] = []; if (getPersonFromNP(nps[0].selection) !== verb.person) { errors.push({ message: "subject must agree with intransitive verb" }); } @@ -141,7 +155,71 @@ export function parseVP( return []; } if (nps.length === 0) { - return []; + // present: + // - no king (subject) + // - servant (object) is shrunken + // past: + // - no king (object) + // - servant (subject) is shrunken + const errors: T.ParseError[] = []; + const miniPronouns = getMiniPronouns(kids); + if (miniPronouns.length > 1) { + errors.push({ + message: "unknown mini-pronoun in kid's section", + }); + } + const blockOpts: T.VPSBlockComplete[][] = getPeopleFromMiniPronouns( + miniPronouns + ).map((person) => + !isPast + ? [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(verb.person), + }), + }, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(person), + }), + }, + ] + : [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(person), + }), + }, + { + key: 2, + block: makeObjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(verb.person), + }), + }, + ] + ); + return blockOpts.flatMap((blocks) => + returnParseResult( + tokens, + { + blocks, + verb: v, + externalComplement: undefined, + form: { + removeKing: true, + shrinkServant: true, + }, + } as T.VPSelectionComplete, + errors + ) + ); } if (nps.length === 1) { const np = nps[0]; @@ -172,13 +250,18 @@ export function parseVP( } : np.selection; const servants: T.NPSelection[] = form.shrinkServant - ? getPeopleFromKids(kids).map((person) => ({ + ? getPeopleFromMiniPronouns(kids).map((person) => ({ type: "NP", selection: makePronounSelection(person), })) : [np.selection]; // check for vp structure errors if (form.removeKing) { + if (getMiniPronouns(kids).length) { + errors.push({ + message: "unknown mini-pronoun in kid's section", + }); + } if (!isPast) { if (isFirstOrSecondPersPronoun(np.selection)) if (!np.inflected) { @@ -358,7 +441,13 @@ export function parseVP( }); } -function getPeopleFromKids(kids: T.ParsedKid[]): T.Person[] { +function getMiniPronouns(kids: T.ParsedKid[]): T.ParsedMiniPronoun[] { + return kids.filter((k): k is T.ParsedMiniPronoun => + ["me", "de", "ye", "mU"].includes(k) + ); +} + +function getPeopleFromMiniPronouns(kids: T.ParsedKid[]): T.Person[] { const p: T.Person[] = []; for (let k of kids) { if (k === "me") { diff --git a/src/lib/src/parsing/utils.test.ts b/src/lib/src/parsing/utils.test.ts new file mode 100644 index 0000000..7c5f5c9 --- /dev/null +++ b/src/lib/src/parsing/utils.test.ts @@ -0,0 +1,19 @@ +import { getPeople } from "./utils"; +import * as T from "../../../types"; + +test("getPeople", () => { + expect(getPeople(1, "sing")).toEqual([ + T.Person.FirstSingMale, + T.Person.FirstSingFemale, + ]); + expect(getPeople(2, "pl")).toEqual([ + T.Person.SecondPlurMale, + T.Person.SecondPlurFemale, + ]); + expect(getPeople(3, "both")).toEqual([ + T.Person.ThirdSingMale, + T.Person.ThirdSingFemale, + T.Person.ThirdPlurMale, + T.Person.ThirdPlurFemale, + ]); +}); diff --git a/src/lib/src/parsing/utils.ts b/src/lib/src/parsing/utils.ts index c859387..d0c735f 100644 --- a/src/lib/src/parsing/utils.ts +++ b/src/lib/src/parsing/utils.ts @@ -108,3 +108,16 @@ export function removeKeys(a: any): any { JSON.stringify(a, (k, v) => (k === "i" || k === "key" ? undefined : v)) ); } + +export function getPeople( + person: 1 | 2 | 3, + number: "sing" | "pl" | "both" +): T.Person[] { + const people: T.Person[] = + person === 1 ? [0, 1, 6, 7] : person === 2 ? [2, 3, 8, 9] : [4, 5, 10, 11]; + return number === "sing" + ? people.filter((p) => p < 6) + : number === "pl" + ? people.filter((p) => p > 5) + : people; +} diff --git a/src/types.ts b/src/types.ts index 4a67e17..f43ccf8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1192,12 +1192,26 @@ export type Block = { | VHead; }; +export type ParsedBlock = ParsedNP | ParsedPH | ParsedVBE; + +export type ParsedNP = { + inflected: boolean; + selection: NPSelection; +}; +export type ParsedPH = { + type: "PH"; + s: string; +}; +export type ParsedVBE = Omit; + export type Kid = { key: number; kid: { type: "ba" } | MiniPronoun; }; -export type ParsedKid = "ba" | "me" | "de" | "ye" | "mU"; +export type ParsedMiniPronoun = "me" | "de" | "ye" | "mU"; + +export type ParsedKid = "ba" | ParsedMiniPronoun; export type MiniPronoun = { type: "mini-pronoun";