diff --git a/Rules/Braille/Russian/Russian_Rules.yaml b/Rules/Braille/Russian/Russian_Rules.yaml
index 4ab7154a..a691101e 100644
--- a/Rules/Braille/Russian/Russian_Rules.yaml
+++ b/Rules/Braille/Russian/Russian_Rules.yaml
@@ -93,6 +93,17 @@
- x: "*[1]"
- t: "⠹"
+-
+ name: nested-fraction
+ tag: mfrac
+ match: "parent::m:mfrac"
+ replace:
+ - t: "⠆"
+ - x: "*[1]"
+ - t: "⠀⠳"
+ - x: "*[2]"
+ - t: "⠰"
+
-
name: simple-numeric
tag: mfrac
@@ -267,6 +278,41 @@
- t: "#"
- x: "*[1]"
+-
+ name: signed-integer-number
+ tag: [msub, munder]
+ match: "*[2][self::m:mn and (substring(., 1, 1)='-' or substring(., 1, 1)='−' or substring(., 1, 1)='+') and translate(substring(., 2), '0123456789', '')='']"
+ replace:
+ - x: "*[1]"
+ - test:
+ if: "self::m:munder"
+ then: [t: "⠨⠡"]
+ else: [t: "⠡"]
+ - test:
+ if: "substring(*[2], 1, 1)='+'"
+ then: [t: "⠖"]
+ else: [t: "⠤"]
+ - x: "BrailleChars(translate(substring(*[2], 2), '0123456789', '\ue000\ue001\ue002\ue003\ue004\ue005\ue006\ue007\ue008\ue009'), 'Russian')"
+
+-
+ name: signed-integer
+ tag: [msub, munder]
+ match:
+ - "*[2][self::m:mrow and count(*)=2 and"
+ - " *[1][self::m:mo][.='-' or .='−' or .='+'] and"
+ - " *[2][self::m:mn and translate(., '0123456789', '')='']]"
+ replace:
+ - x: "*[1]"
+ - test:
+ if: "self::m:munder"
+ then: [t: "⠨⠡"]
+ else: [t: "⠡"]
+ - test:
+ if: "*[2]/*[1][.='+']"
+ then: [t: "⠖"]
+ else: [t: "⠤"]
+ - x: "BrailleChars(translate(*[2]/*[2], '0123456789', '\ue000\ue001\ue002\ue003\ue004\ue005\ue006\ue007\ue008\ue009'), 'Russian')"
+
-
name: integer
tag: [msub, munder]
@@ -289,9 +335,47 @@
if: "self::m:munder"
then: [t: "⠨⠡"]
else: [t: "⠡"]
+ - test:
+ if: "*[2][self::m:mrow[m:mo[.='+']] or self::m:mfrac]"
+ then: [t: "⠐"]
- x: "*[2]"
- t: "⠱"
+-
+ name: signed-integer-number
+ tag: [msup, mover]
+ match: "*[2][self::m:mn and (substring(., 1, 1)='-' or substring(., 1, 1)='−' or substring(., 1, 1)='+') and translate(substring(., 2), '0123456789', '')='']"
+ replace:
+ - x: "*[1]"
+ - test:
+ if: "self::m:mover"
+ then: [t: "⠨⠌"]
+ else: [t: "⠌"]
+ - test:
+ if: "substring(*[2], 1, 1)='+'"
+ then: [t: "⠖"]
+ else: [t: "⠤"]
+ - x: "BrailleChars(translate(substring(*[2], 2), '0123456789', '\ue000\ue001\ue002\ue003\ue004\ue005\ue006\ue007\ue008\ue009'), 'Russian')"
+
+-
+ name: signed-integer
+ tag: [msup, mover]
+ match:
+ - "*[2][self::m:mrow and count(*)=2 and"
+ - " *[1][self::m:mo][.='-' or .='−' or .='+'] and"
+ - " *[2][self::m:mn and translate(., '0123456789', '')='']]"
+ replace:
+ - x: "*[1]"
+ - test:
+ if: "self::m:mover"
+ then: [t: "⠨⠌"]
+ else: [t: "⠌"]
+ - test:
+ if: "*[2]/*[1][.='+']"
+ then: [t: "⠖"]
+ else: [t: "⠤"]
+ - x: "BrailleChars(translate(*[2]/*[2], '0123456789', '\ue000\ue001\ue002\ue003\ue004\ue005\ue006\ue007\ue008\ue009'), 'Russian')"
+
-
name: chemistry-repeated-charge
tag: msup
@@ -457,6 +541,9 @@
if: "self::m:munderover"
then: [t: "⠨⠡"]
else: [t: "⠡"]
+ - test:
+ if: "*[2][self::m:mrow[m:mo[.='+']] or self::m:mfrac]"
+ then: [t: "⠐"]
- x: "*[2]"
- test:
if: "self::m:munderover"
diff --git a/tests/braille/Russian/russian.rs b/tests/braille/Russian/russian.rs
index 859d230a..4d2f9c83 100644
--- a/tests/braille/Russian/russian.rs
+++ b/tests/braille/Russian/russian.rs
@@ -1,6 +1,108 @@
use crate::common::*;
use anyhow::Result;
+#[test]
+fn script_grouping_regressions() -> Result<()> {
+ let cases = vec![
+ ("sup_x", r#""#),
+ ("sup_zero", r#""#),
+ ("sup_ten", r#""#),
+ ("sup_minus_x", r#""#),
+ ("sup_minus_2", r#""#),
+ ("sup_x_plus_1", r#""#),
+ ("sup_sub_x2", r#""#),
+ ("sup_nested", r#""#),
+ ("sup_frac", r#""#),
+ ("sup_sqrt", r#""#),
+ ("sup_follow_letter", r#""#),
+ ("sup_follow_number", r#""#),
+ ("sub_x", r#""#),
+ ("sub_zero", r#""#),
+ ("sub_ten", r#""#),
+ ("sub_minus_x", r#""#),
+ ("sub_minus_2", r#""#),
+ ("sub_x_plus_1", r#""#),
+ ("sub_nested", r#""#),
+ ("sub_follow_letter", r#""#),
+ ("sub_follow_number", r#""#),
+ ("subsup_numeric", r#""#),
+ ("subsup_i_n", r#""#),
+ ("subsup_grouped_sub", r#""#),
+ ("subsup_grouped_sup", r#""#),
+ ("subsup_nested_sup", r#""#),
+ ("negative_base_sup", r#""#),
+ ("paren_base_sup", r#""#),
+ ("frac_base_sup", r#""#),
+ ("root_base_sup", r#""#),
+ ("sup_on_function", r#""#),
+ ("log_sub_sup", r#""#),
+ ("root_index_group", r#""#),
+ ("root_index_sub", r#""#),
+ ("frac_num_group", r#""#),
+ ("frac_den_group", r#""#),
+ ("nested_frac", r#""#),
+ ("sup_after_fraction", r#""#),
+ ("sub_after_fraction", r#""#),
+ ("tensor_like", r#""#),
+ ("pre_negative_power", r#""#),
+ ("power_of_power_follow", r#""#),
+ ("subscripted_power_follow", r#""#),
+ ("power_subscript_follow", r#""#),
+ ];
+
+ let expected = std::collections::HashMap::from([
+ ("sup_x", "⠠⠁⠌⠭⠱"),
+ ("sup_zero", "⠠⠭⠌⠴"),
+ ("sup_ten", "⠠⠭⠌⠂⠴"),
+ ("sup_minus_x", "⠠⠁⠌⠀⠤⠭⠱"),
+ ("sup_minus_2", "⠠⠁⠌⠤⠆"),
+ ("sup_x_plus_1", "⠠⠁⠌⠭⠀⠖⠼⠁⠱"),
+ ("sup_sub_x2", "⠠⠁⠌⠭⠡⠆⠱"),
+ ("sup_nested", "⠠⠁⠌⠭⠌⠆⠱"),
+ ("sup_frac", "⠠⠁⠌⠼⠁⠆⠱"),
+ ("sup_sqrt", "⠠⠁⠌⠩⠱⠭⠹⠱"),
+ ("sup_follow_letter", "⠠⠭⠌⠆⠽"),
+ ("sup_follow_number", "⠠⠭⠌⠆⠼⠉"),
+ ("sub_x", "⠠⠁⠡⠭⠱"),
+ ("sub_zero", "⠠⠭⠡⠴"),
+ ("sub_ten", "⠠⠭⠡⠂⠴"),
+ ("sub_minus_x", "⠠⠁⠡⠀⠤⠭⠱"),
+ ("sub_minus_2", "⠠⠁⠡⠤⠆"),
+ ("sub_x_plus_1", "⠠⠁⠡⠐⠭⠀⠖⠼⠁⠱"),
+ ("sub_nested", "⠠⠁⠡⠭⠡⠆⠱"),
+ ("sub_follow_letter", "⠠⠭⠡⠆⠽"),
+ ("sub_follow_number", "⠠⠭⠡⠆⠼⠉"),
+ ("subsup_numeric", "⠠⠭⠡⠼⠁⠌⠼⠃⠱"),
+ ("subsup_i_n", "⠠⠭⠡⠊⠌⠝⠱"),
+ ("subsup_grouped_sub", "⠠⠭⠡⠐⠊⠀⠖⠼⠁⠌⠼⠃⠱"),
+ ("subsup_grouped_sup", "⠠⠭⠡⠼⠚⠌⠠⠝⠀⠤⠼⠁⠱"),
+ ("subsup_nested_sup", "⠠⠭⠡⠼⠚⠌⠠⠝⠌⠆⠱"),
+ ("negative_base_sup", "⠤⠠⠭⠌⠆"),
+ ("paren_base_sup", "⠣⠠⠭⠀⠖⠼⠁⠜⠌⠆"),
+ ("frac_base_sup", "⠼⠁⠳⠠⠭⠌⠆"),
+ ("root_base_sup", "⠩⠱⠠⠭⠹⠌⠆"),
+ ("sup_on_function", "⠫⠎⠌⠆⠠⠭"),
+ ("log_sub_sup", "⠫⠇⠡⠼⠃⠌⠼⠉⠱⠠⠭"),
+ ("root_index_group", "⠩⠠⠝⠀⠖⠼⠁⠱⠠⠭⠹"),
+ ("root_index_sub", "⠩⠠⠝⠡⠆⠱⠭⠹"),
+ ("frac_num_group", "⠆⠠⠭⠀⠖⠼⠁⠀⠳⠠⠽⠰"),
+ ("frac_den_group", "⠆⠠⠭⠀⠳⠽⠀⠖⠼⠁⠰"),
+ ("nested_frac", "⠆⠆⠼⠁⠀⠳⠠⠭⠰⠀⠳⠆⠼⠁⠀⠳⠠⠽⠰⠰"),
+ ("sup_after_fraction", "⠆⠠⠭⠀⠖⠼⠁⠀⠳⠠⠽⠀⠤⠼⠁⠰⠌⠆"),
+ ("sub_after_fraction", "⠆⠠⠭⠀⠖⠼⠁⠀⠳⠠⠽⠀⠤⠼⠁⠰⠡⠠⠊⠱"),
+ ("tensor_like", "⠨⠞⠡⠠⠊⠌⠚⠱⠭⠡⠚⠌⠅⠱"),
+ ("pre_negative_power", "⠼⠃⠠⠭⠌⠤⠂"),
+ ("power_of_power_follow", "⠠⠭⠌⠆⠌⠒⠽"),
+ ("subscripted_power_follow", "⠠⠭⠡⠆⠌⠒⠽"),
+ ("power_subscript_follow", "⠠⠭⠌⠆⠡⠒⠽"),
+ ]);
+
+ for (label, expr) in cases {
+ test_braille("Russian", expr, expected[label])?;
+ }
+ return Ok(());
+}
+
#[test]
fn numbers_and_operators() -> Result<()> {
let expr = r#""#;