more on parser
This commit is contained in:
parent
b384771db5
commit
288718f69a
|
@ -1,21 +0,0 @@
|
||||||
import * as T from "../../../types";
|
|
||||||
|
|
||||||
export function parseBa(
|
|
||||||
tokens: Readonly<T.Token[]>
|
|
||||||
): T.ParseResult<{ type: "ba" }>[] {
|
|
||||||
if (!tokens.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const [first, ...rest] = tokens;
|
|
||||||
if (first.s === "به") {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
body: {
|
|
||||||
type: "ba",
|
|
||||||
},
|
|
||||||
errors: [],
|
|
||||||
tokens: rest,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
} else return [];
|
|
||||||
}
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
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<T.Token[]>,
|
||||||
|
lookup: (s: Partial<T.DictionaryEntry>) => T.DictionaryEntry[],
|
||||||
|
verbLookup: (s: string) => T.VerbEntry[]
|
||||||
|
): T.ParseResult<
|
||||||
|
| [
|
||||||
|
{
|
||||||
|
inflected: boolean;
|
||||||
|
selection: T.NPSelection;
|
||||||
|
}
|
||||||
|
]
|
||||||
|
| [
|
||||||
|
(
|
||||||
|
| {
|
||||||
|
type: "PH";
|
||||||
|
s: string;
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
),
|
||||||
|
Omit<T.VBE, "ps">
|
||||||
|
]
|
||||||
|
| []
|
||||||
|
>[] {
|
||||||
|
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<T.VBE, "ps">
|
||||||
|
]
|
||||||
|
>[]),
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
import * as T from "../../../types";
|
||||||
|
import { parseBlock } from "./parse-block";
|
||||||
|
import { parseKidsSection } from "./parse-kids-section";
|
||||||
|
import { bindParseResult, returnParseResult } from "./utils";
|
||||||
|
|
||||||
|
export function parseBlocks(
|
||||||
|
tokens: Readonly<T.Token[]>,
|
||||||
|
lookup: (s: Partial<T.DictionaryEntry>) => T.DictionaryEntry[],
|
||||||
|
verbLookup: (s: string) => T.VerbEntry[],
|
||||||
|
prevBlocks: (
|
||||||
|
| {
|
||||||
|
inflected: boolean;
|
||||||
|
selection: T.NPSelection;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "PH";
|
||||||
|
s: string;
|
||||||
|
}
|
||||||
|
| Omit<T.VBE, "ps">
|
||||||
|
)[],
|
||||||
|
kids: T.ParsedKid[]
|
||||||
|
): T.ParseResult<{
|
||||||
|
kids: T.ParsedKid[];
|
||||||
|
blocks: (
|
||||||
|
| {
|
||||||
|
inflected: boolean;
|
||||||
|
selection: T.NPSelection;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "PH";
|
||||||
|
s: string;
|
||||||
|
}
|
||||||
|
| Omit<T.VBE, "ps">
|
||||||
|
)[];
|
||||||
|
}>[] {
|
||||||
|
if (tokens.length === 0) {
|
||||||
|
// console.log("at end", { prevBlocks, kids });
|
||||||
|
return returnParseResult(tokens, { blocks: prevBlocks, kids });
|
||||||
|
}
|
||||||
|
|
||||||
|
const block = parseBlock(tokens, lookup, verbLookup);
|
||||||
|
const kidsR = parseKidsSection(tokens, []);
|
||||||
|
const allResults = [...block, ...kidsR] as T.ParseResult<
|
||||||
|
| [
|
||||||
|
{
|
||||||
|
inflected: boolean;
|
||||||
|
selection: T.NPSelection;
|
||||||
|
}
|
||||||
|
]
|
||||||
|
| [
|
||||||
|
(
|
||||||
|
| {
|
||||||
|
type: "PH";
|
||||||
|
s: string;
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
),
|
||||||
|
Omit<T.VBE, "ps">
|
||||||
|
]
|
||||||
|
| []
|
||||||
|
| { kids: T.ParsedKid[] }
|
||||||
|
>[];
|
||||||
|
if (!allResults.length) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
tokens: [],
|
||||||
|
body: { blocks: prevBlocks, kids },
|
||||||
|
errors: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return bindParseResult(allResults, (tokens, r) => {
|
||||||
|
if ("kids" in r) {
|
||||||
|
return {
|
||||||
|
next: parseBlocks(tokens, lookup, verbLookup, prevBlocks, [
|
||||||
|
...kids,
|
||||||
|
...r.kids,
|
||||||
|
]),
|
||||||
|
errors:
|
||||||
|
prevBlocks.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
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import * as T from "../../../types";
|
||||||
|
import { returnParseResult } from "./utils";
|
||||||
|
|
||||||
|
export function parseKid(
|
||||||
|
tokens: Readonly<T.Token[]>
|
||||||
|
): T.ParseResult<T.ParsedKid>[] {
|
||||||
|
if (tokens.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const [{ s }, ...rest] = tokens;
|
||||||
|
if (s === "به") {
|
||||||
|
return returnParseResult(rest, "ba");
|
||||||
|
}
|
||||||
|
if (s === "یې") {
|
||||||
|
return returnParseResult(rest, "ye");
|
||||||
|
}
|
||||||
|
if (s === "مې") {
|
||||||
|
return returnParseResult(rest, "me");
|
||||||
|
}
|
||||||
|
if (s === "دې") {
|
||||||
|
return returnParseResult(rest, "de");
|
||||||
|
}
|
||||||
|
if (s === "مو") {
|
||||||
|
return returnParseResult(rest, "mU");
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/* eslint-disable jest/no-conditional-expect */
|
||||||
|
/* eslint-disable jest/valid-title */
|
||||||
|
import * as T from "../../../types";
|
||||||
|
import { parseKidsSection } from "./parse-kids-section";
|
||||||
|
import { tokenizer } from "./tokenizer";
|
||||||
|
|
||||||
|
const tests: {
|
||||||
|
label: string;
|
||||||
|
cases: {
|
||||||
|
input: string;
|
||||||
|
output: T.ParsedKid[];
|
||||||
|
error?: boolean;
|
||||||
|
}[];
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
label: "basic kids section",
|
||||||
|
cases: [
|
||||||
|
{
|
||||||
|
input: "به",
|
||||||
|
output: ["ba"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "به دې",
|
||||||
|
output: ["ba", "de"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "",
|
||||||
|
output: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "مې دې یې",
|
||||||
|
output: ["me", "de", "ye"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "دې به مې",
|
||||||
|
output: ["de", "ba", "me"],
|
||||||
|
error: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "مې یې",
|
||||||
|
output: ["me", "ye"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "دې مې",
|
||||||
|
output: ["de", "me"],
|
||||||
|
error: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "can parse kids section when tokens come after",
|
||||||
|
cases: [
|
||||||
|
{
|
||||||
|
input: "به سړی",
|
||||||
|
output: ["ba"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "مې دې واخیسته",
|
||||||
|
output: ["me", "de"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
tests.forEach(({ label, cases }) => {
|
||||||
|
test(label, () => {
|
||||||
|
cases.forEach(({ input, output, error }) => {
|
||||||
|
const tokens = tokenizer(input);
|
||||||
|
const parsed = parseKidsSection(tokens, []);
|
||||||
|
if (output.length) {
|
||||||
|
expect(parsed.length).toBe(1);
|
||||||
|
expect(parsed.map((x) => x.body.kids)).toEqual(
|
||||||
|
output.length ? [output] : []
|
||||||
|
);
|
||||||
|
if (error) {
|
||||||
|
expect(parsed[0].errors.length).toBeTruthy();
|
||||||
|
} else {
|
||||||
|
expect(parsed[0].errors.length).toBe(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,50 @@
|
||||||
|
import * as T from "../../../types";
|
||||||
|
import { parseKid } from "./parse-kid";
|
||||||
|
import { bindParseResult, returnParseResult } from "./utils";
|
||||||
|
|
||||||
|
export function parseKidsSection(
|
||||||
|
tokens: Readonly<T.Token[]>,
|
||||||
|
prevKids: T.ParsedKid[]
|
||||||
|
): T.ParseResult<{ kids: T.ParsedKid[] }>[] {
|
||||||
|
if (tokens.length === 0) {
|
||||||
|
return prevKids.length ? returnParseResult(tokens, { kids: prevKids }) : [];
|
||||||
|
}
|
||||||
|
const parsedKid = parseKid(tokens);
|
||||||
|
// TODO: is this even necessary ??
|
||||||
|
if (!parsedKid.length) {
|
||||||
|
return prevKids.length ? returnParseResult(tokens, { kids: prevKids }) : [];
|
||||||
|
}
|
||||||
|
return bindParseResult(parsedKid, (tokens, r) => {
|
||||||
|
// return parseKidsSection(tokens, [...prevKids, r]);
|
||||||
|
return {
|
||||||
|
errors: kidDoubled(r, prevKids)
|
||||||
|
? [{ message: `double '${r}' in kids section` }]
|
||||||
|
: !kidComesBehind(r, prevKids.at(-1))
|
||||||
|
? [{ message: "kids section out of order" }]
|
||||||
|
: [],
|
||||||
|
next: parseKidsSection(tokens, [...prevKids, r]),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function kidDoubled(k: T.ParsedKid, prev: T.ParsedKid[]): boolean {
|
||||||
|
return !!prev.find((x) => x === k);
|
||||||
|
}
|
||||||
|
|
||||||
|
const kidsOrder: T.ParsedKid[] = ["ba", "me", "de", "ye"];
|
||||||
|
function getKidRank(k: T.ParsedKid): number {
|
||||||
|
if (k === "mU") {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return kidsOrder.indexOf(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
function kidComesBehind(
|
||||||
|
k: T.ParsedKid,
|
||||||
|
prev: T.ParsedKid | undefined
|
||||||
|
): boolean {
|
||||||
|
if (!prev) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return getKidRank(k) >= getKidRank(prev);
|
||||||
|
}
|
|
@ -80,7 +80,7 @@ export function parsePronoun(tokens: Readonly<T.Token[]>): T.ParseResult<{
|
||||||
inflected: false,
|
inflected: false,
|
||||||
selection: {
|
selection: {
|
||||||
type: "pronoun",
|
type: "pronoun",
|
||||||
person: 4,
|
person: 5,
|
||||||
distance: "far",
|
distance: "far",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,6 +12,11 @@ import {
|
||||||
|
|
||||||
// big problem ما سړی یوړ crashes it !!
|
// big problem ما سړی یوړ crashes it !!
|
||||||
|
|
||||||
|
// TODO: کول verbs!
|
||||||
|
// check that aawu stuff is working
|
||||||
|
// check oo`azmooy -
|
||||||
|
// check څاته
|
||||||
|
|
||||||
export function parseVerb(
|
export function parseVerb(
|
||||||
tokens: Readonly<T.Token[]>,
|
tokens: Readonly<T.Token[]>,
|
||||||
verbLookup: (s: string) => T.VerbEntry[]
|
verbLookup: (s: string) => T.VerbEntry[]
|
||||||
|
|
|
@ -1,35 +1,23 @@
|
||||||
import * as T from "../../../types";
|
import * as T from "../../../types";
|
||||||
import { parseNP } from "./parse-np";
|
import { bindParseResult, returnParseResult } from "./utils";
|
||||||
import { bindParseResult } from "./utils";
|
|
||||||
import { parseVerb } from "./parse-verb";
|
|
||||||
import {
|
import {
|
||||||
makeObjectSelectionComplete,
|
makeObjectSelectionComplete,
|
||||||
makeSubjectSelectionComplete,
|
makeSubjectSelectionComplete,
|
||||||
} from "../phrase-building/blocks-utils";
|
} from "../phrase-building/blocks-utils";
|
||||||
import { vEntry } from "../new-verb-engine/rs-helpers";
|
import { getPersonFromNP, isPastTense } from "../phrase-building/vp-tools";
|
||||||
import { getPersonFromNP, isThirdPerson } from "../phrase-building/vp-tools";
|
import { parseBlocks } from "./parse-blocks";
|
||||||
import { parseBa } from "./parse-ba";
|
import { makePronounSelection } from "../phrase-building/make-selections";
|
||||||
|
import { isFirstOrSecondPersPronoun } from "../phrase-building/render-vp";
|
||||||
// to hide equatives type-doubling issue
|
// to hide equatives type-doubling issue
|
||||||
const kedulStat = vEntry({
|
|
||||||
ts: 1581086654898,
|
|
||||||
i: 11100,
|
|
||||||
p: "کېدل",
|
|
||||||
f: "kedul",
|
|
||||||
g: "kedul",
|
|
||||||
e: "to become _____",
|
|
||||||
r: 2,
|
|
||||||
c: "v. intrans.",
|
|
||||||
ssp: "ش",
|
|
||||||
ssf: "sh",
|
|
||||||
prp: "شول",
|
|
||||||
prf: "shwul",
|
|
||||||
pprtp: "شوی",
|
|
||||||
pprtf: "shúway",
|
|
||||||
noOo: true,
|
|
||||||
ec: "become",
|
|
||||||
});
|
|
||||||
|
|
||||||
// cool examples: زه خوږې ماشومې وهم
|
// cool examples:
|
||||||
|
// زه خوږې ماشومې وهم
|
||||||
|
// ماشومان سړي ولیدل
|
||||||
|
// ماشومانو سړي ولیدل
|
||||||
|
|
||||||
|
// make impossible subjects like I saw me, error
|
||||||
|
|
||||||
|
// PROBLEM! ته وینې doesn't work cause it just takes ته as a verb phrase ?
|
||||||
|
|
||||||
export function parseVP(
|
export function parseVP(
|
||||||
tokens: Readonly<T.Token[]>,
|
tokens: Readonly<T.Token[]>,
|
||||||
|
@ -39,127 +27,59 @@ export function parseVP(
|
||||||
if (tokens.length === 0) {
|
if (tokens.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
// how to make this into a nice pipeline... 🤔
|
const blocks = parseBlocks(tokens, lookup, verbLookup, [], []);
|
||||||
const NP1 = parseNP(tokens, lookup).filter(({ errors }) => !errors.length);
|
return bindParseResult(blocks, (tokens, { blocks, kids }) => {
|
||||||
const ba = bindParseResult(NP1, (tokens, np1) => {
|
const ph = blocks.find((x) => "type" in x && x.type === "PH") as
|
||||||
const b = parseBa(tokens);
|
|
||||||
if (!b.length) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
tokens,
|
|
||||||
body: {
|
|
||||||
np1,
|
|
||||||
ba: false,
|
|
||||||
},
|
|
||||||
errors: [],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
return b.map(({ tokens, errors }) => ({
|
|
||||||
body: {
|
|
||||||
np1,
|
|
||||||
ba: true,
|
|
||||||
},
|
|
||||||
errors,
|
|
||||||
tokens,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const NP2 = bindParseResult<
|
|
||||||
{
|
|
||||||
np1: {
|
|
||||||
inflected: boolean;
|
|
||||||
selection: T.NPSelection;
|
|
||||||
};
|
|
||||||
ba: boolean;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
np1: {
|
|
||||||
inflected: boolean;
|
|
||||||
selection: T.NPSelection;
|
|
||||||
};
|
|
||||||
ba: boolean;
|
|
||||||
np2:
|
|
||||||
| {
|
| {
|
||||||
inflected: boolean;
|
type: "PH";
|
||||||
selection: T.NPSelection;
|
s: string;
|
||||||
}
|
}
|
||||||
| undefined;
|
| undefined;
|
||||||
|
const verb = blocks.find((x) => "type" in x && x.type === "VB") as
|
||||||
|
| Omit<T.VBE, "ps">
|
||||||
|
| undefined;
|
||||||
|
const ba = !!kids.find((k) => k === "ba");
|
||||||
|
if (!verb || verb.type !== "VB" || verb.info.type !== "verb") {
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
>(ba, (tokens, { np1, ba }) => {
|
if (verb.info.aspect === "perfective") {
|
||||||
const np2s = parseNP(tokens, lookup);
|
// TODO: check that the perfective head is in the right place and actually matches
|
||||||
if (!np2s.length) {
|
if (!ph) {
|
||||||
const r: T.ParseResult<{
|
return [];
|
||||||
np1: {
|
}
|
||||||
inflected: boolean;
|
}
|
||||||
selection: T.NPSelection;
|
const tense = getTenseFromRootsStems(ba, verb.info.base, verb.info.aspect);
|
||||||
|
const isPast = isPastTense(tense);
|
||||||
|
|
||||||
|
const nps = blocks.filter(
|
||||||
|
(x): x is { inflected: boolean; selection: T.NPSelection } =>
|
||||||
|
"inflected" in x
|
||||||
|
);
|
||||||
|
// TODO: check that verb and PH match
|
||||||
|
if (verb.info.verb.entry.c.includes("intrans")) {
|
||||||
|
if (nps.length > 1) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (nps.length === 0) {
|
||||||
|
const v: T.VerbSelectionComplete = {
|
||||||
|
type: "verb",
|
||||||
|
verb: verb.info.verb,
|
||||||
|
transitivity: "intransitive",
|
||||||
|
canChangeTransitivity: false,
|
||||||
|
canChangeStatDyn: false,
|
||||||
|
negative: false,
|
||||||
|
tense,
|
||||||
|
canChangeVoice: true,
|
||||||
|
isCompound: false,
|
||||||
|
voice: "active",
|
||||||
};
|
};
|
||||||
ba: boolean;
|
|
||||||
np2: undefined;
|
|
||||||
}>[] = [
|
|
||||||
{
|
|
||||||
tokens,
|
|
||||||
body: {
|
|
||||||
np1,
|
|
||||||
np2: undefined,
|
|
||||||
ba,
|
|
||||||
},
|
|
||||||
errors: [],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
return np2s.map((p) => ({
|
|
||||||
tokens: p.tokens,
|
|
||||||
body: {
|
|
||||||
np1,
|
|
||||||
np2: p.body,
|
|
||||||
ba,
|
|
||||||
},
|
|
||||||
errors: p.errors,
|
|
||||||
}));
|
|
||||||
}).filter(({ errors }) => !errors.length);
|
|
||||||
const vb = bindParseResult(NP2, (tokens, nps) => {
|
|
||||||
const vb = parseVerb(tokens, verbLookup);
|
|
||||||
// TODO make a nice functor that just maps or adds in the body
|
|
||||||
return vb.map((p) => ({
|
|
||||||
tokens: p.tokens,
|
|
||||||
body: {
|
|
||||||
np2: nps.np2,
|
|
||||||
v: p.body,
|
|
||||||
np1: nps.np1,
|
|
||||||
ba: nps.ba,
|
|
||||||
},
|
|
||||||
errors: p.errors,
|
|
||||||
}));
|
|
||||||
}).filter(({ errors }) => !errors.length);
|
|
||||||
// TODO: be able to bind mulitple vals
|
|
||||||
return bindParseResult(vb, (tokens, { np1, np2, v: [ph, v], ba }) => {
|
|
||||||
const w: T.ParseResult<T.VPSelectionComplete>[] = [];
|
|
||||||
if (v.info.type === "equative") {
|
|
||||||
throw new Error("not yet implemented");
|
|
||||||
}
|
|
||||||
const isPast = v.info.base === "root";
|
|
||||||
const intransitive =
|
|
||||||
v.info.type === "verb" && v.info.verb.entry.c.includes("intrans.");
|
|
||||||
if (intransitive) {
|
|
||||||
if (np2) return [];
|
|
||||||
const s = np1;
|
|
||||||
const errors: T.ParseError[] = [];
|
|
||||||
if (s.inflected) {
|
|
||||||
errors.push({
|
|
||||||
message: "subject of intransitive verb should not be inflected",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (getPersonFromNP(s.selection) !== v.person) {
|
|
||||||
errors.push({
|
|
||||||
message: "subject should agree with intransitive verb",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const blocks: T.VPSBlockComplete[] = [
|
const blocks: T.VPSBlockComplete[] = [
|
||||||
{
|
{
|
||||||
key: 1,
|
key: 1,
|
||||||
block: makeSubjectSelectionComplete(s.selection),
|
block: makeSubjectSelectionComplete({
|
||||||
|
type: "NP",
|
||||||
|
selection: makePronounSelection(verb.person),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 2,
|
key: 2,
|
||||||
|
@ -169,91 +89,268 @@ export function parseVP(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const verb: T.VerbSelectionComplete = {
|
return returnParseResult(tokens, {
|
||||||
|
blocks,
|
||||||
|
verb: v,
|
||||||
|
externalComplement: undefined,
|
||||||
|
form: {
|
||||||
|
removeKing: true,
|
||||||
|
shrinkServant: false,
|
||||||
|
},
|
||||||
|
} as T.VPSelectionComplete);
|
||||||
|
}
|
||||||
|
if (nps.length === 1) {
|
||||||
|
const errors: T.ParseError[] = [];
|
||||||
|
if (getPersonFromNP(nps[0].selection) !== verb.person) {
|
||||||
|
errors.push({ message: "subject must agree with intransitive verb" });
|
||||||
|
}
|
||||||
|
if (nps[0].inflected) {
|
||||||
|
errors.push({
|
||||||
|
message: "subject of intransitive verb must not be inflected",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const blocks: T.VPSBlockComplete[] = [
|
||||||
|
{
|
||||||
|
key: 1,
|
||||||
|
block: makeSubjectSelectionComplete(nps[0].selection),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
block: {
|
||||||
|
type: "objectSelection",
|
||||||
|
selection: "none",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const v: T.VerbSelectionComplete = {
|
||||||
type: "verb",
|
type: "verb",
|
||||||
verb: v.info.type === "verb" ? v.info.verb : kedulStat,
|
verb: verb.info.verb,
|
||||||
transitivity: "intransitive",
|
transitivity: "intransitive",
|
||||||
canChangeTransitivity: false,
|
canChangeTransitivity: false,
|
||||||
canChangeStatDyn: false,
|
canChangeStatDyn: false,
|
||||||
negative: false,
|
negative: false,
|
||||||
tense: getTenseFromRootsStems(ba, v.info.base, v.info.aspect),
|
tense,
|
||||||
canChangeVoice: true,
|
canChangeVoice: true,
|
||||||
isCompound: false,
|
isCompound: false,
|
||||||
voice: "active",
|
voice: "active",
|
||||||
};
|
};
|
||||||
w.push({
|
return returnParseResult(
|
||||||
tokens,
|
tokens,
|
||||||
body: {
|
{
|
||||||
blocks,
|
blocks,
|
||||||
verb,
|
verb: v,
|
||||||
externalComplement: undefined,
|
externalComplement: undefined,
|
||||||
form: {
|
form: {
|
||||||
removeKing: false,
|
removeKing: false,
|
||||||
shrinkServant: false,
|
shrinkServant: false,
|
||||||
},
|
},
|
||||||
|
} as T.VPSelectionComplete,
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// transitive
|
||||||
|
if (nps.length > 2) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (nps.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (nps.length === 1) {
|
||||||
|
const np = nps[0];
|
||||||
|
return (
|
||||||
|
[
|
||||||
|
{
|
||||||
|
removeKing: true,
|
||||||
|
shrinkServant: false,
|
||||||
},
|
},
|
||||||
errors,
|
{
|
||||||
});
|
removeKing: false,
|
||||||
} else {
|
shrinkServant: true,
|
||||||
// transitive verb
|
},
|
||||||
if (!(np1 && np2)) return [];
|
] as const
|
||||||
[[np1, np2, false] as const, [np2, np1, true] as const].forEach(
|
).flatMap((form) => {
|
||||||
([s, o, reversed]) => {
|
|
||||||
if (v.info.type === "equative") {
|
|
||||||
throw new Error("not yet implemented");
|
|
||||||
}
|
|
||||||
if (!s || !o) return [];
|
|
||||||
// TODO: check if perfective head MATCHES verb
|
|
||||||
if (v.info.aspect === "perfective" && !ph) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const subjPerson = getPersonFromNP(s.selection);
|
|
||||||
const errors: T.ParseError[] = [];
|
const errors: T.ParseError[] = [];
|
||||||
if (intransitive) {
|
if (form.removeKing) {
|
||||||
|
// king is gone
|
||||||
|
// servant is there
|
||||||
|
const king: T.NPSelection = {
|
||||||
|
type: "NP",
|
||||||
|
selection: makePronounSelection(verb.person),
|
||||||
|
};
|
||||||
|
const servant = np.selection;
|
||||||
|
if (!isPast) {
|
||||||
|
if (isFirstOrSecondPersPronoun(np.selection))
|
||||||
|
if (!np.inflected) {
|
||||||
|
errors.push({
|
||||||
|
message:
|
||||||
|
"first or second pronoun object of non-past transitive verb must be inflected",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!np.inflected) {
|
||||||
|
errors.push({
|
||||||
|
message:
|
||||||
|
"object of non-past transitive verb must not be inflected",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const blocks: T.VPSBlockComplete[] = !isPast
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
key: 1,
|
||||||
|
block: makeSubjectSelectionComplete(king),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
block: makeObjectSelectionComplete(servant),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
key: 1,
|
||||||
|
block: makeSubjectSelectionComplete(servant),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
block: makeObjectSelectionComplete(king),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const v: T.VerbSelectionComplete = {
|
||||||
|
type: "verb",
|
||||||
|
// @ts-ignore
|
||||||
|
verb: verb.info.verb,
|
||||||
|
transitivity: "transitive",
|
||||||
|
canChangeTransitivity: false,
|
||||||
|
canChangeStatDyn: false,
|
||||||
|
negative: false,
|
||||||
|
tense,
|
||||||
|
canChangeVoice: true,
|
||||||
|
isCompound: false,
|
||||||
|
voice: "active",
|
||||||
|
};
|
||||||
|
return returnParseResult(
|
||||||
|
tokens,
|
||||||
|
{
|
||||||
|
blocks,
|
||||||
|
verb: v,
|
||||||
|
externalComplement: undefined,
|
||||||
|
form,
|
||||||
|
} as T.VPSelectionComplete,
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// servant is shrunken
|
||||||
|
// king is there
|
||||||
|
const king = np.selection;
|
||||||
|
const shrunkenServantPeople = getPeopleFromKids(kids);
|
||||||
|
if (!shrunkenServantPeople.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
const servants = shrunkenServantPeople.map(
|
||||||
if (isPast) {
|
(person): T.NPSelection => ({
|
||||||
if (getPersonFromNP(o.selection) !== v.person) {
|
type: "NP",
|
||||||
|
selection: makePronounSelection(person),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (!isPast) {
|
||||||
|
if (np.inflected) {
|
||||||
errors.push({
|
errors.push({
|
||||||
message: "transitive past tense verb does not match object",
|
message:
|
||||||
|
"object of a past tense transitive verb should not be inflected",
|
||||||
});
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (np.inflected) {
|
||||||
|
errors.push({
|
||||||
|
message:
|
||||||
|
"subject of a non-past tense transitive verb should not be inflected",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const blocksOps: T.VPSBlockComplete[][] = servants.map((servant) =>
|
||||||
|
!isPast
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
key: 1,
|
||||||
|
block: makeSubjectSelectionComplete(king),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
block: makeObjectSelectionComplete(servant),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
key: 1,
|
||||||
|
block: makeSubjectSelectionComplete(servant),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
block: makeObjectSelectionComplete(king),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
const v: T.VerbSelectionComplete = {
|
||||||
|
type: "verb",
|
||||||
|
// @ts-ignore
|
||||||
|
verb: verb.info.verb,
|
||||||
|
transitivity: "transitive",
|
||||||
|
canChangeTransitivity: false,
|
||||||
|
canChangeStatDyn: false,
|
||||||
|
negative: false,
|
||||||
|
tense,
|
||||||
|
canChangeVoice: true,
|
||||||
|
isCompound: false,
|
||||||
|
voice: "active",
|
||||||
|
};
|
||||||
|
return blocksOps.map((blocks) => ({
|
||||||
|
tokens,
|
||||||
|
body: {
|
||||||
|
blocks,
|
||||||
|
verb: v,
|
||||||
|
externalComplement: undefined,
|
||||||
|
form,
|
||||||
|
} as T.VPSelectionComplete,
|
||||||
|
errors,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// possibilities
|
||||||
|
// present:
|
||||||
|
// - no king (np is servant)
|
||||||
|
// - shrunken servant (np is king)
|
||||||
|
// past:
|
||||||
|
// - no king (np is servant)
|
||||||
|
// - shrunken servant (np is king)
|
||||||
|
} else {
|
||||||
|
if (isPast) {
|
||||||
|
return (
|
||||||
|
[
|
||||||
|
[nps[0], nps[1], false],
|
||||||
|
[nps[1], nps[0], true],
|
||||||
|
] as const
|
||||||
|
).flatMap(([s, o, flip]) => {
|
||||||
|
const errors: T.ParseError[] = [];
|
||||||
if (!s.inflected) {
|
if (!s.inflected) {
|
||||||
errors.push({
|
errors.push({
|
||||||
message: "transitive past tense subject should be inflected",
|
message:
|
||||||
|
"subject of transitive past tense verb must be inflected",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (o.inflected) {
|
if (o.inflected) {
|
||||||
errors.push({
|
errors.push({
|
||||||
message:
|
message:
|
||||||
"transitive past tense object should not be inflected",
|
"object of past tense transitive verb must not be inflected",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
if (getPersonFromNP(o.selection) !== verb.person) {
|
||||||
} else {
|
|
||||||
if (getPersonFromNP(s.selection) !== v.person) {
|
|
||||||
errors.push({
|
|
||||||
message: "verb does not match subject",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (s.inflected) {
|
|
||||||
errors.push({ message: "subject should not be inflected" });
|
|
||||||
}
|
|
||||||
if (o.selection.selection.type === "pronoun") {
|
|
||||||
if (!isThirdPerson(subjPerson) && !o.inflected) {
|
|
||||||
errors.push({
|
errors.push({
|
||||||
message:
|
message:
|
||||||
"1st or 2nd person object pronoun should be inflected",
|
"past tense transitive verb must agree with the object",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (o.inflected) {
|
let blocks: T.VPSBlockComplete[] = [
|
||||||
errors.push({ message: "object should not be inflected" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const blocks: T.VPSBlockComplete[] = [
|
|
||||||
{
|
{
|
||||||
key: 1,
|
key: 1,
|
||||||
block: makeSubjectSelectionComplete(s.selection),
|
block: makeSubjectSelectionComplete(s.selection),
|
||||||
|
@ -263,40 +360,397 @@ export function parseVP(
|
||||||
block: makeObjectSelectionComplete(o.selection),
|
block: makeObjectSelectionComplete(o.selection),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
if (reversed) {
|
if (flip) {
|
||||||
blocks.reverse();
|
blocks = blocks.reverse();
|
||||||
}
|
}
|
||||||
const verb: T.VerbSelectionComplete = {
|
const v: T.VerbSelectionComplete = {
|
||||||
type: "verb",
|
type: "verb",
|
||||||
verb: v.info.type === "verb" ? v.info.verb : kedulStat,
|
// @ts-ignore
|
||||||
|
verb: verb.info.verb,
|
||||||
transitivity: "transitive",
|
transitivity: "transitive",
|
||||||
canChangeTransitivity: false,
|
canChangeTransitivity: false,
|
||||||
canChangeStatDyn: false,
|
canChangeStatDyn: false,
|
||||||
negative: false,
|
negative: false,
|
||||||
tense: getTenseFromRootsStems(ba, v.info.base, v.info.aspect),
|
tense,
|
||||||
canChangeVoice: true,
|
canChangeVoice: true,
|
||||||
isCompound: false,
|
isCompound: false,
|
||||||
voice: "active",
|
voice: "active",
|
||||||
};
|
};
|
||||||
w.push({
|
return returnParseResult(
|
||||||
tokens,
|
tokens,
|
||||||
body: {
|
{
|
||||||
blocks,
|
blocks,
|
||||||
verb,
|
verb: v,
|
||||||
externalComplement: undefined,
|
externalComplement: undefined,
|
||||||
form: {
|
form: {
|
||||||
removeKing: false,
|
removeKing: false,
|
||||||
shrinkServant: false,
|
shrinkServant: false,
|
||||||
},
|
},
|
||||||
},
|
} as T.VPSelectionComplete,
|
||||||
errors,
|
errors
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
return w;
|
} else {
|
||||||
|
return (
|
||||||
|
[
|
||||||
|
[nps[0], nps[1], false],
|
||||||
|
[nps[1], nps[0], true],
|
||||||
|
] as const
|
||||||
|
).flatMap(([s, o, flip]) => {
|
||||||
|
const errors: T.ParseError[] = [];
|
||||||
|
if (isFirstOrSecondPersPronoun(o.selection)) {
|
||||||
|
if (!o.inflected) {
|
||||||
|
errors.push({
|
||||||
|
message:
|
||||||
|
"object of transitive non-past tense verb must be inflected when it's a first or second person pronoun",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (o.inflected) {
|
||||||
|
errors.push({
|
||||||
|
message:
|
||||||
|
"object of transitive non-past tense verb must not be inflected",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s.inflected) {
|
||||||
|
errors.push({
|
||||||
|
message:
|
||||||
|
"subject of transitive non-past tense verb must not be inflected",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (getPersonFromNP(s.selection) !== verb.person) {
|
||||||
|
errors.push({
|
||||||
|
message:
|
||||||
|
"non-past tense transitive verb must agree with the subject",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let blocks: T.VPSBlockComplete[] = [
|
||||||
|
{
|
||||||
|
key: 1,
|
||||||
|
block: makeSubjectSelectionComplete(s.selection),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
block: makeObjectSelectionComplete(o.selection),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
if (flip) {
|
||||||
|
blocks = blocks.reverse();
|
||||||
|
}
|
||||||
|
const v: T.VerbSelectionComplete = {
|
||||||
|
type: "verb",
|
||||||
|
// @ts-ignore
|
||||||
|
verb: verb.info.verb,
|
||||||
|
transitivity: "transitive",
|
||||||
|
canChangeTransitivity: false,
|
||||||
|
canChangeStatDyn: false,
|
||||||
|
negative: false,
|
||||||
|
tense,
|
||||||
|
canChangeVoice: true,
|
||||||
|
isCompound: false,
|
||||||
|
voice: "active",
|
||||||
|
};
|
||||||
|
return returnParseResult(
|
||||||
|
tokens,
|
||||||
|
{
|
||||||
|
blocks,
|
||||||
|
verb: v,
|
||||||
|
externalComplement: undefined,
|
||||||
|
form: {
|
||||||
|
removeKing: false,
|
||||||
|
shrinkServant: false,
|
||||||
|
},
|
||||||
|
} as T.VPSelectionComplete,
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPeopleFromKids(kids: T.ParsedKid[]): T.Person[] {
|
||||||
|
const p: T.Person[] = [];
|
||||||
|
for (let k of kids) {
|
||||||
|
if (k === "me") {
|
||||||
|
p.push(T.Person.FirstSingMale);
|
||||||
|
p.push(T.Person.FirstSingFemale);
|
||||||
|
} else if (k === "de") {
|
||||||
|
p.push(T.Person.SecondSingMale);
|
||||||
|
p.push(T.Person.SecondSingFemale);
|
||||||
|
} else if (k === "ye") {
|
||||||
|
p.push(T.Person.ThirdSingMale);
|
||||||
|
p.push(T.Person.ThirdSingFemale);
|
||||||
|
p.push(T.Person.ThirdPlurMale);
|
||||||
|
p.push(T.Person.ThirdPlurFemale);
|
||||||
|
} else if (k === "mU") {
|
||||||
|
p.push(T.Person.FirstPlurMale);
|
||||||
|
p.push(T.Person.FirstPlurFemale);
|
||||||
|
p.push(T.Person.SecondPlurMale);
|
||||||
|
p.push(T.Person.SecondPlurFemale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// // how to make this into a nice pipeline... 🤔
|
||||||
|
// const NP1 = parseNP(tokens, lookup).filter(({ errors }) => !errors.length);
|
||||||
|
// const ba = bindParseResult(NP1, (tokens, np1) => {
|
||||||
|
// const b = parseBa(tokens);
|
||||||
|
// if (!b.length) {
|
||||||
|
// return [
|
||||||
|
// {
|
||||||
|
// tokens,
|
||||||
|
// body: {
|
||||||
|
// np1,
|
||||||
|
// ba: false,
|
||||||
|
// },
|
||||||
|
// errors: [],
|
||||||
|
// },
|
||||||
|
// ];
|
||||||
|
// } else {
|
||||||
|
// return b.map(({ tokens, errors }) => ({
|
||||||
|
// body: {
|
||||||
|
// np1,
|
||||||
|
// ba: true,
|
||||||
|
// },
|
||||||
|
// errors,
|
||||||
|
// tokens,
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// const NP2 = bindParseResult<
|
||||||
|
// {
|
||||||
|
// np1: {
|
||||||
|
// inflected: boolean;
|
||||||
|
// selection: T.NPSelection;
|
||||||
|
// };
|
||||||
|
// ba: boolean;
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// np1: {
|
||||||
|
// inflected: boolean;
|
||||||
|
// selection: T.NPSelection;
|
||||||
|
// };
|
||||||
|
// ba: boolean;
|
||||||
|
// np2:
|
||||||
|
// | {
|
||||||
|
// inflected: boolean;
|
||||||
|
// selection: T.NPSelection;
|
||||||
|
// }
|
||||||
|
// | undefined;
|
||||||
|
// }
|
||||||
|
// >(ba, (tokens, { np1, ba }) => {
|
||||||
|
// const np2s = parseNP(tokens, lookup);
|
||||||
|
// if (!np2s.length) {
|
||||||
|
// const r: T.ParseResult<{
|
||||||
|
// np1: {
|
||||||
|
// inflected: boolean;
|
||||||
|
// selection: T.NPSelection;
|
||||||
|
// };
|
||||||
|
// ba: boolean;
|
||||||
|
// np2: undefined;
|
||||||
|
// }>[] = [
|
||||||
|
// {
|
||||||
|
// tokens,
|
||||||
|
// body: {
|
||||||
|
// np1,
|
||||||
|
// np2: undefined,
|
||||||
|
// ba,
|
||||||
|
// },
|
||||||
|
// errors: [],
|
||||||
|
// },
|
||||||
|
// ];
|
||||||
|
// return r;
|
||||||
|
// }
|
||||||
|
// return np2s.map((p) => ({
|
||||||
|
// tokens: p.tokens,
|
||||||
|
// body: {
|
||||||
|
// np1,
|
||||||
|
// np2: p.body,
|
||||||
|
// ba,
|
||||||
|
// },
|
||||||
|
// errors: p.errors,
|
||||||
|
// }));
|
||||||
|
// }).filter(({ errors }) => !errors.length);
|
||||||
|
// const vb = bindParseResult(NP2, (tokens, nps) => {
|
||||||
|
// const vb = parseVerb(tokens, verbLookup);
|
||||||
|
// // TODO make a nice functor that just maps or adds in the body
|
||||||
|
// return vb.map((p) => ({
|
||||||
|
// tokens: p.tokens,
|
||||||
|
// body: {
|
||||||
|
// np2: nps.np2,
|
||||||
|
// v: p.body,
|
||||||
|
// np1: nps.np1,
|
||||||
|
// ba: nps.ba,
|
||||||
|
// },
|
||||||
|
// errors: p.errors,
|
||||||
|
// }));
|
||||||
|
// }).filter(({ errors }) => !errors.length);
|
||||||
|
// // TODO: be able to bind mulitple vals
|
||||||
|
// return bindParseResult(vb, (tokens, { np1, np2, v: [ph, v], ba }) => {
|
||||||
|
// const w: T.ParseResult<T.VPSelectionComplete>[] = [];
|
||||||
|
// if (v.info.type === "equative") {
|
||||||
|
// throw new Error("not yet implemented");
|
||||||
|
// }
|
||||||
|
// const isPast = v.info.base === "root";
|
||||||
|
// const intransitive =
|
||||||
|
// v.info.type === "verb" && v.info.verb.entry.c.includes("intrans.");
|
||||||
|
// if (intransitive) {
|
||||||
|
// if (np2) return [];
|
||||||
|
// const s = np1;
|
||||||
|
// const errors: T.ParseError[] = [];
|
||||||
|
// if (s.inflected) {
|
||||||
|
// errors.push({
|
||||||
|
// message: "subject of intransitive verb should not be inflected",
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// if (getPersonFromNP(s.selection) !== v.person) {
|
||||||
|
// errors.push({
|
||||||
|
// message: "subject should agree with intransitive verb",
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// const blocks: T.VPSBlockComplete[] = [
|
||||||
|
// {
|
||||||
|
// key: 1,
|
||||||
|
// block: makeSubjectSelectionComplete(s.selection),
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// key: 2,
|
||||||
|
// block: {
|
||||||
|
// type: "objectSelection",
|
||||||
|
// selection: "none",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ];
|
||||||
|
// const verb: T.VerbSelectionComplete = {
|
||||||
|
// type: "verb",
|
||||||
|
// verb: v.info.type === "verb" ? v.info.verb : kedulStat,
|
||||||
|
// transitivity: "intransitive",
|
||||||
|
// canChangeTransitivity: false,
|
||||||
|
// canChangeStatDyn: false,
|
||||||
|
// negative: false,
|
||||||
|
// tense: getTenseFromRootsStems(ba, v.info.base, v.info.aspect),
|
||||||
|
// canChangeVoice: true,
|
||||||
|
// isCompound: false,
|
||||||
|
// voice: "active",
|
||||||
|
// };
|
||||||
|
// w.push({
|
||||||
|
// tokens,
|
||||||
|
// body: {
|
||||||
|
// blocks,
|
||||||
|
// verb,
|
||||||
|
// externalComplement: undefined,
|
||||||
|
// form: {
|
||||||
|
// removeKing: false,
|
||||||
|
// shrinkServant: false,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// errors,
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// // transitive verb
|
||||||
|
// if (!(np1 && np2)) return [];
|
||||||
|
// [[np1, np2, false] as const, [np2, np1, true] as const].forEach(
|
||||||
|
// ([s, o, reversed]) => {
|
||||||
|
// if (v.info.type === "equative") {
|
||||||
|
// throw new Error("not yet implemented");
|
||||||
|
// }
|
||||||
|
// if (!s || !o) return [];
|
||||||
|
// // TODO: check if perfective head MATCHES verb
|
||||||
|
// if (v.info.aspect === "perfective" && !ph) {
|
||||||
|
// return [];
|
||||||
|
// }
|
||||||
|
// const subjPerson = getPersonFromNP(s.selection);
|
||||||
|
// const errors: T.ParseError[] = [];
|
||||||
|
// if (intransitive) {
|
||||||
|
// return [];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (isPast) {
|
||||||
|
// if (getPersonFromNP(o.selection) !== v.person) {
|
||||||
|
// errors.push({
|
||||||
|
// message: "transitive past tense verb does not match object",
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// if (!s.inflected) {
|
||||||
|
// errors.push({
|
||||||
|
// message: "transitive past tense subject should be inflected",
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// if (o.inflected) {
|
||||||
|
// errors.push({
|
||||||
|
// message:
|
||||||
|
// "transitive past tense object should not be inflected",
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if (getPersonFromNP(s.selection) !== v.person) {
|
||||||
|
// errors.push({
|
||||||
|
// message: "verb does not match subject",
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// if (s.inflected) {
|
||||||
|
// errors.push({ message: "subject should not be inflected" });
|
||||||
|
// }
|
||||||
|
// if (o.selection.selection.type === "pronoun") {
|
||||||
|
// if (!isThirdPerson(subjPerson) && !o.inflected) {
|
||||||
|
// errors.push({
|
||||||
|
// message:
|
||||||
|
// "1st or 2nd person object pronoun should be inflected",
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// } else if (o.inflected) {
|
||||||
|
// errors.push({ message: "object should not be inflected" });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const blocks: T.VPSBlockComplete[] = [
|
||||||
|
// {
|
||||||
|
// key: 1,
|
||||||
|
// block: makeSubjectSelectionComplete(s.selection),
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// key: 2,
|
||||||
|
// block: makeObjectSelectionComplete(o.selection),
|
||||||
|
// },
|
||||||
|
// ];
|
||||||
|
// if (reversed) {
|
||||||
|
// blocks.reverse();
|
||||||
|
// }
|
||||||
|
// const verb: T.VerbSelectionComplete = {
|
||||||
|
// type: "verb",
|
||||||
|
// verb: v.info.type === "verb" ? v.info.verb : kedulStat,
|
||||||
|
// transitivity: "transitive",
|
||||||
|
// canChangeTransitivity: false,
|
||||||
|
// canChangeStatDyn: false,
|
||||||
|
// negative: false,
|
||||||
|
// tense: getTenseFromRootsStems(ba, v.info.base, v.info.aspect),
|
||||||
|
// canChangeVoice: true,
|
||||||
|
// isCompound: false,
|
||||||
|
// voice: "active",
|
||||||
|
// };
|
||||||
|
// w.push({
|
||||||
|
// tokens,
|
||||||
|
// body: {
|
||||||
|
// blocks,
|
||||||
|
// verb,
|
||||||
|
// externalComplement: undefined,
|
||||||
|
// form: {
|
||||||
|
// removeKing: false,
|
||||||
|
// shrinkServant: false,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// errors,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
function getTenseFromRootsStems(
|
function getTenseFromRootsStems(
|
||||||
hasBa: boolean,
|
hasBa: boolean,
|
||||||
|
|
|
@ -20,7 +20,7 @@ import * as T from "../../../types";
|
||||||
* from the different previous results
|
* from the different previous results
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function bindParseResult<C extends object, D extends object>(
|
export function bindParseResult<C, D>(
|
||||||
previous: T.ParseResult<C>[],
|
previous: T.ParseResult<C>[],
|
||||||
f: (
|
f: (
|
||||||
tokens: Readonly<T.Token[]>,
|
tokens: Readonly<T.Token[]>,
|
||||||
|
@ -59,18 +59,42 @@ export function bindParseResult<C extends object, D extends object>(
|
||||||
errors: [...errsPassed, ...x.errors, ...errors],
|
errors: [...errsPassed, ...x.errors, ...errors],
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
return cleanOutFails(nextPossibilities);
|
return cleanOutResults(nextPossibilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cleanOutFails<C extends object>(
|
export function returnParseResult<D>(
|
||||||
|
tokens: Readonly<T.Token[]>,
|
||||||
|
body: D,
|
||||||
|
errors?: T.ParseError[]
|
||||||
|
): T.ParseResult<D>[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
tokens,
|
||||||
|
body,
|
||||||
|
errors: errors || [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finds the most successful path(s) and culls out any other more erroneous
|
||||||
|
* or redundant paths
|
||||||
|
*/
|
||||||
|
export function cleanOutResults<C>(
|
||||||
results: T.ParseResult<C>[]
|
results: T.ParseResult<C>[]
|
||||||
): T.ParseResult<C>[] {
|
): T.ParseResult<C>[] {
|
||||||
// if there's any success anywhere, remove any of the errors
|
if (results.length === 0) {
|
||||||
const errorsGone = results.find((x) => x.errors.length === 0)
|
return results;
|
||||||
? results.filter((x) => x.errors.length === 0)
|
}
|
||||||
: results;
|
let min = Infinity;
|
||||||
|
for (let a of results) {
|
||||||
|
if (a.errors.length < min) {
|
||||||
|
min = a.errors.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const errorsCulled = results.filter((x) => x.errors.length === min);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return Array.from(new Set(errorsGone.map(JSON.stringify))).map(JSON.parse);
|
return Array.from(new Set(errorsCulled.map(JSON.stringify))).map(JSON.parse);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCompleteResult<C extends object>(
|
export function isCompleteResult<C extends object>(
|
||||||
|
|
|
@ -352,7 +352,7 @@ export function getKingAndServant(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFirstOrSecondPersPronoun(
|
export function isFirstOrSecondPersPronoun(
|
||||||
o: "none" | T.NPSelection | T.Person.ThirdPlurMale
|
o: "none" | T.NPSelection | T.Person.ThirdPlurMale
|
||||||
): boolean {
|
): boolean {
|
||||||
if (typeof o !== "object") return false;
|
if (typeof o !== "object") return false;
|
||||||
|
|
|
@ -1197,6 +1197,8 @@ export type Kid = {
|
||||||
kid: { type: "ba" } | MiniPronoun;
|
kid: { type: "ba" } | MiniPronoun;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ParsedKid = "ba" | "me" | "de" | "ye" | "mU";
|
||||||
|
|
||||||
export type MiniPronoun = {
|
export type MiniPronoun = {
|
||||||
type: "mini-pronoun";
|
type: "mini-pronoun";
|
||||||
person: Person;
|
person: Person;
|
||||||
|
|
Loading…
Reference in New Issue