diff --git a/CONTRIBUTING.MD b/CONTRIBUTING.MD index 5432145..e8314d3 100644 --- a/CONTRIBUTING.MD +++ b/CONTRIBUTING.MD @@ -28,4 +28,9 @@ What to do - Tag merge commit on `master` (`git tag -a v1.0.0 -m "Version 1.0.0"`) - `cargo publish` - Update web demo & pull server (`make docker`) - - Update aur package \ No newline at end of file + - Update aur package + +Test `default.nix` with +``sh +nix-build -E 'let pkgs = import { }; in pkgs.callPackage ./default.nix {}' +`` \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 7fcf22f..f47fe92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,7 +28,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "daisycalc" -version = "1.1.5" +version = "1.1.6" dependencies = [ "cfg-if", "num", diff --git a/Cargo.toml b/Cargo.toml index 763b9c7..4cdde82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daisycalc" -version = "1.1.5" +version = "1.1.6" edition = "2021" build = "buildscript/main.rs" license = "GPL-3.0-only" diff --git a/README.md b/README.md index 0c7f9c6..9f7e4ea 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,25 @@ Many features are missing, this is still under development. **Web demo: [here](https://daisy.betalupi.com) (won't work on mobile)** # 📦 Installation + - **From source:** `cargo build --release`, binary will be at `./target/release/daisy` - **Cargo:** `cargo install daisycalc` - **Arch:** `yay -S daisy` - **Debian:** coming soon + - **Nix:** Use `default.nix`. Daisy isn't in nixpkgs yet, you'll need to add something like the following to `configuration.nix`: -From source: `cargo build --release` \ -Binary will be in `target/release/daisy` - +```nix +let + daisy = builtins.fetchGit { + url = "https://github.com/rm-dr/daisy.git"; + ref = "master"; + } + /default.nix; +in +{ + environment.systemPackages = with pkgs; [ + (callPackage daisy { }) + ]; +} +``` # 📹 Screenshot @@ -22,7 +34,7 @@ Binary will be in `target/release/daisy` # 🛠️ Features - Open-source - Extremely high precision - - Uses a rational datatype when possible, and a high-precision float when not. + - Uses a rational datatype when possible, and a high-precision float when not. - Pretty printing in prompt (with special substitutions) - Supports many physical units, with metric and binary prefixes - Supports exponential notation diff --git a/TODO.md b/TODO.md index 4635cb7..d82ea82 100644 --- a/TODO.md +++ b/TODO.md @@ -20,6 +20,8 @@ - Sums and products with functional arguments - Add functions: gcd, inverse mod, dice - Tuple operations + - Number theory: select a group, inverses, etc + - Negative mod ## Prompt - Fix terminal color detection diff --git a/default.nix b/default.nix index 2fe7dbc..57a77ab 100644 --- a/default.nix +++ b/default.nix @@ -1,13 +1,13 @@ { lib, fetchgit, rustPlatform }: rustPlatform.buildRustPackage rec { pname = "daisy"; - version = "1.1.4"; + version = "1.1.6"; cargoLock.lockFile = src + /Cargo.lock; src = fetchgit { url = "https://github.com/rm-dr/daisy.git"; rev = "v${version}"; - sha256 = "sha256-aENuKtE1+tBRN0HZzRr8Gk+dVEYTiP6FNRz817Sk88o="; + sha256 = ""; }; meta = with lib; { diff --git a/src/command/mod.rs b/src/command/mod.rs index 39a0096..ee7bdf5 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -247,7 +247,7 @@ pub fn do_command( if args.len() != 2 { return FormattedText::new( format!( - "[c]{first}[n] [t]takes exactly one argument.[n]\n\n", + "[c]{first}[n] [e]takes exactly one argument.[n]\n\n", ) ); } @@ -261,7 +261,7 @@ pub fn do_command( Err(()) => { FormattedText::new( format!( - "[c]{v}[n] [t]isn't a variable.[n]\n\n", + "[c]{v}[n] [e]isn't a variable.[n]\n\n", ) ) } diff --git a/src/context.rs b/src/context.rs index 3839f2f..6bdbfc6 100644 --- a/src/context.rs +++ b/src/context.rs @@ -90,6 +90,7 @@ impl Context { pub fn delete(&mut self, s: &String) -> Result<(), ()> { if !(self.is_varible(s) || self.is_function(s)) { return Err(()) }; + if s == "ans" { return Err(()) }; if self.is_varible(s) { self.variables.remove(s); } if self.is_function(s) { self.functions.remove(s); } return Ok(()); diff --git a/src/evaluate/evaluate.rs b/src/evaluate/evaluate.rs index d80109a..64173da 100644 --- a/src/evaluate/evaluate.rs +++ b/src/evaluate/evaluate.rs @@ -63,7 +63,7 @@ pub fn evaluate( context.get_variable(&s) }, - Expression::Operator(_, Operator::Function(_), _) => { eval_function(g)? }, + Expression::Operator(_, Operator::Function(_), _) => { eval_function(context, g)? }, Expression::Operator(_, _, _) => { eval_operator(context, g)? }, }; diff --git a/src/evaluate/function.rs b/src/evaluate/function.rs index e24a391..5f3b101 100644 --- a/src/evaluate/function.rs +++ b/src/evaluate/function.rs @@ -3,11 +3,12 @@ use crate::parser::Function; use crate::parser::Operator; use crate::parser::LineLocation; use crate::quantity::FreeUnit; +use crate::quantity::Unit; use crate::quantity::WholeUnit; use crate::quantity::Quantity; use crate::quantity::Scalar; use crate::errors::DaisyError; - +use crate::context::Context; // If unitless, do nothing // If compatible with radians, convert to radians and return unitless @@ -26,7 +27,7 @@ fn to_radians(q: Quantity) -> Result { -pub fn eval_function(g: &Expression) -> Result, (LineLocation, DaisyError)> { +pub fn eval_function(context: &mut Context, g: &Expression) -> Result, (LineLocation, DaisyError)> { let Expression::Operator(loc, Operator::Function(f), args) = g else {unreachable!()}; @@ -154,17 +155,51 @@ pub fn eval_function(g: &Expression) -> Result, (LineLocation Function::ToCelsius => { let mut k = Quantity::new_rational(1f64).unwrap(); k.insert_unit(FreeUnit::from_whole(WholeUnit::Kelvin), Scalar::new_rational(1f64).unwrap()); - let Some(q) = q.convert_to(k) else { return Err((*loc + *l, DaisyError::IncompatibleUnit)) }; + + let q_s: String; + if q.unitless() { + q_s = String::from("scalar"); + } else { + q_s = q.convert_to_base().unit().display(context); + } + + let Some(q) = q.convert_to(k) else { + return Err(( + *loc + *l, + DaisyError::IncompatibleUnits( + q_s, + Unit::from_free(FreeUnit::from_whole(WholeUnit::Kelvin)).display(context) + ) + )) + }; let mut r = q.without_unit(); r += Quantity::new_rational(-273.15f64).unwrap(); return Ok(Some(Expression::Quantity(*loc + *l, r))); }, + + Function::ToFahrenheit => { let mut k = Quantity::new_rational(1f64).unwrap(); k.insert_unit(FreeUnit::from_whole(WholeUnit::Kelvin), Scalar::new_rational(1f64).unwrap()); - let Some(q) = q.convert_to(k) else { return Err((*loc + *l, DaisyError::IncompatibleUnit)) }; + + let q_s: String; + if q.unitless() { + q_s = String::from("scalar"); + } else { + q_s = q.convert_to_base().unit().display(context); + } + + let Some(q) = q.convert_to(k) else { + return Err(( + *loc + *l, + DaisyError::IncompatibleUnits( + q_s, + Unit::from_free(FreeUnit::from_whole(WholeUnit::Kelvin)).display(context) + ) + )) + }; let mut r = q.without_unit(); r *= Quantity::new_rational_from_frac(9i64, 5i64).unwrap(); @@ -173,8 +208,18 @@ pub fn eval_function(g: &Expression) -> Result, (LineLocation return Ok(Some(Expression::Quantity(*loc + *l, r))); }, + + Function::FromCelsius => { - if !q.unitless() { return Err((*loc + *l, DaisyError::IncompatibleUnit));} + if !q.unitless() { + return Err(( + *loc + *l, + DaisyError::IncompatibleUnits( + q.convert_to_base().unit().display(context), + "scalar".to_string() + ) + )); + } let mut r = Quantity::new_rational(273.15f64).unwrap(); r += q.clone(); @@ -182,8 +227,18 @@ pub fn eval_function(g: &Expression) -> Result, (LineLocation return Ok(Some(Expression::Quantity(*loc + *l, r))); }, + + Function::FromFahrenheit => { - if !q.unitless() { return Err((*loc + *l, DaisyError::IncompatibleUnit));} + if !q.unitless() { + return Err(( + *loc + *l, + DaisyError::IncompatibleUnits( + q.convert_to_base().unit().display(context), + "scalar".to_string() + ) + )); + } let mut r = q.clone(); r += Quantity::new_rational(459.67).unwrap(); diff --git a/src/evaluate/operator.rs b/src/evaluate/operator.rs index 22c61cd..cf9bfdf 100644 --- a/src/evaluate/operator.rs +++ b/src/evaluate/operator.rs @@ -124,6 +124,8 @@ pub fn eval_operator(context: &mut Context, g: &Expression) -> Result