Use rustfmt for some files

This commit is contained in:
Kasper 2022-09-12 00:45:29 +02:00
parent a64081ac73
commit 1bb3819350
No known key found for this signature in database
GPG Key ID: 356D5C59EDCEC2D1
5 changed files with 223 additions and 184 deletions

1
rustfmt.toml Normal file
View File

@ -0,0 +1 @@
tab_spaces=2

View File

@ -1,13 +1,13 @@
use decimal::d128;
use crate::{Token, Number};
use crate::units::{Unit, UnitType, convert, add, subtract, multiply, divide, modulo, pow};
use crate::parser::AstNode;
use crate::Operator::{Caret, Divide, Minus, Modulo, Multiply, Plus};
use crate::Constant::{Pi, E};
use crate::UnaryOperator::{Percent, Factorial};
use crate::TextOperator::{To, Of};
use crate::FunctionIdentifier::*;
use crate::lookup::{lookup_factorial, lookup_named_number};
use crate::parser::AstNode;
use crate::units::{add, convert, divide, modulo, multiply, pow, subtract, Unit, UnitType};
use crate::Constant::{Pi, E};
use crate::FunctionIdentifier::*;
use crate::Operator::{Caret, Divide, Minus, Modulo, Multiply, Plus};
use crate::TextOperator::{Of, To};
use crate::UnaryOperator::{Factorial, Percent};
use crate::{Number, Token};
use decimal::d128;
/// Evaluate an [`AstNode`] into a [`Number`]
pub fn evaluate(ast: &AstNode) -> Result<Number, String> {
@ -29,7 +29,7 @@ pub fn sqrt(input: d128) -> d128 {
let mut n = d128!(1);
let half = d128!(0.5);
for _ in 0..10 {
n = (n + input/n) * half;
n = (n + input / n) * half;
}
n
}
@ -40,8 +40,8 @@ pub fn cbrt(input: d128) -> d128 {
// hope that 20 iterations makes it accurate enough
let three = d128!(3);
for _ in 0..20 {
let z2 = n*n;
n = n - ((n*z2 - input) / (three*z2));
let z2 = n * n;
n = n - ((n * z2 - input) / (three * z2));
}
n
}
@ -68,12 +68,11 @@ pub fn sin(mut input: d128) -> d128 {
let mut result = d128!(0);
for i_int in 0..precision {
let i = d128::from(i_int);
let calc_result = two*i+one;
let calc_result = two * i + one;
result += neg_one.pow(i) * (input.pow(calc_result) / factorial(calc_result));
}
negative_correction * result
}
/// Returns the cosine of a [`struct@d128`]
@ -92,18 +91,16 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
let token = &ast_node.token;
let children = &ast_node.children;
match token {
Token::Number(number) => {
Ok(Number::new(*number, Unit::NoUnit))
},
Token::Constant(constant) => {
match constant {
Pi => {
Ok(Number::new(d128!(3.141592653589793238462643383279503), Unit::NoUnit))
},
E => {
Ok(Number::new(d128!(2.718281828459045235360287471352662), Unit::NoUnit))
},
}
Token::Number(number) => Ok(Number::new(*number, Unit::NoUnit)),
Token::Constant(constant) => match constant {
Pi => Ok(Number::new(
d128!(3.141592653589793238462643383279503),
Unit::NoUnit,
)),
E => Ok(Number::new(
d128!(2.718281828459045235360287471352662),
Unit::NoUnit,
)),
},
Token::FunctionIdentifier(function) => {
let child_node = children.get(0).ok_or("Paren has no child[0]")?;
@ -116,7 +113,7 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
} else {
Err("log() only accepts UnitType::NoType".to_string())
}
},
}
Sqrt => {
if child_answer.unit.category() == UnitType::NoType {
let result = sqrt(child_answer.value);
@ -124,7 +121,7 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
} else {
Err("log() only accepts UnitType::NoType".to_string())
}
},
}
Log => {
if child_answer.unit.category() == UnitType::NoType {
let result = child_answer.value.log10();
@ -132,7 +129,7 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
} else {
Err("log() only accepts UnitType::NoType".to_string())
}
},
}
Ln => {
if child_answer.unit.category() == UnitType::NoType {
let result = child_answer.value.ln();
@ -140,7 +137,7 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
} else {
Err("ln() only accepts UnitType::NoType".to_string())
}
},
}
Exp => {
if child_answer.unit.category() == UnitType::NoType {
let result = child_answer.value.exp(child_answer.value);
@ -148,79 +145,92 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
} else {
Err("exp() only accepts UnitType::NoType".to_string())
}
},
}
Round => {
// .quantize() rounds .5 to nearest even integer, so we correct that
let mut result = child_answer.value.quantize(d128!(1));
let rounding_change = result - child_answer.value;
// If the result was rounded down by 0.5, correct by +1
if rounding_change == d128!(-0.5) { result += d128!(1); }
if rounding_change == d128!(-0.5) {
result += d128!(1);
}
Ok(Number::new(result, child_answer.unit))
},
}
Ceil => {
let mut result = child_answer.value.quantize(d128!(1));
let rounding_change = result - child_answer.value;
if rounding_change.is_negative() { result += d128!(1); }
if rounding_change.is_negative() {
result += d128!(1);
}
Ok(Number::new(result, child_answer.unit))
},
}
Floor => {
let mut result = child_answer.value.quantize(d128!(1));
let rounding_change = result - child_answer.value;
if !rounding_change.is_negative() { result -= d128!(1); }
if !rounding_change.is_negative() {
result -= d128!(1);
}
Ok(Number::new(result, child_answer.unit))
},
}
Abs => {
let mut result = child_answer.value.abs();
let rounding_change = result - child_answer.value;
if rounding_change == d128!(-0.5) { result += d128!(1); }
if rounding_change == d128!(-0.5) {
result += d128!(1);
}
Ok(Number::new(result, child_answer.unit))
},
}
Sin => {
let result = sin(child_answer.value);
Ok(Number::new(result, child_answer.unit))
},
}
Cos => {
let result = cos(child_answer.value);
Ok(Number::new(result, child_answer.unit))
},
}
Tan => {
let result = tan(child_answer.value);
Ok(Number::new(result, child_answer.unit))
},
}
}
}
Token::Unit(unit) => {
let child_node = children.get(0).ok_or("Unit has no child[0]")?;
let child_answer = evaluate_node(child_node)?;
Ok(Number::new(child_answer.value, *unit))
},
}
Token::Negative => {
let child_node = children.get(0).ok_or("Negative has no child[0]")?;
let child_answer = evaluate_node(child_node)?;
Ok(Number::new(-child_answer.value, child_answer.unit))
},
}
Token::Paren => {
let child_node = children.get(0).ok_or("Paren has no child[0]")?;
evaluate_node(child_node)
},
}
Token::UnaryOperator(operator) => {
let child_node = children.get(0).ok_or(format!("Token {:?} has no child[0]", token))?;
let child_node = children
.get(0)
.ok_or(format!("Token {:?} has no child[0]", token))?;
let child_answer = evaluate_node(child_node)?;
match operator {
Percent => {
Ok(Number::new(child_answer.value / d128!(100), child_answer.unit))
},
Percent => Ok(Number::new(
child_answer.value / d128!(100),
child_answer.unit,
)),
Factorial => {
let result = factorial(child_answer.value);
if result.is_nan() {
return Err("Can only perform factorial on integers from 0 to 1000".to_string());
}
Ok(Number::new(result, child_answer.unit))
},
}
},
}
}
Token::NamedNumber(named_number) => {
let child_node = children.get(0).ok_or(format!("Token {:?} has no child[0]", token))?;
let child_node = children
.get(0)
.ok_or(format!("Token {:?} has no child[0]", token))?;
let named_number_value = lookup_named_number(named_number);
if let Token::NamedNumber(child_nn) = &child_node.token {
let child_nn_value = lookup_named_number(child_nn);
@ -233,8 +243,12 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
Ok(Number::new(result, child_answer.unit))
}
Token::TextOperator(operator) => {
let left_child = children.get(0).ok_or(format!("Token {:?} has no child[0]", token))?;
let right_child = children.get(1).ok_or(format!("Token {:?} has no child[1]", token))?;
let left_child = children
.get(0)
.ok_or(format!("Token {:?} has no child[0]", token))?;
let right_child = children
.get(1)
.ok_or(format!("Token {:?} has no child[1]", token))?;
match operator {
To => {
@ -245,7 +259,7 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
} else {
Err("Right side of To operator needs to be a unit".to_string())
}
},
}
Of => {
let left = evaluate_node(left_child)?;
let right = evaluate_node(right_child)?;
@ -254,44 +268,40 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
} else {
Err("Left side of the Of operator must be NoUnit".to_string())
}
},
}
},
}
}
Token::Operator(operator) => {
let left_child = children.get(0).ok_or(format!("Token {:?} has no child[0]", token))?;
let right_child = children.get(1).ok_or(format!("Token {:?} has no child[1]", token))?;
let left_child = children
.get(0)
.ok_or(format!("Token {:?} has no child[0]", token))?;
let right_child = children
.get(1)
.ok_or(format!("Token {:?} has no child[1]", token))?;
let left = evaluate_node(left_child)?;
let right = evaluate_node(right_child)?;
match operator {
Plus => {
Ok(add(left, right)?)
},
Minus => {
Ok(subtract(left, right)?)
},
Plus => Ok(add(left, right)?),
Minus => Ok(subtract(left, right)?),
Multiply => {
Ok(multiply(left, right)?)
// }
},
}
Divide => {
Ok(divide(left, right)?)
// }
},
}
Modulo => {
Ok(modulo(left, right)?)
// }
},
}
Caret => {
Ok(pow(left, right)?)
// }
},
_ => {
Err(format!("Unexpected operator {:?}", operator))
}
_ => Err(format!("Unexpected operator {:?}", operator)),
}
}
},
_ => {
Err(format!("Unexpected token {:?}", token))
}
_ => Err(format!("Unexpected token {:?}", token)),
}
}

