Skip to content

Commit

Permalink
Merge pull request #270 from frectonz/power-notation
Browse files Browse the repository at this point in the history
Support power notation via unicode superscript characters
  • Loading branch information
printfn authored Feb 23, 2024
2 parents 3510d59 + 053428d commit 465413f
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
43 changes: 43 additions & 0 deletions core/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,52 @@ fn parse_basic_number<'a, I: Interrupt>(
}
}

// parse exponentiation via unicode superscript digits
if base.base_as_u8() <= 10
&& input
.chars()
.next()
.is_some_and(|c| SUPERSCRIPT_DIGITS.contains(&c))
{
if let Ok((mut power_digits, remaining)) = parse_power_number(input) {
let mut exponent = Number::zero_with_base(base);

power_digits.reverse();

for (i, digit) in power_digits.into_iter().enumerate() {
let num = digit * 10u64.pow(u32::try_from(i).unwrap());
exponent = exponent.add(num.into(), int)?;
}

res = res.pow(exponent, int)?;
input = remaining;
}
}

Ok((res, input))
}

const SUPERSCRIPT_DIGITS: [char; 10] = ['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'];

fn parse_power_number(input: &str) -> FResult<(Vec<u64>, &str)> {
let mut digits: Vec<u64> = Vec::new();

let (mut ch, mut input) = parse_char(input)?;
while let Some((idx, _)) = SUPERSCRIPT_DIGITS
.iter()
.enumerate()
.find(|(_, x)| **x == ch)
{
digits.push(idx as u64);
if input.is_empty() {
break;
}
(ch, input) = parse_char(input)?;
}

Ok((digits, input))
}

fn parse_number<'a, I: Interrupt>(input: &'a str, int: &I) -> FResult<(Number, &'a str)> {
let (base, input) = parse_base_prefix(input).unwrap_or((Base::default(), input));
let (res, input) = parse_basic_number(input, base, int)?;
Expand Down
6 changes: 6 additions & 0 deletions core/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5859,3 +5859,9 @@ fn alias_sqrt() {
"approx. 3527.6684147527 s",
);
}

#[test]
fn test_superscript() {
test_eval("200²", "40000");
test_eval("13¹³ days", "302875106592253 days");
}

0 comments on commit 465413f

Please sign in to comment.