A while ago, I was inspired by calculators like Soulver and Numi, so I set out to make my own calculator in that style with Rust. Here is a demo of what it can accomplish so far:
As a student, I've found it to be an incredibly useful tool for working through calculations with different units and intermediate values, and I'm ultimately hoping others can find similar value in it. It uses a custom parser built with chumsky and astro_float for arbitrary-precision primitives.
It works great for me on macOS, but I haven't yet tested or implemented platform abstractions for Windows/Linux. If you're on either of those platforms, I would really appreciate your help getting it to work there.
Please let me know if you have any questions or ideas!
Repository
Releases (macOS only)
Nice project ! Keep it up !
Thanks for sharing !
Dimensional analysis is the part that makes these worth using over a plain
calculator, so a question about how far you take it: is the unit check done at
parse time or at evaluation time?
Asking because the two give very different error messages. Catching m + s while
parsing lets you underline the offending token, whereas catching it during
evaluation usually means you can only report that the whole line failed. For a
Soulver-style tool where people edit a line repeatedly, the first is a lot nicer.
Also curious about display: astro_float gives you arbitrary precision, but do you
normalise before rendering? These tools reliably get a bug report the first time
0.1 + 0.2 shows up as 0.30000000000000004, and arbitrary precision moves where
that surfaces rather than removing it.
Happy to test on Linux (Mint 22.3) if that is still useful, since you mentioned
platform help.
Gave this an actual build on Linux since you asked for platform help. Mint 22.3, kernel 7.0.0-28-generic, x86_64, cargo 1.96.0, at commit f227976.
Good news is the whole workspace compiles clean. The only failure is the final link:
rust-lld: error: unable to find library -lxkbcommon-x11
collect2: error: ld returned 1 exit status
error: could not compile siffra-desktop (bin "siffra-desktop") due to 1 previous error
It comes down to exactly one missing package. The runtime library was already present (libxkbcommon-x11.so.0), only the dev symlink was absent. libxkbcommon-dev, libfreetype-dev and the xcb dev packages were all already installed, so this was the single gap:
sudo apt install libxkbcommon-x11-dev
Probably worth a short "Linux build requirements" line in the README. gpui links against -lfreetype -lxcb -lxkbcommon -lxkbcommon-x11, and a bare cargo run on an otherwise well-equipped Ubuntu or Mint box stops here with a linker error that does not point at the real cause.
One unrelated small thing I noticed: desktop/src/app/mod.rs:5 has an unused import of crate::platform. It is the only warning in the build.
First of all, thanks a lot for the feedback and help. To answer your first question, unit checks are done during evaluation. This is why storing dimensional values to variables works across multiple lines.
While it is sometimes the case that errors during parsing are better, I get around this by attaching spans to the AST so that errors from eval can specifically reference offending parts of a line. You can see the AST and how I store spans in core/src/parser/representation.rs.
I also make sure to only show errors where meaningful--e.x. if a user is actively typing an expression, most errors will be hidden.
For your second question, I want to clarify that my calculator isn't arbitrary precision right now--it's fixed 256-bit precision, with rounding to 50 decimal places. I think I worded this poorly in my main post--astro_float simply allows me to have a generic Float struct that I can set the precision for. This gives ~20 extra decimal places that are rounded away, which should be more than enough (probably overkill) for most calculations.
My Pleasure !
Spans on the AST plus hiding errors mid-typing is the better answer than checking at parse time, and it explains how a variable can carry its dimension across lines. That tradeoff makes sense.
Good clarification on the precision too. 256-bit rounded to 50 is the right shape: the extra digits act as guard digits and absorb the representation error, so 0.1 + 0.2 lands on 0.3 the way people expect from a calculator rather than the way floats actually behave.