Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions rust/vedyut-cheda/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ repository.workspace = true
description = "Sanskrit text segmentation and morphological analysis"

[dependencies]
vedyut-lipi = { path = "../vedyut-lipi" }
vedyut-sandhi = { path = "../vedyut-sandhi" }
vedyut-kosha = { path = "../vedyut-kosha" }
vedyut-lipi = { path = "../vedyut-lipi", version = "0.1.0" }
vedyut-sandhi = { path = "../vedyut-sandhi", version = "0.1.0" }
vedyut-kosha = { path = "../vedyut-kosha", version = "0.1.0" }
serde = { workspace = true }
rustc-hash = { workspace = true }

Expand Down
12 changes: 6 additions & 6 deletions rust/vedyut-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ name = "vedyut_core"
crate-type = ["cdylib", "rlib"]

[dependencies]
vedyut-lipi = { path = "../vedyut-lipi" }
vedyut-sandhi = { path = "../vedyut-sandhi" }
vedyut-prakriya = { path = "../vedyut-prakriya" }
vedyut-kosha = { path = "../vedyut-kosha" }
vedyut-cheda = { path = "../vedyut-cheda" }
vedyut-sanskritify = { path = "../vedyut-sanskritify" }
vedyut-lipi = { path = "../vedyut-lipi", version = "0.1.0" }
vedyut-sandhi = { path = "../vedyut-sandhi", version = "0.1.0" }
vedyut-prakriya = { path = "../vedyut-prakriya", version = "0.1.0" }
vedyut-kosha = { path = "../vedyut-kosha", version = "0.1.0" }
vedyut-cheda = { path = "../vedyut-cheda", version = "0.1.0" }
vedyut-sanskritify = { path = "../vedyut-sanskritify", version = "0.1.0" }

# PyO3 for Python bindings
pyo3 = { workspace = true }
Expand Down
8 changes: 4 additions & 4 deletions rust/vedyut-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use vedyut_lipi::Scheme;

/// Python module for vedyut
#[pymodule]
fn _core(_py: Python, m: &PyModule) -> PyResult<()> {
fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
// Register classes and functions
m.add_class::<PyScheme>()?;
m.add_function(wrap_pyfunction!(py_transliterate, m)?)?;
Expand Down Expand Up @@ -136,7 +136,7 @@ fn py_analyze(word: &str, script: &str, py: Python) -> PyResult<Vec<PyObject>> {
})?;

if let Some(analysis) = vedyut_cheda::analyze_word(word) {
let dict = PyDict::new(py);
let dict = PyDict::new_bound(py);
dict.set_item("word", analysis.word)?;
dict.set_item("stem", analysis.stem)?;
dict.set_item("linga", analysis.linga)?;
Expand All @@ -158,8 +158,8 @@ mod tests {
fn test_module_creation() {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let module = PyModule::new(py, "_core").unwrap();
assert!(_core(py, module).is_ok());
let module = PyModule::new_bound(py, "_core").unwrap();
assert!(_core(&module).is_ok());
});
}
}
2 changes: 1 addition & 1 deletion rust/vedyut-kosha/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ repository.workspace = true
description = "High-performance lexicon for Sanskrit"

[dependencies]
vedyut-lipi = { path = "../vedyut-lipi" }
vedyut-lipi = { path = "../vedyut-lipi", version = "0.1.0" }
serde = { workspace = true }
serde_json = { workspace = true }
rustc-hash = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion rust/vedyut-prakriya/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ repository.workspace = true
description = "Paninian word generator for Sanskrit"

[dependencies]
vedyut-lipi = { path = "../vedyut-lipi" }
vedyut-lipi = { path = "../vedyut-lipi", version = "0.1.0" }
serde = { workspace = true }
serde_json = { workspace = true }
compact_str = { workspace = true }
Expand Down
226 changes: 226 additions & 0 deletions rust/vedyut-prakriya/src/ac_sandhi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
use crate::prakriya::Prakriya;
use crate::tag::Tag;

/// 6.1.101 akaḥ savarṇe dīrghaḥ
pub fn rule_6_1_101(p: &mut Prakriya) -> bool {
let mut changed = false;
let mut i = 0;
while i < p.terms.len().saturating_sub(1) {
let left = &p.terms[i];
let right = &p.terms[i + 1];

// Simplified check, normally would check Ac
let result = match (left.text.as_str(), right.text.as_str()) {
("a", "a") | ("a", "A") | ("A", "a") | ("A", "A") => Some("A"),
("i", "i") | ("i", "I") | ("I", "i") | ("I", "I") => Some("I"),
("u", "u") | ("u", "U") | ("U", "u") | ("U", "U") => Some("U"),
_ => None,
};

if let Some(res) = result {
p.terms[i].text = res.to_string();
p.terms[i].add_tag(Tag::Guna); // Technically Dirgha
p.terms.remove(i + 1);
p.add_rule("6.1.101 akaḥ savarṇe dīrghaḥ");
changed = true;
} else {
i += 1;
}
}
changed
}

