@fpw/en-wiktionary-la-modules 0.1.2 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/modules/conjugation/LaVerb.d.ts +3 -1
  2. package/dist/modules/conjugation/LaVerb.js +201 -32
  3. package/dist/modules/conjugation/LaVerb.js.map +1 -1
  4. package/dist/modules/conjugation/VerbType.d.ts +5 -1
  5. package/dist/modules/conjugation/VerbType.js +4 -0
  6. package/dist/modules/conjugation/VerbType.js.map +1 -1
  7. package/dist/modules/declination/LaAdjData.d.ts +1 -1
  8. package/dist/modules/declination/LaAdjData.js +45 -24
  9. package/dist/modules/declination/LaAdjData.js.map +1 -1
  10. package/dist/modules/declination/LaNominal.d.ts +9 -5
  11. package/dist/modules/declination/LaNominal.js +195 -171
  12. package/dist/modules/declination/LaNominal.js.map +1 -1
  13. package/dist/modules/declination/LaNounData.js +65 -64
  14. package/dist/modules/declination/LaNounData.js.map +1 -1
  15. package/dist/modules/declination/LaPersonalPronoun.js +1 -0
  16. package/dist/modules/declination/LaPersonalPronoun.js.map +1 -1
  17. package/dist/modules/declination/NominalType.d.ts +116 -0
  18. package/dist/modules/declination/NominalType.js +142 -0
  19. package/dist/modules/declination/NominalType.js.map +1 -0
  20. package/dist/modules/headword/HeadwordParser.js +2 -1
  21. package/dist/modules/headword/HeadwordParser.js.map +1 -1
  22. package/package.json +1 -1
  23. package/src/modules/conjugation/LaVerb.ts +206 -35
  24. package/src/modules/conjugation/VerbType.ts +4 -0
  25. package/src/modules/declination/LaAdjData.ts +47 -24
  26. package/src/modules/declination/LaNominal.ts +223 -187
  27. package/src/modules/declination/LaNounData.ts +67 -66
  28. package/src/modules/declination/LaPersonalPronoun.ts +1 -0
  29. package/src/modules/declination/NominalType.ts +153 -0
  30. package/src/modules/headword/HeadwordParser.ts +2 -1
@@ -3,7 +3,7 @@
3
3
  * It was converted from Lua to TypeScript by Folke Will <folko@solhost.org>.
4
4
  *
5
5
  * Original source: https://en.wiktionary.org/wiki/Module:la-nominal
6
- * Based on version: https://en.wiktionary.org/w/index.php?title=Module:la-nominal&oldid=62391877
6
+ * Based on version: https://en.wiktionary.org/w/index.php?title=Module:la-nominal&oldid=68705587
7
7
  *
8
8
  * Lua idioms, function and variable names kept as in the original in order to easily
9
9
  * backport later changes to this implementation.