View File

@ -30,20 +30,23 @@
//! }
//! ```
use crate::units::Unit;
use decimal::d128;
use std::fmt::{self, Display};
use std::time::Instant;
use decimal::d128;
use crate::units::Unit;
/// Units, and functions you can use with them
pub mod units;
/// Turns a string into [`Token`]s
pub mod lexer;
/// Turns [`Token`]s into an [`AstNode`](parser::AstNode)
pub mod parser;
/// Turns an [`AstNode`](parser::AstNode) into a [`Number`]
pub mod evaluator;
/// Turns a string into [`Token`]s
#[rustfmt::skip]
pub mod lexer;
#[rustfmt::skip]
mod lookup;
/// Turns [`Token`]s into an [`AstNode`](parser::AstNode)
pub mod parser;
/// Units, and functions you can use with them
#[rustfmt::skip]
pub mod units;
#[derive(Clone, Debug)]
/// A number with a `Unit`.
@ -213,7 +216,7 @@ pub enum Token {
macro_rules! numtok {
( $num:literal ) => {
Token::Number(d128!($num))
}
};
}
/// Evaluates a string into a resulting [`Number`].
@ -233,20 +236,28 @@ macro_rules! numtok {
/// }
/// }
/// ```
pub fn eval(input: &str, allow_trailing_operators: bool, default_degree: Unit, verbose: bool) -> Result<Number, String> {
pub fn eval(
input: &str,
allow_trailing_operators: bool,
default_degree: Unit,
verbose: bool,
) -> Result<Number, String> {
let lex_start = Instant::now();
match lexer::lex(input, allow_trailing_operators, default_degree) {
Ok(tokens) => {
let lex_time = Instant::now().duration_since(lex_start).as_nanos() as f32;
if verbose { println!("Lexed TokenVector: {:?}", tokens); }
if verbose {
println!("Lexed TokenVector: {:?}", tokens);
}
let parse_start = Instant::now();
match parser::parse(&tokens) {
Ok(ast) => {
let parse_time = Instant::now().duration_since(parse_start).as_nanos() as f32;
if verbose { println!("Parsed AstNode: {:#?}", ast); }
if verbose {
println!("Parsed AstNode: {:#?}", ast);
}
let eval_start = Instant::now();
match evaluator::evaluate(&ast) {
@ -255,19 +266,19 @@ pub fn eval(input: &str, allow_trailing_operators: bool, default_degree: Unit, v
if verbose {
println!("Evaluated value: {} {:?}", answer.value, answer.unit);
println!("\u{23f1} {:.3}ms lexing", lex_time/1000.0/1000.0);
println!("\u{23f1} {:.3}ms parsing", parse_time/1000.0/1000.0);
println!("\u{23f1} {:.3}ms evaluation", eval_time/1000.0/1000.0);
println!("\u{23f1} {:.3}ms lexing", lex_time / 1000.0 / 1000.0);
println!("\u{23f1} {:.3}ms parsing", parse_time / 1000.0 / 1000.0);
println!("\u{23f1} {:.3}ms evaluation", eval_time / 1000.0 / 1000.0);
}
Ok(answer)
},
}
Err(e) => Err(format!("Eval error: {}", e)),
}
},
}
Err(e) => Err(format!("Parsing error: {}", e)),
}
},
}
Err(e) => Err(format!("Lexing error: {}", e)),
}
}

