more on imperatives

This commit is contained in:
adueck 2023-10-02 22:28:07 -04:00
parent 8c336e8a71
commit 02b6396686
6 changed files with 422 additions and 80 deletions

View File

@ -0,0 +1,243 @@
const expected = [
{
info: {
aspect: "imperfective",
base: "stem",
imperative: true,
type: "verb",
verb: {
entry: {
c: "v. trans.",
e: "to accept, to believe",
ec: "accepting",
f: "manul",
g: "manul",
p: "منل",
r: 4,
tppf: "maanu",
tppp: "مانه",
ts: 1527815085,
},
},
},
person: 2,
type: "VB",
},
{
info: {
aspect: "imperfective",
base: "stem",
imperative: true,
type: "verb",
verb: {
entry: {
c: "v. trans.",
e: "to accept, to believe",
ec: "accepting",
f: "manul",
g: "manul",
p: "منل",
r: 4,
tppf: "maanu",
tppp: "مانه",
ts: 1527815085,
},
},
},
person: 3,
type: "VB",
},
{
info: {
aspect: "perfective",
base: "stem",
imperative: true,
type: "verb",
verb: {
entry: {
c: "v. trans.",
e: "to accept, to believe",
ec: "accepting",
f: "manul",
g: "manul",
p: "منل",
r: 4,
tppf: "maanu",
tppp: "مانه",
ts: 1527815085,
},
},
},
person: 2,
type: "VB",
},
{
info: {
aspect: "perfective",
base: "stem",
imperative: true,
type: "verb",
verb: {
entry: {
c: "v. trans.",
e: "to accept, to believe",
ec: "accepting",
f: "manul",
g: "manul",
p: "منل",
r: 4,
tppf: "maanu",
tppp: "مانه",
ts: 1527815085,
},
},
},
person: 3,
type: "VB",
},
];
const received = [
{
info: {
aspect: "imperfective",
base: "stem",
imperative: true,
type: "verb",
verb: {
entry: {
c: "v. trans.",
e: "to accept, to believe",
ec: "accepting",
f: "manul",
g: "manul",
p: "منل",
r: 4,
tppf: "maanu",
tppp: "مانه",
ts: 1527815085,
},
},
},
person: 2,
type: "VB",
},
{
info: {
aspect: "imperfective",
base: "stem",
imperative: true,
type: "verb",
verb: {
entry: {
c: "v. trans.",
e: "to accept, to believe",
ec: "accepting",
f: "manul",
g: "manul",
p: "منل",
r: 4,
tppf: "maanu",
tppp: "مانه",
ts: 1527815085,
},
},
},
person: 3,
type: "VB",
},
{
info: {
aspect: "perfective",
base: "stem",
imperative: true,
type: "verb",
verb: {
entry: {
c: "v. trans.",
e: "to accept, to believe",
ec: "accepting",
f: "manul",
g: "manul",
p: "منل",
r: 4,
tppf: "maanu",
tppp: "مانه",
ts: 1527815085,
},
},
},
person: 2,
type: "VB",
},
{
info: {
aspect: "perfective",
base: "stem",
imperative: true,
type: "verb",
verb: {
entry: {
c: "v. trans.",
e: "to accept, to believe",
ec: "accepting",
f: "manul",
g: "manul",
p: "منل",
r: 4,
tppf: "maanu",
tppp: "مانه",
ts: 1527815085,
},
},
},
person: 3,
type: "VB",
},
{
info: {
aspect: "imperfective",
base: "root",
type: "verb",
verb: {
entry: {
c: "v. trans.",
e: "to accept, to believe",
ec: "accepting",
f: "manul",
g: "manul",
p: "منل",
r: 4,
tppf: "maanu",
tppp: "مانه",
ts: 1527815085,
},
},
},
person: 5,
type: "VB",
},
{
info: {
aspect: "perfective",
base: "root",
type: "verb",
verb: {
entry: {
c: "v. trans.",
e: "to accept, to believe",
ec: "accepting",
f: "manul",
g: "manul",
p: "منل",
r: 4,
tppf: "maanu",
tppp: "مانه",
ts: 1527815085,
},
},
},
person: 5,
type: "VB",
},
];

View File

