Compare commits

..

No commits in common. "b5e33b1db999f35eafa5b8c7fb35c1e305618260" and "5f356fdb63e80706ffb58995142bd89c1c9afbee" have entirely different histories.

5 changed files with 77 additions and 431 deletions

View File

@ -11,7 +11,7 @@ const working = [
"phrases with simple verbs",
"basic verb tenses",
"noun phrases",
"mini-pronouns",
"mini-pronouns for shrunken servants",
"grammar error correction",
"negatives",
"imperative verbs",
@ -21,12 +21,14 @@ const working = [
const todo = [
"compound verbs",
"adjectival participles",
"adverbial phrases",
"relative clauses",
"equative verbs",
"ability verbs",
"passive verbs",
"quantifiers",
"demonstrative pronouns",
"mini-pronouns for possesives",
"approximate spelling",
];
@ -36,7 +38,7 @@ const examples = [
"یو به مې ړلې",
"د غټې ماشومې زاړه پلار ولیدم",
"ستا پخواني ملګري مې ولیدل",
"پرون مې دې ملګرې ولیده",
"پرون مې ولیدې",
"ما ډوډۍ خوړله",
"وامې نه خیست",
"وبه مې وینې",

View File

@ -13,7 +13,7 @@ import { lookup, wordQuery } from "./lookup";
import { parseVP } from "./parse-vp";
import { tokenizer } from "./tokenizer";
import { tlul } from "./irreg-verbs";
import { addShrunkenPossesor, getPeople, removeKeys } from "./utils";
import { getPeople, removeKeys } from "./utils";
const sarey = wordQuery("سړی", "noun");
const rasedul = wordQuery("رسېدل", "verb");
@ -259,11 +259,6 @@ const tests: {
},
],
},
{
input: "ماشوم ځې",
output: [],
error: true,
},
],
},
{
@ -895,95 +890,47 @@ const tests: {
],
},
{
input: "سړی یې ووهي",
output: [
...getPeople(3, "both").map<T.VPSelectionComplete>((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",
input: "سړی یې وویني",
output: getPeople(3, "both").map((person) => ({
blocks: [
{
key: 1,
block: makeSubjectSelectionComplete({
type: "NP",
selection: makeNounSelection(sarey, undefined),
}),
},
externalComplement: undefined,
form: {
removeKing: false,
shrinkServant: true,
{
key: 1,
block: makeObjectSelectionComplete({
type: "NP",
selection: makePronounSelection(person),
}),
},
})),
...getPeople(3, "both").flatMap<T.VPSelectionComplete>((person) =>
getPeople(3, "both").map<T.VPSelectionComplete>((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,
},
}))
),
],
],
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: [
// the man sees you/us
...[
...getPeople(1, "pl"),
...getPeople(2, "pl"),
].map<T.VPSelectionComplete>((person) => ({
output: [...getPeople(1, "pl"), ...getPeople(2, "pl")].map(
(person) => ({
blocks: [
{
key: 1,
@ -1017,98 +964,13 @@ const tests: {
removeKing: false,
shrinkServant: true,
},
})),
// your/our man sees
...[
...getPeople(1, "pl"),
...getPeople(2, "pl"),
].map<T.VPSelectionComplete>((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<T.VPSelectionComplete>((possPers) =>
getPeople(3, "both").map<T.VPSelectionComplete>((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,
},
}))
),
],
})
),
},
{
input: "سړي مې واهه",
output: [],
error: true,
},
],
},

View File

@ -1,8 +1,6 @@
import * as T from "../../../types";
import {
addShrunkenPossesor,
bindParseResult,
canTakeShrunkenPossesor,
isNeg,
isNonOoPh,
isPH,
@ -30,8 +28,6 @@ import { equals, zip } from "rambda";
import { isImperativeTense } from "../type-predicates";
// to hide equatives type-doubling issue
// TODO: problem with 3rd pers sing verb endings اواز مې دې واورېده
// TODO: word query for kawul/kedul/stat/dyn
// TODO: test all types with pronouns
@ -47,38 +43,33 @@ export function parseVP(
return [];
}
const blocks = parseBlocks(tokens, lookup, [], []);
return bindParseResult(
createPossesivePossibilities(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 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,
})
);
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 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(
@ -320,11 +311,6 @@ function finishIntransitive({
message: "subject of intransitive verb must not be inflected",
});
}
if (subjectPerson !== person) {
errors.push({
message: "subject and verb must agree for intransitive verb",
});
}
const blocks: T.VPSBlockComplete[] = [
...mapOutnpsAndAps(["S"], npsAndAps),
{
@ -501,9 +487,6 @@ function finishTransitive({
}
}
} else {
if (miniPronouns.length > 1) {
errors.push({ message: "unknown mini-pronoun" });
}
if (np.inflected) {
errors.push({
message: !isPast
@ -570,9 +553,6 @@ function finishTransitive({
}));
});
} else {
const miniPronErrors: T.ParseError[] = miniPronouns.length
? [{ message: "unknown mini-pronoun" }]
: [];
if (isPast) {
return (
[
@ -618,7 +598,7 @@ function finishTransitive({
shrinkServant: false,
},
} as T.VPSelectionComplete,
[...miniPronErrors, ...errors]
errors
);
});
} else {
@ -677,7 +657,7 @@ function finishTransitive({
shrinkServant: false,
},
} as T.VPSelectionComplete,
[...miniPronErrors, ...errors]
errors
);
});
}
@ -1053,143 +1033,3 @@ function mapOutnpsAndAps(
}
});
}
/**
* Given a set of blocks and kids, produces all possible arrangements
* with the mini-pronouns being used as possesives, or not
*
* Case 1: no mini pronouns
* 1. return as is
*
* Case 2: one mini pronoun
* 1. don't use any as possesive
* 2. use the mini pronoun as a possesive (in all possible places)
*
* Case 3: two mini pronouns
* 1. don't use any as possesive
* 2. use first as possesive
* 3. use second as possesive
* 4. use both as possesives
*
* @param blocks
* @returns
*/
function createPossesivePossibilities(
blocks: T.ParseResult<{
kids: T.ParsedKid[];
blocks: T.ParsedBlock[];
}>[]
): T.ParseResult<{
kids: T.ParsedKid[];
blocks: T.ParsedBlock[];
}>[] {
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 b;
} 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,
}));
}
});
}

View File

@ -174,61 +174,3 @@ 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,
},
},
},
},
};
}

View File

@ -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(