View File

@ -1,7 +1,7 @@
use cpc::eval;
use cpc::units::Unit;
use std::process::exit;
use std::env;
use std::process::exit;
const VERSION: &str = env!("CARGO_PKG_VERSION");
@ -30,12 +30,12 @@ fn main() {
"--version" => {
println!("{}", VERSION);
exit(0);
},
}
"--help" => {
print_help();
exit(0);
},
_ => {},
}
_ => {}
}
}
let mut verbose = false;
@ -58,7 +58,7 @@ fn main() {
None => {
print_help();
exit(0);
},
}
};
match eval(&expression, true, Unit::Celsius, verbose) {
@ -66,10 +66,10 @@ fn main() {
if !verbose {
println!("{}", answer);
}
},
}
Err(e) => {
eprintln!("{}", e);
exit(1);
},
}
}
}

View File

@ -1,8 +1,8 @@
use crate::Token;
use crate::Operator::{Caret, Divide, LeftParen, Minus, Modulo, Multiply, Plus, RightParen};
use crate::UnaryOperator::{Percent, Factorial};
use crate::TextOperator::{To, Of};
use crate::units::Unit::{Foot, Inch};
use crate::Operator::{Caret, Divide, LeftParen, Minus, Modulo, Multiply, Plus, RightParen};
use crate::TextOperator::{Of, To};
use crate::Token;
use crate::UnaryOperator::{Factorial, Percent};
#[derive(Debug)]
/// A struct with a [`Token`](AstNode::token) and [`AstNode`] [`children`](AstNode::children)
@ -24,10 +24,15 @@ impl AstNode {
/// Parse [`Token`]s into an Abstract Syntax Tree ([`AstNode`])
pub fn parse(tokens: &[Token]) -> Result<AstNode, String> {
parse_level_1(tokens, 0).and_then(|(ast, next_pos)| if next_pos == tokens.len() {
parse_level_1(tokens, 0).and_then(|(ast, next_pos)| {
if next_pos == tokens.len() {
Ok(ast)
} else {
Err(format!("Expected end of input, found {:?} at {}", tokens[next_pos], next_pos))
Err(format!(
"Expected end of input, found {:?} at {}",
tokens[next_pos], next_pos
))
}
})
}
@ -49,12 +54,12 @@ pub fn parse_level_1(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
new_node.children.push(right_node);
node = new_node;
pos = next_pos;
},
}
// if there's no match, we go down to a lower precedence (or, in this
// case, we're done)
_ => {
return Ok((node, pos));
},
}
}
}
}
@ -73,10 +78,10 @@ pub fn parse_level_2(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
new_node.children.push(right_node);
node = new_node;
pos = next_pos;
},
}
_ => {
return Ok((node, pos));
},
}
}
}
}
@ -96,21 +101,17 @@ pub fn parse_level_3(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
let new_node = AstNode {
children: vec![
AstNode {
children: vec![
AstNode::new(token0.unwrap().clone()),
],
children: vec![AstNode::new(token0.unwrap().clone())],
token: Token::Unit(Foot),
},
AstNode {
children: vec![
AstNode::new(token2.unwrap().clone()),
],
children: vec![AstNode::new(token2.unwrap().clone())],
token: Token::Unit(Inch),
},
],
token: Token::Operator(Plus),
};
return Ok((new_node, pos + 4))
return Ok((new_node, pos + 4));
}
}
}
@ -121,14 +122,16 @@ pub fn parse_level_3(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
loop {
let token = tokens.get(pos);
match token {
Some(&Token::Operator(Multiply)) | Some(&Token::Operator(Divide)) | Some(&Token::Operator(Modulo)) => {
Some(&Token::Operator(Multiply))
| Some(&Token::Operator(Divide))
| Some(&Token::Operator(Modulo)) => {
let (right_node, next_pos) = parse_level_4(tokens, pos + 1)?;
let mut new_node = AstNode::new(token.unwrap().clone());
new_node.children.push(node);
new_node.children.push(right_node);
node = new_node;
pos = next_pos;
},
}
// Below is implicative multiplication, for example '2pi'. Constants and
// such will only end up here if they were unable to be parsed as part of
@ -148,12 +151,12 @@ pub fn parse_level_3(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
new_node.children.push(right_node);
node = new_node;
pos = next_pos;
},
}
_ => {
return Ok((node, pos));
},
}
},
}
}
// 2pi, )pi
Some(&Token::Constant(_)) => {
let last_token = tokens.get(pos - 1);
@ -165,12 +168,12 @@ pub fn parse_level_3(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
new_node.children.push(right_node);
node = new_node;
pos = next_pos;
},
}
_ => {
return Ok((node, pos));
},
}
},
}
}
// 2log(1), )log(1)
Some(&Token::FunctionIdentifier(_)) => {
let last_token = tokens.get(pos - 1);
@ -182,32 +185,34 @@ pub fn parse_level_3(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
new_node.children.push(right_node);
node = new_node;
pos = next_pos;
},
}
_ => {
return Ok((node, pos));
},
}
},
}
}
// 2(3), pi(3), )(3)
Some(&Token::Operator(LeftParen)) => {
let last_token = tokens.get(pos - 1);
match last_token {
Some(&Token::Number(_)) | Some(&Token::Constant(_)) | Some(&Token::Operator(RightParen)) => {
Some(&Token::Number(_))
| Some(&Token::Constant(_))
| Some(&Token::Operator(RightParen)) => {
let (right_node, next_pos) = parse_level_4(tokens, pos)?;
let mut new_node = AstNode::new(Token::Operator(Multiply));
new_node.children.push(node);
new_node.children.push(right_node);
node = new_node;
pos = next_pos;
},
_ => {
return Ok((node, pos));
},
}
},
_ => {
return Ok((node, pos));
},
}
}
}
_ => {
return Ok((node, pos));
}
}
}
}
@ -226,10 +231,10 @@ pub fn parse_level_4(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
new_node.children.push(right_node);
node = new_node;
pos = next_pos;
},
}
_ => {
return Ok((node, pos));
},
}
}
}
}
@ -254,8 +259,8 @@ pub fn parse_level_5(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
let mut new_node = AstNode::new(Token::Negative);
new_node.children.push(right_node);
Ok((new_node, next_pos))
},
_ => parse_level_6(tokens, pos)
}
_ => parse_level_6(tokens, pos),
}
}
@ -266,7 +271,9 @@ pub fn parse_level_6(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
loop {
let token = tokens.get(pos);
match token {
Some(&Token::UnaryOperator(Factorial)) | Some(&Token::UnaryOperator(Percent)) | Some(&Token::NamedNumber(_)) => {
Some(&Token::UnaryOperator(Factorial))
| Some(&Token::UnaryOperator(Percent))
| Some(&Token::NamedNumber(_)) => {
// Here we are handling unary operators, aka stuff written as
// "Number Operator" (3!) instead of "Number Operator Number" (3+3).
// Therefore, if we find a match, we don't parse what comes after it.
@ -274,19 +281,19 @@ pub fn parse_level_6(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
new_node.children.push(node);
node = new_node;
pos += 1;
},
}
Some(&Token::Unit(_unit)) => {
// We won't allow units to repeat, like "1min min", so we end the loop if it's found.
let mut new_node = AstNode::new(token.unwrap().clone());
new_node.children.push(node);
return Ok((new_node, pos + 1));
},
}
_ => {
// let's say we parse 1+2. parse_level_7 then returns 1, and token
// is set to plus. Plus has lower precedence than level 4, so we
// don't do anything, and pass the number down to a lower precedence.
return Ok((node, pos));
},
}
}
}
}
@ -298,20 +305,22 @@ pub fn parse_level_6(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
/// [`FunctionIdentifier`](Token::FunctionIdentifier),
/// [`Paren`](Token::Paren)
pub fn parse_level_7(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
let token: &Token = tokens.get(pos).ok_or(format!("Unexpected end of input at {}", pos))?;
let token: &Token = tokens
.get(pos)
.ok_or(format!("Unexpected end of input at {}", pos))?;
match token {
&Token::Number(_number) => {
let node = AstNode::new(token.clone());
Ok((node, pos + 1))
},
}
&Token::Unit(_unit) => {
let node = AstNode::new(token.clone());
Ok((node, pos + 1))
},
}
Token::Constant(_constant) => {
let node = AstNode::new(token.clone());
Ok((node, pos + 1))
},
}
Token::FunctionIdentifier(_function_identifier) => {
let left_paren_pos = pos + 1;
let left_paren_token = tokens.get(left_paren_pos);
@ -326,28 +335,36 @@ pub fn parse_level_7(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
function_node.children.push(node);
Ok((function_node, next_pos + 1))
} else {
Err(format!("Expected closing paren at {} but found {:?}", next_pos, tokens.get(next_pos)))
Err(format!(
"Expected closing paren at {} but found {:?}",
next_pos,
tokens.get(next_pos)
))
}
})
},
_ => {
Err(format!("Expected ( after {} at {:?} but found {:?}", left_paren_pos, token, left_paren_token))
}
_ => Err(format!(
"Expected ( after {} at {:?} but found {:?}",
left_paren_pos, token, left_paren_token
)),
}
}
},
Token::Operator(LeftParen) => {
parse_level_1(tokens, pos + 1).and_then(|(node, next_pos)| {
Token::Operator(LeftParen) => parse_level_1(tokens, pos + 1).and_then(|(node, next_pos)| {
if let Some(&Token::Operator(RightParen)) = tokens.get(next_pos) {
let mut paren_node = AstNode::new(Token::Paren);
paren_node.children.push(node);
Ok((paren_node, next_pos + 1))
} else {
Err(format!("Expected closing paren at {} but found {:?}", next_pos, tokens.get(next_pos)))
Err(format!(
"Expected closing paren at {} but found {:?}",
next_pos,
tokens.get(next_pos)
))
}
})
},
_ => {
Err(format!("Unexpected token {:?}, expected paren or number", token))
},
}),
_ => Err(format!(
"Unexpected token {:?}, expected paren or number",
token
)),
}
}