Use rustfmt for some files
This commit is contained in:
parent
a64081ac73
commit
1bb3819350
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
@ -0,0 +1 @@
|
||||
tab_spaces=2
|
||||
158
src/evaluator.rs
158
src/evaluator.rs
@ -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)),
|
||||
}
|
||||
}
|
||||
|
||||
57
src/lib.rs
57
src/lib.rs
@ -1,9 +1,9 @@
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(
|
||||
clippy::comparison_chain,
|
||||
clippy::if_same_then_else,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::comparison_chain,
|
||||
clippy::if_same_then_else,
|
||||
clippy::match_like_matches_macro,
|
||||
)
|
||||
)]
|
||||
//! calculation + conversion
|
||||
@ -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`.
|
||||
@ -92,7 +95,7 @@ pub enum Operator {
|
||||
Divide,
|
||||
Modulo,
|
||||
Caret,
|
||||
LeftParen, // lexer only
|
||||
LeftParen, // lexer only
|
||||
RightParen, // lexer only
|
||||
}
|
||||
|
||||
@ -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)),
|
||||
}
|
||||
}
|
||||
|
||||
14
src/main.rs
14
src/main.rs
@ -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);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
147
src/parser.rs
147
src/parser.rs
@ -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))
|
||||
} else {
|
||||
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));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)| {
|
||||
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!("Unexpected token {:?}, expected paren or number", token))
|
||||
},
|
||||
}
|
||||
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!(
|
||||
"Unexpected token {:?}, expected paren or number",
|
||||
token
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user