negatives

This commit is contained in:
adueck 2023-08-19 21:09:29 +04:00
parent 56b92a912c
commit fc3431199c
5 changed files with 97 additions and 11 deletions

View File

@ -17,6 +17,7 @@ const working = [
"noun phrases (except participles)",
"mini-pronouns for shrunken servants",
"grammar error correction",
"negatives",
];
const todo = [
@ -42,6 +43,7 @@ const examples = [
"د غټې ماشومې زاړه پلار ولیدم",
"ستا پخواني ملګري مې ولیدل",
"ما ډوډۍ خوړله",
"وامې نه خیست",
];
function ParserDemo({ opts }: { opts: T.TextOptions }) {

View File

@ -1,6 +1,7 @@
import * as T from "../../../types";
import { fmapParseResult } from "../fp-ps";
import { parseKidsSection } from "./parse-kids-section";
import { parseNeg } from "./parse-negative";
import { parseNP } from "./parse-np";
import { parsePH } from "./parse-ph";
import { parseVerb } from "./parse-verb";
@ -31,8 +32,9 @@ export function parseBlocks(
([ph, v]) => (ph ? [ph, v] : [v]),
parseVerb(tokens, verbLookup)
);
const neg = fmapParseResult((x) => [x], parseNeg(tokens));
const kidsR = parseKidsSection(tokens, []);
const allResults = [...np, ...ph, ...vb, ...kidsR] as T.ParseResult<
const allResults = [...np, ...ph, ...neg, ...vb, ...kidsR] as T.ParseResult<
T.ParsedBlock[] | { kids: T.ParsedKid[] }
>[];
// TODO: is this necessary?
@ -46,6 +48,7 @@ export function parseBlocks(
// ];
// }
return bindParseResult(allResults, (tokens, r) => {
const errors: T.ParseError[] = [];
if ("kids" in r) {
return {
next: parseBlocks(tokens, lookup, verbLookup, blocks, [
@ -65,7 +68,18 @@ export function parseBlocks(
if (!phMatches(prevPh, vb)) {
return [];
}
return parseBlocks(tokens, lookup, verbLookup, [...blocks, ...r], kids);
// don't allow two negatives
if (
"type" in r[0] &&
r[0].type === "negative" &&
blocks.some((b) => "type" in b && b.type === "negative")
) {
return [];
}
return {
next: parseBlocks(tokens, lookup, verbLookup, [...blocks, ...r], kids),
errors,
};
});
}

View File

@ -0,0 +1,24 @@
import * as T from "../../../types";
import { returnParseResult } from "./utils";
export function parseNeg(
tokens: Readonly<T.Token[]>
): T.ParseResult<T.NegativeBlock>[] {
if (tokens.length === 0) {
return [];
}
const [{ s }, ...rest] = tokens;
if (s === "نه") {
return returnParseResult(rest, {
type: "negative",
imperative: false,
});
}
if (s === "مه") {
return returnParseResult(rest, {
type: "negative",
imperative: true,
});
}
return [];
}

View File

@ -36,6 +36,8 @@ import { isFirstOrSecondPersPronoun } from "../phrase-building/render-vp";
// TODO: transitivity options
// TODO: the و is really making it slow down... why?
export function parseVP(
tokens: Readonly<T.Token[]>,
lookup: (s: Partial<T.DictionaryEntry>) => T.DictionaryEntry[],
@ -46,16 +48,30 @@ 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
| T.ParsedPH
| undefined;
const verb = blocks.find((x) => "type" in x && x.type === "VB") as
| T.ParsedVBE
| undefined;
const phIndex = blocks.findIndex((x) => "type" in x && x.type === "PH");
const vbeIndex = blocks.findIndex((x) => "type" in x && x.type === "VB");
const ba = !!kids.find((k) => k === "ba");
const negIndex = blocks.findIndex(
(x) => "type" in x && x.type === "negative" && !x.imperative
);
const ph = phIndex !== -1 ? (blocks[phIndex] as T.ParsedPH) : undefined;
const verb =
vbeIndex !== -1 ? (blocks[vbeIndex] as T.ParsedVBE) : undefined;
const negative = negIndex !== -1;
if (!verb || verb.type !== "VB" || verb.info.type !== "verb") {
return [];
}
if (
!negativeInPlace({
neg: negIndex,
v: vbeIndex,
phIndex: phIndex,
ph,
kids: !!kids.length,
})
) {
return [];
}
if (verb.info.aspect === "perfective") {
// TODO: check that the perfective head is in the right place and actually matches
if (!ph) {
@ -77,7 +93,7 @@ export function parseVP(
: "transitive",
canChangeTransitivity: false,
canChangeStatDyn: false,
negative: false,
negative,
tense,
canChangeVoice: true,
isCompound: false,
@ -509,3 +525,31 @@ function getTenseFromRootsStems(
}
}
}
function negativeInPlace({
neg,
v,
phIndex,
ph,
kids,
}: {
neg: number;
v: number;
phIndex: number;
ph: T.ParsedPH | undefined;
kids: boolean;
}): boolean {
if (neg === -1) {
return true;
}
if (ph) {
if (!kids && !["و", "وا"].includes(ph.s) && neg === phIndex - 1) {
return true;
}
return neg === phIndex + 1;
}
if (neg < v - 1) {
return false;
}
return true;
}

View File

@ -1176,6 +1176,8 @@ export type EntryLookupPortal<X extends VerbEntry | DictionaryEntry> = {
export type EquativeBlock = { type: "equative"; equative: EquativeRendered };
export type NegativeBlock = { type: "negative"; imperative: boolean };
export type Block = {
key: number;
block:
@ -1185,14 +1187,14 @@ export type Block = {
| Rendered<PredicateSelectionComplete>
| Rendered<ComplementSelection>
| Rendered<UnselectedComplementSelection>
| { type: "negative"; imperative: boolean }
| NegativeBlock
| EquativeBlock
| VB
| VBE
| VHead;
};
export type ParsedBlock = ParsedNP | ParsedPH | ParsedVBE;
export type ParsedBlock = ParsedNP | ParsedPH | ParsedVBE | NegativeBlock;
export type ParsedNP = {
inflected: boolean;