···2233calculation + conversion
4455-cpc parses and evaluates strings of math, with support for units and conversion. 128-bit decimal floating points are used for high accuracy.
55+cpc calculates complex strings of math, with support for units and conversion. 128-bit decimal floating points are used for high accuracy.
6677-It also lets you mix units, so for example `1 km - 1m` results in `999 Meter`.
77+For example `1tonne * 1sqm / 2second^3 / 5ampere` results in `100 volts`.
8899[](https://crates.io/crates/cpc)
1010[](https://docs.rs/cpc)
···3232```
33333 + 4 * 2
34343535-8 % 3
3535+6'3" to cm
36363737-(4 + 1)km to light years
3737+1tonne * 1sqm / 2s^3 / 5a
3838+3939+(7 % 4)km to light years
3840394110m/2s * 5 trillion s
404241431 lightyear * 0.001mm in km2
42444343-1m/s + 1mi/h in kilometers per h
4545+1m/s + 1mi/5h in kilometers per h
44464547round(sqrt(2)^4)! liters
4648
+30-5
src/evaluator.rs
···66use crate::lookup::{lookup_factorial, lookup_named_number};
77use crate::parser::AstNode;
88use crate::units::Unit;
99+use crate::units::multiply_any;
1010+use crate::units::to_ideal_unit;
911use crate::units::{add, convert, divide, modulo, multiply, pow, subtract};
1012use crate::{Number, Token};
1113use fastnum::decimal::Context;
···259261 }
260262 }
261263 Per => {
262262- let left = evaluate_node(left_child)?;
263263- let right = evaluate_node(right_child)?;
264264- Ok(divide(left, right)?)
264264+ let mut node = AstNode::new(Token::Operator(Divide));
265265+ node.children = children.to_vec();
266266+ Ok(evaluate_node(&node)?)
265267 }
266268 }
267269 }
···273275 .get(1)
274276 .ok_or(format!("Token {:?} has no child[1]", token))?;
275277 let left = evaluate_node(left_child)?;
278278+ if matches!(operator, Multiply | Divide)
279279+ && let Ok(right) = evaluate_unit(right_child)
280280+ {
281281+ // multiply/divide by unit, for example `2km`, `2ft/s`, `2*m`
282282+ let raw_result = match operator {
283283+ Multiply => multiply_any(left, Number::with_unit(d!(1), right))?,
284284+ Divide => divide(left, Number::with_unit(d!(1), right))?,
285285+ _ => panic!(),
286286+ };
287287+ let ideal_result = to_ideal_unit(raw_result.clone());
288288+ // If the ideal unit has a different category/exponent, then we use it.
289289+ // For example, we want to keep `v*a` -> `watt`, but not `ft/s` -> `cm/s`.
290290+ if raw_result.unit.len() != ideal_result.unit.len() {
291291+ return Ok(ideal_result);
292292+ }
293293+ for (ideal, raw) in ideal_result.unit.iter().zip(raw_result.unit.iter()) {
294294+ if ideal.0.category() != raw.0.category() || ideal.1 != raw.1 {
295295+ return Ok(ideal_result);
296296+ }
297297+ }
298298+ return Ok(raw_result);
299299+ }
300300+276301 let right = evaluate_node(right_child)?;
277302 match operator {
278303 Plus => Ok(add(left, right)?),
279304 Minus => Ok(subtract(left, right)?),
280280- Multiply => Ok(multiply(left, right)?),
281281- Divide => Ok(divide(left, right)?),
305305+ Multiply => Ok(to_ideal_unit(multiply(left, right)?)),
306306+ Divide => Ok(to_ideal_unit(divide(left, right)?)),
282307 Modulo => Ok(modulo(left, right)?),
283308 Caret => Ok(pow(left, right)?),
284309 _ => Err(format!("Unexpected operator {:?}", operator)),
+74-15
src/parser.rs
···44use crate::UnaryOperator::*;
55use crate::units::Unit;
66use crate::units::Unit::{Foot, Inch};
77+use core::fmt;
7888-#[derive(Debug)]
99/// A struct with a [`Token`](AstNode::token) and [`AstNode`] [`children`](AstNode::children)
1010+#[derive(Clone)]
1011pub struct AstNode {
1112 /// The children of the [`AstNode`]
1213 pub children: Vec<AstNode>,
1314 /// The token of the [`AstNode`]
1415 pub token: Token,
1516}
1616-1717impl AstNode {
1818 pub const fn new(token: Token) -> AstNode {
1919 AstNode {
2020 children: Vec::new(),
2121 token,
2222 }
2323+ }
2424+}
2525+impl fmt::Debug for AstNode {
2626+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2727+ let mut d = f.debug_struct("AstNode");
2828+ d.field("token", &self.token);
2929+ if self.children.is_empty() {
3030+ d.field("children", &self.children);
3131+ } else {
3232+ for (i, child) in self.children.iter().enumerate() {
3333+ d.field(&i.to_string(), child);
3434+ }
3535+ }
3636+ d.finish()
2337 }
2438}
2539···140154 }
141155 }
142156143143- let (mut node, mut pos) = parse_caret(tokens, pos)?;
157157+ let (mut node, mut pos) = parse_implicit_unit_mult(tokens, pos)?;
144158145159 loop {
146160 let token = tokens.get(pos);
···149163 | Some(&Token::Operator(Divide))
150164 | Some(&Token::TextOperator(Per))
151165 | Some(&Token::Operator(Modulo)) => {
152152- let (right_node, next_pos) = parse_caret(tokens, pos + 1)?;
166166+ let (right_node, next_pos) = parse_implicit_unit_mult(tokens, pos + 1)?;
153167 let mut new_node = AstNode::new(token.unwrap().clone());
154168 new_node.children.push(node);
155169 new_node.children.push(right_node);
···169183 let last_token = tokens.get(pos - 1);
170184 match last_token {
171185 Some(&Token::Constant(_)) | Some(&Token::Operator(RightParen)) => {
172172- let (right_node, next_pos) = parse_caret(tokens, pos)?;
186186+ let (right_node, next_pos) = parse_implicit_unit_mult(tokens, pos)?;
173187 let mut new_node = AstNode::new(Token::Operator(Multiply));
174188 new_node.children.push(node);
175189 new_node.children.push(right_node);
···186200 let last_token = tokens.get(pos - 1);
187201 match last_token {
188202 Some(&Token::Number(_)) | Some(&Token::Operator(RightParen)) => {
189189- let (right_node, next_pos) = parse_caret(tokens, pos)?;
203203+ let (right_node, next_pos) = parse_implicit_unit_mult(tokens, pos)?;
190204 let mut new_node = AstNode::new(Token::Operator(Multiply));
191205 new_node.children.push(node);
192206 new_node.children.push(right_node);
···203217 let last_token = tokens.get(pos - 1);
204218 match last_token {
205219 Some(&Token::Number(_)) | Some(&Token::Operator(RightParen)) => {
206206- let (right_node, next_pos) = parse_caret(tokens, pos)?;
220220+ let (right_node, next_pos) = parse_implicit_unit_mult(tokens, pos)?;
207221 let mut new_node = AstNode::new(Token::Operator(Multiply));
208222 new_node.children.push(node);
209223 new_node.children.push(right_node);
···222236 Some(&Token::Number(_))
223237 | Some(&Token::Constant(_))
224238 | Some(&Token::Operator(RightParen)) => {
225225- let (right_node, next_pos) = parse_caret(tokens, pos)?;
239239+ let (right_node, next_pos) = parse_implicit_unit_mult(tokens, pos)?;
226240 let mut new_node = AstNode::new(Token::Operator(Multiply));
227241 new_node.children.push(node);
228242 new_node.children.push(right_node);
···241255 }
242256}
243257244244-/// Parse [`^`](crate::Operator::Caret)
258258+/// Parse numbers with units (for example `2km`)
259259+pub fn parse_implicit_unit_mult(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
260260+ let (mut node, mut pos) = parse_unit_mult_level(tokens, pos)?;
261261+ loop {
262262+ let token = tokens.get(pos);
263263+ match token {
264264+ // maybe this can be in parse_mult_level instead?
265265+ Some(&Token::Unit(_)) => {
266266+ // implicit unit multiplication, e.g. `ft s`
267267+ let (right_node, next_pos) = parse_unit_mult_level(tokens, pos)?;
268268+ let mut new_node = AstNode::new(Token::Operator(Multiply));
269269+ new_node.children.push(node);
270270+ new_node.children.push(right_node);
271271+ node = new_node;
272272+ pos = next_pos;
273273+ }
274274+ _ => {
275275+ return Ok((node, pos));
276276+ }
277277+ }
278278+ }
279279+}
280280+281281+/// Parse multiplication and division with units (for example `km/h` or `km*km`)
282282+pub fn parse_unit_mult_level(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
283283+ let (mut node, mut pos) = parse_caret(tokens, pos)?;
284284+ loop {
285285+ let token = tokens.get(pos);
286286+ match token {
287287+ Some(&Token::Operator(Multiply))
288288+ | Some(&Token::Operator(Divide))
289289+ | Some(&Token::TextOperator(Per)) => {
290290+ // only consume if the right side is a unit
291291+ if let Some(&Token::Unit(_)) = tokens.get(pos + 1) {
292292+ let (right_node, next_pos) = parse_caret(tokens, pos + 1)?;
293293+ let mut new_node = AstNode::new(token.unwrap().clone());
294294+ new_node.children.push(node);
295295+ new_node.children.push(right_node);
296296+ node = new_node;
297297+ pos = next_pos;
298298+ } else {
299299+ return Ok((node, pos));
300300+ }
301301+ }
302302+ _ => {
303303+ return Ok((node, pos));
304304+ }
305305+ }
306306+ }
307307+}
308308+309309+/// Parse [`^`](crate::Operator::Caret), unit suffix (for example `2km` or `2km^2`)
245310pub fn parse_caret(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
246311 let (mut node, mut pos) = parse_unary_high(tokens, pos)?;
247312 loop {
···292357 new_node.children.push(node);
293358 node = new_node;
294359 pos += 1;
295295- }
296296- Some(Token::Unit(_unit)) => {
297297- // We won't allow units to repeat, like "1min min", so we end the loop if it's found.
298298- let mut new_node = AstNode::new(token.unwrap().clone());
299299- new_node.children.push(node);
300300- return Ok((new_node, pos + 1));
301360 }
302361 _ => {
303362 // let's say we parse 1+2. parse_level_7 then returns 1, and token
+27-20
src/units.rs
···703703 if left.contains_primitive(Temperature) || right.contains_primitive(Temperature) {
704704 Err(format!("Cannot multiply {} and {}", left, right))
705705 } else {
706706- let mut new_number = left;
707707- new_number.value *= right.value;
708708- for (r_unit, r_exp) in right.unit {
709709- let existing = new_number.unit.iter_mut().find(|(u, _)| u == &r_unit);
710710- match existing {
711711- Some(existing) => existing.1 += r_exp,
712712- None => new_number.unit.push((r_unit, r_exp)),
713713- }
706706+ multiply_any(left, right)
707707+ }
708708+}
709709+710710+pub(crate) fn multiply_any(left: Number, right: Number) -> Result<Number, String> {
711711+ let mut new_number = left;
712712+ new_number.value *= right.value;
713713+ for (r_unit, r_exp) in right.unit {
714714+ let existing = new_number.unit.iter_mut().find(|(u, _)| u == &r_unit);
715715+ match existing {
716716+ Some(existing) => existing.1 += r_exp,
717717+ None => new_number.unit.push((r_unit, r_exp)),
714718 }
715715- let new_number = to_ideal_unit(new_number);
716716- Ok(new_number)
717719 }
720720+ Ok(new_number)
718721}
719722720723/// Divide a [`Number`] by another [`Number`].
···726729 if left.contains_primitive(Temperature) || right.contains_primitive(Temperature) {
727730 Err(format!("Cannot divide {} by {}", left, right))
728731 } else {
729729- let mut new_number = left;
730730- new_number.value = new_number.value / right.value;
731731- for (r_unit, r_exp) in right.unit {
732732- let existing = new_number.unit.iter_mut().find(|(u, _)| u == &r_unit);
733733- match existing {
734734- Some(existing) => existing.1 -= r_exp,
735735- None => new_number.unit.push((r_unit, -r_exp)),
736736- }
732732+ divide_any(left, right)
733733+ }
734734+}
735735+736736+pub fn divide_any(left: Number, right: Number) -> Result<Number, String> {
737737+ let mut new_number = left;
738738+ new_number.value = new_number.value / right.value;
739739+ for (r_unit, r_exp) in right.unit {
740740+ let existing = new_number.unit.iter_mut().find(|(u, _)| u == &r_unit);
741741+ match existing {
742742+ Some(existing) => existing.1 -= r_exp,
743743+ None => new_number.unit.push((r_unit, -r_exp)),
737744 }
738738- let new_number = to_ideal_unit(new_number);
739739- Ok(new_number)
740745 }
746746+ Ok(new_number)
741747}
742748743749/// Modulo a [`Number`] by another [`Number`].
···1199120512001206 #[test]
12011207 fn test_unit_evals() {
12081208+ eval_test("100kg*sqm / 2s^2", "50j");
12021209 eval_test("3.6km/1h", "3.6 kph");
12031210 eval_test("0.3048 m/s to ft/s", "1 ft/s");
12041211 eval_test("1.609344 km/1h to mph", "1 mph");