Switch indentation to tabs

This commit is contained in:
Kasper 2022-09-12 00:47:20 +02:00
parent 1bb3819350
commit 4ac7e74c6b
No known key found for this signature in database
GPG Key ID: 356D5C59EDCEC2D1
8 changed files with 3800 additions and 3792 deletions

View File

@ -1 +1 @@
tab_spaces=2 hard_tabs=true

View File

@ -11,8 +11,8 @@ use decimal::d128;
/// Evaluate an [`AstNode`] into a [`Number`] /// Evaluate an [`AstNode`] into a [`Number`]
pub fn evaluate(ast: &AstNode) -> Result<Number, String> { pub fn evaluate(ast: &AstNode) -> Result<Number, String> {
let answer = evaluate_node(ast)?; let answer = evaluate_node(ast)?;
Ok(answer) Ok(answer)
} }
/// Returns the factorial of a [`struct@d128`] up to `1000!` without doing any math /// Returns the factorial of a [`struct@d128`] up to `1000!` without doing any math
@ -21,287 +21,289 @@ pub fn evaluate(ast: &AstNode) -> Result<Number, String> {
/// ///
/// All return values of this function are hard-coded. /// All return values of this function are hard-coded.
pub fn factorial(input: d128) -> d128 { pub fn factorial(input: d128) -> d128 {
lookup_factorial(input.into()) lookup_factorial(input.into())
} }
/// Returns the square root of a [`struct@d128`] /// Returns the square root of a [`struct@d128`]
pub fn sqrt(input: d128) -> d128 { pub fn sqrt(input: d128) -> d128 {
let mut n = d128!(1); let mut n = d128!(1);
let half = d128!(0.5); let half = d128!(0.5);
for _ in 0..10 { for _ in 0..10 {
n = (n + input / n) * half; n = (n + input / n) * half;
} }
n n
} }
/// Returns the cube root of a [`struct@d128`] /// Returns the cube root of a [`struct@d128`]
pub fn cbrt(input: d128) -> d128 { pub fn cbrt(input: d128) -> d128 {
let mut n: d128 = input; let mut n: d128 = input;
// hope that 20 iterations makes it accurate enough // hope that 20 iterations makes it accurate enough
let three = d128!(3); let three = d128!(3);
for _ in 0..20 { for _ in 0..20 {
let z2 = n * n; let z2 = n * n;
n = n - ((n * z2 - input) / (three * z2)); n = n - ((n * z2 - input) / (three * z2));
} }
n n
} }
/// Returns the sine of a [`struct@d128`] /// Returns the sine of a [`struct@d128`]
pub fn sin(mut input: d128) -> d128 { pub fn sin(mut input: d128) -> d128 {
let pi = d128!(3.141592653589793238462643383279503); let pi = d128!(3.141592653589793238462643383279503);
let pi2 = d128!(6.283185307179586476925286766559006); let pi2 = d128!(6.283185307179586476925286766559006);
input %= pi2; input %= pi2;
let negative_correction = if input.is_negative() { let negative_correction = if input.is_negative() {
input -= pi; input -= pi;
d128!(-1) d128!(-1)
} else { } else {
d128!(1) d128!(1)
}; };
let one = d128!(1); let one = d128!(1);
let two = d128!(2); let two = d128!(2);
let neg_one = -one; let neg_one = -one;
let precision = 37; let precision = 37;
let mut result = d128!(0); let mut result = d128!(0);
for i_int in 0..precision { for i_int in 0..precision {
let i = d128::from(i_int); 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)); result += neg_one.pow(i) * (input.pow(calc_result) / factorial(calc_result));
} }
negative_correction * result negative_correction * result
} }
/// Returns the cosine of a [`struct@d128`] /// Returns the cosine of a [`struct@d128`]
pub fn cos(input: d128) -> d128 { pub fn cos(input: d128) -> d128 {
let half_pi = d128!(1.570796326794896619231321691639751); let half_pi = d128!(1.570796326794896619231321691639751);
sin(half_pi - input) sin(half_pi - input)
} }
/// Returns the tangent of a [`struct@d128`] /// Returns the tangent of a [`struct@d128`]
pub fn tan(input: d128) -> d128 { pub fn tan(input: d128) -> d128 {
sin(input) / cos(input) sin(input) / cos(input)
} }
/// Evaluate an [`AstNode`] into a [`Number`] /// Evaluate an [`AstNode`] into a [`Number`]
fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> { fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
let token = &ast_node.token; let token = &ast_node.token;
let children = &ast_node.children; let children = &ast_node.children;
match token { match token {
Token::Number(number) => Ok(Number::new(*number, Unit::NoUnit)), Token::Number(number) => Ok(Number::new(*number, Unit::NoUnit)),
Token::Constant(constant) => match constant { Token::Constant(constant) => match constant {
Pi => Ok(Number::new( Pi => Ok(Number::new(
d128!(3.141592653589793238462643383279503), d128!(3.141592653589793238462643383279503),
Unit::NoUnit, Unit::NoUnit,
)), )),
E => Ok(Number::new( E => Ok(Number::new(
d128!(2.718281828459045235360287471352662), d128!(2.718281828459045235360287471352662),
Unit::NoUnit, Unit::NoUnit,
)), )),
}, },
Token::FunctionIdentifier(function) => { Token::FunctionIdentifier(function) => {
let child_node = children.get(0).ok_or("Paren has no child[0]")?; let child_node = children.get(0).ok_or("Paren has no child[0]")?;
let child_answer = evaluate_node(child_node)?; let child_answer = evaluate_node(child_node)?;
match function { match function {
Cbrt => { Cbrt => {
if child_answer.unit.category() == UnitType::NoType { if child_answer.unit.category() == UnitType::NoType {
let result = cbrt(child_answer.value); let result = cbrt(child_answer.value);
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} else { } else {
Err("log() only accepts UnitType::NoType".to_string()) Err("log() only accepts UnitType::NoType".to_string())
} }
} }
Sqrt => { Sqrt => {
if child_answer.unit.category() == UnitType::NoType { if child_answer.unit.category() == UnitType::NoType {
let result = sqrt(child_answer.value); let result = sqrt(child_answer.value);
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} else { } else {
Err("log() only accepts UnitType::NoType".to_string()) Err("log() only accepts UnitType::NoType".to_string())
} }
} }
Log => { Log => {
if child_answer.unit.category() == UnitType::NoType { if child_answer.unit.category() == UnitType::NoType {
let result = child_answer.value.log10(); let result = child_answer.value.log10();
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} else { } else {
Err("log() only accepts UnitType::NoType".to_string()) Err("log() only accepts UnitType::NoType".to_string())
} }
} }
Ln => { Ln => {
if child_answer.unit.category() == UnitType::NoType { if child_answer.unit.category() == UnitType::NoType {
let result = child_answer.value.ln(); let result = child_answer.value.ln();
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} else { } else {
Err("ln() only accepts UnitType::NoType".to_string()) Err("ln() only accepts UnitType::NoType".to_string())
} }
} }
Exp => { Exp => {
if child_answer.unit.category() == UnitType::NoType { if child_answer.unit.category() == UnitType::NoType {
let result = child_answer.value.exp(child_answer.value); let result = child_answer.value.exp(child_answer.value);
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} else { } else {
Err("exp() only accepts UnitType::NoType".to_string()) Err("exp() only accepts UnitType::NoType".to_string())
} }
} }
Round => { Round => {
// .quantize() rounds .5 to nearest even integer, so we correct that // .quantize() rounds .5 to nearest even integer, so we correct that
let mut result = child_answer.value.quantize(d128!(1)); let mut result = child_answer.value.quantize(d128!(1));
let rounding_change = result - child_answer.value; let rounding_change = result - child_answer.value;
// If the result was rounded down by 0.5, correct by +1 // If the result was rounded down by 0.5, correct by +1
if rounding_change == d128!(-0.5) { if rounding_change == d128!(-0.5) {
result += d128!(1); result += d128!(1);
} }
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} }
Ceil => { Ceil => {
let mut result = child_answer.value.quantize(d128!(1)); let mut result = child_answer.value.quantize(d128!(1));
let rounding_change = result - child_answer.value; let rounding_change = result - child_answer.value;
if rounding_change.is_negative() { if rounding_change.is_negative() {
result += d128!(1); result += d128!(1);
} }
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} }
Floor => { Floor => {
let mut result = child_answer.value.quantize(d128!(1)); let mut result = child_answer.value.quantize(d128!(1));
let rounding_change = result - child_answer.value; let rounding_change = result - child_answer.value;
if !rounding_change.is_negative() { if !rounding_change.is_negative() {
result -= d128!(1); result -= d128!(1);
} }
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} }
Abs => { Abs => {
let mut result = child_answer.value.abs(); let mut result = child_answer.value.abs();
let rounding_change = result - child_answer.value; let rounding_change = result - child_answer.value;
if rounding_change == d128!(-0.5) { if rounding_change == d128!(-0.5) {
result += d128!(1); result += d128!(1);
} }
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} }
Sin => { Sin => {
let result = sin(child_answer.value); let result = sin(child_answer.value);
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} }
Cos => { Cos => {
let result = cos(child_answer.value); let result = cos(child_answer.value);
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} }
Tan => { Tan => {
let result = tan(child_answer.value); let result = tan(child_answer.value);
Ok(Number::new(result, child_answer.unit)) Ok(Number::new(result, child_answer.unit))
} }
} }
} }
Token::Unit(unit) => { Token::Unit(unit) => {
let child_node = children.get(0).ok_or("Unit has no child[0]")?; let child_node = children.get(0).ok_or("Unit has no child[0]")?;
let child_answer = evaluate_node(child_node)?; let child_answer = evaluate_node(child_node)?;
Ok(Number::new(child_answer.value, *unit)) Ok(Number::new(child_answer.value, *unit))
} }
Token::Negative => { Token::Negative => {
let child_node = children.get(0).ok_or("Negative has no child[0]")?; let child_node = children.get(0).ok_or("Negative has no child[0]")?;
let child_answer = evaluate_node(child_node)?; let child_answer = evaluate_node(child_node)?;
Ok(Number::new(-child_answer.value, child_answer.unit)) Ok(Number::new(-child_answer.value, child_answer.unit))
} }
Token::Paren => { Token::Paren => {
let child_node = children.get(0).ok_or("Paren has no child[0]")?; let child_node = children.get(0).ok_or("Paren has no child[0]")?;
evaluate_node(child_node) evaluate_node(child_node)
} }
Token::UnaryOperator(operator) => { Token::UnaryOperator(operator) => {
let child_node = children let child_node = children
.get(0) .get(0)
.ok_or(format!("Token {:?} has no child[0]", token))?; .ok_or(format!("Token {:?} has no child[0]", token))?;
let child_answer = evaluate_node(child_node)?; let child_answer = evaluate_node(child_node)?;
match operator { match operator {
Percent => Ok(Number::new( Percent => Ok(Number::new(
child_answer.value / d128!(100), child_answer.value / d128!(100),
child_answer.unit, child_answer.unit,
)), )),
Factorial => { Factorial => {
let result = factorial(child_answer.value); let result = factorial(child_answer.value);
if result.is_nan() { if result.is_nan() {
return Err("Can only perform factorial on integers from 0 to 1000".to_string()); return Err(
} "Can only perform factorial on integers from 0 to 1000".to_string()
Ok(Number::new(result, child_answer.unit)) );
} }
} Ok(Number::new(result, child_answer.unit))
} }
Token::NamedNumber(named_number) => { }
let child_node = children }
.get(0) Token::NamedNumber(named_number) => {
.ok_or(format!("Token {:?} has no child[0]", token))?; let child_node = children
let named_number_value = lookup_named_number(named_number); .get(0)
if let Token::NamedNumber(child_nn) = &child_node.token { .ok_or(format!("Token {:?} has no child[0]", token))?;
let child_nn_value = lookup_named_number(child_nn); let named_number_value = lookup_named_number(named_number);
if child_nn_value > named_number_value { if let Token::NamedNumber(child_nn) = &child_node.token {
return Err(format!("Unexpected smaller token {:?}", token)); let child_nn_value = lookup_named_number(child_nn);
} if child_nn_value > named_number_value {
} return Err(format!("Unexpected smaller token {:?}", token));
let child_answer = evaluate_node(child_node)?; }
let result = child_answer.value * named_number_value; }
Ok(Number::new(result, child_answer.unit)) let child_answer = evaluate_node(child_node)?;
} let result = child_answer.value * named_number_value;
Token::TextOperator(operator) => { Ok(Number::new(result, child_answer.unit))
let left_child = children }
.get(0) Token::TextOperator(operator) => {
.ok_or(format!("Token {:?} has no child[0]", token))?; let left_child = children
let right_child = children .get(0)
.get(1) .ok_or(format!("Token {:?} has no child[0]", token))?;
.ok_or(format!("Token {:?} has no child[1]", token))?; let right_child = children
.get(1)
.ok_or(format!("Token {:?} has no child[1]", token))?;
match operator { match operator {
To => { To => {
if let Token::Unit(right_unit) = right_child.token { if let Token::Unit(right_unit) = right_child.token {
let left = evaluate_node(left_child)?; let left = evaluate_node(left_child)?;
let result = convert(left, right_unit)?; let result = convert(left, right_unit)?;
Ok(result) Ok(result)
} else { } else {
Err("Right side of To operator needs to be a unit".to_string()) Err("Right side of To operator needs to be a unit".to_string())
} }
} }
Of => { Of => {
let left = evaluate_node(left_child)?; let left = evaluate_node(left_child)?;
let right = evaluate_node(right_child)?; let right = evaluate_node(right_child)?;
if left.unit == Unit::NoUnit { if left.unit == Unit::NoUnit {
Ok(Number::new(left.value * right.value, right.unit)) Ok(Number::new(left.value * right.value, right.unit))
} else { } else {
Err("Left side of the Of operator must be NoUnit".to_string()) Err("Left side of the Of operator must be NoUnit".to_string())
} }
} }
} }
} }
Token::Operator(operator) => { Token::Operator(operator) => {
let left_child = children let left_child = children
.get(0) .get(0)
.ok_or(format!("Token {:?} has no child[0]", token))?; .ok_or(format!("Token {:?} has no child[0]", token))?;
let right_child = children let right_child = children
.get(1) .get(1)
.ok_or(format!("Token {:?} has no child[1]", token))?; .ok_or(format!("Token {:?} has no child[1]", token))?;
let left = evaluate_node(left_child)?; let left = evaluate_node(left_child)?;
let right = evaluate_node(right_child)?; let right = evaluate_node(right_child)?;
match operator { match operator {
Plus => Ok(add(left, right)?), Plus => Ok(add(left, right)?),
Minus => Ok(subtract(left, right)?), Minus => Ok(subtract(left, right)?),
Multiply => { Multiply => {
Ok(multiply(left, right)?) Ok(multiply(left, right)?)
// } // }
} }
Divide => { Divide => {
Ok(divide(left, right)?) Ok(divide(left, right)?)
// } // }
} }
Modulo => { Modulo => {
Ok(modulo(left, right)?) Ok(modulo(left, right)?)
// } // }
} }
Caret => { Caret => {
Ok(pow(left, right)?) Ok(pow(left, right)?)
// } // }
} }
_ => Err(format!("Unexpected operator {:?}", operator)), _ => Err(format!("Unexpected operator {:?}", operator)),
} }
} }
_ => Err(format!("Unexpected token {:?}", token)), _ => Err(format!("Unexpected token {:?}", token)),
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
#![cfg_attr( #![cfg_attr(
feature = "cargo-clippy", feature = "cargo-clippy",
allow( allow(
clippy::comparison_chain, clippy::comparison_chain,
clippy::if_same_then_else, clippy::if_same_then_else,
clippy::match_like_matches_macro, clippy::match_like_matches_macro,
) )
)] )]
//! calculation + conversion //! calculation + conversion
//! //!
@ -63,110 +63,110 @@ pub mod units;
/// }; /// };
/// ``` /// ```
pub struct Number { pub struct Number {
/// The number part of a [`Number`] struct /// The number part of a [`Number`] struct
pub value: d128, pub value: d128,
/// The unit of a [`Number`] struct. This can be [`NoType`](units::UnitType::NoType) /// The unit of a [`Number`] struct. This can be [`NoType`](units::UnitType::NoType)
pub unit: Unit, pub unit: Unit,
} }
impl Number { impl Number {
pub const fn new(value: d128, unit: Unit) -> Number { pub const fn new(value: d128, unit: Unit) -> Number {
Number { value, unit } Number { value, unit }
} }
} }
impl Display for Number { impl Display for Number {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// 0.2/0.01 results in 2E+1, but if we add zero it becomes 20 // 0.2/0.01 results in 2E+1, but if we add zero it becomes 20
let fixed_value = self.value + d128!(0); let fixed_value = self.value + d128!(0);
let output = match self.unit { let output = match self.unit {
Unit::NoUnit => format!("{}", fixed_value), Unit::NoUnit => format!("{}", fixed_value),
unit => format!("{} {:?}", fixed_value, unit), unit => format!("{} {:?}", fixed_value, unit),
}; };
write!(f, "{}", output) write!(f, "{}", output)
} }
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
/// Math operators like [`Multiply`](Operator::Multiply), parentheses, etc. /// Math operators like [`Multiply`](Operator::Multiply), parentheses, etc.
pub enum Operator { pub enum Operator {
Plus, Plus,
Minus, Minus,
Multiply, Multiply,
Divide, Divide,
Modulo, Modulo,
Caret, Caret,
LeftParen, // lexer only LeftParen, // lexer only
RightParen, // lexer only RightParen, // lexer only
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
/// Unary operators like [`Percent`](UnaryOperator::Percent) and [`Factorial`](UnaryOperator::Factorial). /// Unary operators like [`Percent`](UnaryOperator::Percent) and [`Factorial`](UnaryOperator::Factorial).
pub enum UnaryOperator { pub enum UnaryOperator {
Percent, Percent,
Factorial, Factorial,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
/// A Text operator like [`To`](TextOperator::To) or [`Of`](TextOperator::Of). /// A Text operator like [`To`](TextOperator::To) or [`Of`](TextOperator::Of).
pub enum TextOperator { pub enum TextOperator {
To, To,
Of, Of,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
/// A named number like [`Million`](NamedNumber::Million). /// A named number like [`Million`](NamedNumber::Million).
pub enum NamedNumber { pub enum NamedNumber {
Hundred, Hundred,
Thousand, Thousand,
Million, Million,
Billion, Billion,
Trillion, Trillion,
Quadrillion, Quadrillion,
Quintillion, Quintillion,
Sextillion, Sextillion,
Septillion, Septillion,
Octillion, Octillion,
Nonillion, Nonillion,
Decillion, Decillion,
Undecillion, Undecillion,
Duodecillion, Duodecillion,
Tredecillion, Tredecillion,
Quattuordecillion, Quattuordecillion,
Quindecillion, Quindecillion,
Sexdecillion, Sexdecillion,
Septendecillion, Septendecillion,
Octodecillion, Octodecillion,
Novemdecillion, Novemdecillion,
Vigintillion, Vigintillion,
Centillion, Centillion,
Googol, Googol,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
/// A constant like [`Pi`](Constant::Pi) or [`E`](Constant::E). /// A constant like [`Pi`](Constant::Pi) or [`E`](Constant::E).
pub enum Constant { pub enum Constant {
Pi, Pi,
E, E,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
/// Functions identifiers like [`Sqrt`](FunctionIdentifier::Sqrt), [`Sin`](FunctionIdentifier::Sin), [`Round`](FunctionIdentifier::Round), etc. /// Functions identifiers like [`Sqrt`](FunctionIdentifier::Sqrt), [`Sin`](FunctionIdentifier::Sin), [`Round`](FunctionIdentifier::Round), etc.
pub enum FunctionIdentifier { pub enum FunctionIdentifier {
Sqrt, Sqrt,
Cbrt, Cbrt,
Log, Log,
Ln, Ln,
Exp, Exp,
Round, Round,
Ceil, Ceil,
Floor, Floor,
Abs, Abs,
Sin, Sin,
Cos, Cos,
Tan, Tan,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -178,15 +178,15 @@ pub enum FunctionIdentifier {
/// dependingon them, turns it into a [`Percent`](UnaryOperator::Percent) or /// dependingon them, turns it into a [`Percent`](UnaryOperator::Percent) or
/// [`Modulo`](Operator::Modulo) [`Token`]. /// [`Modulo`](Operator::Modulo) [`Token`].
pub enum LexerKeyword { pub enum LexerKeyword {
Per, Per,
PercentChar, PercentChar,
In, In,
DoubleQuotes, DoubleQuotes,
Mercury, Mercury,
Hg, Hg,
PoundForce, PoundForce,
Force, Force,
Revolution, Revolution,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -194,29 +194,29 @@ pub enum LexerKeyword {
/// ///
/// Strings can be divided up into these tokens by the [`lexer`], and then put into the [`parser`]. /// Strings can be divided up into these tokens by the [`lexer`], and then put into the [`parser`].
pub enum Token { pub enum Token {
Operator(Operator), Operator(Operator),
UnaryOperator(UnaryOperator), UnaryOperator(UnaryOperator),
Number(d128), Number(d128),
FunctionIdentifier(FunctionIdentifier), FunctionIdentifier(FunctionIdentifier),
Constant(Constant), Constant(Constant),
/// Used by the parser only /// Used by the parser only
Paren, Paren,
/// Used by the lexer only /// Used by the lexer only
Per, Per,
/// Used by the parser only /// Used by the parser only
LexerKeyword(LexerKeyword), LexerKeyword(LexerKeyword),
TextOperator(TextOperator), TextOperator(TextOperator),
NamedNumber(NamedNumber), NamedNumber(NamedNumber),
/// The `-` symbol, specifically when used as `-5` and not `5-5`. Used by the parser only /// The `-` symbol, specifically when used as `-5` and not `5-5`. Used by the parser only
Negative, Negative,
Unit(units::Unit), Unit(units::Unit),
} }
#[macro_export] #[macro_export]
macro_rules! numtok { macro_rules! numtok {
( $num:literal ) => { ( $num:literal ) => {
Token::Number(d128!($num)) Token::Number(d128!($num))
}; };
} }
/// Evaluates a string into a resulting [`Number`]. /// Evaluates a string into a resulting [`Number`].
@ -237,48 +237,52 @@ macro_rules! numtok {
/// } /// }
/// ``` /// ```
pub fn eval( pub fn eval(
input: &str, input: &str,
allow_trailing_operators: bool, allow_trailing_operators: bool,
default_degree: Unit, default_degree: Unit,
verbose: bool, verbose: bool,
) -> Result<Number, String> { ) -> Result<Number, String> {
let lex_start = Instant::now(); let lex_start = Instant::now();
match lexer::lex(input, allow_trailing_operators, default_degree) { match lexer::lex(input, allow_trailing_operators, default_degree) {
Ok(tokens) => { Ok(tokens) => {
let lex_time = Instant::now().duration_since(lex_start).as_nanos() as f32; let lex_time = Instant::now().duration_since(lex_start).as_nanos() as f32;
if verbose { if verbose {
println!("Lexed TokenVector: {:?}", tokens); println!("Lexed TokenVector: {:?}", tokens);
} }
let parse_start = Instant::now(); let parse_start = Instant::now();
match parser::parse(&tokens) { match parser::parse(&tokens) {
Ok(ast) => { Ok(ast) => {
let parse_time = Instant::now().duration_since(parse_start).as_nanos() as f32; let parse_time = Instant::now().duration_since(parse_start).as_nanos() as f32;
if verbose { if verbose {
println!("Parsed AstNode: {:#?}", ast); println!("Parsed AstNode: {:#?}", ast);
} }
let eval_start = Instant::now(); let eval_start = Instant::now();
match evaluator::evaluate(&ast) { match evaluator::evaluate(&ast) {
Ok(answer) => { Ok(answer) => {
let eval_time = Instant::now().duration_since(eval_start).as_nanos() as f32; let eval_time =
Instant::now().duration_since(eval_start).as_nanos() as f32;
if verbose { if verbose {
println!("Evaluated value: {} {:?}", answer.value, answer.unit); println!("Evaluated value: {} {:?}", answer.value, answer.unit);
println!("\u{23f1} {:.3}ms lexing", lex_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 parsing", parse_time / 1000.0 / 1000.0);
println!("\u{23f1} {:.3}ms evaluation", eval_time / 1000.0 / 1000.0); println!(
} "\u{23f1} {:.3}ms evaluation",
eval_time / 1000.0 / 1000.0
);
}
Ok(answer) Ok(answer)
} }
Err(e) => Err(format!("Eval error: {}", e)), Err(e) => Err(format!("Eval error: {}", e)),
} }
} }
Err(e) => Err(format!("Parsing error: {}", e)), Err(e) => Err(format!("Parsing error: {}", e)),
} }
} }
Err(e) => Err(format!("Lexing error: {}", e)), Err(e) => Err(format!("Lexing error: {}", e)),
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -6,70 +6,70 @@ use std::process::exit;
const VERSION: &str = env!("CARGO_PKG_VERSION"); const VERSION: &str = env!("CARGO_PKG_VERSION");
fn print_help() { fn print_help() {
println!(concat!( println!(concat!(
"Usage: cpc '<expression>' [options]", "Usage: cpc '<expression>' [options]",
"\n", "\n",
"\nOptions:", "\nOptions:",
"\n --verbose Enable verbose logging", "\n --verbose Enable verbose logging",
"\n --version Show cpc version", "\n --version Show cpc version",
"\n --help Show this help page", "\n --help Show this help page",
)); ));
} }
fn get_args() -> env::Args { fn get_args() -> env::Args {
let mut args = env::args(); let mut args = env::args();
args.next(); // skip binary name args.next(); // skip binary name
args args
} }
/// CLI interface /// CLI interface
fn main() { fn main() {
// parse these first so they work if there are unexpected args // parse these first so they work if there are unexpected args
for arg in get_args() { for arg in get_args() {
match arg.as_str() { match arg.as_str() {
"--version" => { "--version" => {
println!("{}", VERSION); println!("{}", VERSION);
exit(0); exit(0);
} }
"--help" => { "--help" => {
print_help(); print_help();
exit(0); exit(0);
} }
_ => {} _ => {}
} }
} }
let mut verbose = false; let mut verbose = false;
let mut expression_opt = None; let mut expression_opt = None;
for arg in get_args() { for arg in get_args() {
match arg.as_str() { match arg.as_str() {
"-v" | "--verbose" => verbose = true, "-v" | "--verbose" => verbose = true,
_ => { _ => {
if expression_opt.is_none() { if expression_opt.is_none() {
expression_opt = Some(arg); expression_opt = Some(arg);
} else { } else {
eprintln!("Unexpected argument: {}", arg); eprintln!("Unexpected argument: {}", arg);
exit(1); exit(1);
} }
} }
} }
} }
let expression = match expression_opt { let expression = match expression_opt {
Some(expression) => expression, Some(expression) => expression,
None => { None => {
print_help(); print_help();
exit(0); exit(0);
} }
}; };
match eval(&expression, true, Unit::Celsius, verbose) { match eval(&expression, true, Unit::Celsius, verbose) {
Ok(answer) => { Ok(answer) => {
if !verbose { if !verbose {
println!("{}", answer); println!("{}", answer);
} }
} }
Err(e) => { Err(e) => {
eprintln!("{}", e); eprintln!("{}", e);
exit(1); exit(1);
} }
} }
} }

View File

@ -7,295 +7,295 @@ use crate::UnaryOperator::{Factorial, Percent};
#[derive(Debug)] #[derive(Debug)]
/// A struct with a [`Token`](AstNode::token) and [`AstNode`] [`children`](AstNode::children) /// A struct with a [`Token`](AstNode::token) and [`AstNode`] [`children`](AstNode::children)
pub struct AstNode { pub struct AstNode {
/// The children of the [`AstNode`] /// The children of the [`AstNode`]
pub children: Vec<AstNode>, pub children: Vec<AstNode>,
/// The token of the [`AstNode`] /// The token of the [`AstNode`]
pub token: Token, pub token: Token,
} }
impl AstNode { impl AstNode {
pub const fn new(token: Token) -> AstNode { pub const fn new(token: Token) -> AstNode {
AstNode { AstNode {
children: Vec::new(), children: Vec::new(),
token, token,
} }
} }
} }
/// Parse [`Token`]s into an Abstract Syntax Tree ([`AstNode`]) /// Parse [`Token`]s into an Abstract Syntax Tree ([`AstNode`])
pub fn parse(tokens: &[Token]) -> Result<AstNode, String> { pub fn parse(tokens: &[Token]) -> Result<AstNode, String> {
parse_level_1(tokens, 0).and_then(|(ast, next_pos)| { parse_level_1(tokens, 0).and_then(|(ast, next_pos)| {
if next_pos == tokens.len() { if next_pos == tokens.len() {
Ok(ast) Ok(ast)
} else { } else {
Err(format!( Err(format!(
"Expected end of input, found {:?} at {}", "Expected end of input, found {:?} at {}",
tokens[next_pos], next_pos tokens[next_pos], next_pos
)) ))
} }
}) })
} }
// level 1 precedence (lowest): to, of // level 1 precedence (lowest): to, of
/// Parse [`To`](crate::TextOperator::To) and [`Of`](crate::TextOperator::Of) /// Parse [`To`](crate::TextOperator::To) and [`Of`](crate::TextOperator::Of)
pub fn parse_level_1(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> { pub fn parse_level_1(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
// do higher precedences first, then come back down // do higher precedences first, then come back down
let (mut node, mut pos) = parse_level_2(tokens, pos)?; let (mut node, mut pos) = parse_level_2(tokens, pos)?;
// now we loop through the next tokens // now we loop through the next tokens
loop { loop {
let token = tokens.get(pos); let token = tokens.get(pos);
match token { match token {
// if there's a match, we once again do higher precedences, then come // if there's a match, we once again do higher precedences, then come
// back down again and continue the loop // back down again and continue the loop
Some(&Token::TextOperator(To)) | Some(&Token::TextOperator(Of)) => { Some(&Token::TextOperator(To)) | Some(&Token::TextOperator(Of)) => {
let (right_node, next_pos) = parse_level_2(tokens, pos + 1)?; let (right_node, next_pos) = parse_level_2(tokens, pos + 1)?;
let mut new_node = AstNode::new(token.unwrap().clone()); let mut new_node = AstNode::new(token.unwrap().clone());
new_node.children.push(node); new_node.children.push(node);
new_node.children.push(right_node); new_node.children.push(right_node);
node = new_node; node = new_node;
pos = next_pos; pos = next_pos;
} }
// if there's no match, we go down to a lower precedence (or, in this // if there's no match, we go down to a lower precedence (or, in this
// case, we're done) // case, we're done)
_ => { _ => {
return Ok((node, pos)); return Ok((node, pos));
} }
} }
} }
} }
// level 2 precedence: +, - // level 2 precedence: +, -
/// Parse [`Plus`](crate::Operator::Plus) and [`Minus`](crate::Operator::Minus) /// Parse [`Plus`](crate::Operator::Plus) and [`Minus`](crate::Operator::Minus)
pub fn parse_level_2(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> { pub fn parse_level_2(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
let (mut node, mut pos) = parse_level_3(tokens, pos)?; let (mut node, mut pos) = parse_level_3(tokens, pos)?;
loop { loop {
let token = tokens.get(pos); let token = tokens.get(pos);
match token { match token {
Some(&Token::Operator(Plus)) | Some(&Token::Operator(Minus)) => { Some(&Token::Operator(Plus)) | Some(&Token::Operator(Minus)) => {
let (right_node, next_pos) = parse_level_3(tokens, pos + 1)?; let (right_node, next_pos) = parse_level_3(tokens, pos + 1)?;
let mut new_node = AstNode::new(token.unwrap().clone()); let mut new_node = AstNode::new(token.unwrap().clone());
new_node.children.push(node); new_node.children.push(node);
new_node.children.push(right_node); new_node.children.push(right_node);
node = new_node; node = new_node;
pos = next_pos; pos = next_pos;
} }
_ => { _ => {
return Ok((node, pos)); return Ok((node, pos));
} }
} }
} }
} }
// level 3 precedence: *, /, modulo, implicative multiplication, foot-inch 6'4" // level 3 precedence: *, /, modulo, implicative multiplication, foot-inch 6'4"
/// Parse [`Multiply`](crate::Operator::Multiply), [`Divide`](crate::Operator::Divide), [`Modulo`](crate::Operator::Modulo) and implicative multiplication (for example`2pi`) /// Parse [`Multiply`](crate::Operator::Multiply), [`Divide`](crate::Operator::Divide), [`Modulo`](crate::Operator::Modulo) and implicative multiplication (for example`2pi`)
pub fn parse_level_3(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> { pub fn parse_level_3(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
// parse foot-inch syntax 6'4" // parse foot-inch syntax 6'4"
let token0 = tokens.get(pos); let token0 = tokens.get(pos);
if let Some(Token::Number(_number)) = token0 { if let Some(Token::Number(_number)) = token0 {
let token1 = tokens.get(pos + 1); let token1 = tokens.get(pos + 1);
if let Some(Token::Unit(Foot)) = token1 { if let Some(Token::Unit(Foot)) = token1 {
let token2 = tokens.get(pos + 2); let token2 = tokens.get(pos + 2);
if let Some(Token::Number(_number)) = token2 { if let Some(Token::Number(_number)) = token2 {
let token3 = tokens.get(pos + 3); let token3 = tokens.get(pos + 3);
if let Some(Token::Unit(Inch)) = token3 { if let Some(Token::Unit(Inch)) = token3 {
let new_node = AstNode { let new_node = AstNode {
children: vec![ children: vec![
AstNode { AstNode {
children: vec![AstNode::new(token0.unwrap().clone())], children: vec![AstNode::new(token0.unwrap().clone())],
token: Token::Unit(Foot), token: Token::Unit(Foot),
}, },
AstNode { AstNode {
children: vec![AstNode::new(token2.unwrap().clone())], children: vec![AstNode::new(token2.unwrap().clone())],
token: Token::Unit(Inch), token: Token::Unit(Inch),
}, },
], ],
token: Token::Operator(Plus), token: Token::Operator(Plus),
}; };
return Ok((new_node, pos + 4)); return Ok((new_node, pos + 4));
} }
} }
} }
} }
let (mut node, mut pos) = parse_level_4(tokens, pos)?; let (mut node, mut pos) = parse_level_4(tokens, pos)?;
loop { loop {
let token = tokens.get(pos); let token = tokens.get(pos);
match token { match token {
Some(&Token::Operator(Multiply)) Some(&Token::Operator(Multiply))
| Some(&Token::Operator(Divide)) | Some(&Token::Operator(Divide))
| Some(&Token::Operator(Modulo)) => { | Some(&Token::Operator(Modulo)) => {
let (right_node, next_pos) = parse_level_4(tokens, pos + 1)?; let (right_node, next_pos) = parse_level_4(tokens, pos + 1)?;
let mut new_node = AstNode::new(token.unwrap().clone()); let mut new_node = AstNode::new(token.unwrap().clone());
new_node.children.push(node); new_node.children.push(node);
new_node.children.push(right_node); new_node.children.push(right_node);
node = new_node; node = new_node;
pos = next_pos; pos = next_pos;
} }
// Below is implicative multiplication, for example '2pi'. Constants and // 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 // such will only end up here if they were unable to be parsed as part of
// other operators. // other operators.
// Note that this match statement matches an AstNode token, but the // Note that this match statement matches an AstNode token, but the
// matches nested inside check the [`Token`]s. That's why we for example // matches nested inside check the [`Token`]s. That's why we for example
// match a FunctionIdentifier, and inside that, a RightParen. // match a FunctionIdentifier, and inside that, a RightParen.
// pi2, )2 // pi2, )2
Some(&Token::Number(_)) => { Some(&Token::Number(_)) => {
let last_token = tokens.get(pos - 1); let last_token = tokens.get(pos - 1);
match last_token { match last_token {
Some(&Token::Constant(_)) | Some(&Token::Operator(RightParen)) => { Some(&Token::Constant(_)) | Some(&Token::Operator(RightParen)) => {
let (right_node, next_pos) = parse_level_4(tokens, pos)?; let (right_node, next_pos) = parse_level_4(tokens, pos)?;
let mut new_node = AstNode::new(Token::Operator(Multiply)); let mut new_node = AstNode::new(Token::Operator(Multiply));
new_node.children.push(node); new_node.children.push(node);
new_node.children.push(right_node); new_node.children.push(right_node);
node = new_node; node = new_node;
pos = next_pos; pos = next_pos;
} }
_ => { _ => {
return Ok((node, pos)); return Ok((node, pos));
} }
} }
} }
// 2pi, )pi // 2pi, )pi
Some(&Token::Constant(_)) => { Some(&Token::Constant(_)) => {
let last_token = tokens.get(pos - 1); let last_token = tokens.get(pos - 1);
match last_token { match last_token {
Some(&Token::Number(_)) | Some(&Token::Operator(RightParen)) => { Some(&Token::Number(_)) | Some(&Token::Operator(RightParen)) => {
let (right_node, next_pos) = parse_level_4(tokens, pos)?; let (right_node, next_pos) = parse_level_4(tokens, pos)?;
let mut new_node = AstNode::new(Token::Operator(Multiply)); let mut new_node = AstNode::new(Token::Operator(Multiply));
new_node.children.push(node); new_node.children.push(node);
new_node.children.push(right_node); new_node.children.push(right_node);
node = new_node; node = new_node;
pos = next_pos; pos = next_pos;
} }
_ => { _ => {
return Ok((node, pos)); return Ok((node, pos));
} }
} }
} }
// 2log(1), )log(1) // 2log(1), )log(1)
Some(&Token::FunctionIdentifier(_)) => { Some(&Token::FunctionIdentifier(_)) => {
let last_token = tokens.get(pos - 1); let last_token = tokens.get(pos - 1);
match last_token { match last_token {
Some(&Token::Number(_)) | Some(&Token::Operator(RightParen)) => { Some(&Token::Number(_)) | Some(&Token::Operator(RightParen)) => {
let (right_node, next_pos) = parse_level_4(tokens, pos)?; let (right_node, next_pos) = parse_level_4(tokens, pos)?;
let mut new_node = AstNode::new(Token::Operator(Multiply)); let mut new_node = AstNode::new(Token::Operator(Multiply));
new_node.children.push(node); new_node.children.push(node);
new_node.children.push(right_node); new_node.children.push(right_node);
node = new_node; node = new_node;
pos = next_pos; pos = next_pos;
} }
_ => { _ => {
return Ok((node, pos)); return Ok((node, pos));
} }
} }
} }
// 2(3), pi(3), )(3) // 2(3), pi(3), )(3)
Some(&Token::Operator(LeftParen)) => { Some(&Token::Operator(LeftParen)) => {
let last_token = tokens.get(pos - 1); let last_token = tokens.get(pos - 1);
match last_token { match last_token {
Some(&Token::Number(_)) Some(&Token::Number(_))
| Some(&Token::Constant(_)) | Some(&Token::Constant(_))
| Some(&Token::Operator(RightParen)) => { | Some(&Token::Operator(RightParen)) => {
let (right_node, next_pos) = parse_level_4(tokens, pos)?; let (right_node, next_pos) = parse_level_4(tokens, pos)?;
let mut new_node = AstNode::new(Token::Operator(Multiply)); let mut new_node = AstNode::new(Token::Operator(Multiply));
new_node.children.push(node); new_node.children.push(node);
new_node.children.push(right_node); new_node.children.push(right_node);
node = new_node; node = new_node;
pos = next_pos; pos = next_pos;
} }
_ => { _ => {
return Ok((node, pos)); return Ok((node, pos));
} }
} }
} }
_ => { _ => {
return Ok((node, pos)); return Ok((node, pos));
} }
} }
} }
} }
// level 4 precedence: ^ // level 4 precedence: ^
/// Parse [`Caret`](crate::Operator::Caret) /// Parse [`Caret`](crate::Operator::Caret)
pub fn parse_level_4(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> { pub fn parse_level_4(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
let (mut node, mut pos) = parse_level_5(tokens, pos)?; let (mut node, mut pos) = parse_level_5(tokens, pos)?;
loop { loop {
let token = tokens.get(pos); let token = tokens.get(pos);
match token { match token {
Some(&Token::Operator(Caret)) => { Some(&Token::Operator(Caret)) => {
let (right_node, next_pos) = parse_level_5(tokens, pos + 1)?; let (right_node, next_pos) = parse_level_5(tokens, pos + 1)?;
let mut new_node = AstNode::new(token.unwrap().clone()); let mut new_node = AstNode::new(token.unwrap().clone());
new_node.children.push(node); new_node.children.push(node);
new_node.children.push(right_node); new_node.children.push(right_node);
node = new_node; node = new_node;
pos = next_pos; pos = next_pos;
} }
_ => { _ => {
return Ok((node, pos)); return Ok((node, pos));
} }
} }
} }
} }
// level 5 precedence: - (as in -5, but not 4-5) // level 5 precedence: - (as in -5, but not 4-5)
/// Parse [`Negative`](Token::Negative) /// Parse [`Negative`](Token::Negative)
pub fn parse_level_5(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> { pub fn parse_level_5(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
// Here we parse the negative unary operator. If the current token // Here we parse the negative unary operator. If the current token
// is a minus, we wrap the right_node inside a Negative AstNode. // is a minus, we wrap the right_node inside a Negative AstNode.
// //
// Why doesn't this parse 4-5? First, we will first get a 4. In which case, // Why doesn't this parse 4-5? First, we will first get a 4. In which case,
// we just return the result of parse_level_6(), which will include the pos // we just return the result of parse_level_6(), which will include the pos
// of +. This will then go down to level 2 and be parsed as a normal minus // of +. This will then go down to level 2 and be parsed as a normal minus
// operator. // operator.
// The difference is that in other levels, we parse higher priorities // The difference is that in other levels, we parse higher priorities
// immediately, while in this one we instead check if the current token // immediately, while in this one we instead check if the current token
// is a minus, and if not, we then return the higher priority as normal. // is a minus, and if not, we then return the higher priority as normal.
let token = tokens.get(pos); let token = tokens.get(pos);
match token { match token {
Some(&Token::Operator(Minus)) => { Some(&Token::Operator(Minus)) => {
let (right_node, next_pos) = parse_level_6(tokens, pos + 1)?; let (right_node, next_pos) = parse_level_6(tokens, pos + 1)?;
let mut new_node = AstNode::new(Token::Negative); let mut new_node = AstNode::new(Token::Negative);
new_node.children.push(right_node); new_node.children.push(right_node);
Ok((new_node, next_pos)) Ok((new_node, next_pos))
} }
_ => parse_level_6(tokens, pos), _ => parse_level_6(tokens, pos),
} }
} }
// level 6 precedence: !, percent, units attached to values // level 6 precedence: !, percent, units attached to values
/// Parse [`Factorial`](crate::UnaryOperator::Factorial) and [`Percent`](crate::UnaryOperator::Percent) /// Parse [`Factorial`](crate::UnaryOperator::Factorial) and [`Percent`](crate::UnaryOperator::Percent)
pub fn parse_level_6(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> { pub fn parse_level_6(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
let (mut node, mut pos) = parse_level_7(tokens, pos)?; let (mut node, mut pos) = parse_level_7(tokens, pos)?;
loop { loop {
let token = tokens.get(pos); let token = tokens.get(pos);
match token { match token {
Some(&Token::UnaryOperator(Factorial)) Some(&Token::UnaryOperator(Factorial))
| Some(&Token::UnaryOperator(Percent)) | Some(&Token::UnaryOperator(Percent))
| Some(&Token::NamedNumber(_)) => { | Some(&Token::NamedNumber(_)) => {
// Here we are handling unary operators, aka stuff written as // Here we are handling unary operators, aka stuff written as
// "Number Operator" (3!) instead of "Number Operator Number" (3+3). // "Number Operator" (3!) instead of "Number Operator Number" (3+3).
// Therefore, if we find a match, we don't parse what comes after it. // Therefore, if we find a match, we don't parse what comes after it.
let mut new_node = AstNode::new(token.unwrap().clone()); let mut new_node = AstNode::new(token.unwrap().clone());
new_node.children.push(node); new_node.children.push(node);
node = new_node; node = new_node;
pos += 1; pos += 1;
} }
Some(&Token::Unit(_unit)) => { Some(&Token::Unit(_unit)) => {
// We won't allow units to repeat, like "1min min", so we end the loop if it's found. // 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()); let mut new_node = AstNode::new(token.unwrap().clone());
new_node.children.push(node); new_node.children.push(node);
return Ok((new_node, pos + 1)); return Ok((new_node, pos + 1));
} }
_ => { _ => {
// let's say we parse 1+2. parse_level_7 then returns 1, and token // 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 // 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. // don't do anything, and pass the number down to a lower precedence.
return Ok((node, pos)); return Ok((node, pos));
} }
} }
} }
} }
// level 7 precedence: numbers, standalone units, constants, functions, parens // level 7 precedence: numbers, standalone units, constants, functions, parens
@ -305,66 +305,68 @@ pub fn parse_level_6(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), S
/// [`FunctionIdentifier`](Token::FunctionIdentifier), /// [`FunctionIdentifier`](Token::FunctionIdentifier),
/// [`Paren`](Token::Paren) /// [`Paren`](Token::Paren)
pub fn parse_level_7(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> { pub fn parse_level_7(tokens: &[Token], pos: usize) -> Result<(AstNode, usize), String> {
let token: &Token = tokens let token: &Token = tokens
.get(pos) .get(pos)
.ok_or(format!("Unexpected end of input at {}", pos))?; .ok_or(format!("Unexpected end of input at {}", pos))?;
match token { match token {
&Token::Number(_number) => { &Token::Number(_number) => {
let node = AstNode::new(token.clone()); let node = AstNode::new(token.clone());
Ok((node, pos + 1)) Ok((node, pos + 1))
} }
&Token::Unit(_unit) => { &Token::Unit(_unit) => {
let node = AstNode::new(token.clone()); let node = AstNode::new(token.clone());
Ok((node, pos + 1)) Ok((node, pos + 1))
} }
Token::Constant(_constant) => { Token::Constant(_constant) => {
let node = AstNode::new(token.clone()); let node = AstNode::new(token.clone());
Ok((node, pos + 1)) Ok((node, pos + 1))
} }
Token::FunctionIdentifier(_function_identifier) => { Token::FunctionIdentifier(_function_identifier) => {
let left_paren_pos = pos + 1; let left_paren_pos = pos + 1;
let left_paren_token = tokens.get(left_paren_pos); let left_paren_token = tokens.get(left_paren_pos);
// check if '(' comes after function identifier, like 'log(' // check if '(' comes after function identifier, like 'log('
match left_paren_token { match left_paren_token {
Some(&Token::Operator(LeftParen)) => { Some(&Token::Operator(LeftParen)) => {
// parse everything inside as you would with normal parentheses, // parse everything inside as you would with normal parentheses,
// then put it inside an ast node. // then put it inside an ast node.
parse_level_1(tokens, left_paren_pos + 1).and_then(|(node, next_pos)| { parse_level_1(tokens, left_paren_pos + 1).and_then(|(node, next_pos)| {
if let Some(&Token::Operator(RightParen)) = tokens.get(next_pos) { if let Some(&Token::Operator(RightParen)) = tokens.get(next_pos) {
let mut function_node = AstNode::new(token.clone()); let mut function_node = AstNode::new(token.clone());
function_node.children.push(node); function_node.children.push(node);
Ok((function_node, next_pos + 1)) Ok((function_node, next_pos + 1))
} else { } else {
Err(format!( Err(format!(
"Expected closing paren at {} but found {:?}", "Expected closing paren at {} but found {:?}",
next_pos, next_pos,
tokens.get(next_pos) tokens.get(next_pos)
)) ))
} }
}) })
} }
_ => Err(format!( _ => Err(format!(
"Expected ( after {} at {:?} but found {:?}", "Expected ( after {} at {:?} but found {:?}",
left_paren_pos, token, left_paren_token left_paren_pos, token, left_paren_token
)), )),
} }
} }
Token::Operator(LeftParen) => parse_level_1(tokens, pos + 1).and_then(|(node, next_pos)| { Token::Operator(LeftParen) => {
if let Some(&Token::Operator(RightParen)) = tokens.get(next_pos) { parse_level_1(tokens, pos + 1).and_then(|(node, next_pos)| {
let mut paren_node = AstNode::new(Token::Paren); if let Some(&Token::Operator(RightParen)) = tokens.get(next_pos) {
paren_node.children.push(node); let mut paren_node = AstNode::new(Token::Paren);
Ok((paren_node, next_pos + 1)) paren_node.children.push(node);
} else { Ok((paren_node, next_pos + 1))
Err(format!( } else {
"Expected closing paren at {} but found {:?}", Err(format!(
next_pos, "Expected closing paren at {} but found {:?}",
tokens.get(next_pos) next_pos,
)) tokens.get(next_pos)
} ))
}), }
_ => Err(format!( })
"Unexpected token {:?}, expected paren or number", }
token _ => Err(format!(
)), "Unexpected token {:?}, expected paren or number",
} token
)),
}
} }

File diff suppressed because it is too large Load Diff