diff --git a/vidyut-prakriya/src/angasya/abhyasasya.rs b/vidyut-prakriya/src/angasya/abhyasasya.rs index 59531b8..d606a7c 100644 --- a/vidyut-prakriya/src/angasya/abhyasasya.rs +++ b/vidyut-prakriya/src/angasya/abhyasasya.rs @@ -249,23 +249,59 @@ fn try_general_rules(p: &mut Prakriya, i: usize) -> Option<()> { p.run_at("7.4.68", i, op::text("viT")); } - let abhyasa = p.get(i)?; - if abhyasa.has_adi(SHAR) && abhyasa.has_at(1, KHAY) { - let abhyasa = &mut p.get_mut(i)?; - let res = try_shar_purva(&abhyasa.text); - if res != abhyasa.text { - abhyasa.text = res; - p.step("7.4.61"); + let mut abhyasa_has_changed = true; + let mut current_abhyasa_text; + + // The transformations prescribed in abhyasa angakarya + // seem to be designed to converge on repetition. This may be the + // vivakshA + while abhyasa_has_changed { + let abhyasa = p.get(i)?; + current_abhyasa_text = abhyasa.text.clone(); + + if abhyasa.has_adi(SHAR) && abhyasa.has_at(1, KHAY) { + let abhyasa = p.get_mut(i)?; + let res = try_shar_purva(&abhyasa.text); + if res != abhyasa.text { + abhyasa.text = res; + p.step("7.4.61"); + } + } else { + let abhyasa = p.get_mut(i)?; + let res = try_haladi(&abhyasa.text); + if res != abhyasa.text { + abhyasa.text = res; + p.step("7.4.60"); + } } - } else { - let abhyasa = &mut p.get_mut(i)?; - let res = try_haladi(&abhyasa.text); - if res != abhyasa.text { - abhyasa.text = res; - p.step("7.4.60"); + + if p.has(i, |t| t.has_antya('f') || t.has_antya('F')) { + p.run_at("7.4.66", i, op::antya("a")); + p.run_at("1.1.51", i, op::antya("ar")); + } + + // no-hrasva is for pA --> apIpyat. + let abhyasa = p.get(i)?; + if al::is_dirgha(abhyasa.antya()?) && !abhyasa.has_tag(T::FlagNoHrasva) { + let val = al::to_hrasva(abhyasa.antya()?)?; + p.run_at("7.4.59", i, op::antya_char(&val)); + } + + let dhatu = p.get(i_dhatu)?; + let last = p.terms().last()?; + if dhatu.has_u("i\\R") && last.has_tag(T::kit) && last.has_lakara(Lit) { + // IyatuH, IyuH + p.run_at("7.4.69", i, op::adi("I")); + } + + let abhyasa = p.get_mut(i)?; + if abhyasa.text == current_abhyasa_text { + abhyasa_has_changed = false; } } + // Keeping this outside the loop as this needs to be done only once + // after abhyasa has converged. let abhyasa = p.get(i)?; let dhatu = p.get(i_dhatu)?; if let Some(val) = KUH_CU @@ -279,25 +315,6 @@ fn try_general_rules(p: &mut Prakriya, i: usize) -> Option<()> { p.run_at("7.4.62", i, |t| t.set_adi_char(val)); } } - - // no-hrasva is for pA --> apIpyat. - let abhyasa = p.get(i)?; - if al::is_dirgha(abhyasa.antya()?) && !abhyasa.has_tag(T::FlagNoHrasva) { - let val = al::to_hrasva(abhyasa.antya()?)?; - p.run_at("7.4.59", i, op::antya_char(&val)); - } - - if p.has(i, |t| t.has_antya('f')) { - p.run_at("7.4.66", i, op::antya("a")); - } - - let dhatu = p.get(i_dhatu)?; - let last = p.terms().last()?; - if dhatu.has_u("i\\R") && last.has_tag(T::kit) && last.has_lakara(Lit) { - // IyatuH, IyuH - p.run_at("7.4.69", i, op::adi("I")); - } - Some(()) } diff --git a/vidyut-prakriya/tests/integration/kashika_7_4.rs b/vidyut-prakriya/tests/integration/kashika_7_4.rs index 199baeb..d158c29 100644 --- a/vidyut-prakriya/tests/integration/kashika_7_4.rs +++ b/vidyut-prakriya/tests/integration/kashika_7_4.rs @@ -694,7 +694,22 @@ fn sutra_7_4_66() { assert_has_lit(&[], &d("vftu~\\", Bhvadi), &["vavfte"]); assert_has_lit(&[], &d("vfDu~\\", Bhvadi), &["vavfDe"]); assert_has_lit(&[], &d("SfDu~\\", Bhvadi), &["SaSfDe"]); - // TODO: yaNluk examples. + + assert_has_lat( + &[], + &yan_luk(&d("nftI~", Divadi)), + &[ + "narInarti", + "narInartti", + "narInftIti", + "narinarti", + "narinartti", + "narinftIti", + "narnarti", + "narnartti", + "narnftIti", + ], + ); } #[test] diff --git a/vidyut-prakriya/tests/integration/prakriyas.rs b/vidyut-prakriya/tests/integration/prakriyas.rs index 5fad5ca..22f1162 100644 --- a/vidyut-prakriya/tests/integration/prakriyas.rs +++ b/vidyut-prakriya/tests/integration/prakriyas.rs @@ -235,3 +235,64 @@ fn edha() { let p = ps.iter().find(|p| p.text() == "eDA").unwrap(); assert_matches_prakriya(p, &[(A("6.1.101"), vec!["eD", "A", "", ""])]); } + +// Fixes https://github.com/ambuda-org/vidyut/issues/205 +// +// Tests validate that the prakriya has 7.4.66 immediately followed by 1.1.51 as "nitya" +// and that the resultant outputs are as expected for ऋकारान्त dhatus i.e. 'f' and 'F' +#[test] +#[allow(non_snake_case)] +fn cakAra_etc() { + use Rule::Ashtadhyayi as A; + + let args = tip_args(d("qukf\\Y", Tanadi), Lit); + let t = Tester::default(); + let ps = t.derive_tinantas(&args); + let p = ps.iter().find(|p| p.text() == "cakAra").unwrap(); + + assert_matches_prakriya( + p, + &[ + (A("7.2.115"), vec!["kf", "kAr", "a"]), + (A("7.4.66"), vec!["ka", "kAr", "a"]), + (A("1.1.51"), vec!["kar", "kAr", "a"]), + (A("7.4.60"), vec!["ka", "kAr", "a"]), + (A("7.4.62"), vec!["ca", "kAr", "a"]), + ], + ); + + // "f" is not in the end + let args = tip_args(d("kfpa~\\", Bhvadi), Lit); + let ps = t.derive_tinantas(&args); + let p = ps.iter().find(|p| p.text() == "cakxpe").unwrap(); + + assert_matches_prakriya( + p, + &[ + (A("1.1.5"), vec!["kfp", "kfp", "e"]), + (A("7.4.60"), vec!["kf", "kfp", "e"]), + (A("7.4.66"), vec!["ka", "kfp", "e"]), + (A("1.1.51"), vec!["kar", "kfp", "e"]), + (A("7.4.60"), vec!["ka", "kfp", "e"]), + (A("7.4.62"), vec!["ca", "kfp", "e"]), + (A("8.2.18"), vec!["ca", "kxp", "e"]), + ], + ); + + // Try with dhatu having "F" + let args = tip_args(d("stFY", Kryadi), Lit); + let ps = t.derive_tinantas(&args); + let p = ps.iter().find(|p| p.text() == "tastare").unwrap(); + assert_matches_prakriya( + p, + &[ + (A("1.1.5"), vec!["stF", "stF", "e"]), + (A("7.4.11"), vec!["stF", "star", "e"]), + (A("7.4.61"), vec!["tF", "star", "e"]), + (A("7.4.66"), vec!["ta", "star", "e"]), + (A("1.1.51"), vec!["tar", "star", "e"]), + (A("7.4.60"), vec!["ta", "star", "e"]), + (A("6.4.126"), vec!["ta", "star", "e"]), + ], + ); +} diff --git a/vidyut-prakriya/www/static/vidyut-prakriya-app.js b/vidyut-prakriya/www/static/vidyut-prakriya-app.js index ab28596..b144f4b 100644 --- a/vidyut-prakriya/www/static/vidyut-prakriya-app.js +++ b/vidyut-prakriya/www/static/vidyut-prakriya-app.js @@ -467,7 +467,7 @@ const App = () => ({ stepClasses(step) { const code = step.rule.code; - let minor = new Set(["1.3.1", "1.3.2", "1.3.3", "1.3.4", "1.3.5", "1.3.6", "1.3.7", "1.3.8", "1.3.9", "1.2.45", "3.4.114", "1.1.43", + let minor = new Set(["1.1.51", "1.3.1", "1.3.2", "1.3.3", "1.3.4", "1.3.5", "1.3.6", "1.3.7", "1.3.8", "1.3.9", "1.2.45", "3.4.114", "1.1.43", "1.4.58", "1.4.59", "1.4.60", "1.4.80", "6.1.4", "6.1.5", "8.4.68", "3.4.113", "2.3.48", "1.4.17", "2.3.49", "1.4.7", ]); let samjna = new Set (["1.2.46", "1.4.14", "3.1.32"]);