Compare commits

..
Author SHA1 Message Date
2d6f03c28c
build: update flake (late commit) 2026-10-09 18:57:26 -07:00
5cdfbfea5e
refactor: avoid extra owned string
I think this is more readable, too
2026-10-09 18:53:02 -07:00
acc49edd31
feat: generalize removing and adding back prefix 2026-10-09 18:50:19 -07:00
da82532361
refactor(formatting): move tests into module 2026-10-09 16:20:04 -07:00
046a3e5b20
feat: ignore underscores in input
this isn't useful for typst usually,
since underscores are subscript and don't appear in expressions much.

however, when using tylc as a standalone calculator,
this is useful eg to seperate sets of three digits.

idea totally stolen from rust literals

note that this might cause problems when it comes to special variables,
eg A_n for Avogadro's number (but just A is fine)
2026-10-09 16:10:32 -07:00
3 changed files with 61 additions and 70 deletions

17
flake.lock generated
View file

@ -20,18 +20,15 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1780749050,
"narHash": "sha256-3av0pIjlOWQ6rDbNOmpUSvbNnJkGORQKKjb4LtCZsIY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a799d3e3886da994fa307f817a6bc705ae538eeb",
"type": "github"
"lastModified": 1791260994,
"narHash": "sha256-MFBjw66d4h06MvpW6lIl7RwarLteD0sk859CncGwb1Q=",
"rev": "151fa4e8ddfdd8dd25d945ad94ed54a13de9f6e4",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.11pre1086391.151fa4e8ddfd/nixexprs.tar.zst?lastModified=1791260994&rev=151fa4e8ddfdd8dd25d945ad94ed54a13de9f6e4"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
"type": "tarball",
"url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.zst"
}
},
"root": {

View file

@ -1,6 +1,6 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.zst";
flake-utils.url = "github:numtide/flake-utils";
};

View file

@ -3,20 +3,19 @@ use rug::Float;
use crate::nodes::{self, Error};
pub fn pretty_eval(input: &str, max_digits: usize) -> Result<String, Error> {
let mut input = input.replace('_', "");
let (prefix, deliminator, input) = input
.rsplit_once('=')
.map(|(p, i)| (p, "= ", i))
.unwrap_or_else(|| {
input
.rsplit_once('&')
.map(|(p, i)| (p, "& ", i))
.unwrap_or(("", "", input))
});
// no need to remove the characters here,
// as we ignore the them in all other logic already
let should_add_back_alignment = input.contains('&');
// no need to remove the character here,
// as we ignore it in all other logic already
let should_add_back_backslash = input.contains('\\');
let leading_spaces = input.chars().take_while(|c| *c == ' ').count();
let should_add_back_equals = input
.find('=')
.inspect(|i| {
input.remove(*i);
})
.is_some();
let result = nodes::eval(&input)?;
let display_digits =
@ -34,38 +33,11 @@ pub fn pretty_eval(input: &str, max_digits: usize) -> Result<String, Error> {
});
Ok(format!(
"{}{}{result:.display_digits$}{}",
" ".repeat(leading_spaces),
if should_add_back_equals && should_add_back_alignment {
"& = "
} else if should_add_back_equals {
"= "
} else if should_add_back_alignment {
"& "
} else {
""
},
"{prefix}{deliminator}{result:.display_digits$}{}",
if should_add_back_backslash { " \\" } else { "" }
)
.replace('e', " * 10^"))
}
#[test]
fn test_character_readdition() {
assert_eq!(pretty_eval(" = 11", 10).unwrap(), " = 11");
assert_eq!(pretty_eval(" &= 11", 10).unwrap(), " & = 11");
assert_eq!(pretty_eval(" & 11", 10).unwrap(), " & 11");
assert_eq!(pretty_eval(" & 11 \\", 10).unwrap(), " & 11 \\");
}
#[test]
fn test_basic_up_to_999() {
assert_eq!(pretty_eval("1", 10).unwrap(), "1");
assert_eq!(pretty_eval("10", 10).unwrap(), "10");
assert_eq!(pretty_eval("100", 10).unwrap(), "100");
assert_eq!(pretty_eval("999", 10).unwrap(), "999");
assert_eq!(pretty_eval("1000", 10).unwrap(), "1 * 10^3");
assert_eq!(pretty_eval("11.111111", 10).unwrap(), "11.111111");
}
pub fn get_significant_digits(n: &Float) -> usize {
let raw_string = n.to_string().replace('.', "");
@ -101,23 +73,45 @@ pub fn get_significant_digits(n: &Float) -> usize {
}
#[cfg(test)]
fn eval(s: &str) -> Float {
crate::nodes::eval(s).unwrap()
}
mod tests {
use super::*;
fn eval(s: &str) -> Float {
crate::nodes::eval(s).unwrap()
}
#[test]
fn test_get_significant_digits() {
let many_zeros = eval("14.00643 + 1.00784 * 4 + 35.446 + 15.9994 * 4");
assert_eq!(many_zeros.to_f64(), 117.48139);
let many_nines = eval("12.0096 + 15.9994 * 2");
assert_eq!(many_nines.to_f64(), 44.0084);
let zero_nine_zero = eval("2+12321(5+123)");
assert_eq!(zero_nine_zero.to_f64(), 1577090.0);
let test_4 = eval("12.0096 + 1.00784 * 3 + 12.0096 + 1.00784 * 2 + 15.9994 + 1.00784");
assert_eq!(test_4.to_f64(), 46.06564);
#[test]
fn character_readdition() {
assert_eq!(pretty_eval(" = 11", 10).unwrap(), " = 11");
assert_eq!(pretty_eval(" &= 11", 10).unwrap(), " &= 11");
assert_eq!(pretty_eval(" & 11", 10).unwrap(), " & 11");
assert_eq!(pretty_eval(" & 11 \\", 10).unwrap(), " & 11 \\");
}
assert_eq!(get_significant_digits(&many_zeros), 8);
assert_eq!(get_significant_digits(&many_nines), 6);
assert_eq!(get_significant_digits(&zero_nine_zero), 6);
assert_eq!(get_significant_digits(&test_4), 7);
#[test]
fn basic_output_up_to_999() {
assert_eq!(pretty_eval("1", 10).unwrap(), "1");
assert_eq!(pretty_eval("10", 10).unwrap(), "10");
assert_eq!(pretty_eval("100", 10).unwrap(), "100");
assert_eq!(pretty_eval("999", 10).unwrap(), "999");
assert_eq!(pretty_eval("1000", 10).unwrap(), "1 * 10^3");
assert_eq!(pretty_eval("11.111111", 10).unwrap(), "11.111111");
}
#[test]
fn basic_get_significant_digits() {
let many_zeros = eval("14.00643 + 1.00784 * 4 + 35.446 + 15.9994 * 4");
assert_eq!(many_zeros.to_f64(), 117.48139);
let many_nines = eval("12.0096 + 15.9994 * 2");
assert_eq!(many_nines.to_f64(), 44.0084);
let zero_nine_zero = eval("2+12321(5+123)");
assert_eq!(zero_nine_zero.to_f64(), 1577090.0);
let test_4 = eval("12.0096 + 1.00784 * 3 + 12.0096 + 1.00784 * 2 + 15.9994 + 1.00784");
assert_eq!(test_4.to_f64(), 46.06564);
assert_eq!(get_significant_digits(&many_zeros), 8);
assert_eq!(get_significant_digits(&many_nines), 6);
assert_eq!(get_significant_digits(&zero_nine_zero), 6);
assert_eq!(get_significant_digits(&test_4), 7);
}
}