@ -33,6 +33,7 @@ const alwatul = wordQuery("الوتل", "verb");
// TODO: azmoyul etc
// TODO: cleaner and more thorough handling of ا seperating verbs ee - wee etc
// TODO: test imperatives
const tests: {
label: string;
@ -47,6 +48,10 @@ const tests: {
persons: T.Person[];
aspects: T.Aspect[];
};
imperative?: {
persons: T.Person[];
aspects: T.Aspect[];
};
verb: T.VerbEntry;
}[];
}[];
@ -191,11 +196,30 @@ const tests: {
persons: [T.Person.SecondPlurMale, T.Person.SecondPlurFemale],
aspects: ["imperfective", "perfective"],
},
imperative: {
persons: getPeople(2, "pl"),
aspects: ["imperfective", "perfective"],
},
verb: manul,
},
],
},
{
input: "منه",
output: [
{
imperative: {
persons: getPeople(2, "sing"),
aspects: ["imperfective", "perfective"],
},
root: {
persons: [T.Person.ThirdSingFemale],
aspects: ["imperfective", "perfective"],
},
verb: manul,
},
],
},
{
input: "منلم",
output: [
@ -258,6 +282,10 @@ const tests: {
persons: [T.Person.SecondPlurMale, T.Person.SecondPlurFemale],
aspects: ["imperfective", "perfective"],
},
imperative: {
persons: getPeople(2, "pl"),
aspects: ["imperfective", "perfective"],
},
verb: rasedul,
},
],
@ -309,7 +337,6 @@ const tests: {
},
],
},
{
input: "خورې",
output: [
@ -322,7 +349,6 @@ const tests: {
},
],
},
{
input: "خوړي",
output: [],
@ -351,7 +377,6 @@ const tests: {
},
],
},
{
input: "کوت",
output: [
@ -376,7 +401,6 @@ const tests: {
},
],
},
{
input: "خلم",
output: [
@ -401,7 +425,6 @@ const tests: {
},
],
},
{
input: "خیستلم",
output: [
@ -426,7 +449,6 @@ const tests: {
},
],
},
{
input: "لوځې",
output: [
@ -913,7 +935,6 @@ const tests: {
},
],
},
// TODO: It would probably be more effecient just to return the kedul verb options
// and then when we put things together with the perfective head parsed they could
// become raatlul etc...
@ -994,7 +1015,7 @@ tests.forEach(({ label, cases }) => {
const madeVbsS = output.reduce<T.ParsedVBE[]>((acc, o) => {
return [
...acc,
...(["root", "stem"] as const).flatMap((base) =>
...(["root", "stem", "imperative"] as const).flatMap((base) =>
(o[base]?.aspects || []).flatMap((aspect) =>
(o[base]?.persons || []).flatMap<T.ParsedVBE>((person) => [
{
@ -1003,8 +1024,13 @@ tests.forEach(({ label, cases }) => {
info: {
type: "verb" as const,
aspect,
base,
base: base === "imperative" ? "stem" : base,
verb: o.verb,
...(base === "imperative"
? {
imperative: true,
}
: {}),
},
},
])

View File

@ -36,7 +36,9 @@ export function parseVerb(
errors: [],
}));
}
const people = getVerbEnding(first.s);
const ending = first.s.at(-1) || "";
const people = getVerbEnding(ending);
const imperativePeople = getImperativeVerbEnding(ending);
// First do rough verb lookup, grab wide pool of possible verbs (low searching complexity for fast lookup)
// TODO: can optimize this to not have to look for possible stems/roots if none
const verbs = lookup(first.s, "verb");
@ -44,7 +46,7 @@ export function parseVerb(
// console.log({ verbs: JSON.stringify(verbs) });
// }
// Then find out which ones match exactly and how
return matchVerbs(first.s, verbs, people).map((body) => ({
return matchVerbs(first.s, verbs, people, imperativePeople).map((body) => ({
tokens: rest,
body,
errors: [],
@ -57,7 +59,8 @@ function matchVerbs(
people: {
root: T.Person[];
stem: T.Person[];
}
},
imperativePeople: T.Person[]
): T.ParsedVBE[] {
const w: T.ParsedVBE[] = [];
const lEnding = s.endsWith("ل");
@ -65,7 +68,7 @@ function matchVerbs(
const matchShortOrLong = (b: string, x: string) => {
return b === x || (!lEnding && b === x.slice(0, -1));
};
if (people.stem.length) {
if (people.stem.length || imperativePeople.length) {
const stemMatches = {
imperfective: entries.filter(({ entry: e }) => {
if (e.c.includes("comp")) {
@ -152,6 +155,19 @@ function matchVerbs(
},
});
});
imperativePeople.forEach((person) => {
w.push({
type: "VB",
person,
info: {
type: "verb",
aspect: aspect as T.Aspect,
base: "stem",
verb: removeFVarientsFromVerb(verb),
imperative: true,
},
});
});
});
});
}
@ -291,16 +307,26 @@ function matchVerbs(
return w;
}
function getVerbEnding(p: string): {
root: T.Person[];
function getImperativeVerbEnding(e: string): T.Person[] {
if (e === "ه") {
return [T.Person.SecondSingMale, T.Person.SecondSingFemale];
}
if (e === "ئ") {
return [T.Person.SecondPlurMale, T.Person.SecondPlurFemale];
}
return [];
}
function getVerbEnding(e: string): {
stem: T.Person[];
root: T.Person[];
} {
if (p.endsWith("م")) {
if (e === "م") {
return {
root: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
stem: [T.Person.FirstSingMale, T.Person.FirstSingFemale],
};
} else if (p.endsWith("ې")) {
} else if (e === "ې") {
return {
root: [
T.Person.SecondSingMale,
@ -309,7 +335,7 @@ function getVerbEnding(p: string): {
],
stem: [T.Person.SecondSingMale, T.Person.SecondSingFemale],
};
} else if (p.endsWith("ي")) {
} else if (e === "ي") {
return {
stem: [
T.Person.ThirdSingMale,
@ -319,22 +345,22 @@ function getVerbEnding(p: string): {
],
root: [],
};
} else if (p.endsWith("و")) {
} else if (e === "و") {
return {
root: [T.Person.FirstPlurMale, T.Person.FirstPlurFemale],
stem: [T.Person.FirstPlurMale, T.Person.FirstPlurFemale],
};
} else if (p.endsWith("ئ")) {
} else if (e === "ئ") {
return {
root: [T.Person.SecondPlurMale, T.Person.SecondPlurFemale],
stem: [T.Person.SecondPlurMale, T.Person.SecondPlurFemale],
};
} else if (p.endsWith("ه")) {
} else if (e === "ه") {
return {
root: [T.Person.ThirdSingFemale],
stem: [],
};
} else if (p.endsWith("ل")) {
} else if (e === "ل") {
return {
root: [T.Person.ThirdPlurMale],
stem: [],

View File

@ -10,6 +10,7 @@ import {
startsVerbSection,
} from "./utils";
import {
getSubjectSelection,
makeObjectSelectionComplete,
makeSubjectSelectionComplete,
} from "../phrase-building/blocks-utils";
@ -22,8 +23,10 @@ import { parseBlocks } from "./parse-blocks";
import { makePronounSelection } from "../phrase-building/make-selections";
import { isFirstOrSecondPersPronoun } from "../phrase-building/render-vp";
import { LookupFunction } from "./lookup";
import { personToGenNum } from "../misc-helpers";
import { isSecondPerson, personToGenNum } from "../misc-helpers";
import { equals, zip } from "rambda";
import { isPrimitive } from "util";
import { isImperativeTense } from "../type-predicates";
// to hide equatives type-doubling issue
// TODO: word query for kawul/kedul/stat/dyn
@ -74,16 +77,16 @@ function getTenses(
blocks: T.ParsedBlock[],
ba: boolean
): {
tense: T.VerbTense | T.PerfectTense;
tense: T.VerbTense | T.PerfectTense | T.ImperativeTense;
person: T.Person;
transitivities: T.Transitivity[];
negative: boolean;
verb: T.VerbEntry;
}[] {
const negIndex = blocks.findIndex(
(x) => x.type === "negative" && !x.imperative
);
const negative = negIndex !== -1;
const negIndex = blocks.findIndex((x) => x.type === "negative");
const negative: T.NegativeBlock | undefined = blocks[negIndex] as
| T.NegativeBlock
| undefined;
const phIndex = blocks.findIndex((x) => x.type === "PH");
const vbeIndex = blocks.findIndex((x) => x.type === "VB");
const ph = phIndex !== -1 ? (blocks[phIndex] as T.ParsedPH) : undefined;
@ -101,13 +104,28 @@ function getTenses(
return [];
}
}
const tense = getTenseFromRootsStems(ba, verb.info.base, verb.info.aspect);
const tense = getTenseFromRootsStems(
ba,
verb.info.base,
verb.info.aspect,
!!negative,
verb.info.imperative
);
if (!tense) {
return [];
}
const transitivities = getTransitivities(verb.info.verb);
if (verb.info.imperative && negative && !negative.imperative) {
return [];
}
if (!verb.info.imperative && negative && negative.imperative) {
return [];
}
return [
{
tense,
transitivities,
negative,
negative: !!negative,
person: verb.person,
verb: verb.info.verb,
},
@ -141,7 +159,7 @@ function getTenses(
{
tense,
transitivities,
negative,
negative: !!negative,
person: equative.person,
verb: pPart.info.verb,
},
@ -159,7 +177,7 @@ function finishPossibleVPSs({
tokens,
person,
}: {
tense: T.VerbTense | T.PerfectTense;
tense: T.VerbTense | T.PerfectTense | T.ImperativeTense;
transitivities: T.Transitivity[];
npsAndAps: (T.ParsedNP | T.APSelection)[];
miniPronouns: T.ParsedMiniPronoun[];
@ -169,49 +187,63 @@ function finishPossibleVPSs({
person: T.Person;
}): T.ParseResult<T.VPSelectionComplete>[] {
const isPast = isPastTense(tense);
return transitivities.flatMap<T.ParseResult<T.VPSelectionComplete>>(
(transitivity): T.ParseResult<T.VPSelectionComplete>[] => {
const v: T.VerbSelectionComplete = {
type: "verb",
verb,
transitivity,
canChangeTransitivity: false,
canChangeStatDyn: false,
negative,
tense,
canChangeVoice: true,
isCompound: false,
voice: "active",
};
if (transitivity === "intransitive") {
return finishIntransitive({
miniPronouns,
npsAndAps,
tokens,
v,
person,
});
} else if (transitivity === "transitive") {
return finishTransitive({
miniPronouns,
npsAndAps,
tokens,
v,
person,
isPast,
});
} else {
return finishGrammaticallyTransitive({
miniPronouns,
npsAndAps,
tokens,
v,
person,
isPast,
});
return transitivities
.flatMap<T.ParseResult<T.VPSelectionComplete>>(
(transitivity): T.ParseResult<T.VPSelectionComplete>[] => {
const v: T.VerbSelectionComplete = {
type: "verb",
verb,
transitivity,
canChangeTransitivity: false,
canChangeStatDyn: false,
negative,
tense,
canChangeVoice: true,
isCompound: false,
voice: "active",
};
if (transitivity === "intransitive") {
return finishIntransitive({
miniPronouns,
npsAndAps,
tokens,
v,
person,
});
} else if (transitivity === "transitive") {
return finishTransitive({
miniPronouns,
npsAndAps,
tokens,
v,
person,
isPast,
});
} else {
return finishGrammaticallyTransitive({
miniPronouns,
npsAndAps,
tokens,
v,
person,
isPast,
});
}
}
}
)
.filter(checkImperative2ndPers);
}
function checkImperative2ndPers({
body: vps,
}: T.ParseResult<T.VPSelectionComplete>): boolean {
if (!isImperativeTense(vps.verb.tense)) {
return true;
}
const subjectPerson = getPersonFromNP(
getSubjectSelection(vps.blocks).selection
);
return isSecondPerson(subjectPerson);
}
function finishIntransitive({
@ -271,8 +303,9 @@ function finishIntransitive({
},
];
}
if (getPersonFromNP(nps[0].selection) !== person) {
errors.push({ message: "subject must agree with intransitive verb" });
const subjectPerson = getPersonFromNP(nps[0].selection);
if (isImperativeTense(v.tense) && !isSecondPerson(subjectPerson)) {
return [];
}
if (nps[0].inflected) {
errors.push({
@ -864,8 +897,21 @@ function getPeopleFromMiniPronouns(kids: T.ParsedKid[]): T.Person[] {
function getTenseFromRootsStems(
hasBa: boolean,
base: "root" | "stem",
aspect: T.Aspect
): T.VerbTense {
aspect: T.Aspect,
negative: boolean,
imperative?: true
): T.VerbTense | T.ImperativeTense | undefined {
if (imperative) {
if (base === "root") {
return undefined;
}
if (hasBa) {
return undefined;
}
return aspect === "imperfective" || negative
? "imperfectiveImperative"
: "perfectiveImperative";
}
if (!hasBa) {
if (base === "root") {
return aspect === "perfective" ? "perfectivePast" : "imperfectivePast";

View File

@ -291,8 +291,8 @@ export function uncompleteVPSelection(
: isPerfectTense(tense)
? "perfect"
: isImperativeTense(tense)
? "modal"
: "imperative";
? "imperative"
: "modal";
return {
...vps,
verb: {

View File

@ -1257,6 +1257,7 @@ export type VBE = VB & {
aspect: Aspect;
base: "stem" | "root";
verb: VerbEntry;
imperative?: true;
abilityAux?: boolean;
};
};