some error messages

This commit is contained in:
adueck 2023-07-31 00:06:21 +04:00
parent c38e0645d3
commit 6aec2dfeb2
6 changed files with 138 additions and 22 deletions

View File

@ -7,16 +7,19 @@ import { tokenizer } from "../lib/src/parsing/tokenizer";
function ParserDemo({ opts }: { opts: T.TextOptions }) {
const [text, setText] = useState<string>("");
const [result, setResult] = useState<string>("");
const [errors, setErrors] = useState<string[]>([]);
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
const value = e.target.value;
if (!value) {
setText("");
setResult("");
setErrors([]);
return;
}
const r = parsePhrase(tokenizer(value), lookup);
const { success, errors } = parsePhrase(tokenizer(value), lookup);
setText(value);
setResult(JSON.stringify(r, null, " "));
setErrors(errors);
setResult(JSON.stringify(success, null, " "));
}
return (
<div className="mt-3" style={{ marginBottom: "1000px" }}>
@ -32,6 +35,13 @@ function ParserDemo({ opts }: { opts: T.TextOptions }) {
onChange={handleChange}
/>
</div>
{result === "[]" && errors.length > 0 && (
<div className="alert alert-danger" role="alert">
{errors.map((e) => (
<div key={Math.random()}>{e}</div>
))}
</div>
)}
<samp>
<pre>{result}</pre>
</samp>

View File

@ -6,6 +6,7 @@ import {
isPattern,
isPattern5Entry,
isPattern4Entry,
isPattern6FemEntry,
} from "../type-predicates";
import { equals } from "rambda";
@ -135,6 +136,14 @@ export function getInflectionQueries(
predicate: (e) => isPattern2Entry(e) || isPattern3Entry(e),
},
});
queries.push({
search: { p: s },
details: {
inflection: [0],
gender: ["fem"],
predicate: isPattern6FemEntry,
},
});
} else if (s.endsWith("و")) {
queries.push({
search: { p: s.slice(0, -1) },
@ -179,6 +188,24 @@ export function getInflectionQueries(
predicate: isPattern3Entry,
},
});
if (includeNouns) {
queries.push({
search: { p: s.slice(0, -1) + "ي" },
details: {
inflection: [1],
gender: ["fem"],
predicate: isPattern6FemEntry,
},
});
queries.push({
search: { p: s },
details: {
inflection: [0, 1],
gender: ["fem"],
predicate: isPattern3Entry,
},
});
}
}
const coallated: ReturnType<typeof getInflectionQueries> = [];

View File

@ -313,7 +313,12 @@ describe("parsing adjectives", () => {
cases.forEach(({ input, output }) => {
const tokens = tokenizer(input);
const possibilities = parseAdjective(tokens, lookup).map((x) => x[1]);
expect(possibilities).toEqual(output);
expect(
possibilities.map((x) => {
const { given, ...rest } = x;
return rest;
})
).toEqual(output);
});
});
});

View File

@ -11,6 +11,7 @@ export function parseAdjective(
{
inflection: (0 | 1 | 2)[];
gender: T.Gender[];
given: string;
selection: T.AdjectiveSelection;
}
][] {
@ -32,6 +33,7 @@ export function parseAdjective(
selection,
inflection: deets.inflection,
gender: deets.gender,
given: first,
},
]);
});

View File

@ -15,17 +15,28 @@ export function parseNoun(
adjectives: {
inflection: (0 | 1 | 2)[];
gender: T.Gender[];
given: string;
selection: T.AdjectiveSelection;
}[]
): [string[], { inflection: (0 | 1 | 2)[]; selection: T.NounSelection }][] {
): {
success: [
string[],
{ inflection: (0 | 1 | 2)[]; selection: T.NounSelection }
][];
errors: string[];
} {
if (tokens.length === 0) {
return [];
return {
success: [],
errors: [],
};
}
const adjRes = parseAdjective(tokens, lookup);
const withAdj = adjRes.flatMap(([tkns, adj]) =>
const withAdj = adjRes.map(([tkns, adj]) =>
parseNoun(tkns, lookup, [...adjectives, adj])
);
const w: ReturnType<typeof parseNoun> = [];
const success: ReturnType<typeof parseNoun>["success"] = [];
const errors: string[] = [];
const [first, ...rest] = tokens;
const searches = getInflectionQueries(first, true);
@ -34,11 +45,15 @@ export function parseNoun(
details.forEach((deets) => {
const fittingEntries = nounEntries.filter(deets.predicate);
fittingEntries.forEach((entry) => {
console.log({ entry, deets });
if (isUnisexNounEntry(entry)) {
deets.gender.forEach((gender) => {
if (adjsMatch(adjectives, gender, deets.inflection)) {
w.push([
const { ok, error } = adjsMatch(
adjectives,
gender,
deets.inflection
);
if (ok) {
success.push([
rest,
{
inflection: deets.inflection,
@ -49,11 +64,16 @@ export function parseNoun(
},
},
]);
} else {
error.forEach((e) => {
errors.push(e);
});
}
});
} else if (isMascNounEntry(entry) && deets.gender.includes("masc")) {
if (adjsMatch(adjectives, "masc", deets.inflection)) {
w.push([
const { ok, error } = adjsMatch(adjectives, "masc", deets.inflection);
if (ok) {
success.push([
rest,
{
inflection: deets.inflection,
@ -63,10 +83,15 @@ export function parseNoun(
},
},
]);
} else {
error.forEach((e) => {
errors.push(e);
});
}
} else if (isFemNounEntry(entry) && deets.gender.includes("fem")) {
if (adjsMatch(adjectives, "fem", deets.inflection)) {
w.push([
const { ok, error } = adjsMatch(adjectives, "fem", deets.inflection);
if (ok) {
success.push([
rest,
{
inflection: deets.inflection,
@ -76,22 +101,63 @@ export function parseNoun(
},
},
]);
} else {
error.forEach((e) => {
errors.push(e);
});
}
}
});
});
});
return [...withAdj, ...w];
return {
success: [...withAdj.map((x) => x.success).flat(), ...success],
errors: [...withAdj.map((x) => x.errors).flat(), ...errors],
};
}
function adjsMatch(
adjectives: Parameters<typeof parseNoun>[2],
gender: T.Gender,
inflection: (0 | 1 | 2)[]
): boolean {
return adjectives.every(
): { ok: boolean; error: string[] } {
const unmatching = adjectives.filter(
(adj) =>
adj.gender.includes(gender) &&
adj.inflection.some((i) => inflection.includes(i))
!adj.gender.includes(gender) ||
!adj.inflection.some((i) => inflection.includes(i))
);
if (unmatching.length) {
return {
ok: false,
error: unmatching.map((x) => {
const adjText =
x.given === x.selection.entry.p
? x.given
: `${x.given} (${x.selection.entry.p})`;
const inflectionIssue = !x.inflection.some((x) =>
inflection.includes(x)
)
? ` should be ${showInflection(inflection)}`
: ``;
return `Adjective agreement error: ${adjText} should be ${inflectionIssue} ${gender}.`;
}),
};
} else {
return {
ok: true,
error: [],
};
}
}
function showInflection(inf: (0 | 1 | 2)[]): string {
const [last, ...rest] = inf.reverse();
const template = rest.length
? `${rest.join(", ")}, or ${last}`
: last.toString();
console.log(template);
return template
.replace("0", "plain")
.replace("1", "first inflection")
.replace("2", "second inflection");
}

View File

@ -6,13 +6,19 @@ import { parseNoun } from "./parse-noun";
export function parsePhrase(
s: string[],
lookup: (s: Partial<T.DictionaryEntry>) => T.DictionaryEntry[]
): any[] {
): {
success: any[];
errors: string[];
} {
const adjsRes = parseAdjective(s, lookup);
const prnsRes = parsePronoun(s);
const nounsRes = parseNoun(s, lookup, []);
const correct = [...adjsRes, ...prnsRes, ...nounsRes]
const correct = [...adjsRes, ...prnsRes, ...nounsRes.success]
.filter(([tkns]) => tkns.length === 0)
.map((x) => x[1]);
return correct;
return {
success: correct,
errors: nounsRes.errors,
};
}