conjugator.js (19488B)
1 import { Geulja, findVowelToAppend, getLead, getPadchim, getVowel, join } from "./hangul.js"; 2 import { isDIrregular, isHIrregular, isLEuIrregular, isLIrregular, isPIrregular, isSIrregular } from "./irregulars.js"; 3 import { merge_rules } from "./merge_rules.js"; 4 export class Conjugator { 5 constructor() { 6 this.tense_rules = []; 7 this.reasons = []; 8 this.tense_rules = [ 9 { name: "base", rule: (infinitive, regular) => this.base(infinitive, regular) }, 10 { name: "base2", rule: (infinitive, regular) => this.base2(infinitive, regular) }, 11 { name: "base3", rule: (infinitive, regular) => this.base3(infinitive, regular) }, 12 { name: "declarative present informal low", rule: (infinitive, regular) => this.declarativePresentInformalLow(infinitive, regular) }, 13 { name: "declarative present informal high", rule: (infinitive, regular) => this.declarativePresentInformalHigh(infinitive, regular) }, 14 { name: "declarative present formal low", rule: (infinitive, regular) => this.declarativePresentFormalLow(infinitive, regular) }, 15 { name: "declarative present formal high", rule: (infinitive, regular) => this.declarativePresentFormalHigh(infinitive, regular) }, 16 { name: "past base", rule: (infinitive, regular) => this.pastBase(infinitive, regular) }, 17 { name: "declarative past informal low", rule: (infinitive, regular) => this.declarativePastInformalLow(infinitive, regular) }, 18 { name: "declarative past informal high", rule: (infinitive, regular) => this.declarativePastInformalHigh(infinitive, regular) }, 19 { name: "declarative past formal low", rule: (infinitive, regular) => this.declarativePastFormalLow(infinitive, regular) }, 20 { name: "declarative past formal high", rule: (infinitive, regular) => this.declarativePastFormalHigh(infinitive, regular) }, 21 { name: "future base", rule: (infinitive, regular) => this.futureBase(infinitive, regular) }, 22 { name: "declarative future informal low", rule: (infinitive, regular) => this.declarativeFutureInformalLow(infinitive, regular) }, 23 { name: "declarative future informal high", rule: (infinitive, regular) => this.declarativeFutureInformalHigh(infinitive, regular) }, 24 { name: "declarative future formal low", rule: (infinitive, regular) => this.declarativeFutureFormalLow(infinitive, regular) }, 25 { name: "declarative future formal high", rule: (infinitive, regular) => this.declarativeFutureFormalHigh(infinitive, regular) }, 26 { name: "declarative future conditional informal low", rule: (infinitive, regular) => this.declarativeFutureConditionalInformalLow(infinitive, regular) }, 27 { name: "declarative future conditional informal high", rule: (infinitive, regular) => this.declarativeFutureConditionalInformalHigh(infinitive, regular) }, 28 { name: "declarative future conditional formal low", rule: (infinitive, regular) => this.declarativeFutureConditionalFormalLow(infinitive, regular) }, 29 { name: "declarative future conditional formal high", rule: (infinitive, regular) => this.declarativeFutureConditionalFormalHigh(infinitive, regular) }, 30 { name: "inquisitive present informal low", rule: (infinitive, regular) => this.inquisitivePresentInformalLow(infinitive, regular) }, 31 { name: "inquisitive present informal high", rule: (infinitive, regular) => this.inquisitivePresentInformalHigh(infinitive, regular) }, 32 { name: "inquisitive present formal low", rule: (infinitive, regular) => this.inquisitivePresentFormalLow(infinitive, regular) }, 33 { name: "inquisitive present formal high", rule: (infinitive, regular) => this.inquisitivePresentFormalHigh(infinitive, regular) }, 34 { name: "inquisitive past informal low", rule: (infinitive, regular) => this.inquisitivePastInformalLow(infinitive, regular) }, 35 { name: "inquisitive past informal high", rule: (infinitive, regular) => this.inquisitivePastInformalHigh(infinitive, regular) }, 36 { name: "inquisitive past formal low", rule: (infinitive, regular) => this.inquisitivePastFormalLow(infinitive, regular) }, 37 { name: "inquisitive past formal high", rule: (infinitive, regular) => this.inquisitivePastFormalHigh(infinitive, regular) }, 38 { name: "imperative present informal low", rule: (infinitive, regular) => this.imperativePresentInformalLow(infinitive, regular) }, 39 { name: "imperative present informal high", rule: (infinitive, regular) => this.imperativePresentInformalHigh(infinitive, regular) }, 40 { name: "imperative present formal low", rule: (infinitive, regular) => this.imperativePresentFormalLow(infinitive, regular) }, 41 { name: "imperative present formal high", rule: (infinitive, regular) => this.imperativePresentFormalHigh(infinitive, regular) }, 42 { name: "propositive present informal low", rule: (infinitive, regular) => this.propositivePresentInformalLow(infinitive, regular) }, 43 { name: "propositive present informal high", rule: (infinitive, regular) => this.propositivePresentInformalHigh(infinitive, regular) }, 44 { name: "propositive present formal low", rule: (infinitive, regular) => this.propositivePresentFormalLow(infinitive, regular) }, 45 { name: "propositive present formal high", rule: (infinitive, regular) => this.propositivePresentFormalHigh(infinitive, regular) }, 46 { name: "connective if", rule: (infinitive, regular) => this.connectiveIf(infinitive, regular) }, 47 { name: "connective and", rule: (infinitive, regular) => this.connectiveAnd(infinitive, regular) }, 48 { name: "nominal ing", rule: (infinitive, regular) => this.nominalIng(infinitive, regular) }, 49 ]; 50 } 51 perform(infinitive, regular = false) { 52 const results = []; 53 for (const tense of this.tense_rules) { 54 this.reasons = []; 55 const conjugation = tense.rule(infinitive, regular); 56 results.push({ 57 tense: tense.name, 58 conjugation: conjugation.toString(), 59 reasons: this.reasons 60 }); 61 } 62 return results; 63 } 64 dropL(x, y) { 65 if (getPadchim(x[x.length - 1]) === "ᆯ") { 66 this.reasons.push("drop ㄹ"); 67 return x.substring(0, x.length - 1) + join(getLead(x[x.length - 1]), getVowel(x[x.length - 1])) + y; 68 } 69 throw new Error("Not an L padchim"); 70 } 71 dropLAndBorrowPadchim(x, y) { 72 if (getPadchim(x[x.length - 1]) === "ᆯ") { 73 this.reasons.push(`drop ${getPadchim(x[x.length - 1])} borrow padchim`); 74 return x.substring(0, x.length - 1) + join(getLead(x[x.length - 1]), getVowel(x[x.length - 1]), getPadchim(y[0])) + y.substring(1); 75 } 76 throw new Error("Not an L padchim"); 77 } 78 merge(x, y) { 79 for (let i = 0; i < merge_rules.length; i++) { 80 const rule = merge_rules[i]; 81 const output = rule(x, y); 82 if (output) { 83 this.reasons.push(`${output[0] && output[0] || ""} (${x} + ${y} -> ${output[1]})`); 84 return output[1]; 85 } 86 } 87 throw new Error("Unable to match on rule"); 88 } 89 // eslint-disable-next-line @typescript-eslint/no-unused-vars 90 base(infinitive, _regular = false) { 91 if (infinitive.endsWith("다")) { 92 return infinitive.substring(0, infinitive.split("").length - 1); 93 } 94 return infinitive; 95 } 96 base2(infinitive, regular = false) { 97 infinitive = this.base(infinitive, regular); 98 if (infinitive === "아니") { 99 const geulja = new Geulja("아니"); 100 geulja.hidden_padchim = true; 101 return geulja; 102 } 103 if (infinitive === "뵙") 104 return "뵈"; 105 if (infinitive === "푸") 106 return "퍼"; 107 let new_infinitive = infinitive; 108 if (isHIrregular(infinitive, regular)) { 109 new_infinitive = this.merge(infinitive.substring(0, infinitive.length - 1) + join(getLead(infinitive[infinitive.length - 1]), getVowel(infinitive[infinitive.length - 1])), "이"); 110 this.reasons.push(`ㅎ irregular (${infinitive} -> ${new_infinitive})`); 111 } 112 else if (isPIrregular(infinitive, regular)) { 113 let new_vowel = ""; 114 // only some verbs get ㅗ (highly irregular) 115 if (["묻잡"].includes(infinitive.toString()) || ["돕", "곱"].includes(infinitive[infinitive.length - 1])) { 116 new_vowel = "ㅗ"; 117 } 118 else { 119 new_vowel = "ㅜ"; 120 } 121 new_infinitive = this.merge(infinitive.substring(0, infinitive.length - 1) + join(getLead(infinitive[infinitive.length - 1]), getVowel(infinitive[infinitive.length - 1])), join("ᄋ", new_vowel)); 122 this.reasons.push(`ㅂ irregular (${infinitive} -> ${new_infinitive})`); 123 } 124 else if (isDIrregular(infinitive, regular)) { 125 new_infinitive = new Geulja(infinitive.substring(0, infinitive.length - 1) + join(getLead(infinitive[infinitive.length - 1]), getVowel(infinitive[infinitive.length - 1]), "ᆯ")); 126 new_infinitive.original_padchim = "ᆮ"; 127 this.reasons.push(`ㄷ irregular (${infinitive} -> ${new_infinitive})`); 128 } 129 else if (isSIrregular(infinitive, regular)) { 130 new_infinitive = new Geulja(infinitive.substring(0, infinitive.length - 1) + join(getLead(infinitive[infinitive.length - 1]), getVowel(infinitive[infinitive.length - 1]))); 131 new_infinitive.hidden_padchim = true; 132 this.reasons.push(`ㅅ irregular (${infinitive} -> ${new_infinitive} [hidden padchim])`); 133 } 134 return new_infinitive; 135 } 136 base3(infinitive, regular = false) { 137 infinitive = this.base(infinitive, regular); 138 if (infinitive === "아니") 139 return "아니"; 140 if (infinitive == "푸") 141 return "푸"; 142 if (infinitive == "뵙") 143 return "뵈"; 144 if (isHIrregular(infinitive, regular)) { 145 return infinitive.substring(0, infinitive.length - 1) + join(getLead(infinitive[infinitive.length - 1]), getVowel(infinitive[infinitive.length - 1])); 146 } 147 else if (isPIrregular(infinitive, regular)) { 148 return infinitive.substring(0, infinitive.length - 1) + join(getLead(infinitive[infinitive.length - 1]), getVowel(infinitive[infinitive.length - 1])) + "우"; 149 } 150 else { 151 return this.base2(infinitive, regular); 152 } 153 } 154 declarativePresentInformalLow(infinitive, regular = false, further_use = false) { 155 infinitive = this.base2(infinitive, regular); 156 if (!further_use && ((infinitive[infinitive.length - 1] === "이" && !(infinitive instanceof Geulja)) || infinitive === "아니")) { 157 this.reasons.push("야 irregular"); 158 return infinitive + "야"; 159 } 160 // 르 irregular 161 if (regular && infinitive === "이르") { 162 return "일러"; 163 } 164 if (isLEuIrregular(infinitive, regular)) { 165 let new_base = infinitive.substring(0, infinitive.length - 2) + join(getLead(infinitive[infinitive.length - 2]), getVowel(infinitive[infinitive.length - 2]), "ᆯ"); 166 if (["푸르", "이르"].includes(infinitive.substring(infinitive.length - 2))) { 167 new_base = new_base + join("ᄅ", getVowel(findVowelToAppend(new_base))); 168 this.reasons.push(`irregular stem + ${infinitive} -> ${new_base}`); 169 return infinitive + "러"; 170 } 171 else if (findVowelToAppend(infinitive.substring(0, infinitive.length - 1)) === "아") { 172 new_base += "라"; 173 this.reasons.push(`르 irregular stem change [${infinitive} -> ${new_base}]`); 174 return new_base; 175 } 176 else { 177 new_base += "러"; 178 this.reasons.push(`르 irregular stem change [${infinitive} -> ${new_base}]`); 179 return new_base; 180 } 181 } 182 else if (infinitive[infinitive.length - 1] === "하") { 183 return this.merge(infinitive, "여"); 184 } 185 else if (isHIrregular(infinitive, regular)) { 186 return this.merge(infinitive, "이"); 187 } 188 return this.merge(infinitive, findVowelToAppend(infinitive)); 189 } 190 declarativePresentInformalHigh(infinitive, regular = false) { 191 infinitive = this.base2(infinitive, regular); 192 if ((infinitive[infinitive.length - 1] === "이" && !(infinitive instanceof Geulja)) || infinitive === "아니") { 193 this.reasons.push("에요 irregular"); 194 return infinitive + "에요"; 195 } 196 return this.merge(this.declarativePresentInformalLow(infinitive, regular, true), "요"); 197 } 198 declarativePresentFormalLow(infinitive, regular = false) { 199 if (isLIrregular(this.base(infinitive), regular)) { 200 return this.dropLAndBorrowPadchim(this.base(infinitive, regular), "는다"); 201 } 202 return this.merge(this.base(infinitive, regular), "는다"); 203 } 204 declarativePresentFormalHigh(infinitive, regular = false) { 205 if (isLIrregular(this.base(infinitive), regular)) { 206 return this.dropLAndBorrowPadchim(this.base(infinitive, regular), "습니다"); 207 } 208 return this.merge(this.base(infinitive, regular), "습니다"); 209 } 210 pastBase(infinitive, regular = false) { 211 const ps = this.declarativePresentInformalLow(infinitive, regular, true); 212 if (findVowelToAppend(ps) == "아") { 213 return this.merge(ps, "았"); 214 } 215 return this.merge(ps, "었"); 216 } 217 declarativePastInformalLow(infinitive, regular = false) { 218 return this.merge(this.pastBase(infinitive, regular), "어"); 219 } 220 declarativePastInformalHigh(infinitive, regular = false) { 221 return this.merge(this.declarativePastInformalLow(infinitive, regular), "요"); 222 } 223 declarativePastFormalLow(infinitive, regular = false) { 224 return this.merge(this.pastBase(infinitive, regular), "다"); 225 } 226 declarativePastFormalHigh(infinitive, regular = false) { 227 return this.merge(this.pastBase(infinitive, regular), "습니다"); 228 } 229 futureBase(infinitive, regular = false) { 230 if (isLIrregular(this.base(infinitive, regular))) { 231 return this.dropLAndBorrowPadchim(this.base3(infinitive, regular), "을"); 232 } 233 return this.merge(this.base3(infinitive, regular), "을"); 234 } 235 declarativeFutureInformalLow(infinitive, regular = false) { 236 return this.merge(this.futureBase(infinitive, regular), " 거야"); 237 } 238 declarativeFutureInformalHigh(infinitive, regular = false) { 239 return this.merge(this.futureBase(infinitive, regular), " 거예요"); 240 } 241 declarativeFutureFormalLow(infinitive, regular = false) { 242 return this.merge(this.futureBase(infinitive, regular), " 거다"); 243 } 244 declarativeFutureFormalHigh(infinitive, regular = false) { 245 return this.merge(this.futureBase(infinitive, regular), " 겁니다"); 246 } 247 declarativeFutureConditionalInformalLow(infinitive, regular = false) { 248 return this.merge(this.base(infinitive, regular), "겠어"); 249 } 250 declarativeFutureConditionalInformalHigh(infinitive, regular = false) { 251 return this.merge(this.base(infinitive, regular), "겠어요"); 252 } 253 declarativeFutureConditionalFormalLow(infinitive, regular = false) { 254 return this.merge(this.base(infinitive, regular), "겠다"); 255 } 256 declarativeFutureConditionalFormalHigh(infinitive, regular = false) { 257 return this.merge(this.base(infinitive, regular), "겠습니다"); 258 } 259 inquisitivePresentInformalLow(infinitive, regular = false) { 260 return this.merge(this.declarativePresentInformalLow(infinitive, regular), "?"); 261 } 262 inquisitivePresentInformalHigh(infinitive, regular = false) { 263 return this.merge(this.declarativePresentInformalHigh(infinitive, regular), "?"); 264 } 265 inquisitivePresentFormalLow(infinitive, regular = false) { 266 infinitive = this.base(infinitive, regular); 267 if (isLIrregular(infinitive, regular)) { 268 return this.dropL(infinitive, "니?"); 269 } 270 return this.merge(infinitive, "니?"); 271 } 272 inquisitivePresentFormalHigh(infinitive, regular = false) { 273 infinitive = this.base(infinitive, regular); 274 if (isLIrregular(infinitive, regular)) { 275 return this.dropLAndBorrowPadchim(infinitive, "습니까?"); 276 } 277 return this.merge(infinitive, "습니까?"); 278 } 279 inquisitivePastInformalLow(infinitive, regular = false) { 280 return this.declarativePastInformalLow(infinitive, regular) + "?"; 281 } 282 inquisitivePastInformalHigh(infinitive, regular = false) { 283 return this.merge(this.declarativePastInformalHigh(infinitive, regular), "?"); 284 } 285 inquisitivePastFormalLow(infinitive, regular = false) { 286 return this.merge(this.pastBase(infinitive, regular), "니?"); 287 } 288 inquisitivePastFormalHigh(infinitive, regular = false) { 289 return this.merge(this.pastBase(infinitive, regular), "습니까?"); 290 } 291 imperativePresentInformalLow(infinitive, regular = false) { 292 return this.declarativePresentInformalLow(infinitive, regular); 293 } 294 imperativePresentInformalHigh(infinitive, regular = false) { 295 if (isLIrregular(this.base(infinitive, regular))) { 296 return this.dropL(this.base3(infinitive, regular), "세요"); 297 } 298 return this.merge(this.base3(infinitive, regular), "세요"); 299 } 300 imperativePresentFormalLow(infinitive, regular = false) { 301 return this.merge(this.imperativePresentInformalLow(infinitive, regular), "라"); 302 } 303 imperativePresentFormalHigh(infinitive, regular = false) { 304 if (isLIrregular(this.base(infinitive, regular))) { 305 return this.dropL(this.base3(infinitive, regular), "십시오"); 306 } 307 return this.merge(this.base3(infinitive, regular), "십시오"); 308 } 309 propositivePresentInformalLow(infinitive, regular = false) { 310 return this.declarativePresentInformalLow(infinitive, regular); 311 } 312 propositivePresentInformalHigh(infinitive, regular = false) { 313 return this.declarativePresentInformalHigh(infinitive, regular); 314 } 315 propositivePresentFormalLow(infinitive, regular = false) { 316 return this.merge(this.base(infinitive, regular), "자"); 317 } 318 propositivePresentFormalHigh(infinitive, regular = false) { 319 infinitive = this.base(infinitive); 320 if (isLIrregular(infinitive, regular)) { 321 return this.dropLAndBorrowPadchim(this.base3(infinitive, regular), "읍시다"); 322 } 323 return this.merge(this.base3(infinitive, regular), "읍시다"); 324 } 325 connectiveIf(infinitive, regular = false) { 326 return this.merge(this.base3(infinitive, regular), "면"); 327 } 328 connectiveAnd(infinitive, regular = false) { 329 infinitive = this.base(infinitive, regular); 330 return this.merge(this.base(infinitive, regular), "고"); 331 } 332 nominalIng(infinitive, regular = false) { 333 return this.merge(this.base3(infinitive, regular), "음"); 334 } 335 }