some error messages
This commit is contained in:
parent
c38e0645d3
commit
6aec2dfeb2
|
@ -7,16 +7,19 @@ import { tokenizer } from "../lib/src/parsing/tokenizer";
|
||||||
function ParserDemo({ opts }: { opts: T.TextOptions }) {
|
function ParserDemo({ opts }: { opts: T.TextOptions }) {
|
||||||
const [text, setText] = useState<string>("");
|
const [text, setText] = useState<string>("");
|
||||||
const [result, setResult] = useState<string>("");
|
const [result, setResult] = useState<string>("");
|
||||||
|
const [errors, setErrors] = useState<string[]>([]);
|
||||||
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
|
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
if (!value) {
|
if (!value) {
|
||||||
setText("");
|
setText("");
|
||||||
setResult("");
|
setResult("");
|
||||||
|
setErrors([]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const r = parsePhrase(tokenizer(value), lookup);
|
const { success, errors } = parsePhrase(tokenizer(value), lookup);
|
||||||
setText(value);
|
setText(value);
|
||||||
setResult(JSON.stringify(r, null, " "));
|
setErrors(errors);
|
||||||
|
setResult(JSON.stringify(success, null, " "));
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="mt-3" style={{ marginBottom: "1000px" }}>
|
<div className="mt-3" style={{ marginBottom: "1000px" }}>
|
||||||
|
@ -32,6 +35,13 @@ function ParserDemo({ opts }: { opts: T.TextOptions }) {
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{result === "[]" && errors.length > 0 && (
|
||||||
|
<div className="alert alert-danger" role="alert">
|
||||||
|
{errors.map((e) => (
|
||||||
|
<div key={Math.random()}>{e}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<samp>
|
<samp>
|
||||||
<pre>{result}</pre>
|
<pre>{result}</pre>
|
||||||
</samp>
|
</samp>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
isPattern,
|
isPattern,
|
||||||
isPattern5Entry,
|
isPattern5Entry,
|
||||||
isPattern4Entry,
|
isPattern4Entry,
|
||||||
|
isPattern6FemEntry,
|
||||||
} from "../type-predicates";
|
} from "../type-predicates";
|
||||||
import { equals } from "rambda";
|
import { equals } from "rambda";
|
||||||
|
|
||||||
|
@ -135,6 +136,14 @@ export function getInflectionQueries(
|
||||||
predicate: (e) => isPattern2Entry(e) || isPattern3Entry(e),
|
predicate: (e) => isPattern2Entry(e) || isPattern3Entry(e),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
queries.push({
|
||||||
|
search: { p: s },
|
||||||
|
details: {
|
||||||
|
inflection: [0],
|
||||||
|
gender: ["fem"],
|
||||||
|
predicate: isPattern6FemEntry,
|
||||||
|
},
|
||||||
|
});
|
||||||
} else if (s.endsWith("و")) {
|
} else if (s.endsWith("و")) {
|
||||||
queries.push({
|
queries.push({
|
||||||
search: { p: s.slice(0, -1) },
|
search: { p: s.slice(0, -1) },
|
||||||
|
@ -179,6 +188,24 @@ export function getInflectionQueries(
|
||||||
predicate: isPattern3Entry,
|
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> = [];
|
const coallated: ReturnType<typeof getInflectionQueries> = [];
|
||||||
|
|
|
@ -313,7 +313,12 @@ describe("parsing adjectives", () => {
|
||||||
cases.forEach(({ input, output }) => {
|
cases.forEach(({ input, output }) => {
|
||||||
const tokens = tokenizer(input);
|
const tokens = tokenizer(input);
|
||||||
const possibilities = parseAdjective(tokens, lookup).map((x) => x[1]);
|
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,7 @@ export function parseAdjective(
|
||||||
{
|
{
|
||||||
inflection: (0 | 1 | 2)[];
|
inflection: (0 | 1 | 2)[];
|
||||||
gender: T.Gender[];
|
gender: T.Gender[];
|
||||||
|
given: string;
|
||||||
selection: T.AdjectiveSelection;
|
selection: T.AdjectiveSelection;
|
||||||
}
|
}
|
||||||
][] {
|
][] {
|
||||||
|
@ -32,6 +33,7 @@ export function parseAdjective(
|
||||||
selection,
|
selection,
|
||||||
inflection: deets.inflection,
|
inflection: deets.inflection,
|
||||||
gender: deets.gender,
|
gender: deets.gender,
|
||||||
|
given: first,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,17 +15,28 @@ export function parseNoun(
|
||||||
adjectives: {
|
adjectives: {
|
||||||
inflection: (0 | 1 | 2)[];
|
inflection: (0 | 1 | 2)[];
|
||||||
gender: T.Gender[];
|
gender: T.Gender[];
|
||||||
|
given: string;
|
||||||
selection: T.AdjectiveSelection;
|
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) {
|
if (tokens.length === 0) {
|
||||||
return [];
|
return {
|
||||||
|
success: [],
|
||||||
|
errors: [],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const adjRes = parseAdjective(tokens, lookup);
|
const adjRes = parseAdjective(tokens, lookup);
|
||||||
const withAdj = adjRes.flatMap(([tkns, adj]) =>
|
const withAdj = adjRes.map(([tkns, adj]) =>
|
||||||
parseNoun(tkns, lookup, [...adjectives, 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 [first, ...rest] = tokens;
|
||||||
|
|
||||||
const searches = getInflectionQueries(first, true);
|
const searches = getInflectionQueries(first, true);
|
||||||
|
@ -34,11 +45,15 @@ export function parseNoun(
|
||||||
details.forEach((deets) => {
|
details.forEach((deets) => {
|
||||||
const fittingEntries = nounEntries.filter(deets.predicate);
|
const fittingEntries = nounEntries.filter(deets.predicate);
|
||||||
fittingEntries.forEach((entry) => {
|
fittingEntries.forEach((entry) => {
|
||||||
console.log({ entry, deets });
|
|
||||||
if (isUnisexNounEntry(entry)) {
|
if (isUnisexNounEntry(entry)) {
|
||||||
deets.gender.forEach((gender) => {
|
deets.gender.forEach((gender) => {
|
||||||
if (adjsMatch(adjectives, gender, deets.inflection)) {
|
const { ok, error } = adjsMatch(
|
||||||
w.push([
|
adjectives,
|
||||||
|
gender,
|
||||||
|
deets.inflection
|
||||||
|
);
|
||||||
|
if (ok) {
|
||||||
|
success.push([
|
||||||
rest,
|
rest,
|
||||||
{
|
{
|
||||||
inflection: deets.inflection,
|
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")) {
|
} else if (isMascNounEntry(entry) && deets.gender.includes("masc")) {
|
||||||
if (adjsMatch(adjectives, "masc", deets.inflection)) {
|
const { ok, error } = adjsMatch(adjectives, "masc", deets.inflection);
|
||||||
w.push([
|
if (ok) {
|
||||||
|
success.push([
|
||||||
rest,
|
rest,
|
||||||
{
|
{
|
||||||
inflection: deets.inflection,
|
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")) {
|
} else if (isFemNounEntry(entry) && deets.gender.includes("fem")) {
|
||||||
if (adjsMatch(adjectives, "fem", deets.inflection)) {
|
const { ok, error } = adjsMatch(adjectives, "fem", deets.inflection);
|
||||||
w.push([
|
if (ok) {
|
||||||
|
success.push([
|
||||||
rest,
|
rest,
|
||||||
{
|
{
|
||||||
inflection: deets.inflection,
|
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(
|
function adjsMatch(
|
||||||
adjectives: Parameters<typeof parseNoun>[2],
|
adjectives: Parameters<typeof parseNoun>[2],
|
||||||
gender: T.Gender,
|
gender: T.Gender,
|
||||||
inflection: (0 | 1 | 2)[]
|
inflection: (0 | 1 | 2)[]
|
||||||
): boolean {
|
): { ok: boolean; error: string[] } {
|
||||||
return adjectives.every(
|
const unmatching = adjectives.filter(
|
||||||
(adj) =>
|
(adj) =>
|
||||||
adj.gender.includes(gender) &&
|
!adj.gender.includes(gender) ||
|
||||||
adj.inflection.some((i) => inflection.includes(i))
|
!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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,19 @@ import { parseNoun } from "./parse-noun";
|
||||||
export function parsePhrase(
|
export function parsePhrase(
|
||||||
s: string[],
|
s: string[],
|
||||||
lookup: (s: Partial<T.DictionaryEntry>) => T.DictionaryEntry[]
|
lookup: (s: Partial<T.DictionaryEntry>) => T.DictionaryEntry[]
|
||||||
): any[] {
|
): {
|
||||||
|
success: any[];
|
||||||
|
errors: string[];
|
||||||
|
} {
|
||||||
const adjsRes = parseAdjective(s, lookup);
|
const adjsRes = parseAdjective(s, lookup);
|
||||||
const prnsRes = parsePronoun(s);
|
const prnsRes = parsePronoun(s);
|
||||||
const nounsRes = parseNoun(s, lookup, []);
|
const nounsRes = parseNoun(s, lookup, []);
|
||||||
|
|
||||||
const correct = [...adjsRes, ...prnsRes, ...nounsRes]
|
const correct = [...adjsRes, ...prnsRes, ...nounsRes.success]
|
||||||
.filter(([tkns]) => tkns.length === 0)
|
.filter(([tkns]) => tkns.length === 0)
|
||||||
.map((x) => x[1]);
|
.map((x) => x[1]);
|
||||||
return correct;
|
return {
|
||||||
|
success: correct,
|
||||||
|
errors: nounsRes.errors,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue