refactor np and add negative in equative clause

This commit is contained in:
lingdocs 2021-11-01 15:57:12 -04:00
parent 1d9ff2b9e1
commit 440a9decb7
9 changed files with 87 additions and 77 deletions

View File

@ -10,18 +10,13 @@ import {
ExplorerState, ExplorerState,
ExplorerReducerAction, ExplorerReducerAction,
} from "./explorer-types"; } from "./explorer-types";
// import {
// makeBlockWPronouns,
// } from "./explorer-helpers";
import { import {
equativeMachine, equativeMachine,
assembleEquativeOutput, assembleEquativeOutput,
} from "../../lib/equative-machine"; } from "../../lib/equative-machine";
import { import {
isPluralNounEntry,
isUnisexNounEntry, isUnisexNounEntry,
isAdjectiveEntry, isAdjectiveEntry,
isSingularEntry,
isVerbEntry, isVerbEntry,
isLocativeAdverbEntry, isLocativeAdverbEntry,
isNounEntry, isNounEntry,
@ -47,6 +42,7 @@ function SingleItemDisplay({ state }: { state: ExplorerState }) {
subject, subject,
predicate, predicate,
tense: state.tense, tense: state.tense,
negative: state.negative,
}) })
); );
return <div> return <div>
@ -72,56 +68,27 @@ function makeNounPhrase(entry: NounEntry | UnisexNounEntry | VerbEntry, state: E
entry, entry,
}; };
} }
const isUnisex = isUnisexNounEntry(entry); return {
if (isUnisex && isSingularEntry(entry)) { type: "noun",
return { number: state[entity].info.number,
type: "unisex noun", gender: state[entity].info.gender,
number: state[entity].info.number, entry,
gender: state[entity].info.gender, };
entry,
};
}
if (isUnisex && isPluralNounEntry(entry)) {
return {
type: "unisex noun",
number: state[entity].info.number,
gender: state[entity].info.gender,
entry,
};
}
if (isUnisex) {
throw new Error("improper unisex noun");
}
if (isPluralNounEntry(entry)) {
const e = entry as PluralNounEntry<MascNounEntry | FemNounEntry>;
return {
type: "plural noun",
entry: e,
};
}
if (isSingularEntry(entry)) {
const e = entry as SingularEntry<MascNounEntry | FemNounEntry>;
return {
type: "singular noun",
entry: e,
number: state[entity].info.number,
};
}
throw new Error("unable to make subject input from entry");
} }
export function makeBlockWPronouns(e: AdjectiveEntry | UnisexNounEntry | LocativeAdverbEntry, tense: EquativeTense, length?: "short" | "long"): T.SingleOrLengthOpts<T.VerbBlock> { export function makeBlockWPronouns(e: AdjectiveEntry | UnisexNounEntry | LocativeAdverbEntry, tense: EquativeTense, negative: boolean, length?: "short" | "long"): T.SingleOrLengthOpts<T.VerbBlock> {
// if the output's gonna have long / short forms (if it's past or wouldBe) then recursive call to make the long and short versions // if the output's gonna have long / short forms (if it's past or wouldBe) then recursive call to make the long and short versions
if (!length && "long" in assembleEquativeOutput(equativeMachine({ if (!length && "long" in assembleEquativeOutput(equativeMachine({
subject: { type: "pronoun", pronounType: "near", person: 0 }, subject: { type: "pronoun", pronounType: "near", person: 0 },
predicate: (isAdjectiveEntry(e) || isLocativeAdverbEntry(e)) predicate: (isAdjectiveEntry(e) || isLocativeAdverbEntry(e))
? { type: "compliment", entry: e } ? { type: "compliment", entry: e }
: { type: "unisex noun", gender: "masc", number: "singular", entry: e }, : { type: "noun", gender: "masc", number: "singular", entry: e },
tense, tense,
negative,
}))) { }))) {
return { return {
short: makeBlockWPronouns(e, tense, "short") as T.VerbBlock, short: makeBlockWPronouns(e, tense, negative, "short") as T.VerbBlock,
long: makeBlockWPronouns(e, tense, "long") as T.VerbBlock, long: makeBlockWPronouns(e, tense, negative, "long") as T.VerbBlock,
}; };
} }
const makeP = (p: T.Person): T.ArrayOneOrMore<T.PsString> => { const makeP = (p: T.Person): T.ArrayOneOrMore<T.PsString> => {
@ -129,8 +96,9 @@ export function makeBlockWPronouns(e: AdjectiveEntry | UnisexNounEntry | Locativ
subject: { type: "pronoun", pronounType: "far", person: p }, subject: { type: "pronoun", pronounType: "far", person: p },
predicate: (isAdjectiveEntry(e) || isLocativeAdverbEntry(e)) predicate: (isAdjectiveEntry(e) || isLocativeAdverbEntry(e))
? { type: "compliment", entry: e } ? { type: "compliment", entry: e }
: { type: "unisex noun", gender: personGender(p), number: personIsPlural(p) ? "plural" : "singular", entry: e }, : { type: "noun", gender: personGender(p), number: personIsPlural(p) ? "plural" : "singular", entry: e },
tense, tense,
negative,
})); }));
if ("long" in b) { if ("long" in b) {
if (!length) throw new Error("bad length processing"); if (!length) throw new Error("bad length processing");
@ -151,7 +119,7 @@ export function makeBlockWPronouns(e: AdjectiveEntry | UnisexNounEntry | Locativ
function PronounBlockDisplay({ state }: { state: ExplorerState }) { function PronounBlockDisplay({ state }: { state: ExplorerState }) {
const pred = state.predicate[state.predicate.type]; const pred = state.predicate[state.predicate.type];
if (!isVerbEntry(pred) && (isAdjectiveEntry(pred) || isLocativeAdverbEntry(pred) || (isNounEntry(pred) && isUnisexNounEntry(pred)))) { if (!isVerbEntry(pred) && (isAdjectiveEntry(pred) || isLocativeAdverbEntry(pred) || (isNounEntry(pred) && isUnisexNounEntry(pred)))) {
const block = makeBlockWPronouns(pred, state.tense); const block = makeBlockWPronouns(pred, state.tense, state.negative);
return <VerbTable return <VerbTable
textOptions={opts} textOptions={opts}
block={chooseLength(block, state.length)} block={chooseLength(block, state.length)}

View File

@ -22,6 +22,7 @@ import EquativeDisplay from "./EquativeDisplay";
const defaultState: ExplorerState = { const defaultState: ExplorerState = {
tense: "present", tense: "present",
length: "short", length: "short",
negative: false,
predicate: { predicate: {
type: "adjective", type: "adjective",
adjective: defaultAdjective, adjective: defaultAdjective,

View File

@ -94,6 +94,12 @@ export function reducer(state: ExplorerState, action: ExplorerReducerAction): Ex
// }, // },
// }; // };
// } // }
if (action.type === "setNegative") {
return {
...state,
negative: action.payload,
};
}
return { return {
...state, ...state,
length: action.payload, length: action.payload,

View File

@ -209,5 +209,16 @@ export function TenseSelector({ state, dispatch }: {
placeholder={options.find(o => o.value === state.tense)?.label} placeholder={options.find(o => o.value === state.tense)?.label}
{...zIndexProps} {...zIndexProps}
/> />
<div className="text-center mb-2">
<ButtonSelect
small
options={[
{ label: "Pos.", value: "pos" },
{ label: "Neg.", value: "neg" },
]}
value={state.negative ? "neg" : "pos"}
handleChange={(p) => dispatch({ type: "setNegative", payload: p === "neg" })}
/>
</div>
</div> </div>
} }

View File

@ -10,6 +10,7 @@ export type ExplorerState = {
length: "short" | "long", length: "short" | "long",
subject: SubjectEntityInfo, subject: SubjectEntityInfo,
predicate: PredicateEntityInfo, predicate: PredicateEntityInfo,
negative: boolean,
}; };
export type SubjectEntityInfo = EntitiyInfo & { type: SubjectType }; export type SubjectEntityInfo = EntitiyInfo & { type: SubjectType };
@ -46,4 +47,6 @@ export type ExplorerReducerAction = {
type: "setTense", payload: EquativeTense, type: "setTense", payload: EquativeTense,
} | { } | {
type: "setLength", payload: "short" | "long", type: "setLength", payload: "short" | "long",
} | {
type: "setNegative", payload: boolean,
}; };

View File

@ -4,6 +4,7 @@ import {
getVerbBlockPosFromPerson, getVerbBlockPosFromPerson,
getPersonFromVerbForm, getPersonFromVerbForm,
concatPsString, concatPsString,
removeAccents,
} from "@lingdocs/pashto-inflector"; } from "@lingdocs/pashto-inflector";
import { import {
personFromNP, personFromNP,
@ -12,6 +13,7 @@ import {
import { import {
evaluateCompliment, evaluateCompliment,
} from "./compliment-tools"; } from "./compliment-tools";
import { isPluralNounEntry } from "./type-predicates";
// Equative Rules // Equative Rules
// - An equative equates a SUBJECT: Noun Phrase and a PREDICATE: Noun Phrase | Compliment // - An equative equates a SUBJECT: Noun Phrase and a PREDICATE: Noun Phrase | Compliment
@ -27,11 +29,13 @@ export function equativeMachine(e: EquativeClause): EquativeClauseOutput {
? evaluateCompliment(e.predicate, personFromNP(e.subject)) ? evaluateCompliment(e.predicate, personFromNP(e.subject))
: evaluateNP(e.predicate); : evaluateNP(e.predicate);
const equative = makeEquative(e); const equative = makeEquative(e);
const negative = !!e?.negative;
return { return {
ba, ba,
subject, subject,
predicate, predicate,
equative, equative,
negative,
}; };
} }
@ -47,10 +51,19 @@ export function assembleEquativeOutput(o: EquativeClauseOutput): T.SingleOrLengt
const equatives = o.equative.ps; const equatives = o.equative.ps;
const predicates = o.predicate.ps; const predicates = o.predicate.ps;
const ba = o.ba ? { p: " به", f: " ba" } : ""; const ba = o.ba ? { p: " به", f: " ba" } : "";
const neg = o.negative ? { p: "نه ", f: "nú " } : "";
const ps = o.subject.ps.flatMap(subj => ( const ps = o.subject.ps.flatMap(subj => (
predicates.flatMap(pred => ( predicates.flatMap(pred => (
equatives.map(eq => ( equatives.map(eq => (
concatPsString(subj, ba, " ", pred, " ", eq)) concatPsString(
subj,
ba,
" ",
pred,
" ",
neg,
o.negative ? removeAccents(eq) : eq,
))
) )
)) ))
)); ));
@ -71,7 +84,7 @@ function makeEquative(e: EquativeClause) {
? "past" ? "past"
: e.tense; : e.tense;
const subjP = personFromNP(e.subject); const subjP = personFromNP(e.subject);
const englishPerson = (e.subject.type === "plural noun" || e.subject.type === "participle") const englishPerson = (e.subject.type === "participle" || (e.subject.type === "noun" && isPluralNounEntry(e.subject.entry)))
? T.Person.ThirdSingMale ? T.Person.ThirdSingMale
: subjP : subjP
const pashtoPerson = (e.subject.type === "pronoun") const pashtoPerson = (e.subject.type === "pronoun")

0
src/lib/np-tools.test.ts Normal file
View File

View File

@ -1,4 +1,4 @@
import { isMascNounEntry } from "./type-predicates"; import { isMascNounEntry, isPluralNounEntry, isUnisexNounEntry } from "./type-predicates";
import { import {
Types as T, Types as T,
getEnglishWord, getEnglishWord,
@ -18,14 +18,8 @@ export function personFromNP(np: NounPhrase): T.Person {
if (np.type === "pronoun") { if (np.type === "pronoun") {
return np.person; return np.person;
} }
const gender: T.Gender = "gender" in np const gender = nounGender(np);
? np.gender const number = nounNumber(np);
: isMascNounEntry(np.entry)
? "masc"
: "fem";
const number: NounNumber = np.type === "plural noun"
? "plural"
: np.number;
return number === "plural" return number === "plural"
? (gender === "masc" ? T.Person.ThirdPlurMale : T.Person.ThirdPlurFemale) ? (gender === "masc" ? T.Person.ThirdPlurMale : T.Person.ThirdPlurFemale)
: (gender === "masc" ? T.Person.ThirdSingMale : T.Person.ThirdSingFemale); : (gender === "masc" ? T.Person.ThirdSingMale : T.Person.ThirdSingFemale);
@ -41,6 +35,30 @@ export function evaluateNP(np: NounPhrase): { ps: T.PsString[], e: string } {
return evaluateNoun(np); return evaluateNoun(np);
} }
function nounGender(n: Noun): T.Gender {
const nGender = isUnisexNounEntry(n.entry)
? "unisex"
: isMascNounEntry(n.entry)
? "masc"
: "fem";
return (nGender === "unisex" && n.gender)
? n.gender
: (nGender === "unisex")
? "masc"
: nGender;
}
function nounNumber(n: Noun): NounNumber {
const nNumber = isPluralNounEntry(n.entry)
? "plural"
: "singular";
return nNumber === "plural"
? "plural"
: n.number
? n.number
: nNumber;
}
function evaluatePronoun(p: Pronoun): { ps: T.PsString[], e: string } { function evaluatePronoun(p: Pronoun): { ps: T.PsString[], e: string } {
// TODO: Will need to handle inflecting and inflecting english pronouns etc. // TODO: Will need to handle inflecting and inflecting english pronouns etc.
const [row, col] = getVerbBlockPosFromPerson(p.person); const [row, col] = getVerbBlockPosFromPerson(p.person);
@ -51,12 +69,11 @@ function evaluatePronoun(p: Pronoun): { ps: T.PsString[], e: string } {
} }
function evaluateNoun(n: Noun): { ps: T.PsString[], e: string } { function evaluateNoun(n: Noun): { ps: T.PsString[], e: string } {
const number: NounNumber = "number" in n ? n.number : "plural"; const number = nounNumber(n);
const english = getEnglishFromNoun(n.entry, number); const english = getEnglishFromNoun(n.entry, number);
const pashto = ((): T.PsString[] => { const pashto = ((): T.PsString[] => {
const infs = inflectWord(n.entry); const infs = inflectWord(n.entry);
const gender: T.Gender = "gender" in n ? n.gender : const gender = nounGender(n);
(isMascNounEntry(n.entry) ? "masc" : "fem");
const ps = number === "singular" const ps = number === "singular"
? getInf(infs, "inflections", gender, false) ? getInf(infs, "inflections", gender, false)
: [ : [

View File

@ -5,6 +5,7 @@ type EquativeClause = {
subject: NounPhrase, subject: NounPhrase,
predicate: NounPhrase | Compliment, predicate: NounPhrase | Compliment,
tense: EquativeTense, tense: EquativeTense,
negative?: boolean,
}; };
type EquativeClauseOutput = { type EquativeClauseOutput = {
@ -17,6 +18,7 @@ type EquativeClauseOutput = {
e: string, e: string,
}, },
ba: boolean, ba: boolean,
negative: boolean,
equative: { equative: {
ps: import("@lingdocs/pashto-inflector").Types.SentenceForm, ps: import("@lingdocs/pashto-inflector").Types.SentenceForm,
e: string[], e: string[],
@ -25,23 +27,12 @@ type EquativeClauseOutput = {
type NounPhrase = Pronoun | Noun | Participle; type NounPhrase = Pronoun | Noun | Participle;
// TODO: better, simpler type here // The gender and number can be added, if it conflicts with the noun it will be ignored
type Noun = { type Noun = {
type: "unisex noun", type: "noun",
number: NounNumber, entry: NounEntry,
gender: import("@lingdocs/pashto-inflector").Types.Gender, number?: NounNumber,
entry: UnisexNounEntry, gender?: import("@lingdocs/pashto-inflector").Types.Gender,
possesor?: Noun,
adjectives?: AdjectiveEntry[],
} | {
type: "plural noun",
entry: PluralNounEntry<MascNounEntry | FemNounEntry>,
possesor?: Noun,
adjectives?: AdjectiveEntry[],
} | {
type: "singular noun",
number: NounNumber,
entry: SingularEntry<MascNounEntry | FemNounEntry>,
possesor?: Noun, possesor?: Noun,
adjectives?: AdjectiveEntry[], adjectives?: AdjectiveEntry[],
}; };