/// 6.1.87 ādguṇaḥ
pub fn rule_6_1_87(p: &mut Prakriya) -> bool {
let mut changed = false;
let mut i = 0;
while i < p.terms.len().saturating_sub(1) {
let left_text = p.terms[i].text.clone();
let right_text = p.terms[i+1].text.clone();

let left_last = left_text.chars().last().unwrap();
let right_first = right_text.chars().next().unwrap();

// a/A + i/u/r/l -> e/o/ar/al
// Condition: following is ac
if "aA".contains(left_last) && "iIuUfFxX".contains(right_first) {
let replacement = match right_first {
'i' | 'I' => "e",
'u' | 'U' => "o",
'f' | 'F' => "ar",
'x' | 'X' => "al",
_ => "",
};

if !replacement.is_empty() {
let new_left = format!("{}{}", &left_text[..left_text.len()-left_last.len_utf8()], replacement);
// Note: right term needs to lose its first char?
// Sandhi merges two sounds.
// Left loses last, Right loses first, both replaced by replacement.
// My previous implementations were a bit simplified.
// Correct logic: Merge (last + first) -> replacement

p.terms[i].text = new_left;
// Need to remove first char of right term, or merge entirely if it's single char
// Here we simplify by merging entire terms if right is single char, or handling string manipulation
// For subanta/tinanta, right terms are often suffixes starting with vowel

// Let's assume right term loses its first char
let new_right = right_text[right_first.len_utf8()..].to_string();
if new_right.is_empty() {
p.terms.remove(i+1);
} else {
p.terms[i+1].text = new_right;
}

p.add_rule("6.1.87 ādguṇaḥ");
changed = true;
}
}
i += 1;
}
changed
}

/// 6.1.88 vṛddhireci
pub fn rule_6_1_88(p: &mut Prakriya) -> bool {
let mut changed = false;
let mut i = 0;
while i < p.terms.len().saturating_sub(1) {
let left_text = p.terms[i].text.clone();
let right_text = p.terms[i+1].text.clone();

let left_last = left_text.chars().last().unwrap();
let right_first = right_text.chars().next().unwrap();

// a/A + e/o/ai/au -> ai/au
if "aA".contains(left_last) && "eEoO".contains(right_first) {
let replacement = match right_first {
'e' | 'E' => "E", // ai
'o' | 'O' => "O", // au
_ => "",
};

if !replacement.is_empty() {
let new_left = format!("{}{}", &left_text[..left_text.len()-left_last.len_utf8()], replacement);

p.terms[i].text = new_left;
let new_right = right_text[right_first.len_utf8()..].to_string();
if new_right.is_empty() {
p.terms.remove(i+1);
} else {
p.terms[i+1].text = new_right;
}

p.add_rule("6.1.88 vṛddhireci");
changed = true;
}
}
i += 1;
}
changed
}


/// 6.1.77 iko yaṇaci
pub fn rule_6_1_77(p: &mut Prakriya) -> bool {
let mut changed = false;
let mut i = 0;
while i < p.terms.len().saturating_sub(1) {
let left_text = p.terms[i].text.clone();
let right_text = p.terms[i+1].text.clone();

let left_last = left_text.chars().last().unwrap();
let right_first = right_text.chars().next().unwrap();

if "iIuUfFxX".contains(left_last) && "aAiIuUfFxXeEoO".contains(right_first) {
let replacement = match left_last {
'i' | 'I' => "y",
'u' | 'U' => "v",
'f' | 'F' => "r",
'x' | 'X' => "l",
_ => "",
};

if !replacement.is_empty() {
let new_left = format!("{}{}", &left_text[..left_text.len()-left_last.len_utf8()], replacement);
p.terms[i].text = new_left;
p.add_rule("6.1.77 iko yaṇaci");
changed = true;
}
}
i += 1;
}
changed
}

/// 8.2.66 sasajuṣo ruḥ
pub fn rule_8_2_66(p: &mut Prakriya) -> bool {
let mut changed = false;
// Iterate indices to avoid borrowing conflict
for i in 0..p.terms.len() {
let term = &p.terms[i];
if term.text.ends_with('s') && term.has_tag(Tag::Pada) {
p.terms[i].text.pop();
p.terms[i].text.push_str("ru~");
p.add_rule("8.2.66 sasajuṣo ruḥ");
changed = true;
}
}
changed
}

/// 6.1.78 eco'yavāyāvaḥ
pub fn rule_6_1_78(p: &mut Prakriya) -> bool {
let mut changed = false;
let mut i = 0;
while i < p.terms.len().saturating_sub(1) {
let left_text = p.terms[i].text.clone();
let right_text = p.terms[i+1].text.clone();

// Simplified check: if left ends in e/o/ai/au and right starts with vowel
let last = left_text.chars().last().unwrap();
let first = right_text.chars().next().unwrap();

if "eEoO".contains(last) && "aAiIuUfFxXeEoO".contains(first) {
let replacement = match last {
'e' => "ay",
'o' => "av",
'E' => "Ay",
'O' => "Av",
_ => "",
};

if !replacement.is_empty() {
let new_left = format!("{}{}", &left_text[..left_text.len()-last.len_utf8()], replacement);
p.terms[i].text = new_left;
p.add_rule("6.1.78 eco'yavāyāvaḥ");
changed = true;
}
}
i += 1;
}
changed
}

/// 8.3.15 kharavasānayorvisarjanīyaḥ
pub fn rule_8_3_15(p: &mut Prakriya) -> bool {
let mut changed = false;
let len = p.terms.len();
if len > 0 {
let last_idx = len - 1;
let text = &p.terms[last_idx].text;
if text.ends_with("r") || text.ends_with("ru~") {
if text.ends_with("ru~") {
let new_text = text.trim_end_matches("ru~").to_string();
p.terms[last_idx].text = new_text;
} else {
p.terms[last_idx].text.pop();
}
p.terms[last_idx].text.push('H');
p.add_rule("8.3.15 kharavasānayorvisarjanīyaḥ");
changed = true;
}
}
changed
}
Loading
Loading