@@ -16,6 +16,7 @@ import { ArgMap, array_equals, extract_base, FormMap, is_enum_value, read_list,
16
16
  import { m_adj_decl } from "./LaAdjData";
17
17
  import { m_noun_decl } from "./LaNounData";
18
18
  import { getNominalForm, NominalForm, setNominalForm } from "./NominalForm";
19
+ import { addNominalType, delNominalType, hasNominalType, NominalType } from "./NominalType";
19
20
 
20
21
  export interface DeclOptions {
21
22
  suppressOldGenitive?: boolean;
@@ -44,6 +45,7 @@ interface SegmentRun {
44
45
  gender?: Gender;
45
46
  is_adj?: boolean;
46
47
  propses: DeclProp[];
48
+ apparent_decl?: string;
47
49
  }
48
50
 
49
51
  interface Segment {
@@ -56,7 +58,7 @@ interface Segment {
56
58
  orig_lemma: string;
57
59
  stem2?: string;
58
60
  gender?: Gender;
59
- types: Set<string>;
61
+ types: Set<NominalType>;
60
62
  num?: NumberTantum;
61
63
  loc: boolean;
62
64
  args: string[];
@@ -78,7 +80,7 @@ interface Alternant {
78
80
  export interface DeclProp {
79
81
  decl: string;
80
82
  headword_decl: string;
81
- types: Set<string>;
83
+ types: Set<NominalType>;
82
84
  }
83
85
 
84
86
  interface Declensions {
@@ -90,6 +92,7 @@ interface Declensions {
90
92
  categories: string[];
91
93
  voc: boolean;
92
94
  noneut: boolean;
95
+ nomf: boolean;
93
96
  }
94
97
 
95
98
  export interface DeclensionData {
@@ -126,6 +129,7 @@ export interface AdjectiveData extends DeclensionData {
126
129
 
127
130
  voc: boolean;
128
131
  noneut: boolean;
132
+ nomf: boolean;
129
133
 
130
134
  // only in headwords
131
135
  comp: string[];
@@ -142,7 +146,7 @@ export interface SegmentData {
142
146
  loc?: boolean;
143
147
  pos: string;
144
148
  forms: FormMap<NominalForm>;
145
- types: Set<string>;
149
+ types: Set<NominalType>;
146
150
  categories: string[];
147
151
  notes: Map<string, string>;
148
152
 
@@ -150,12 +154,13 @@ export interface SegmentData {
150
154
  gender?: Gender;
151
155
  voc?: boolean;
152
156
  noneut?: boolean;
157
+ nomf?: boolean;
153
158
  }
154
159
 
155
160
  type EndingTable = [
156
161
  string | string[],
157
162
  string,
158
- string[],
163
+ NominalType[],
159
164
  ((base: string, stem2: string) => [string, string])?
160
165
  ][];
161
166
 
@@ -220,11 +225,14 @@ export class LaNominal {
220
225
  ["5", "fifth"],
221
226
  ]);
222
227
 
228
+ private title: string | undefined;
229
+
223
230
  public constructor(options?: DeclOptions) {
224
231
  this.options = options || {};
225
232
  }
226
233
 
227
- public do_generate_noun_forms(args: ArgMap, pos: string = "nouns", from_headword = false): NounData {
234
+ public do_generate_noun_forms(args: ArgMap, pos: string = "nouns", from_headword = false, title?: string): NounData {
235
+ this.title = title;
228
236
  const parsed_run = this.parse_segment_run_allowing_alternants(args.get("1")?.trim() || "");
229
237
  parsed_run.loc = parsed_run.loc || args.has("loc_sg") || args.has("loc_pl");
230
238
 
@@ -280,7 +288,8 @@ export class LaNominal {
280
288
  return all_data;
281
289
  }
282
290
 
283
- public do_generate_adj_forms(args: ArgMap, pos: string = "adjectives", from_headword = false): AdjectiveData {
291
+ public do_generate_adj_forms(args: ArgMap, pos: string = "adjectives", from_headword = false, title?: string): AdjectiveData {
292
+ this.title = title;
284
293
  let segment_run = args.get("1")?.trim() || "";
285
294
  if (!segment_run.match(/[<(]/)) {
286
295
  segment_run = segment_run + (args.has("indecl") ? "<0+>" : "<+>");
@@ -331,6 +340,7 @@ export class LaNominal {
331
340
  user_specified: new Set(),
332
341
  voc: declensions.voc,
333
342
  noneut: args.has("noneut") || declensions.noneut,
343
+ nomf: args.has("nomf") || declensions.nomf,
334
344
  pos: pos,
335
345
  num_type: args.get("type"),
336
346
 
@@ -378,10 +388,13 @@ export class LaNominal {
378
388
  if (parsed_run.loc) {
379
389
  post_text_parts.push(", with locative");
380
390
  }
381
- if (parsed_run.num == "sg") {
382
- post_text_parts.push(", singular only");
383
- } else if (parsed_run.num == "pl") {
384
- post_text_parts.push(", plural only");
391
+
392
+ if (parsed_run.apparent_decl == "indecl") {
393
+ if (parsed_run.num == "sg") {
394
+ post_text_parts.push(", singular only");
395
+ } else if (parsed_run.num == "pl") {
396
+ post_text_parts.push(", plural only");
397
+ }
385
398
  }
386
399
 
387
400
  const post_text = post_text_parts.join("");
@@ -441,6 +454,9 @@ export class LaNominal {
441
454
  if (data.noneut && slot.match(/_n/)) {
442
455
  setNominalForm(data.forms, slot, undefined);
443
456
  }
457
+ if (data.nomf && (slot.match(/_m/) || slot.match(/_f/))) {
458
+ setNominalForm(data.forms, slot, undefined);
459
+ }
444
460
  let val: string[] | undefined;
445
461
  const ovr = args.get(slot);
446
462
  if (ovr) {
@@ -619,7 +635,7 @@ export class LaNominal {
619
635
  num: num,
620
636
  gender: gender,
621
637
  is_adj: is_adj,
622
- propses: propses
638
+ propses: propses,
623
639
  };
624
640
  }
625
641
 
@@ -736,7 +752,7 @@ export class LaNominal {
736
752
  loc: loc,
737
753
  num: num,
738
754
  gender: gender,
739
- propses: propses
755
+ propses: propses,
740
756
  };
741
757
  }
742
758
 
@@ -754,7 +770,7 @@ export class LaNominal {
754
770
  const stems = stem_part.split("/");
755
771
  const specs = spec_part.split(".");
756
772
 
757
- const types = new Set<string>();
773
+ const types = new Set<NominalType>();
758
774
  let num: NumberTantum | undefined;
759
775
  let loc = false;
760
776
 
@@ -769,12 +785,14 @@ export class LaNominal {
769
785
  const begins_with_hypen = m2[1];
770
786
  spec = m2[2];
771
787
  spec = begins_with_hypen + spec.replace(/-/g, "_");
772
- types.add(spec);
788
+ if (spec) {
789
+ addNominalType(types, spec);
790
+ }
773
791
  }
774
792
  }
775
793
  }
776
794
 
777
- const orig_lemma = stems[0];
795
+ const orig_lemma = stems[0] || this.title;
778
796
  if (!orig_lemma) {
779
797
  throw Error("No lemma");
780
798
  }
@@ -790,7 +808,7 @@ export class LaNominal {
790
808
 
791
809
  let headword_decl;
792
810
  let base;
793
- let detected_subtypes;
811
+ let detected_subtypes: Set<NominalType>;
794
812
 
795
813
  if (decl.match(/\+/)) {
796
814
  decl = decl.replace(/\+/g, "");
@@ -805,8 +823,8 @@ export class LaNominal {
805
823
  }
806
824
 
807
825
  for (const subtype of detected_subtypes) {
808
- if (types.has("-" + subtype)) {
809
- types.delete("-" + subtype);
826
+ if (hasNominalType(types, "-" + subtype)) {
827
+ delNominalType(types, "-" + subtype);
810
828
  } else {
811
829
  types.add(subtype);
812
830
  }
@@ -822,42 +840,48 @@ export class LaNominal {
822
840
  }
823
841
 
824
842
  for (const subtype of detected_subtypes) {
825
- if (types.has("-" + subtype)) {
826
- types.delete("-" + subtype);
827
- } else if ((subtype == "M" || subtype == "F" || subtype == "N") && (types.has("M") || types.has("F") || types.has("N"))) {
843
+ if (hasNominalType(types, "-" + subtype)) {
844
+ delNominalType(types, "-" + subtype);
845
+ } else if (
846
+ (subtype == NominalType.Masculine || subtype == NominalType.Feminine || subtype == NominalType.Neuter) &&
847
+ (types.has(NominalType.Masculine) || types.has(NominalType.Feminine) || types.has(NominalType.Neuter))
848
+ ) {
828
849
  // don't create conflicting gender specs
829
- } else if ((subtype == "sg" || subtype == "pl" || subtype == "both") && (types.has("sg") || types.has("pl") || types.has("both"))) {
850
+ } else if (
851
+ (subtype == NominalType.Singular || subtype == NominalType.Plural || subtype == NominalType.Both) &&
852
+ (types.has(NominalType.Singular) || types.has(NominalType.Plural) || types.has(NominalType.Both))
853
+ ) {
830
854
  // don't create conflicting number restrictions
831
855
  } else {
832
856
  types.add(subtype);
833
857
  }
834
858
  }
835
859
 
836
- if (!types.has("pl") && !types.has("both") && lemma.match(/^[A-ZĀĒĪŌŪȲĂĔĬŎŬ]/)) {
837
- types.add("sg");
860
+ if (!types.has(NominalType.Plural) && !types.has(NominalType.Both) && lemma.match(/^[A-ZĀĒĪŌŪȲĂĔĬŎŬ]/)) {
861
+ types.add(NominalType.Singular);
838
862
  }
839
863
  }
840
864
 
841
- if (types.has("loc")) {
865
+ if (types.has(NominalType.Locative)) {
842
866
  loc = true;
843
- types.delete("loc");
867
+ types.delete(NominalType.Locative);
844
868
  }
845
869
 
846
870
  let gender: Gender | undefined;
847
- if (types.has("M")) {
871
+ if (types.has(NominalType.Masculine)) {
848
872
  gender = Gender.M;
849
- } else if (types.has("F")) {
873
+ } else if (types.has(NominalType.Feminine)) {
850
874
  gender = Gender.F;
851
- } else if (types.has("N")) {
875
+ } else if (types.has(NominalType.Neuter)) {
852
876
  gender = Gender.N;
853
877
  }
854
878
 
855
- if (types.has("pl")) {
879
+ if (types.has(NominalType.Plural)) {
856
880
  num = NumberTantum.Plural;
857
- types.delete("pl");
858
- } else if (types.has("sg")) {
881
+ types.delete(NominalType.Plural);
882
+ } else if (types.has(NominalType.Singular)) {
859
883
  num = NumberTantum.Singular;
860
- types.delete("sg");
884
+ types.delete(NominalType.Singular);
861
885
  }
862
886
 
863
887
  const args = [base, stem2];
@@ -878,10 +902,10 @@ export class LaNominal {
878
902
  };
879
903
  }
880
904
 
881
- private detect_adj_type_and_subtype(lemma: string, stem2: string, typ: string, subtypes: Set<string>): [any, any, any, any] {
882
- if (!typ.match(/^[0123]/) && !typ.match(/^irreg/)) {
883
- subtypes = new Set(subtypes);
884
- subtypes.add(typ);
905
+ private detect_adj_type_and_subtype(lemma: string, stem2: string, typ: string, subtypes: Set<NominalType>): [any, any, any, any] {
906
+ if (!typ.match(/^[0123]/) && !typ.match(/^irreg/) && typ) {
907
+ subtypes = new Set<NominalType>(subtypes);
908
+ addNominalType(subtypes, typ);
885
909
  typ = "";
886
910
  }
887
911
 
@@ -905,17 +929,17 @@ export class LaNominal {
905
929
  ["us", "1&2", []],
906
930
  ["a", "1&2", []],
907
931
  ["um", "1&2", []],
908
- ["ī", "1&2", ["pl"]],
909
- ["ae", "1&2", ["pl"]],
910
- ["a", "1&2", ["pl"]],
911
- ["os", "1&2", ["greekA", "-greekE"]],
912
- ["os", "1&2", ["greekE", "-greekA"]],
913
- ["ē", "1&2", ["greekE", "-greekA"]],
914
- ["on", "1&2", ["greekA", "-greekE"]],
915
- ["on", "1&2", ["greekE", "-greekA"]],
916
- ["^(.*er)$", "1&2", ["er"]],
917
- ["^(.*ur)$", "1&2", ["er"]],
918
- ["^(h)ic$", "1&2", ["ic"]],
932
+ ["ī", "1&2", [NominalType.Plural]],
933
+ ["ae", "1&2", [NominalType.Plural]],
934
+ ["a", "1&2", [NominalType.Plural]],
935
+ ["os", "1&2", [NominalType.GreekA, NominalType.NoGreekE]],
936
+ ["os", "1&2", [NominalType.GreekE, NominalType.NoGreekA]],
937
+ ["ē", "1&2", [NominalType.GreekE, NominalType.NoGreekA]],
938
+ ["on", "1&2", [NominalType.GreekA, NominalType.NoGreekE]],
939
+ ["on", "1&2", [NominalType.GreekE, NominalType.NoGreekA]],
940
+ ["^(.*er)$", "1&2", [NominalType.Er]],
941
+ ["^(.*ur)$", "1&2", [NominalType.Er]],
942
+ ["^(h)ic$", "1&2", [NominalType.Ic]],
919
943
  ];
920
944
 
921
945
  const decl3_entries: EndingTable = [
@@ -924,16 +948,16 @@ export class LaNominal {
924
948
  ["e", "3-2", []],
925
949
  ["^(.*[ij])or$", "3-C", []],
926
950
  ["^(min)or$", "3-C", []],
927
- ["^(.*ēs)$", "3-1", ["I"]],
928
- ["^(.*ēs)$", "3-1", ["par"]],
929
- ["^(.*[ij])ōrēs$", "3-C", ["pl"]],
930
- ["^(min)ōrēs$", "3-C", ["pl"]],
931
- ["ēs", "3-2", ["pl", "I"]],
932
- ["ēs", "3-1", ["pl", "par"], base_as_stem2],
933
- ["ia", "3-2", ["pl", "I"]],
934
- ["a", "3-1", ["pl", "par"], base_as_stem2],
935
- ["", "3-1", ["I"]],
936
- ["", "3-1", ["par"]],
951
+ ["^(.*ēs)$", "3-1", [NominalType.I]],
952
+ ["^(.*ēs)$", "3-1", [NominalType.Par]],
953
+ ["^(.*[ij])ōrēs$", "3-C", [NominalType.Plural]],
954
+ ["^(min)ōrēs$", "3-C", [NominalType.Plural]],
955
+ ["ēs", "3-2", [NominalType.Plural, NominalType.I]],
956
+ ["ēs", "3-1", [NominalType.Plural, NominalType.Par], base_as_stem2],
957
+ ["ia", "3-2", [NominalType.Plural, NominalType.I]],
958
+ ["a", "3-1", [NominalType.Plural, NominalType.Par], base_as_stem2],
959
+ ["", "3-1", [NominalType.I]],
960
+ ["", "3-1", [NominalType.Par]],
937
961
  ];
938
962
 
939
963
  if (!typ) {
@@ -952,77 +976,77 @@ export class LaNominal {
952
976
  } else if (typ == "1-1") {
953
977
  return this.get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, [
954
978
  ["a", "1-1", []],
955
- ["ae", "1-1", ["pl"]]
979
+ ["ae", "1-1", [NominalType.Plural]]
956
980
  ]);
957
981
  } else if (typ == "2-2") {
958
982
  return this.get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, [
959
983
  ["us", "2-2", []],
960
984
  ["um", "2-2", []],
961
- ["ī", "2-2", ["pl"]],
962
- ["a", "2-2", ["pl"]],
963
- ["os", "2-2", ["greek"]],
964
- ["on", "2-2", ["greek"]],
965
- ["oe", "2-2", ["greek", "pl"]],
985
+ ["ī", "2-2", [NominalType.Plural]],
986
+ ["a", "2-2", [NominalType.Plural]],
987
+ ["os", "2-2", [NominalType.greek]],
988
+ ["on", "2-2", [NominalType.greek]],
989
+ ["oe", "2-2", [NominalType.greek, NominalType.Plural]],
966
990
  ]);
967
991
  } else if (typ == "3-1") {
968
992
  return this.get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, [
969
- ["^(.*ēs)$", "3-1", ["I"]],
970
- ["^(.*ēs)$", "3-1", ["par"]],
971
- ["ēs", "3-1", ["pl", "I"], base_as_stem2],
972
- ["ēs", "3-1", ["pl", "par"], base_as_stem2],
973
- ["ia", "3-1", ["pl", "I"], base_as_stem2],
974
- ["a", "3-1", ["pl", "par"], base_as_stem2],
975
- ["", "3-1", ["I"]],
976
- ["", "3-1", ["par"]],
993
+ ["^(.*ēs)$", "3-1", [NominalType.I]],
994
+ ["^(.*ēs)$", "3-1", [NominalType.Par]],
995
+ ["ēs", "3-1", [NominalType.Plural, NominalType.I], base_as_stem2],
996
+ ["ēs", "3-1", [NominalType.Plural, NominalType.Par], base_as_stem2],
997
+ ["ia", "3-1", [NominalType.Plural, NominalType.I], base_as_stem2],
998
+ ["a", "3-1", [NominalType.Plural, NominalType.Par], base_as_stem2],
999
+ ["", "3-1", [NominalType.I]],
1000
+ ["", "3-1", [NominalType.Par]],
977
1001
  ], decl3_stem2);
978
1002
  } else if (typ == "3-2") {
979
1003
  return this.get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, [
980
1004
  ["is", "3-2", []],
981
1005
  ["e", "3-2", []],
982
1006
  ["ēs", "3-2", []],
983
- ["ēs", "3-2", ["pl"]],
984
- ["ia", "3-2", ["pl"]],
1007
+ ["ēs", "3-2", [NominalType.Plural]],
1008
+ ["ia", "3-2", [NominalType.Plural]],
985
1009
  ], decl3_stem2);
986
1010
  } else if (typ == "3-C") {
987
1011
  return this.get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, [
988
1012
  ["^(.*[ij])or$", "3-C", []],
989
1013
  ["^(min)or$", "3-C", []],
990
- ["^(.*[ij])ōrēs$", "3-C", ["pl"]],
991
- ["^(min)ōrēs$", "3-C", ["pl"]],
1014
+ ["^(.*[ij])ōrēs$", "3-C", [NominalType.Plural]],
1015
+ ["^(min)ōrēs$", "3-C", [NominalType.Plural]],
992
1016
  ], decl3_stem2);
993
1017
  } else if (typ == "irreg") {
994
1018
  return this.get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, [
995
- ["^(duo)$", typ, ["pl"]],
996
- ["^(ambō)$", typ, ["pl"]],
997
- ["^(mīll?ia)$", typ, ["N", "pl"], constant_base("mīlle")],
1019
+ ["^(duo)$", typ, [NominalType.Plural]],
1020
+ ["^(ambō)$", typ, [NominalType.Plural]],
1021
+ ["^(mīll?ia)$", typ, [NominalType.Neuter, NominalType.Plural], constant_base("mīlle")],
998
1022
  ["^(ea)$", typ, [], constant_base("is")],
999
1023
  ["^(id)$", typ, [], constant_base("is")],
1000
- ["^([ei]ī)$", typ, ["pl"], constant_base("is")],
1001
- ["^(eae?)$", typ, ["pl"], constant_base("is")],
1024
+ ["^([ei]ī)$", typ, [NominalType.Plural], constant_base("is")],
1025
+ ["^(eae?)$", typ, [NominalType.Plural], constant_base("is")],
1002
1026
  ["^(eadem)$", typ, [], constant_base("īdem")],
1003
1027
  ["^([īi]dem)$", typ, [], constant_base("īdem")],
1004
- ["^(īdem)$", typ, ["pl"]],
1005
- ["^(eae?dem)$", typ, ["pl"], constant_base("īdem")],
1028
+ ["^(īdem)$", typ, [NominalType.Plural]],
1029
+ ["^(eae?dem)$", typ, [NominalType.Plural], constant_base("īdem")],
1006
1030
  ["^(i[lps][lst])a$", typ, [], (base: string, s2: string) => [base + "e", ""]],
1007
1031
  ["^(i[ls][lt])ud$", typ, [], (base: string, s2: string) => [base + "e", ""]],
1008
1032
  ["^(ipsum)$", typ, [], constant_base("ipse")],
1009
- ["^(i[lps][lst])ī$", typ, ["pl"], (base: string, s2: string) => [base + "e", ""]],
1010
- ["^(i[lps][lst])ae?$", typ, ["pl"], (base: string, s2: string) => [base + "e", ""]],
1033
+ ["^(i[lps][lst])ī$", typ, [NominalType.Plural], (base: string, s2: string) => [base + "e", ""]],
1034
+ ["^(i[lps][lst])ae?$", typ, [NominalType.Plural], (base: string, s2: string) => [base + "e", ""]],
1011
1035
  ["^(quī)$", typ, []],
1012
- ["^(quī)$", typ, ["pl"]],
1036
+ ["^(quī)$", typ, [NominalType.Plural]],
1013
1037
  ["^(quae)$", typ, [], constant_base("quī")],
1014
- ["^(quae)$", typ, ["pl"], constant_base("quī")],
1038
+ ["^(quae)$", typ, [NominalType.Plural], constant_base("quī")],
1015
1039
  ["^(quid)$", typ, [], constant_base("quis")],
1016
1040
  ["^(quod)$", typ, [], constant_base("quī")],
1017
1041
  ["^(qui[cd]quid)$", typ, [], constant_base("quisquis")],
1018
- ["^(quīquī)$", typ, ["pl"], constant_base("quisquis")],
1019
- ["^(quaequae)$", typ, ["pl"], constant_base("quisquis")],
1042
+ ["^(quīquī)$", typ, [NominalType.Plural], constant_base("quisquis")],
1043
+ ["^(quaequae)$", typ, [NominalType.Plural], constant_base("quisquis")],
1020
1044
  ["", typ, []],
1021
1045
  ]);
1022
1046
  } else {
1023
1047
  return this.get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, [
1024
- ["ēs", typ, ["pl"], base_as_stem2],
1025
- ["ia", typ, ["pl"], base_as_stem2],
1048
+ ["ēs", typ, [NominalType.Plural], base_as_stem2],
1049
+ ["ia", typ, [NominalType.Plural], base_as_stem2],
1026
1050
  ["", typ, []],
1027
1051
  ], decl3_stem2);
1028
1052
  }
@@ -1032,23 +1056,23 @@ export class LaNominal {
1032
1056
  lemma: string,
1033
1057
  stem2: string,
1034
1058
  decltype: string | undefined,
1035
- specified_subtypes: Set<string>,
1059
+ specified_subtypes: Set<NominalType>,
1036
1060
  endings_and_subtypes: EndingTable,
1037
1061
  process_stem2?: (base: string) => string):
1038
- [string, string, string, string[]]
1062
+ [string, string, string, NominalType[]]
1039
1063
  {
1040
1064
  for (const [ending, rettype, subtypes, process_retval] of endings_and_subtypes) {
1041
1065
  let not_this_subtype = false;
1042
- if (specified_subtypes.has("pl") && !subtypes.includes("pl")) {
1066
+ if (specified_subtypes.has(NominalType.Plural) && !subtypes.includes(NominalType.Plural)) {
1043
1067
  not_this_subtype = true;
1044
1068
  } else {
1045
1069
  for (const subtype of subtypes) {
1046
- if (specified_subtypes.has("-" + subtype)) {
1070
+ if (!subtype.startsWith("-") && hasNominalType(specified_subtypes, "-" + subtype)) {
1047
1071
  not_this_subtype = true;
1048
1072
  break;
1049
1073
  }
1050
1074
  const must_not_be_present = subtype.match(/^-(.*)$/);
1051
- if (must_not_be_present && specified_subtypes.has(must_not_be_present[1])) {
1075
+ if (must_not_be_present && hasNominalType(specified_subtypes, must_not_be_present[1])) {
1052
1076
  not_this_subtype = true;
1053
1077
  break;
1054
1078
  }
@@ -1093,50 +1117,50 @@ export class LaNominal {
1093
1117
  }
1094
1118
  }
1095
1119
 
1096
- private detect_noun_subtype(lemma: string, stem2: string, typ: string, subtypes: Set<string>): [string, string, Set<string>] {
1120
+ private detect_noun_subtype(lemma: string, stem2: string, typ: string, subtypes: Set<NominalType>): [string, string, Set<NominalType>] {
1097
1121
  if (typ == "1") {
1098
1122
  return this.get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, [
1099
- ["ām", ["F", "am"]],
1100
- ["ās", ["M", "Greek", "Ma"]],
1101
- ["ēs", ["M", "Greek", "Me"]],
1102
- ["ē", ["F", "Greek"]],
1103
- ["ae", ["F", "pl"]],
1104
- ["a", ["F"]],
1123
+ ["ām", [NominalType.Feminine, NominalType.Am]],
1124
+ ["ās", [NominalType.Masculine, NominalType.Greek, NominalType.Ma]],
1125
+ ["ēs", [NominalType.Masculine, NominalType.Greek, NominalType.Me]],
1126
+ ["ē", [NominalType.Feminine, NominalType.Greek]],
1127
+ ["ae", [NominalType.Feminine, NominalType.Plural]],
1128
+ ["a", [NominalType.Feminine]],
1105
1129
  ]);
1106
1130
  } else if (typ == "2") {
1107
1131
  let detected_subtypes;
1108
1132
  [lemma, stem2, detected_subtypes] = this.get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, [
1109
- ["^(.*r)$", ["M", "er"]],
1110
- ["^(.*v)os$", ["M", "vos"]],
1111
- ["^(.*v)om$", ["N", "vom"]],
1112
- ["os", ["M", "Greek"]],
1113
- ["os", ["N", "Greek", "us"]],
1114
- ["on", ["N", "Greek"]],
1115
- ["^([A-ZĀĒĪŌŪȲĂĔĬŎŬ].*)ius$", ["M", "ius", "voci", "sg"]],
1116
- ["ius", ["M", "ius"]],
1117
- ["ium", ["N", "ium"]],
1118
- ["us", ["M"]],
1119
- ["us", ["N", "us"]],
1120
- ["um", ["N"]],
1121
- ["iī", ["M", "ius", "pl"]],
1122
- ["ia", ["N", "ium", "pl"]],
1123
- ["ī", ["M", "pl"]],
1124
- ["ī", ["N", "us", "pl"]],
1125
- ["a", ["N", "pl"]],
1133
+ ["^(.*r)$", [NominalType.Masculine, NominalType.Er]],
1134
+ ["^(.*v)os$", [NominalType.Masculine, NominalType.Vos]],
1135
+ ["^(.*v)om$", [NominalType.Neuter, NominalType.Vom]],
1136
+ ["os", [NominalType.Masculine, NominalType.Greek]],
1137
+ ["os", [NominalType.Neuter, NominalType.Greek, NominalType.Us]],
1138
+ ["on", [NominalType.Neuter, NominalType.Greek]],
1139
+ ["^([A-ZĀĒĪŌŪȲĂĔĬŎŬ].*)ius$", [NominalType.Masculine, NominalType.Ius, NominalType.VocI, NominalType.Singular]],
1140
+ [NominalType.Ius, [NominalType.Masculine, NominalType.Ius]],
1141
+ [NominalType.Ium, [NominalType.Neuter, NominalType.Ium]],
1142
+ [NominalType.Us, [NominalType.Masculine]],
1143
+ [NominalType.Us, [NominalType.Neuter, NominalType.Us]],
1144
+ ["um", [NominalType.Neuter]],
1145
+ ["iī", [NominalType.Masculine, NominalType.Ius, NominalType.Plural]],
1146
+ ["ia", [NominalType.Neuter, NominalType.Ium, NominalType.Plural]],
1147
+ ["ī", [NominalType.Masculine, NominalType.Plural]],
1148
+ ["ī", [NominalType.Neuter, NominalType.Us, NominalType.Plural]],
1149
+ ["a", [NominalType.Neuter, NominalType.Plural]],
1126
1150
  ]);
1127
1151
  stem2 = stem2 || lemma;
1128
1152
  return [lemma, stem2, detected_subtypes];
1129
1153
  } else if (typ == "3") {
1130
1154
  let match;
1131
- if (subtypes.has("pl")) {
1132
- if (subtypes.has("Greek")) {
1155
+ if (subtypes.has(NominalType.Plural)) {
1156
+ if (subtypes.has(NominalType.Greek)) {
1133
1157
  match = lemma.match(/^(.*)erēs$/);
1134
1158
  if (match) {
1135
- return [match[1] + "ēr", match[1] + "er", new Set(["er"])];
1159
+ return [match[1] + "ēr", match[1] + "er", new Set([NominalType.Er])];
1136
1160
  }
1137
1161
  match = lemma.match(/^(.*)ontēs$/);
1138
1162
  if (match) {
1139
- return [match[1] + "ōn", match[1] + "ont", new Set(["on"])];
1163
+ return [match[1] + "ōn", match[1] + "ont", new Set([NominalType.On])];
1140
1164
  }
1141
1165
  match = lemma.match(/^(.*)es$/);
1142
1166
  if (match) {
@@ -1146,11 +1170,11 @@ export class LaNominal {
1146
1170
  }
1147
1171
  match = lemma.match(/^(.*)ia$/);
1148
1172
  if (match) {
1149
- return ["foo", stem2 || match[1], new Set(["N", "I", "pure"])];
1173
+ return ["foo", stem2 || match[1], new Set([NominalType.Neuter, NominalType.I, NominalType.Pure])];
1150
1174
  }
1151
1175
  match = lemma.match(/^(.*)a$/);
1152
1176
  if (match) {
1153
- return ["foo", stem2 || match[1], new Set(["N"])];
1177
+ return ["foo", stem2 || match[1], new Set([NominalType.Neuter])];
1154
1178
  }
1155
1179
  match = lemma.match(/^(.*)ēs$/);
1156
1180
  if (match) {
@@ -1163,32 +1187,32 @@ export class LaNominal {
1163
1187
  let detected_subtypes;
1164
1188
  let base;
1165
1189
  let tmp;
1166
- if (subtypes.has("Greek")) {
1190
+ if (subtypes.has(NominalType.Greek)) {
1167
1191
  [base, tmp, detected_subtypes] = this.get_noun_subtype_by_ending(lemma, stem2, "", subtypes, [
1168
- [["is", ""], ["I"]],
1169
- ["ēr", ["er"]],
1170
- ["ōn", ["on"]],
1192
+ [["is", ""], [NominalType.I]],
1193
+ ["ēr", [NominalType.Er]],
1194
+ ["ōn", [NominalType.On]],
1171
1195
  ]);
1172
1196
  if (base) {
1173
1197
  return [lemma, stem2, detected_subtypes];
1174
1198
  }
1175
1199
  return [lemma, stem2, new Set()];
1176
1200
  }
1177
- if (!subtypes.has("N")) {
1201
+ if (!subtypes.has(NominalType.Neuter)) {
1178
1202
  [base, tmp, detected_subtypes] = this.get_noun_subtype_by_ending(lemma, stem2, "", subtypes, [
1179
- [["^([A-ZĀĒĪŌŪȲĂĔĬŎŬ].*pol)is$", ""], ["F", "polis", "sg", "loc"]],
1180
- [["tūdō", "tūdin"], ["F"]],
1181
- [["tās", "tāt"], ["F"]],
1182
- [["tūs", "tūt"], ["F"]],
1183
- [["tiō", "tiōn"], ["F"]],
1184
- [["siō", "siōn"], ["F"]],
1185
- [["xiō", "xiōn"], ["F"]],
1186
- [["gō", "gin"], ["F"]],
1187
- [["or", "ōr"], ["M"]],
1188
- [["trīx", "trīc"], ["F"]],
1189
- [["trix", "trīc"], ["F"]],
1190
- [["is", ""], ["I"]],
1191
- [["^([a-zāēīōūȳăĕĭŏŭ].*)ēs$", ""], ["I"]],
1203
+ [["^([A-ZĀĒĪŌŪȲĂĔĬŎŬ].*pol)is$", ""], [NominalType.Feminine, NominalType.Polis, NominalType.Singular, NominalType.Locative]],
1204
+ [["tūdō", "tūdin"], [NominalType.Feminine]],
1205
+ [["tās", "tāt"], [NominalType.Feminine]],
1206
+ [["tūs", "tūt"], [NominalType.Feminine]],
1207
+ [["tiō", "tiōn"], [NominalType.Feminine]],
1208
+ [["siō", "siōn"], [NominalType.Feminine]],
1209
+ [["xiō", "xiōn"], [NominalType.Feminine]],
1210
+ [["gō", "gin"], [NominalType.Feminine]],
1211
+ [["or", "ōr"], [NominalType.Masculine]],
1212
+ [["trīx", "trīc"], [NominalType.Feminine]],
1213
+ [["trix", "trīc"], [NominalType.Feminine]],
1214
+ [["is", ""], [NominalType.I]],
1215
+ [["^([a-zāēīōūȳăĕĭŏŭ].*)ēs$", ""], [NominalType.I]],
1192
1216
  ]);
1193
1217
  if (base) {
1194
1218
  return [lemma, stem2, detected_subtypes];
@@ -1196,49 +1220,49 @@ export class LaNominal {
1196
1220
  }
1197
1221
 
1198
1222
  [base, tmp, detected_subtypes] = this.get_noun_subtype_by_ending(lemma, stem2, "", subtypes, [
1199
- [["us", "or"], ["N"]],
1200
- [["us", "er"], ["N"]],
1201
- [["ma", "mat"], ["N"]],
1202
- [["men", "min"], ["N"]],
1203
- [["^([A-ZĀĒĪŌŪȲĂĔĬŎŬ].*)e$", ""], ["N", "sg"]],
1204
- [["e", ""], ["N", "I", "pure"]],
1205
- [["al", "āl"], ["N", "I", "pure"]],
1206
- [["ar", "ār"], ["N", "I", "pure"]],
1223
+ [["us", "or"], [NominalType.Neuter]],
1224
+ [["us", "er"], [NominalType.Neuter]],
1225
+ [["ma", "mat"], [NominalType.Neuter]],
1226
+ [["men", "min"], [NominalType.Neuter]],
1227
+ [["^([A-ZĀĒĪŌŪȲĂĔĬŎŬ].*)e$", ""], [NominalType.Neuter, NominalType.Singular]],
1228
+ [["e", ""], [NominalType.Neuter, NominalType.I, NominalType.Pure]],
1229
+ [["al", "āl"], [NominalType.Neuter, NominalType.I, NominalType.Pure]],
1230
+ [["ar", "ār"], [NominalType.Neuter, NominalType.I, NominalType.Pure]],
1207
1231
  ]);
1208
1232
  if (base) {
1209
1233
  return [lemma, stem2, detected_subtypes];
1210
1234
  }
1211
1235
  return [lemma, stem2, new Set()];
1212
1236
  } else if (typ == "4") {
1213
- if (subtypes.has("echo") || subtypes.has("argo") || subtypes.has("Callisto")) {
1237
+ if (subtypes.has(NominalType.Echo) || subtypes.has(NominalType.argo) || subtypes.has(NominalType.Callisto)) {
1214
1238
  const match = lemma.match(/^(.*)ō$/);
1215
1239
  if (!match) {
1216
1240
  throw Error(`Declension-4 noun of subtype .echo, .argo or .Callisto should end in -ō: ${lemma}`);
1217
1241
  }
1218
1242
  const base = match[1];
1219
- if (subtypes.has("Callisto")) {
1220
- return [base, "", new Set(["F", "sg"])];
1243
+ if (subtypes.has(NominalType.Callisto)) {
1244
+ return [base, "", new Set([NominalType.Feminine, NominalType.Singular])];
1221
1245
  } else {
1222
- return [base, "", new Set(["F"])];
1246
+ return [base, "", new Set([NominalType.Feminine])];
1223
1247
  }
1224
1248
  }
1225
1249
  return this.get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, [
1226
- ["us", ["M"]],
1227
- ["ū", ["N"]],
1228
- ["ūs", ["M", "pl"]],
1229
- ["ua", ["N", "pl"]],
1250
+ ["us", [NominalType.Masculine]],
1251
+ ["ū", [NominalType.Neuter]],
1252
+ ["ūs", [NominalType.Masculine, NominalType.Plural]],
1253
+ ["ua", [NominalType.Neuter, NominalType.Plural]],
1230
1254
  ]);
1231
1255
  } else if (typ == "5") {
1232
1256
  return this.get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, [
1233
- ["iēs", ["F", "i"]],
1234
- ["iēs", ["F", "i", "pl"]],
1235
- ["ēs", ["F"]],
1236
- ["ēs", ["F", "pl"]],
1257
+ ["iēs", [NominalType.Feminine, NominalType.i]],
1258
+ ["iēs", [NominalType.Feminine, NominalType.i, NominalType.Plural]],
1259
+ ["ēs", [NominalType.Feminine]],
1260
+ ["ēs", [NominalType.Feminine, NominalType.Plural]],
1237
1261
  ]);
1238
1262
  } else if (typ == "irreg" && lemma == "domus") {
1239
- return [lemma, "", new Set(["loc"])];
1263
+ return [lemma, "", new Set([NominalType.Locative])];
1240
1264
  } else if (typ == "indecl" || (typ == "irreg" && (lemma == "Deus" || lemma == "Iēsus" || lemma == "Jēsus" || lemma == "Athōs" || lemma == "vēnum"))) {
1241
- return [lemma, "", new Set(["sg"])];
1265
+ return [lemma, "", new Set([NominalType.Singular])];
1242
1266
  } else {
1243
1267
  return [lemma, "", new Set()];
1244
1268
  }
@@ -1284,23 +1308,23 @@ export class LaNominal {
1284
1308
  lemma: string,
1285
1309
  stem2: string,
1286
1310
  decltype: string,
1287
- specified_subtypes: Set<string>,
1288
- endings_and_subtypes: [(string | string[]), string[]][]):
1289
- [string, string, Set<string>]
1311
+ specified_subtypes: Set<NominalType>,
1312
+ endings_and_subtypes: [(string | string[]), NominalType[]][]):
1313
+ [string, string, Set<NominalType>]
1290
1314
  {
1291
1315
  for (const ending_and_subtype of endings_and_subtypes) {
1292
1316
  const ending = ending_and_subtype[0];
1293
1317
  const subtypes = ending_and_subtype[1];
1294
1318
  let not_this_subtype = false;
1295
- if (specified_subtypes.has("pl") && !subtypes.includes("pl")) {
1319
+ if (specified_subtypes.has(NominalType.Plural) && !subtypes.includes(NominalType.Plural)) {
1296
1320
  not_this_subtype = true;
1297
1321
  } else {
1298
1322
  for (const subtype of subtypes) {
1299
- if (specified_subtypes.has("-" + subtype) ||
1300
- (subtype == "N" && (specified_subtypes.has("M") || specified_subtypes.has("F"))) ||
1301
- ((subtype == "M" || subtype == "F") && specified_subtypes.has("N")) ||
1302
- (subtype == "sg" && specified_subtypes.has("pl")) ||
1303
- (subtype == "pl" && specified_subtypes.has("sg"))) {
1323
+ if (hasNominalType(specified_subtypes, "-" + subtype) ||
1324
+ (subtype == NominalType.Neuter && (specified_subtypes.has(NominalType.Masculine) || specified_subtypes.has(NominalType.Feminine))) ||
1325
+ ((subtype == NominalType.Masculine || subtype == NominalType.Feminine) && specified_subtypes.has(NominalType.Neuter)) ||
1326
+ (subtype == NominalType.Singular && specified_subtypes.has(NominalType.Plural)) ||
1327
+ (subtype == NominalType.Plural && specified_subtypes.has(NominalType.Singular))) {
1304
1328
  not_this_subtype = true;
1305
1329
  break;
1306
1330
  }
@@ -1339,6 +1363,7 @@ export class LaNominal {
1339
1363
  categories: [],
1340
1364
  voc: true,
1341
1365
  noneut: false,
1366
+ nomf: false,
1342
1367
  };
1343
1368
 
1344
1369
  for (const slot of this.iter_slots(is_adj)) {
@@ -1367,8 +1392,10 @@ export class LaNominal {
1367
1392
  footnote: "",
1368
1393
  num: seg.num,
1369
1394
  gender: seg.gender,
1395
+ loc: seg.loc,
1370
1396
  voc: true,
1371
1397
  noneut: false,
1398
+ nomf: false,
1372
1399
  pos: is_adj ? pos : "adjectives",
1373
1400
  forms: new Map(),
1374
1401
  types: seg.types,
@@ -1383,10 +1410,13 @@ export class LaNominal {
1383
1410
  if (data.noneut) {
1384
1411
  declensions.noneut = true;
1385
1412
  }
1413
+ if (data.nomf) {
1414
+ declensions.nomf = true;
1415
+ }
1386
1416
 
1387
- if (data.types.has("sufn")) {
1417
+ if (data.types.has(NominalType.SuffixN)) {
1388
1418
  data.subtitles.push(["with", " 'm' optionally → 'n' in compounds"]);
1389
- } else if (data.types.has("not_sufn")) {
1419
+ } else if (data.types.has(NominalType.NotSuffixN)) {
1390
1420
  data.subtitles.push(["without", " 'm' optionally → 'n' in compounds"]);
1391
1421
  }
1392
1422
 
@@ -1449,11 +1479,12 @@ export class LaNominal {
1449
1479
  } else {
1450
1480
  throw Error(`Internal error! Don't recognize noun declension ${apparent_decl}`);
1451
1481
  }
1482
+ parsed_run.apparent_decl = apparent_decl;
1452
1483
  data.title = data.title + " noun";
1453
1484
  }
1454
- if (data.types.has("sufn")) {
1485
+ if (data.types.has(NominalType.SuffixN)) {
1455
1486
  data.subtitles.push(["with", " 'm' optionally → 'n' in compounds"]);
1456
- } else if (data.types.has("not_sufn")) {
1487
+ } else if (data.types.has(NominalType.NotSuffixN)) {
1457
1488
  data.subtitles.push(["without", " 'm' optionally → 'n' in compounds"]);
1458
1489
  }
1459
1490
  declensions.orig_titles.push(data.title);
@@ -1489,11 +1520,11 @@ export class LaNominal {
1489
1520
  }
1490
1521
  }
1491
1522
 
1492
- if (seg.types.has("lig")) {
1523
+ if (seg.types.has(NominalType.Ligature)) {
1493
1524
  this.apply_ligatures(data.forms, is_adj);
1494
1525
  }
1495
1526
 
1496
- if (seg.types.has("sufn")) {
1527
+ if (seg.types.has(NominalType.SuffixN)) {
1497
1528
  this.apply_sufn(data.forms, is_adj);
1498
1529
  }
1499
1530
 
@@ -1536,7 +1567,7 @@ export class LaNominal {
1536
1567
  declensions.notes.set(slot, notes);
1537
1568
  }
1538
1569
 
1539
- if (!seg.types.has("nocat") && (is_adj || !seg.is_adj)) {
1570
+ if (!seg.types.has(NominalType.NoCategories) && (is_adj || !seg.is_adj)) {
1540
1571
  for (const cat of data.categories) {
1541
1572
  this.insert_if_not(declensions.categories, cat);
1542
1573
  }
@@ -1579,7 +1610,7 @@ export class LaNominal {
1579
1610
  }
1580
1611
  }
1581
1612
  if (!title_the_hard_way) {
1582
- const subtypeses: Set<string> = new Set();
1613
+ const subtypeses = new Set<NominalType>();
1583
1614
  for (const this_parsed_run of seg.alternants) {
1584
1615
  for (const segment of this_parsed_run.segments) {
1585
1616
  if (segment.type == "Segment" && segment.decl) {
@@ -1593,7 +1624,7 @@ export class LaNominal {
1593
1624
  if (segment.type == "Segment" && segment.decl) {
1594
1625
  const neg_subtypes = this.set_difference(subtypeses, segment.types);
1595
1626
  for (const neg_subtype of neg_subtypes) {
1596
- segment.types.add("not_" + neg_subtype);
1627
+ addNominalType(segment.types, "not_" + neg_subtype);
1597
1628
  }
1598
1629
  }
1599
1630
  }
@@ -1614,6 +1645,10 @@ export class LaNominal {
1614
1645
  declensions.noneut = true;
1615
1646
  }
1616
1647
 
1648
+ if (this_declensions.nomf) {
1649
+ declensions.nomf = true;
1650
+ }
1651
+
1617
1652
  if (this_parsed_run.num == "sg" || this_parsed_run.num == "pl") {
1618
1653
  for (const slot of (this.iter_slots(is_adj))) {
1619
1654
  if ((this_parsed_run.num == "sg" && slot.includes("pl")) ||
@@ -1862,8 +1897,8 @@ export class LaNominal {
1862
1897
  return sentences_to_join.join(joiner);
1863
1898
  }
1864
1899
 
1865
- private set_difference(a: Set<string>, b: Set<string>): Set<string> {
1866
- const res = new Set<string>();
1900
+ private set_difference<T>(a: Set<T>, b: Set<T>): Set<T> {
1901
+ const res = new Set<T>();
1867
1902
  for (const key of a.keys()) {
1868
1903
  if (!b.has(key)) {
1869
1904
  res.add(key);
@@ -1963,6 +1998,7 @@ export class LaNominal {
1963
1998
  }
1964
1999
  newval.push(form);
1965
2000
  }
2001
+ setNominalForm(forms, slot, newval);
1966
2002
  }
1967
2003
  }
1968
2004
  }