From db3bc8303b3d8ca4971a6d0eead0e935c3478b52 Mon Sep 17 00:00:00 2001 From: adueck Date: Thu, 8 Feb 2024 22:33:24 +0100 Subject: [PATCH] possesive mini pronouns --- src/lib/src/parsing/parse-vp.test.ts | 221 +++++++++++++++++++----- src/lib/src/parsing/parse-vp.ts | 209 +++++++++++++++++++--- src/lib/src/parsing/utils.ts | 58 +++++++ src/lib/src/phrase-building/np-tools.ts | 2 +- 4 files changed, 417 insertions(+), 73 deletions(-) diff --git a/src/lib/src/parsing/parse-vp.test.ts b/src/lib/src/parsing/parse-vp.test.ts index 4f9134d..42c52e6 100644 --- a/src/lib/src/parsing/parse-vp.test.ts +++ b/src/lib/src/parsing/parse-vp.test.ts @@ -13,7 +13,7 @@ import { lookup, wordQuery } from "./lookup"; import { parseVP } from "./parse-vp"; import { tokenizer } from "./tokenizer"; import { tlul } from "./irreg-verbs"; -import { getPeople, removeKeys } from "./utils"; +import { addShrunkenPossesor, getPeople, removeKeys } from "./utils"; const sarey = wordQuery("سړی", "noun"); const rasedul = wordQuery("رسېدل", "verb"); @@ -890,47 +890,95 @@ const tests: { ], }, { - input: "سړی یې وویني", - output: getPeople(3, "both").map((person) => ({ - blocks: [ - { - key: 1, - block: makeSubjectSelectionComplete({ - type: "NP", - selection: makeNounSelection(sarey, undefined), - }), + 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: wahul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "subjunctiveVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", }, - { - key: 1, - block: makeObjectSelectionComplete({ - type: "NP", - selection: makePronounSelection(person), - }), + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: true, }, - ], - 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, - }, - })), + })), + ...getPeople(3, "both").flatMap((person) => + getPeople(3, "both").map((person2) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(person), + }), + }, + { + key: 1, + block: makeObjectSelectionComplete( + addShrunkenPossesor( + { + type: "NP", + selection: makeNounSelection(sarey, undefined), + }, + person2 + ) + ), + }, + ], + verb: { + type: "verb", + verb: wahul, + transitivity: "transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "subjunctiveVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: true, + shrinkServant: false, + }, + })) + ), + ], }, { input: "سړی مو ویني", - output: [...getPeople(1, "pl"), ...getPeople(2, "pl")].map( - (person) => ({ + output: [ + // the man sees you/us + ...[ + ...getPeople(1, "pl"), + ...getPeople(2, "pl"), + ].map((person) => ({ blocks: [ { key: 1, @@ -964,13 +1012,98 @@ const tests: { removeKing: false, shrinkServant: true, }, - }) - ), - }, - { - input: "سړي مې واهه", - output: [], - error: true, + })), + // your/our man sees + ...[ + ...getPeople(1, "pl"), + ...getPeople(2, "pl"), + ].map((person) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete( + addShrunkenPossesor( + { + type: "NP", + selection: makeNounSelection(sarey, undefined), + }, + person + ) + ), + }, + { + key: 1, + block: { + type: "objectSelection", + selection: T.Person.ThirdPlurMale, + }, + }, + ], + verb: { + type: "verb", + verb: leedul, + transitivity: "grammatically transitive", + canChangeTransitivity: false, + canChangeStatDyn: false, + negative: false, + tense: "presentVerb", + canChangeVoice: true, + isCompound: false, + voice: "active", + }, + externalComplement: undefined, + form: { + removeKing: false, + shrinkServant: false, + }, + })), + // they/he sees your/our man + ...[ + ...getPeople(1, "pl"), + ...getPeople(2, "pl"), + ].flatMap((possPers) => + getPeople(3, "both").map((subjPers) => ({ + blocks: [ + { + key: 1, + block: makeSubjectSelectionComplete({ + type: "NP", + selection: makePronounSelection(subjPers), + }), + }, + { + key: 1, + block: makeObjectSelectionComplete( + addShrunkenPossesor( + { + type: "NP", + selection: makeNounSelection(sarey, undefined), + }, + possPers + ) + ), + }, + ], + 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, + }, + })) + ), + ], }, ], }, diff --git a/src/lib/src/parsing/parse-vp.ts b/src/lib/src/parsing/parse-vp.ts index 3190037..a5dfd0b 100644 --- a/src/lib/src/parsing/parse-vp.ts +++ b/src/lib/src/parsing/parse-vp.ts @@ -1,6 +1,8 @@ import * as T from "../../../types"; import { + addShrunkenPossesor, bindParseResult, + canTakeShrunkenPossesor, isNeg, isNonOoPh, isPH, @@ -27,6 +29,11 @@ import { isSecondPerson, personToGenNum } from "../misc-helpers"; import { equals, zip } from "rambda"; import { isImperativeTense } from "../type-predicates"; // to hide equatives type-doubling issue +// TODO: THESE SHOULD ERROR!! +// ماشومانې لاړل +// ماشومان لاړلې + +// TODO: problem with 3rd pers seng verb endings اواز مې دې واورېده // TODO: word query for kawul/kedul/stat/dyn @@ -43,33 +50,39 @@ export function parseVP( return []; } const blocks = parseBlocks(tokens, lookup, [], []); - return bindParseResult(blocks, (tokens, { blocks, kids }) => { - const ba = kids.some((k) => k === "ba"); - const miniPronouns = getMiniPronouns(kids); - const npsAndAps = blocks.filter( - (x): x is T.ParsedNP | T.APSelection => x.type === "NP" || x.type === "AP" - ); - const verbSection = blocks.findIndex(startsVerbSection); - // TODO: would be nice if this could pass error messages about the - // negative being out of place etc - if (!verbSectionOK(blocks.slice(verbSection))) { - return []; + const blocksWPossPossibilities = createPossesivePossibilities(blocks); + return bindParseResult( + blocksWPossPossibilities, + (tokens, { blocks, kids }) => { + const ba = kids.some((k) => k === "ba"); + const miniPronouns = getMiniPronouns(kids); + const npsAndAps = blocks.filter( + (x): x is T.ParsedNP | T.APSelection => + x.type === "NP" || x.type === "AP" + ); + const verbSection = blocks.findIndex(startsVerbSection); + // TODO: would be nice if this could pass error messages about the + // negative being out of place etc + if (!verbSectionOK(blocks.slice(verbSection))) { + return []; + } + const tenses = getTenses(blocks, ba); + // TODO get errors from the get tenses (perfect verbs not agreeing) + return tenses.flatMap( + ({ tense, person, transitivities, negative, verb }) => + finishPossibleVPSs({ + tense, + transitivities, + npsAndAps, + miniPronouns, + tokens, + negative, + verb, + person, + }) + ); } - const tenses = getTenses(blocks, ba); - // TODO get errors from the get tenses (perfect verbs not agreeing) - return tenses.flatMap(({ tense, person, transitivities, negative, verb }) => - finishPossibleVPSs({ - tense, - transitivities, - npsAndAps, - miniPronouns, - tokens, - negative, - verb, - person, - }) - ); - }); + ); } function getTenses( @@ -487,6 +500,9 @@ function finishTransitive({ } } } else { + if (miniPronouns.length > 1) { + errors.push({ message: "unknown mini-pronoun" }); + } if (np.inflected) { errors.push({ message: !isPast @@ -553,6 +569,9 @@ function finishTransitive({ })); }); } else { + const miniPronErrors: T.ParseError[] = miniPronouns.length + ? [{ message: "unknown mini-pronoun" }] + : []; if (isPast) { return ( [ @@ -598,7 +617,7 @@ function finishTransitive({ shrinkServant: false, }, } as T.VPSelectionComplete, - errors + [...miniPronErrors, ...errors] ); }); } else { @@ -657,7 +676,7 @@ function finishTransitive({ shrinkServant: false, }, } as T.VPSelectionComplete, - errors + [...miniPronErrors, ...errors] ); }); } @@ -1033,3 +1052,137 @@ function mapOutnpsAndAps( } }); } + +function createPossesivePossibilities( + blocks: T.ParseResult<{ + kids: T.ParsedKid[]; + blocks: T.ParsedBlock[]; + }>[] +): T.ParseResult<{ + kids: T.ParsedKid[]; + blocks: T.ParsedBlock[]; +}>[] { + // Case 1: no mini pronouns + // Case 2: 1 mini pronoun + // - don't use any as possesive + // Case 3: 2 mini pronouns + // - don't use any as possesive + // - use first as possesive + // - use second as possesive + // - use both as possesive + function pullOutMiniPronoun( + body: { + kids: T.ParsedKid[]; + blocks: T.ParsedBlock[]; + }, + pos: 0 | 1 + ): { + adjusted: { + kids: T.ParsedKid[]; + blocks: T.ParsedBlock[]; + }; + miniPronoun: T.ParsedMiniPronoun; + } { + const miniPronoun = getMiniPronouns(body.kids)[pos]; + if (!miniPronoun) { + throw new Error("tried to pull out non-existent mini-pronoun"); + } + return { + miniPronoun, + adjusted: { + kids: body.kids.filter((x) => x !== miniPronoun), + blocks: body.blocks, + }, + }; + } + function spreadOutPoss( + body: { + kids: T.ParsedKid[]; + blocks: T.ParsedBlock[]; + }, + pos: 0 | 1 + ): { + kids: T.ParsedKid[]; + blocks: T.ParsedBlock[]; + }[] { + const { miniPronoun, adjusted } = pullOutMiniPronoun(body, pos); + const people = getPeopleFromMiniPronouns([miniPronoun]); + // TODO: turn into reduce? + // TODO: allow possesives for sandwiches + return adjusted.blocks + .flatMap((x, i) => { + if ( + (x.type === "NP" && canTakeShrunkenPossesor(x.selection)) || + (x.type === "AP" && canTakeShrunkenPossesor(x)) + ) { + return addPossesiveAtIndex(people, adjusted.blocks, i); + } else { + return []; + } + }) + .map((xb) => ({ + kids: adjusted.kids, + blocks: xb, + })); + } + function addPossesiveAtIndex( + people: T.Person[], + blocks: T.ParsedBlock[], + i: number + ): T.ParsedBlock[][] { + return people.map((person) => { + return blocks.map((x, j) => { + if (i !== j) return x; + // TODO: this is redundant ? + if (x.type === "NP" && canTakeShrunkenPossesor(x.selection)) { + return { + ...x, + selection: addShrunkenPossesor(x.selection, person), + }; + } else if (x.type === "AP" && canTakeShrunkenPossesor(x)) { + return addShrunkenPossesor(x, person); + } else { + throw new Error( + "improper index for adding possesor - addPossesiveAtIndex" + ); + } + }); + }); + } + return blocks.flatMap((b) => { + const miniPronouns = getMiniPronouns(b.body.kids); + if (miniPronouns.length === 0) { + return [ + { + tokens: b.tokens, + body: b.body, + errors: b.errors, + }, + ]; + } else if (miniPronouns.length === 1) { + const withFirstMiniAsPossesive = spreadOutPoss(b.body, 0); + return [b.body, ...withFirstMiniAsPossesive].map((x) => ({ + tokens: b.tokens, + body: x, + errors: b.errors, + })); + } else { + const withFirstMiniAsPossesive = spreadOutPoss(b.body, 0); + const withSecondMiniAsPossesive = spreadOutPoss(b.body, 1); + return [ + // using none of the mini-pronouns as possesives + b.body, + // using the first mini-pronoun as a possesive + ...withFirstMiniAsPossesive, + // using the second mini-pronoun as a prossesive + ...withSecondMiniAsPossesive, + // using both mini pronouns as possesives + ...withFirstMiniAsPossesive.flatMap((x) => spreadOutPoss(x, 0)), + ].map((x) => ({ + tokens: b.tokens, + body: x, + errors: b.errors, + })); + } + }); +} diff --git a/src/lib/src/parsing/utils.ts b/src/lib/src/parsing/utils.ts index f0fc413..1ed4943 100644 --- a/src/lib/src/parsing/utils.ts +++ b/src/lib/src/parsing/utils.ts @@ -174,3 +174,61 @@ export function startsVerbSection(b: T.ParsedBlock): boolean { b.type === "negative" ); } + +export function canTakeShrunkenPossesor( + block: T.NPSelection | T.APSelection +): boolean { + if (block.type === "NP") { + return block.selection.type !== "pronoun" && !block.selection.possesor; + } + if (block.selection.type === "sandwich") { + return canTakeShrunkenPossesor(block.selection.inside); + } + return false; +} + +export function addShrunkenPossesor( + b: T.NPSelection, + person: T.Person +): T.NPSelection; +export function addShrunkenPossesor( + b: T.APSelection, + person: T.Person +): T.APSelection; +export function addShrunkenPossesor( + b: T.NPSelection | T.APSelection, + person: T.Person +): T.NPSelection | T.APSelection { + if (b.selection.type === "adverb" || b.selection.type === "pronoun") { + throw new Error("cannot add shrunken possesor"); + } + if (b.type === "AP") { + return { + ...b, + selection: { + ...b.selection, + inside: addShrunkenPossesor(b.selection.inside, person), + }, + }; + } + if (b.selection.possesor) { + throw new Error("cannot add another possesor"); + } + return { + ...b, + selection: { + ...b.selection, + possesor: { + shrunken: true, + np: { + type: "NP", + selection: { + type: "pronoun", + distance: "far", + person, + }, + }, + }, + }, + }; +} diff --git a/src/lib/src/phrase-building/np-tools.ts b/src/lib/src/phrase-building/np-tools.ts index 52af8a5..cef7fb5 100644 --- a/src/lib/src/phrase-building/np-tools.ts +++ b/src/lib/src/phrase-building/np-tools.ts @@ -252,7 +252,7 @@ function pronounPossEng(p: T.Person): string { if (p === T.Person.ThirdSingFemale) { return "her/its"; } - return `their ${gend(p)}`; + return `their (${gend(p)})`; } export function getEnglishFromRendered(