Skip to content

Commit

Permalink
math fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Brett Mayson committed Aug 2, 2023
1 parent b8f9f62 commit ae9447b
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 21 deletions.
3 changes: 3 additions & 0 deletions libs/config/src/parse/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use chumsky::prelude::*;

use crate::{Array, Item};

use super::value::math;

pub fn array(expand: bool) -> impl Parser<char, Array, Error = Simple<char>> {
recursive(|value| {
value
Expand All @@ -28,6 +30,7 @@ pub fn array(expand: bool) -> impl Parser<char, Array, Error = Simple<char>> {
fn array_value() -> impl Parser<char, Item, Error = Simple<char>> {
choice((
super::str::string('"').map(Item::Str),
math().map(Item::Number),
super::number::number().map(Item::Number),
))
}
Expand Down
28 changes: 28 additions & 0 deletions libs/config/src/parse/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,4 +399,32 @@ mod tests {
})
);
}

#[test]
fn math() {
assert_eq!(
property().parse("math = 1 + 1;"),
Ok(Property::Entry {
name: crate::Ident {
value: "math".to_string(),
span: 0..4,
},
value: Value::Number(crate::Number::Int32 {
value: 2,
span: 7..12,
}),
expected_array: false,
})
);
assert_eq!(
property().parse("math = 1 + one;"),
Ok(Property::MissingSemicolon(
crate::Ident {
value: "math".to_string(),
span: 0..4,
},
0..9,
))
);
}
}
19 changes: 10 additions & 9 deletions libs/config/src/parse/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,18 @@ pub fn math() -> impl Parser<char, Number, Error = Simple<char>> {
.at_least(2)
.collect::<String>()
.map(|s| s.trim().to_string())
.validate(|expr, span: Range<usize>, emit| {
.try_map(|expr, span: Range<usize>| {
let number = Number::try_evaulation(&expr, span.clone());
if number.is_none() {
emit(Simple::custom(
span,
format!("{expr} is not a valid math expression"),
));
}
number
number.map_or_else(
|| {
Err(Simple::custom(
span,
format!("{expr} is not a valid math expression"),
))
},
Ok,
)
})
.map(|number| number.expect("math expression should be valid"))
}

#[cfg(test)]
Expand Down
24 changes: 12 additions & 12 deletions libs/math/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::collections::HashMap;
use std::{collections::HashMap, str::FromStr};

pub fn eval(expression: &str) -> Option<f64> {
evaluate_postfix(&shunting_yard(expression))
evaluate_postfix(&shunting_yard(expression)?)
}

fn shunting_yard(expression: &str) -> Vec<Token> {
fn shunting_yard(expression: &str) -> Option<Vec<Token>> {
let mut output_queue: Vec<Token> = Vec::new();
let mut operator_stack: Vec<Token> = Vec::new();
let operators: HashMap<char, (u8, Associativity)> = [
Expand All @@ -19,7 +19,7 @@ fn shunting_yard(expression: &str) -> Vec<Token> {
.cloned()
.collect();

let tokens = tokenize(expression);
let tokens = tokenize(expression).ok()?;

for token in tokens {
match token {
Expand All @@ -33,7 +33,7 @@ fn shunting_yard(expression: &str) -> Vec<Token> {
|| (associativity == &Associativity::Right
&& precedence < top_precedence)
{
output_queue.push(operator_stack.pop().unwrap());
output_queue.push(operator_stack.pop()?);
continue;
}
}
Expand All @@ -58,7 +58,7 @@ fn shunting_yard(expression: &str) -> Vec<Token> {
output_queue.push(operator);
}

output_queue
Some(output_queue)
}

fn evaluate_postfix(tokens: &[Token]) -> Option<f64> {
Expand All @@ -68,8 +68,8 @@ fn evaluate_postfix(tokens: &[Token]) -> Option<f64> {
match token {
Token::Number(num) => stack.push(*num),
Token::Operator(op) => {
let right = stack.pop().unwrap();
let left = stack.pop().unwrap();
let right = stack.pop()?;
let left = stack.pop()?;
let result = match op {
'+' => left + right,
'-' => left - right,
Expand Down Expand Up @@ -102,7 +102,7 @@ enum Associativity {
Right,
}

fn tokenize(expression: &str) -> Vec<Token> {
fn tokenize(expression: &str) -> Result<Vec<Token>, <f64 as FromStr>::Err> {
let mut tokens: Vec<Token> = Vec::new();
let mut current_number = String::new();

Expand All @@ -111,7 +111,7 @@ fn tokenize(expression: &str) -> Vec<Token> {
'0'..='9' | '.' => current_number.push(c),
_ => {
if !current_number.is_empty() {
tokens.push(Token::Number(current_number.parse().unwrap()));
tokens.push(Token::Number(current_number.parse()?));
current_number.clear();
}
match c {
Expand All @@ -135,8 +135,8 @@ fn tokenize(expression: &str) -> Vec<Token> {
}

if !current_number.is_empty() {
tokens.push(Token::Number(current_number.parse().unwrap()));
tokens.push(Token::Number(current_number.parse()?));
}

tokens
Ok(tokens)
}

0 comments on commit ae9447b

Please sign in to comment.