diff --git a/vidyut-prakriya/data/varttikas.tsv b/vidyut-prakriya/data/varttikas.tsv index 4b426b3..4e248c4 100644 --- a/vidyut-prakriya/data/varttikas.tsv +++ b/vidyut-prakriya/data/varttikas.tsv @@ -29,6 +29,7 @@ 3.1.97.1 takiSasicatiyatijanInAmupasaNKyAnam 3.1.97.2 hano vA vaDa ca 3.1.100.1 carerANi cAgurO +3.1.140.1 tanoterRasyopasaNKyAnaM kartavyam 3.2.8.1 pibateH surASIDvoriti vaktavyam 3.2.9.1 SaktilANgalANkuSayazwitomaraGawaGawIDanuzzu graherupasaNKyAnam 3.2.9.2 sUtre ca DAryarTe diff --git a/vidyut-prakriya/src/args/internal.rs b/vidyut-prakriya/src/args/internal.rs index e153fad..1278f40 100644 --- a/vidyut-prakriya/src/args/internal.rs +++ b/vidyut-prakriya/src/args/internal.rs @@ -233,6 +233,7 @@ internal_term!(Aupadeshika, { kfvi => "kfvi~", ovijI_u => "o~vijI~", ovijI_a => "o~vijI~\\", + qudAY => "qudA\\Y", quDAY => "quDA\\Y", qukfY => "qukf\\Y", vyaca => "vyaca~", diff --git a/vidyut-prakriya/src/args/krt.rs b/vidyut-prakriya/src/args/krt.rs index 9344ed2..14eca92 100644 --- a/vidyut-prakriya/src/args/krt.rs +++ b/vidyut-prakriya/src/args/krt.rs @@ -1,6 +1,7 @@ use crate::args::dhatu::Dhatu; use crate::args::unadi::Unadi; use crate::args::Lakara; +use crate::args::Prayoga; use crate::args::Subanta; use crate::core::errors::*; use crate::enum_boilerplate; @@ -100,7 +101,7 @@ pub enum BaseKrt { /// -ru (BIru) kru, /// -ruka (BIruka) - kruka, + krukan, /// -luka (BIluka) klukan, /// -van @@ -269,7 +270,7 @@ enum_boilerplate!(BaseKrt, { kmarac => "kmarac", kyap => "kyap", kru => "kru", - kruka => "kruka", + krukan => "krukan", klukan => "klukan", kvanip => "kvani~p", kvarap => "kvarap", @@ -419,9 +420,14 @@ pub struct Krdanta { krt: Krt, /// Whether this krdanta must follow a specific `KrtArtha` condition. artha: Option, - /// Whether this krdanta must replace a specific `Lakara`. If unset, default to `Lat` if - /// necessary. + /// Whether this krdanta must replace a specific lakara. If unset, default to `Lat`. + /// + /// (`Satf` and `SAnac` only. This field is ignored for all other values.) lakara: Option, + /// Whether this krdanta must use a specific prayoga. If unset, default to `Kartari`. + /// + /// (`Satf` and `SAnac` only. This field is ignored for all other values.) + prayoga: Option, /// Whether this krdanta is allowed only with a specific *upapada*. upapada: Option, /// Whether the derived krdanta must have exactly the specified value. @@ -438,6 +444,7 @@ impl Krdanta { krt: krt.into(), artha: None, lakara: None, + prayoga: None, upapada: None, require: None, } @@ -477,6 +484,11 @@ impl Krdanta { } } + /// The prayoga that this krt-pratyaya should use. + pub fn prayoga(&self) -> Option { + self.prayoga + } + /// The upapada that conditions the krt pratyaya. pub fn upapada(&self) -> &Option { &self.upapada @@ -507,45 +519,55 @@ pub struct KrdantaBuilder { upapada: Option, artha: Option, lakara: Option, + prayoga: Option, require: Option, } impl KrdantaBuilder { /// Sets the krt-pratyaya to use in the derivation. - pub fn dhatu(&mut self, dhatu: Dhatu) -> &mut Self { + pub fn dhatu(mut self, dhatu: Dhatu) -> Self { self.dhatu = Some(dhatu); self } /// Sets the krt-pratyaya to use in the derivation. - pub fn krt(&mut self, val: impl Into) -> &mut Self { + pub fn krt(mut self, val: impl Into) -> Self { self.krt = Some(val.into()); self } /// Sets the upapada to use in the derivation. - pub fn upapada(&mut self, upapada: Subanta) -> &mut Self { + pub fn upapada(mut self, upapada: Subanta) -> Self { self.upapada = Some(upapada); self } /// Sets the upapada to use in the derivation. - pub fn artha(&mut self, artha: KrtArtha) -> &mut Self { + pub fn artha(mut self, artha: KrtArtha) -> Self { self.artha = Some(artha); self } /// Sets the lakara to use in the derivation. /// - /// This field is necessary for pratyayas like Satf and SAnac, which replace a specific lakara. - /// If `lakara` is not specified, prakriyas will default to lat-lakara. - pub fn lakara(&mut self, lakara: Lakara) -> &mut Self { + /// This field is used only for the pratyayas Satf and SAnac, which replace a specific lakara. + /// If `lakara` is left unspecified, the program defaults to `Lakara::Lat`. + pub fn lakara(mut self, lakara: Lakara) -> Self { self.lakara = Some(lakara); self } + /// Sets the prayoga to use in the derivation. + /// + /// This field is used only for the pratyayas Satf and SAnac, which require a specific prayoga. + /// If `prayoga` is left unspecified, the program defaults to `Prayoga::Kartari`. + pub fn prayoga(mut self, prayoga: Prayoga) -> Self { + self.prayoga = Some(prayoga); + self + } + /// Sets the value that the krdanta must have. - pub fn require(&mut self, text: impl AsRef) -> &mut Self { + pub fn require(mut self, text: impl AsRef) -> Self { self.require = Some(text.as_ref().to_string()); self } @@ -565,6 +587,7 @@ impl KrdantaBuilder { }, upapada: self.upapada.as_ref().cloned(), lakara: self.lakara, + prayoga: self.prayoga, artha: self.artha, require: self.require.clone(), }) diff --git a/vidyut-prakriya/src/ashtadhyayi.rs b/vidyut-prakriya/src/ashtadhyayi.rs index ef2f98b..2587505 100644 --- a/vidyut-prakriya/src/ashtadhyayi.rs +++ b/vidyut-prakriya/src/ashtadhyayi.rs @@ -249,7 +249,8 @@ fn prepare_krdanta(p: &mut Prakriya, args: &Krdanta) -> Result<()> { } if let Some(la) = args.lakara() { - p.add_tag(PT::Kartari); + let prayoga = args.prayoga().unwrap_or(Prayoga::Kartari); + p.add_tag(prayoga.as_tag()); add_lakara_and_decide_pada(p, la); } diff --git a/vidyut-prakriya/src/krt/basic.rs b/vidyut-prakriya/src/krt/basic.rs index 71c4d23..deb4eed 100644 --- a/vidyut-prakriya/src/krt/basic.rs +++ b/vidyut-prakriya/src/krt/basic.rs @@ -106,7 +106,7 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { // // That said, there are some minor exceptions here and there where multiple pratyayas can apply. kp.with_context(TacchilaTaddharmaTatsadhukara, |kp| { - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); let i_dhatu = kp.i_dhatu; let has_prefix_and_text = |x, y| kp.has_upapada(x) && dhatu.has_text(y); @@ -167,7 +167,7 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { } // Break the `if` chain so that pari-kzip and pari-raw can match again here. - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); let has_prefix_and_text = |x, y| kp.has_upapada(x) && dhatu.has_text(y); let has_upasarga_and_text = |x, y| kp.has_upasarga(x) && dhatu.has_text(y); if dhatu.has_text_in(&["nind", "hins", "kliS", "KAd"]) @@ -220,8 +220,8 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { // SarAru, vandAru kp.try_add("3.2.173", Aru); } else if dhatu.has_text("BI") { - if kp.expects_krt(kruka) { - kp.try_add(Varttika("3.2.174.1"), kruka); + if kp.expects_krt(krukan) { + kp.try_add(Varttika("3.2.174.1"), krukan); } else if kp.expects_krt(kru) { kp.try_add("3.2.174", kru); } else { @@ -246,7 +246,7 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { }); kp.with_context(Bhava, |kp| { - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); let i_dhatu = kp.i_dhatu; if dhatu.has_text_in(&["pad", "ruj", "viS", "spfS"]) { // pAda, roga, veSa, sparSa @@ -313,20 +313,16 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { if kp.has_upasarga(U::ud) { // udgrAha kp.try_add("3.3.35", GaY); - } - if kp.has_upasarga(U::sam) { + } else if kp.has_upasarga(U::sam) { // saNgrAha kp.try_artha_add("3.3.36", GaY); - } - if kp.has_upasarga_in(&[U::ava, U::ni]) { + } else if kp.has_upasarga_in(&[U::ava, U::ni]) { // avagrAha, nigrAha kp.try_artha_add("3.3.45", GaY); - } - if kp.has_upasarga(U::pra) { + } else if kp.has_upasarga(U::pra) { // pragrAha kp.try_artha_add("3.3.46", GaY); - } - if kp.has_upasarga(U::pari) { + } else if kp.has_upasarga(U::pari) { // parigrAha kp.try_artha_add("3.3.47", GaY); } @@ -354,13 +350,12 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { } // TODO: vibhasha - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); if kp.had_match { } else if dhatu.has_u("graha~^") { if kp.has_upasarga(U::ava) { kp.try_artha_add("3.3.51", GaY); - } - if kp.has_upasarga(U::pra) { + } else if kp.has_upasarga(U::pra) { kp.try_artha_add("3.3.52", GaY); kp.try_artha_add("3.3.53", GaY); } @@ -372,7 +367,7 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { kp.optional_try_add("3.3.55", GaY); } - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); if kp.had_match { // Skip. } else if dhatu.has_u_in(&["graha~^", "vfY", "df", "ga\\mx~"]) @@ -431,7 +426,7 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { } // Base cases - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); if kp.had_match { } else if dhatu.has_antya(II) { // caya, ... @@ -445,7 +440,7 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { }); let i_dhatu = kp.i_dhatu; - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); let is_han = dhatu.is_u(Au::hana); kp.with_context(Murti, |kp| { if is_han { @@ -459,7 +454,7 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { }); kp.with_context(Samjna, |kp| { - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); if kp.has_upasarga(U::ava) && dhatu.has_u_in(&["tF", "stFY"]) { kp.try_add("3.3.120", GaY); } else if dhatu.has_u("Kanu~^") { @@ -471,7 +466,7 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { } // Base case - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); if dhatu.has_antya(HAL) { kp.try_add("3.3.121", GaY); } @@ -479,7 +474,7 @@ fn try_add_various_pratyayas(kp: &mut KrtPrakriya) { } fn is_nandi_grahi_pacadi(kp: &KrtPrakriya) -> bool { - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); // TODO: add the others. const NAND_ADI: &[&str] = &["nand", "jalp", "ram", "dfp"]; @@ -512,7 +507,7 @@ fn is_nandi_grahi_pacadi(kp: &KrtPrakriya) -> bool { dhatu.has_text_in(NAND_ADI) || dhatu.has_text_in(PAC_ADI) } -fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { +fn try_add_upapada_krt(kp: &mut KrtPrakriya) -> Option { use BaseKrt::*; const DIVA_ADI: &[&str] = &[ @@ -524,24 +519,21 @@ fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { "AQya", "suBaga", "sTUla", "palita", "nagna", "anDa", "priya", ]; - // For convenience below, wrap `Prakriya` in a new `KrtPrakriya` type that contains `krt` and - // records whether or not any of these rules were applied. - let mut kp = KrtPrakriya::new(p, krt); - try_add_various_pratyayas(&mut kp); - let i_dhatu = kp.p.find_first_where(|t| t.is_dhatu())?; - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); let upapada = match kp.p.get_if(0, |t| t.has_tag(T::Pratipadika)) { Some(t) => t, None => &EMPTY_TERM, }; + let upapade = kp.p.has(0, |t| t.has_tag(T::Pratipadika)); let nau = kp.p.has(i_dhatu + 1, |t| t.is(S::Ric)); let upasarge = kp.p.has_prev_non_empty(i_dhatu, |t| t.is_upasarga()); + let krt = kp.krt; match krt { - aR | ka | ac | wa | wak => { + aR | ka | ac | wa | wak if upapade => { if upapada.has_text_in(&["kzema", "priya", "madre"]) && dhatu.is_u(Au::qukfY) { // Also repeated for khac below. kp.try_add("3.2.44", aR); @@ -646,7 +638,7 @@ fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { } } - in_ => { + in_ if upapade => { if upapada.has_text_in(&["stamba", "Sakft"]) && dhatu.is_u(Au::qukfY) { kp.try_add("3.2.24", krt); } else if dhatu.has_u("hf\\Y") { @@ -664,7 +656,7 @@ fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { kp.do_nipatana("3.2.26", sub); } } - KaS => { + KaS if upapade => { let nasika = upapada.has_text("nAsikA"); let stana = upapada.has_text("stana"); let dhma = dhatu.has_u("DmA\\"); @@ -711,7 +703,7 @@ fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { } } - Kac => { + Kac if upapade => { if upapada.has_text_in(&["priya", "vaSa"]) && dhatu.has_u("vada~") { kp.try_add("3.2.38", krt); } else if upapada.has_text_in(&["dvizat", "para"]) && dhatu.has_text("tAp") && nau { @@ -737,7 +729,7 @@ fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { } } - qa => { + qa if upapade => { if dhatu.has_u("ga\\mx~") { if upapada.has_text_in(&[ "anta", "atyanta", "aDvan", "dUra", "pAra", "sarva", "ananta", @@ -756,7 +748,7 @@ fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { } } - Rini => { + Rini if upapade => { if upapada.has_text_in(&["kumAra", "Sirza"]) && dhatu.is_u(Au::hana) { kp.try_add("3.2.51", krt); } else if upapada.has_text("vrata") { @@ -772,13 +764,13 @@ fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { } } - Kyun => { + Kyun if upapade => { if upapada.has_text_in(ADHYA_ADI) && dhatu.is_u(Au::qukfY) { kp.try_add("3.2.56", krt); } } - KizRuc | KukaY => { + KizRuc | KukaY if upapade => { if upapada.has_text_in(ADHYA_ADI) && dhatu.has_u("BU") { kp.try_add("3.2.57", krt); } @@ -817,7 +809,7 @@ fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { } } - viw => { + viw if upapade => { if dhatu.has_u_in(&["janI~\\", "zaRu~^", "Kanu~^", "kramu~", "ga\\mx~"]) { // abjAH, ... kp.try_add("3.2.67", krt); @@ -879,7 +871,7 @@ fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { } if kp.has_krt && krt == kvip { - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); if dhatu.has_text("Sri") { // SrI // TODO: others @@ -918,30 +910,33 @@ fn try_add_upapada_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { /// ("a") if their it letters are removed, and therefore the *ap* rule will block the *ghañ* rule. /// /// For details, see: -fn try_add_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { +fn try_add_krt(kp: &mut KrtPrakriya) -> Option { use BaseKrt as K; - let i = p.find_last_with_tag(T::Dhatu)?; + let i_start = kp.p.find_first_with_tag(T::Dhatu)?; + let i_end = kp.p.find_last_with_tag(T::Dhatu)?; // Pre-calculate some common properties. - let upasarge = i > 1 && p.has(i - 2, |t| t.is_upasarga()); - let supi = i > 0 && p.has(i - 1, |t| t.is_sup()); + let i_upasarga = kp.p.find_prev_where(i_start, |t| t.is_upasarga()); + let upasarge = i_upasarga.is_some(); + let nau = kp.p.has(i_end, |t| t.is_nic()); + let supi = i_end > 0 && kp.p.has(i_end - 1, |t| t.is_sup()); // For convenience below, wrap `Prakriya` in a new `KrtPrakriya` type that contains `krt` and // records whether or not any of these rules were applied. - let mut kp = KrtPrakriya::new(p, krt); - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); let i_dhatu = kp.i_dhatu; + let krt = kp.krt; match krt { // ------------------------------------------ // krtyAH // ------------------------------------------ K::tavyat | K::tavya | K::anIyar => { let added = kp.try_add("3.1.96", krt); - if added && krt == K::tavyat && kp.dhatu().has_u("va\\sa~") { + if added && krt == K::tavyat && kp.dhatu_start().has_u("va\\sa~") { // vAstavya - kp.p.optional_run_at(Varttika("3.1.96.1"), i + 1, |t| t.add_tag(T::Rit)); + kp.p.optional_run_at(Varttika("3.1.96.1"), i_end + 1, |t| t.add_tag(T::Rit)); } } @@ -962,7 +957,7 @@ fn try_add_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { let mut skip_3_1_110 = false; // Specific rules (optional) - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); if dhatu.has_u("fca~") { // ṛdupadhādapi ṛcerata eva nipātanāt ṇyat bhavati kp.try_add("7.3.66", K::Ryat); @@ -981,7 +976,7 @@ fn try_add_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { } // Specific rules (required) - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); let mut avashyaka_blocked = false; if dhatu.has_u_in(&["Sa\\kx~", "zaha~\\"]) { kp.try_add("3.1.99", K::yat); @@ -1016,7 +1011,7 @@ fn try_add_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { } // General rules (optional) - let dhatu = kp.dhatu(); + let dhatu = kp.dhatu_start(); if (dhatu.has_antya('u') || dhatu.has_antya('U')) && !avashyaka_blocked { kp.optional_try_add("3.1.125", K::Ryat); } else if dhatu.is_u(Au::hana) { @@ -1057,29 +1052,110 @@ fn try_add_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { // "a" (3.1.134 - ???) K::ac | K::Sa | K::ka | K::Ra => { // These are all bhvAdi dhAtus, so also check for `Bhvadi` to avoid other dhatus. - let pa_ghra = &["pA\\", "GrA\\", "DmA\\", "De\\w", "df\\Si~r"]; + const PA_GHRA: &[&str] = &["pA\\", "GrA\\", "DmA\\", "De\\w", "df\\Si~r"]; + const JVAL_ADI: &[&str] = &[ + "jvala~", + "cala~", + "jala~", + "wala~", + "wvala~", + "zWala~", + "hala~", + "Rala~", + "pala~", + "bala~", + "pula~", + "kula~", + "Sala~", + "hula~", + "patx~", + "kzala~", + "kvaTe~", + "paTe~", + "maTe~", + "wuvama~", + "Bramu~", + "kzara~", + "dvf\\", + "zaha~\\", + "ra\\mu~\\", + "za\\dx~", + "Sa\\dx~", + "kru\\Sa~", + "kuca~", + "buDa~", + "ru\\ha~", + "kasa~", + ]; + let dhatu = kp.dhatu_end(); - if upasarge && dhatu.has_u_in(pa_ghra) && dhatu.has_gana(Gana::Bhvadi) { + if !upasarge && dhatu.is_any_u(&[Au::qudAY, Au::quDAY]) { + // dada, daDa + // (if rejected: dAya, DAya by 3.1.141) + kp.optional_try_add("3.1.139", K::Sa); + } else if !upasarge && dhatu.has_u_in(JVAL_ADI) { + // jvAla, cAla + kp.optional_try_add("3.1.140", K::Ra); + } else if dhatu.has_u("graha~^") { + kp.optional_try_add("3.1.143", K::Ra); + kp.optional_try_add("3.1.144", K::ka); + } + + let dhatu = kp.dhatu_end(); + let dhatu_start = kp.dhatu_start(); + if dhatu.has_u("tanu~^") { + // avatAna + kp.try_add(Varttika("3.1.140.1"), K::Ra); + } else if upasarge && dhatu.has_u_in(PA_GHRA) && dhatu.has_gana(Gana::Bhvadi) { kp.try_add("3.1.137", K::Sa); - } else if dhatu.has_u_in(&["li\\pa~^", "vi\\dx~^", "pF", "cita~", "sAti", "zaha~\\"]) - || dhatu.is_u(Au::vida_2) + } else if (!upasarge && dhatu.has_u_in(&["li\\pa~^", "vi\\dx~^"])) + || (!upasarge + && dhatu_start.has_u_in(&["Df\\Y", "pF", "vida~", "cita~", "zaha~\\"]) + && nau) + || (kp.has_upasarga(U::ud) && dhatu_start.has_u(&"ejf~\\") && nau) + || (!upasarge && dhatu.has_u("sAti")) { + // limpa, vinda, DAraya, pAraya, vedaya, udejaya, cetaya, sAtaya, sAhaya kp.try_add("3.1.138", K::Sa); - } else if dhatu.has_upadha(IK) || dhatu.has_u_in(&["JYA\\", "prI\\Y", "kF"]) { - // vikzipa, viliKa, buDa - kp.try_add("3.1.135", K::ka); } else if upasarge && dhatu.has_antya('A') { + // prasTa, sugla, sumla kp.try_add("3.1.136", K::ka); + } else if dhatu.has_u_in(&["jYA\\", "prI\\Y", "kF"]) { + // Part 1 of 2 (jYa, ...) + kp.try_add("3.1.135", K::ka); + } else if dhatu.has_u_in(&["SyE\\N", "vya\\Da~", "li\\ha~^", "Sli\\za~", "Svasa~"]) + || (kp.has_upasarga_in(&[U::AN, U::sam]) && dhatu.has_u("sru\\")) + || (kp.has_upasarga(U::ati) && dhatu.has_u("i\\R")) + || (kp.has_upasarga(U::ava) && dhatu.has_u("zo\\")) + || (kp.has_upasarga(U::ava) && dhatu.has_u("hf\\Y")) + || dhatu.has_antya('A') + { + // avaSyAya, pratiSyAya, ... + kp.try_add("3.1.141", K::Ra); + } else if dhatu.has_upadha(IK) { + // Part 2 of 2 (vikzipa, viliKa, buDa) + kp.try_add("3.1.135", K::ka); + } else if dhatu.has_u_in(&["wudu\\", "RI\\Y"]) && !upasarge { + kp.try_add("3.1.142", K::Ra); } else if krt == K::ac { // ajvidhiḥ sarvadhātubhyaḥ paṭhyante ca pacādayaḥ। aṇbādhanārtham eva // syāt sidhyanti śvapacādayaḥ। kp.try_add(Rule::Kashika("3.1.134"), K::ac); - } else if dhatu.has_u_in(&["wudu\\", "RI\\Y"]) && !upasarge { - kp.try_add("3.1.142", K::Ra); - } else if dhatu.has_u("graha~^") { - kp.optional_try_add("3.1.143", K::aR); - kp.optional_try_add("3.1.144", K::ka); + } + + let dhatu = kp.dhatu_start(); + if krt == K::Sa { + if dhatu.has_u("qukf\\Y") { + // kriyA + kp.try_add_with("3.3.100", krt, |p| { + p.add_tag(PT::Stri); + p.add_tag(PT::Bhave); + }); + } else if dhatu.has_u("izu~") { + // icCA + kp.do_nipatana("3.3.101", "icCA"); + } } } @@ -1136,7 +1212,7 @@ fn try_add_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { K::Rvi => { if dhatu.has_u("Ba\\ja~^") { kp.try_add("3.2.62", krt); - } else if i > 0 && dhatu.has_u("va\\ha~^") { + } else if i_end > 0 && dhatu.has_u("va\\ha~^") { kp.try_add("3.2.64", krt); } } @@ -1233,6 +1309,7 @@ fn try_add_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { let i_la = kp.p.terms().len() - 1; kp.try_replace_lakara("3.2.128", i_la, krt); kp.p.add_tag_at("3.2.127", i_la, T::Sat); + // TODO: 3.3.14 } } @@ -1301,7 +1378,7 @@ fn try_add_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { kp.p.run("4.4.20", |p| { p.push(Taddhita::map.into()); }); - it_samjna::run(kp.p, i + 2).expect("should never fail"); + it_samjna::run(kp.p, i_end + 2).expect("should never fail"); } } } @@ -1332,7 +1409,7 @@ fn try_add_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { } K::a => { - if kp.p.has(i, |t| t.is_pratyaya()) { + if kp.p.has(i_end, |t| t.is_pratyaya()) { kp.try_add_with("3.3.102", krt, |p| p.add_tag(PT::Stri)); } else if dhatu.is_guru() && dhatu.has_antya(HAL) { kp.try_add_with("3.3.103", krt, |p| p.add_tag(PT::Stri)); @@ -1398,10 +1475,14 @@ fn try_add_krt(p: &mut Prakriya, krt: BaseKrt) -> Option { /// Runs the rules that add a krt-pratyaya to a given dhatu. Returns whether a pratyaya was added. pub fn run(p: &mut Prakriya, krt: Krt) -> bool { if let Krt::Base(base) = krt { - if try_add_upapada_krt(p, base).unwrap_or(false) { + let mut kp = KrtPrakriya::new(p, base); + try_add_various_pratyayas(&mut kp); + if try_add_upapada_krt(&mut kp).unwrap_or(false) { return true; } - try_add_krt(p, base).unwrap_or(false) + + let mut kp = KrtPrakriya::new(p, base); + try_add_krt(&mut kp).unwrap_or(false) } else { false } diff --git a/vidyut-prakriya/src/krt/utils.rs b/vidyut-prakriya/src/krt/utils.rs index fb076ae..a78c753 100644 --- a/vidyut-prakriya/src/krt/utils.rs +++ b/vidyut-prakriya/src/krt/utils.rs @@ -33,6 +33,7 @@ impl Krt { /// - remembers which `krt` pratyaya the caller wishes to add, which simplifies the calling API. /// - records whether a `krt` pratyaya has been added or not, which simplifies the control flow for /// optional rules. +#[derive(Debug)] pub(crate) struct KrtPrakriya<'a> { /// The underlying prakriya. pub p: &'a mut Prakriya, @@ -60,7 +61,7 @@ impl<'a> KrtPrakriya<'a> { } /// Returns a reference to the underlying dhatu for this prakriya. - pub fn dhatu(&self) -> &Term { + pub fn dhatu_start(&self) -> &Term { self.p.get(self.i_dhatu).expect("present") } diff --git a/vidyut-prakriya/src/wasm.rs b/vidyut-prakriya/src/wasm.rs index f628109..db2d058 100644 --- a/vidyut-prakriya/src/wasm.rs +++ b/vidyut-prakriya/src/wasm.rs @@ -146,6 +146,8 @@ struct KrdantaArgs { krt: BaseKrt, sanadi: Vec, upasarga: Vec, + lakara: Option, + prayoga: Option, } #[derive(Serialize, Deserialize)] @@ -175,11 +177,15 @@ impl TinantaArgs { impl KrdantaArgs { fn into_rust(self, raw_dhatu: &Dhatu) -> Krdanta { let dhatu = try_expand_dhatu(raw_dhatu, &self.sanadi, &self.upasarga); - Krdanta::builder() - .dhatu(dhatu) - .krt(self.krt) - .build() - .expect("should be well-formed") + let mut builder = Krdanta::builder().dhatu(dhatu).krt(self.krt); + if let Some(la) = self.lakara { + builder = builder.lakara(la); + } + if let Some(prayoga) = self.prayoga { + builder = builder.prayoga(prayoga); + } + + builder.build().expect("should be well-formed") } } diff --git a/vidyut-prakriya/test_utils/src/lib.rs b/vidyut-prakriya/test_utils/src/lib.rs index 7f2ea2d..3d68843 100644 --- a/vidyut-prakriya/test_utils/src/lib.rs +++ b/vidyut-prakriya/test_utils/src/lib.rs @@ -70,17 +70,17 @@ impl Tester { } /// Derives subantas from the given conditions. - fn derive_subantas(&self, args: &Subanta) -> Vec { + pub fn derive_subantas(&self, args: &Subanta) -> Vec { self.vyakarana.derive_subantas(args) } /// Derives krdantas from the given conditions. - fn derive_krdantas(&self, args: &Krdanta) -> Vec { + pub fn derive_krdantas(&self, args: &Krdanta) -> Vec { self.vyakarana.derive_krdantas(args) } /// Derives taddhitantas from the given conditions. - fn derive_taddhitantas(&self, args: &Taddhitanta) -> Vec { + pub fn derive_taddhitantas(&self, args: &Taddhitanta) -> Vec { self.vyakarana.derive_taddhitantas(args) } diff --git a/vidyut-prakriya/tests/integration/kashika_3_1.rs b/vidyut-prakriya/tests/integration/kashika_3_1.rs index 8ca2474..bea548f 100644 --- a/vidyut-prakriya/tests/integration/kashika_3_1.rs +++ b/vidyut-prakriya/tests/integration/kashika_3_1.rs @@ -1197,34 +1197,90 @@ fn sutra_3_1_137() { assert_has_krdanta(&["vi"], &dfs, Krt::Sa, &["vipaSya"]); } -#[ignore] #[test] fn sutra_3_1_138() { - assert_has_krdanta(&[], &d("li\\pa~^", Tudadi), Krt::Sa, &["limpa"]); + let lip = d("li\\pa~^", Tudadi); + assert_has_krdanta(&[], &lip, Krt::Sa, &["limpa"]); assert_has_krdanta(&[], &d("vi\\dx~^", Tudadi), Krt::Sa, &["vinda"]); - assert_has_krdanta(&[], &d("", Bhvadi), Krt::Sa, &["DAraya"]); + assert_has_krdanta(&[], &nic(&d("Df\\Y", Bhvadi)), Krt::Sa, &["DAraya"]); assert_has_krdanta(&[], &d("pF", Curadi), Krt::Sa, &["pAraya"]); - assert_has_krdanta(&[], &d("vida~", Bhvadi), Krt::Sa, &["vedaya"]); - assert_has_krdanta(&["ud"], &d("ejf~\\", Bhvadi), Krt::Sa, &["udejaya"]); + assert_has_krdanta(&[], &nic(&d("vida~", Bhvadi)), Krt::Sa, &["vedaya"]); + assert_has_krdanta(&["ud"], &nic(&d("ejf~\\", Bhvadi)), Krt::Sa, &["udejaya"]); assert_has_krdanta(&[], &d("cita~", Curadi), Krt::Sa, &["cetaya"]); assert_has_krdanta(&[], &d("sAti", Bhvadi), Krt::Sa, &["sAtaya"]); - assert_has_krdanta(&[], &d("zaha~\\", Bhvadi), Krt::Sa, &["sAhaya"]); + assert_has_krdanta(&[], &nic(&d("zaha~\\", Bhvadi)), Krt::Sa, &["sAhaya"]); + + // anupasargAt? + assert_has_krdanta(&["pra"], &lip, Krt::Sa, &[]); + assert_has_krdanta(&["pra"], &lip, Krt::ka, &["pralipa"]); +} + +#[test] +fn sutra_3_1_139() { + let da = d("qudA\\Y", Juhotyadi); + let dha = d("quDA\\Y", Juhotyadi); + assert_has_krdanta(&[], &da, Krt::Sa, &["dada"]); + assert_has_krdanta(&[], &da, Krt::Ra, &["dAya"]); + assert_has_krdanta(&[], &dha, Krt::Sa, &["daDa"]); + assert_has_krdanta(&[], &dha, Krt::Ra, &["DAya"]); + + assert_has_krdanta(&["pra"], &da, Krt::Sa, &[]); + assert_has_krdanta(&["pra"], &dha, Krt::Sa, &[]); + assert_has_krdanta(&["pra"], &da, Krt::ka, &["prada"]); + assert_has_krdanta(&["pra"], &dha, Krt::ka, &["praDa"]); +} + +#[test] +fn sutra_3_1_140() { + assert_has_krdanta(&[], &d("jvala~", Bhvadi), Krt::Ra, &["jvAla"]); + assert_has_krdanta(&[], &d("jvala~", Bhvadi), Krt::ac, &["jvala"]); + assert_has_krdanta(&[], &d("cala~", Bhvadi), Krt::Ra, &["cAla"]); + assert_has_krdanta(&[], &d("cala~", Bhvadi), Krt::ac, &["cala"]); + + // anupasargAt? + assert_has_krdanta(&["pra"], &d("jvala~", Bhvadi), Krt::Ra, &[]); + assert_has_krdanta(&["pra"], &d("jvala~", Bhvadi), Krt::ac, &["prajvala"]); +} + +#[test] +fn sutra_3_1_140_v1() { + assert_has_krdanta(&["ava"], &d("tanu~^", Tanadi), Krt::Ra, &["avatAna"]); + assert_has_krdanta(&["ava"], &d("tanu~^", Tanadi), Krt::ac, &[]); +} + +#[test] +fn sutra_3_1_141() { + assert_has_krdanta(&["ava"], &d("SyE\\N", Bhvadi), Krt::Ra, &["avaSyAya"]); + assert_has_krdanta(&["prati"], &d("SyE\\N", Bhvadi), Krt::Ra, &["pratiSyAya"]); + assert_has_krdanta(&[], &d("qudA\\Y", Juhotyadi), Krt::Ra, &["dAya"]); + assert_has_krdanta(&[], &d("quDA\\Y", Juhotyadi), Krt::Ra, &["DAya"]); + assert_has_krdanta(&[], &d("vya\\Da~", Divadi), Krt::Ra, &["vyADa"]); + assert_has_krdanta(&["AN"], &d("sru\\", Bhvadi), Krt::Ra, &["AsrAva"]); + assert_has_krdanta(&["sam"], &d("sru\\", Bhvadi), Krt::Ra, &["saMsrAva"]); + assert_has_krdanta(&["ati"], &d("i\\R", Adadi), Krt::Ra, &["atyAya"]); + assert_has_krdanta(&["ava"], &d("zo\\", Divadi), Krt::Ra, &["avasAya"]); + assert_has_krdanta(&["ava"], &d("hf\\Y", Bhvadi), Krt::Ra, &["avahAra"]); + assert_has_krdanta(&[], &d("li\\ha~^", Adadi), Krt::Ra, &["leha"]); + assert_has_krdanta(&[], &d("Sli\\za~", Divadi), Krt::Ra, &["Sleza"]); + assert_has_krdanta(&[], &d("Svasa~", Adadi), Krt::Ra, &["SvAsa"]); } #[test] fn sutra_3_1_142() { assert_has_krdanta(&[], &d("wudu\\", Svadi), Krt::Ra, &["dAva"]); assert_has_krdanta(&[], &d("RI\\Y", Bhvadi), Krt::Ra, &["nAya"]); - // anupasarge + + // anupasarge? assert_has_krdanta(&["pra"], &d("wudu\\", Svadi), Krt::Ra, &[]); + assert_has_krdanta(&["pra"], &d("wudu\\", Svadi), Krt::ac, &["pradava"]); assert_has_krdanta(&["pra"], &d("RI\\Y", Bhvadi), Krt::Ra, &[]); - // TODO: others + assert_has_krdanta(&["pra"], &d("RI\\Y", Bhvadi), Krt::ac, &["praRaya"]); } #[test] fn sutra_3_1_143() { let grah = d("graha~^", Kryadi); - assert_has_krdanta(&[], &grah, Krt::aR, &["grAha"]); + assert_has_krdanta(&[], &grah, Krt::Ra, &["grAha"]); assert_has_krdanta(&[], &grah, Krt::ac, &["graha"]); } diff --git a/vidyut-prakriya/tests/integration/kashika_3_2.rs b/vidyut-prakriya/tests/integration/kashika_3_2.rs index 595245a..f6ce650 100644 --- a/vidyut-prakriya/tests/integration/kashika_3_2.rs +++ b/vidyut-prakriya/tests/integration/kashika_3_2.rs @@ -1282,7 +1282,7 @@ fn sutra_3_2_174() { #[test] fn sutra_3_2_174_v1() { let bhi = d("YiBI\\", Juhotyadi); - assert_has_krdanta(&[], &bhi, Krt::kruka, &["BIruka"]); + assert_has_krdanta(&[], &bhi, Krt::krukan, &["BIruka"]); } #[ignore] diff --git a/vidyut-prakriya/tests/integration/kashika_3_3.rs b/vidyut-prakriya/tests/integration/kashika_3_3.rs index dd40580..4cb11b0 100644 --- a/vidyut-prakriya/tests/integration/kashika_3_3.rs +++ b/vidyut-prakriya/tests/integration/kashika_3_3.rs @@ -426,7 +426,7 @@ fn sutra_3_3_59() { fn sutra_3_3_60() { let ad = d("a\\da~", Adadi); assert_has_bhave_krdanta(&["ni"], &ad, Krt::ap, &["niGasa"]); - assert_has_bhave_krdanta(&["ni"], &ad, Krt::aR, &["nyAda"]); + assert_has_bhave_krdanta(&["ni"], &ad, Krt::Ra, &["nyAda"]); } #[test] @@ -619,6 +619,20 @@ fn sutra_3_3_94() { // TODO: others } +#[ignore] +#[test] +fn sutra_3_3_100() { + let kr = d("qukf\\Y", Tanadi); + assert_has_krdanta(&[], &kr, Krt::Sa, &["kriyA"]); + assert_has_krdanta(&[], &kr, Krt::kyap, &["kftyA"]); + assert_has_krdanta(&[], &kr, Krt::ktin, &["kfti"]); +} + +#[test] +fn sutra_3_3_101() { + assert_has_krdanta(&[], &d("izu~", Tudadi), Krt::Sa, &["icCA"]); +} + #[test] fn sutra_3_3_102() { assert_has_krdanta(&[], &san(&d("qukf\\Y", Tanadi)), Krt::a, &["cikIrzA"]); diff --git a/vidyut-prakriya/tests/integration/prakriyas.rs b/vidyut-prakriya/tests/integration/prakriyas.rs index b64a723..eb738d4 100644 --- a/vidyut-prakriya/tests/integration/prakriyas.rs +++ b/vidyut-prakriya/tests/integration/prakriyas.rs @@ -3,6 +3,7 @@ //! TODO: add tests from the पाणिनीयव्याकरणोदाहरणकोषः extern crate test_utils; use test_utils::*; +use vidyut_prakriya::args::BaseKrt as K; use vidyut_prakriya::args::Gana::*; use vidyut_prakriya::args::Lakara::*; use vidyut_prakriya::args::*; @@ -19,6 +20,21 @@ fn tip_args(dhatu: Dhatu, la: Lakara) -> Tinanta { .unwrap() } +fn subanta( + pratipadika: impl Into, + linga: Linga, + vibhakti: Vibhakti, + vacana: Vacana, +) -> Subanta { + Subanta::builder() + .pratipadika(pratipadika.into()) + .linga(linga) + .vibhakti(vibhakti) + .vacana(vacana) + .build() + .unwrap() +} + // Sample test for `Bavati`. #[test] fn bhavati() { @@ -201,3 +217,21 @@ fn nlp_mode() { t.assert_has_tas(&[], &d("BU", Bhvadi), Lat, &["Bavatas"]); t.assert_has_sup_1s("dvAr", Linga::Pum, &["dvAr"]); } + +// Fixes a bug reported by Neelesh B. +#[test] +fn edha() { + use Rule::Ashtadhyayi as A; + + let args = subanta( + krdanta(&[], &d("eDa~\\", Tanadi), K::GaY), + Linga::Stri, + Vibhakti::Prathama, + Vacana::Eka, + ); + let t = Tester::default(); + let ps = t.derive_subantas(&args); + + let p = ps.iter().find(|p| p.text() == "eDA").unwrap(); + assert_matches_prakriya(p, &[(A("6.1.101"), vec!["eD", "A", "", ""])]); +} diff --git a/vidyut-prakriya/tests/integration/regressions.rs b/vidyut-prakriya/tests/integration/regressions.rs index e82dd3a..7e4648a 100644 --- a/vidyut-prakriya/tests/integration/regressions.rs +++ b/vidyut-prakriya/tests/integration/regressions.rs @@ -4,11 +4,12 @@ //! has been fixed and help ensure that the bug does not reappear. extern crate test_utils; use test_utils::*; -use vidyut_prakriya::args::BaseKrt as Krt; use vidyut_prakriya::args::Gana::*; use vidyut_prakriya::args::Krdanta; use vidyut_prakriya::args::Lakara::*; use vidyut_prakriya::args::Linga::*; +use vidyut_prakriya::args::{BaseKrt as Krt, Dhatu, Lakara, Prayoga}; +use vidyut_prakriya::Vyakarana; #[test] fn ambibat() { @@ -213,3 +214,44 @@ fn pampanyamanan() { assert_has_sup_1s(&krt, Pum, &["pampaRyamAnaH"]); assert_has_sup_1d(&krt, Pum, &["pampaRyamAnO"]); } + +#[test] +fn kr_sat() { + use Prayoga::*; + + fn assert_has_sat( + dhatu: &Dhatu, + krt: Krt, + lakara: Lakara, + prayoga: Prayoga, + expected: &[&str], + ) { + let v = Vyakarana::new(); + let args = Krdanta::builder() + .lakara(Lrt) + .dhatu(dhatu.clone()) + .lakara(lakara) + .prayoga(prayoga) + .krt(krt) + .build() + .unwrap(); + let prakriyas = v.derive_krdantas(&args); + assert_has_results(prakriyas, expected) + } + + let kr = d("qukf\\Y", Tanadi); + assert_has_sat(&kr, Krt::Satf, Lat, Kartari, &["kurvat"]); + assert_has_sat(&kr, Krt::SAnac, Lat, Kartari, &["kurvARa"]); + assert_has_sat(&kr, Krt::Satf, Lat, Karmani, &[]); + assert_has_sat(&kr, Krt::SAnac, Lat, Karmani, &["kriyamARa"]); + assert_has_sat(&kr, Krt::Satf, Lrt, Kartari, &["karizyat"]); + assert_has_sat(&kr, Krt::SAnac, Lrt, Kartari, &["karizyamARa"]); + assert_has_sat(&kr, Krt::Satf, Lrt, Karmani, &[]); + assert_has_sat( + &kr, + Krt::SAnac, + Lrt, + Karmani, + &["karizyamARa", "kArizyamARa"], + ); +} diff --git a/vidyut-prakriya/www/static/vidyut-prakriya-app.js b/vidyut-prakriya/www/static/vidyut-prakriya-app.js index 03cf0bf..b6332e3 100644 --- a/vidyut-prakriya/www/static/vidyut-prakriya-app.js +++ b/vidyut-prakriya/www/static/vidyut-prakriya-app.js @@ -117,14 +117,19 @@ class Vidyut { * krt: a `Krt` * sanadi: a list of strings. Valid values are "san", "Ric", "yaN", and "yaNluk". * upasargas: a list of strings. For the upasarga "A", pass "AN". + * + * lakara: (for Satf and SAnac only) the lakAra to use. + * prayoga: (for Satf and SAnac only) the prayoga to use. */ - deriveKrdantas({ dhatu, krt, sanadi = [], upasarga = [] }) { + deriveKrdantas({ dhatu, krt, sanadi = [], upasarga = [], lakara = null, prayoga = null }) { // For argument order, see wasm.rs. return this.wasm.deriveKrdantas({ code: dhatu.code, krt: BaseKrt[krt], sanadi, upasarga, + lakara: lakara ? Lakara[lakara] : null, + prayoga: prayoga ? Prayoga[prayoga] : null, }) } } @@ -764,6 +769,25 @@ const App = () => ({ }); }); + // Expansion for Satf/SAnac. + if (krt == BaseKrt.Satf || krt == BaseKrt.SAnac) { + let allArgs = [ + { ...args, prayoga: Prayoga.Karmani, lakara: Lakara.Lat }, + { ...args, prayoga: Prayoga.Kartari, lakara: Lakara.Lrt }, + { ...args, prayoga: Prayoga.Karmani, lakara: Lakara.Lrt }, + ]; + allArgs.forEach((args) => { + const prakriyas = this.vidyut.deriveKrdantas(args) + prakriyas.forEach((p) => { + padas.push({ + text: p.text, + type: "krdanta", + args + }); + }); + }); + } + if (padas.length !== 0) { ret.push({ title: BaseKrt[krt],