Evaluation of plus and minus
This commit is contained in:
parent
c247b6c899
commit
8fcd76a098
79
src/evaluator.rs
Normal file
79
src/evaluator.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use decimal::d128;
|
||||||
|
use crate::Token;
|
||||||
|
use crate::units::Unit;
|
||||||
|
use crate::parser::AstNode;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use crate::Operator::{Percent, Caret, Divide, Factorial, LeftParen, Minus, Modulo, Multiply, Plus, RightParen};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Answer {
|
||||||
|
value: d128,
|
||||||
|
unit: Unit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Answer {
|
||||||
|
pub fn new(value: d128, unit: Unit) -> Answer {
|
||||||
|
Answer {
|
||||||
|
value: value,
|
||||||
|
unit: unit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn evaluate(ast: &AstNode) -> Result<Answer, String> {
|
||||||
|
let answer = evaluate_node(ast)?;
|
||||||
|
Ok(answer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn evaluate_node(ast_node: &AstNode) -> Result<Answer, String> {
|
||||||
|
let token = &ast_node.token;
|
||||||
|
let children = &ast_node.children;
|
||||||
|
match token {
|
||||||
|
Token::Number(number) => {
|
||||||
|
Ok(Answer::new(number.clone(), Unit::NoUnit))
|
||||||
|
},
|
||||||
|
Token::Unit(unit) => {
|
||||||
|
let child_node = ast_node.children.get(0).expect("Unit has no child[0]");
|
||||||
|
let child_answer = evaluate_node(child_node)?;
|
||||||
|
Ok(Answer::new(child_answer.value, unit.clone()))
|
||||||
|
},
|
||||||
|
Token::Paren => {
|
||||||
|
let child_node = ast_node.children.get(0).expect("Paren has no child[0]");
|
||||||
|
return evaluate_node(child_node)
|
||||||
|
},
|
||||||
|
Token::Operator(operator) => {
|
||||||
|
let left_child = children.get(0).expect(format!("Token {:?} has no child[0]", token).as_str());
|
||||||
|
let right_child = children.get(1).expect(format!("Token {:?} has no child[1]", token).as_str());
|
||||||
|
let left = evaluate_node(left_child)?;
|
||||||
|
let right = evaluate_node(right_child)?;
|
||||||
|
match operator {
|
||||||
|
Plus => {
|
||||||
|
if left.unit == right.unit {
|
||||||
|
Ok(Answer::new(left.value + right.value, left.unit))
|
||||||
|
} else if left.unit.category() == right.unit.category() {
|
||||||
|
let result = left.value * left.unit.weight() + right.value * right.unit.weight();
|
||||||
|
Ok(Answer::new(result, Unit::Millimeter))
|
||||||
|
} else {
|
||||||
|
return Err(format!("Cannot add {:?} and {:?}", left.unit, right.unit))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Minus => {
|
||||||
|
if left.unit == right.unit {
|
||||||
|
Ok(Answer::new(left.value - right.value, left.unit))
|
||||||
|
} else if left.unit.category() == right.unit.category() {
|
||||||
|
let result = left.value * left.unit.weight() - right.value * right.unit.weight();
|
||||||
|
Ok(Answer::new(result, Unit::Millimeter))
|
||||||
|
} else {
|
||||||
|
return Err(format!("Cannot subtract {:?} and {:?}", left.unit, right.unit))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
Err(format!("Unexpected operator {:?}", operator))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
Err(format!("Unexpected ast node {:?}", token))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,7 @@ use crate::Operator::{Percent, Caret, Divide, Factorial, LeftParen, Minus, Modul
|
|||||||
use crate::TextOperator::{Of, To};
|
use crate::TextOperator::{Of, To};
|
||||||
use crate::Constant::{E, Pi};
|
use crate::Constant::{E, Pi};
|
||||||
use crate::FunctionIdentifier::{Acos, Acosh, Asin, Asinh, Atan, Atanh, Cbrt, Ceil, Cos, Cosh, Exp, Fabs, Floor, Ln, Log, Round, Sin, Sinh, Sqrt, Tan, Tanh};
|
use crate::FunctionIdentifier::{Acos, Acosh, Asin, Asinh, Atan, Atanh, Cbrt, Ceil, Cos, Cosh, Exp, Fabs, Floor, Ln, Log, Round, Sin, Sinh, Sqrt, Tan, Tanh};
|
||||||
use crate::Unit::*;
|
use crate::units::Unit::*;
|
||||||
|
|
||||||
pub fn lex(input: &str) -> Result<TokenVector, String> {
|
pub fn lex(input: &str) -> Result<TokenVector, String> {
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ pub fn lex(input: &str) -> Result<TokenVector, String> {
|
|||||||
"yr" | "year" | "years" => tokens.push(Token::Unit(Year)),
|
"yr" | "year" | "years" => tokens.push(Token::Unit(Year)),
|
||||||
"decade" | "decades" => tokens.push(Token::Unit(Decade)),
|
"decade" | "decades" => tokens.push(Token::Unit(Decade)),
|
||||||
"century" | "centuries" => tokens.push(Token::Unit(Century)),
|
"century" | "centuries" => tokens.push(Token::Unit(Century)),
|
||||||
"millenium" | "milleniums" => tokens.push(Token::Unit(Milleniums)),
|
"millenium" | "millenia" | "milleniums" => tokens.push(Token::Unit(Millenium)),
|
||||||
|
|
||||||
"mm" | "millimeter" | "millimeters" => tokens.push(Token::Unit(Millimeter)),
|
"mm" | "millimeter" | "millimeters" => tokens.push(Token::Unit(Millimeter)),
|
||||||
"cm" | "centimeter" | "centimeters" => tokens.push(Token::Unit(Centimeter)),
|
"cm" | "centimeter" | "centimeters" => tokens.push(Token::Unit(Centimeter)),
|
||||||
|
|||||||
66
src/main.rs
66
src/main.rs
@ -8,8 +8,8 @@ pub enum Operator {
|
|||||||
Multiply,
|
Multiply,
|
||||||
Divide,
|
Divide,
|
||||||
Modulo,
|
Modulo,
|
||||||
Percent,
|
|
||||||
Caret,
|
Caret,
|
||||||
|
Percent,
|
||||||
Factorial,
|
Factorial,
|
||||||
LeftParen, // lexer only
|
LeftParen, // lexer only
|
||||||
RightParen, // lexer only
|
RightParen, // lexer only
|
||||||
@ -55,42 +55,7 @@ pub enum FunctionIdentifier {
|
|||||||
Atanh,
|
Atanh,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
mod units;
|
||||||
pub enum Unit {
|
|
||||||
Nanosecond,
|
|
||||||
Microsecond,
|
|
||||||
Millisecond,
|
|
||||||
Second,
|
|
||||||
Minute,
|
|
||||||
Hour,
|
|
||||||
Day,
|
|
||||||
Week,
|
|
||||||
Month,
|
|
||||||
Quarter,
|
|
||||||
Year,
|
|
||||||
Decade,
|
|
||||||
Century,
|
|
||||||
Milleniums,
|
|
||||||
|
|
||||||
Millimeter,
|
|
||||||
Centimeter,
|
|
||||||
Decimeter,
|
|
||||||
Meter,
|
|
||||||
Kilometer,
|
|
||||||
Inch,
|
|
||||||
Foot,
|
|
||||||
Yard,
|
|
||||||
Mile,
|
|
||||||
NauticalMile,
|
|
||||||
|
|
||||||
SquareMeter,
|
|
||||||
// etc
|
|
||||||
|
|
||||||
CubicMeter,
|
|
||||||
//etc
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
@ -101,13 +66,14 @@ pub enum Token {
|
|||||||
Paren, // parser only
|
Paren, // parser only
|
||||||
TextOperator(TextOperator),
|
TextOperator(TextOperator),
|
||||||
Negative, // parser only
|
Negative, // parser only
|
||||||
Unit(Unit),
|
Unit(units::Unit),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type TokenVector = Vec<Token>;
|
pub type TokenVector = Vec<Token>;
|
||||||
|
|
||||||
mod lexer;
|
mod lexer;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
mod evaluator;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let lex_start = Instant::now();
|
let lex_start = Instant::now();
|
||||||
@ -119,20 +85,32 @@ fn main() {
|
|||||||
match lexer::lex(s) {
|
match lexer::lex(s) {
|
||||||
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;
|
||||||
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;
|
||||||
println!("Parsed AstNode: {:#?}", ast);
|
// println!("Parsed AstNode: {:#?}", ast);
|
||||||
println!("\u{23f1} {:.3}ms lexing", lex_time/1000.0/1000.0);
|
|
||||||
println!("\u{23f1} {:.3}ms parsing", parse_time/1000.0/1000.0);
|
let eval_start = Instant::now();
|
||||||
|
match evaluator::evaluate(&ast) {
|
||||||
|
Ok(answer) => {
|
||||||
|
let eval_time = Instant::now().duration_since(eval_start).as_nanos() as f32;
|
||||||
|
println!("Evaluated answer: {:#?}", answer);
|
||||||
|
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
Err(e) => println!("Eval error: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
Err(e) => println!("parsing error: {}", e),
|
Err(e) => println!("Parsing error: {}", e),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => println!("lexing error: {}", e),
|
Err(e) => println!("Lexing error: {}", e),
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
use crate::{Token, TokenVector};
|
use crate::{Token, TokenVector};
|
||||||
#[allow(unused_imports)]
|
|
||||||
use crate::Operator::{Percent, Caret, Divide, Factorial, LeftParen, Minus, Modulo, Multiply, Plus, RightParen};
|
use crate::Operator::{Percent, Caret, Divide, Factorial, LeftParen, Minus, Modulo, Multiply, Plus, RightParen};
|
||||||
use crate::TextOperator::{To, Of};
|
use crate::TextOperator::{To, Of};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AstNode {
|
pub struct AstNode {
|
||||||
children: Vec<AstNode>,
|
pub children: Vec<AstNode>,
|
||||||
token: Token,
|
pub token: Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AstNode {
|
impl AstNode {
|
||||||
|
|||||||
94
src/units.rs
Normal file
94
src/units.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use decimal::d128;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
pub enum UnitType {
|
||||||
|
NoUnit,
|
||||||
|
Time,
|
||||||
|
Length,
|
||||||
|
Area,
|
||||||
|
Volume,
|
||||||
|
}
|
||||||
|
use UnitType::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
pub enum Unit {
|
||||||
|
NoUnit,
|
||||||
|
|
||||||
|
Nanosecond,
|
||||||
|
Microsecond,
|
||||||
|
Millisecond,
|
||||||
|
Second,
|
||||||
|
Minute,
|
||||||
|
Hour,
|
||||||
|
Day,
|
||||||
|
Week,
|
||||||
|
Month,
|
||||||
|
Quarter,
|
||||||
|
Year,
|
||||||
|
Decade,
|
||||||
|
Century,
|
||||||
|
Millenium,
|
||||||
|
|
||||||
|
Millimeter,
|
||||||
|
Centimeter,
|
||||||
|
Decimeter,
|
||||||
|
Meter,
|
||||||
|
Kilometer,
|
||||||
|
Inch,
|
||||||
|
Foot,
|
||||||
|
Yard,
|
||||||
|
Mile,
|
||||||
|
NauticalMile,
|
||||||
|
|
||||||
|
SquareMeter,
|
||||||
|
// etc
|
||||||
|
|
||||||
|
CubicMeter,
|
||||||
|
// etc
|
||||||
|
}
|
||||||
|
use Unit::*;
|
||||||
|
|
||||||
|
fn get_info(unit: &Unit) -> (UnitType, d128) {
|
||||||
|
match unit {
|
||||||
|
Unit::NoUnit => (UnitType::NoUnit, d128!(1)),
|
||||||
|
|
||||||
|
Nanosecond => (Time, d128!(1)),
|
||||||
|
Microsecond => (Time, d128!(1000)),
|
||||||
|
Millisecond => (Time, d128!(1000000)),
|
||||||
|
Second => (Time, d128!(1000000000)),
|
||||||
|
Minute => (Time, d128!(60000000000)),
|
||||||
|
Hour => (Time, d128!(3600000000000)),
|
||||||
|
Day => (Time, d128!(86400000000000)),
|
||||||
|
Week => (Time, d128!(604800000000000)),
|
||||||
|
Month => (Time, d128!(2629746000000000)),
|
||||||
|
Quarter => (Time, d128!(7889238000000000)),
|
||||||
|
Year => (Time, d128!(31556952000000000)),
|
||||||
|
Decade => (Time, d128!(315569520000000000)),
|
||||||
|
Century => (Time, d128!(3155695200000000000)),
|
||||||
|
Millenium => (Time, d128!(31556952000000000000)),
|
||||||
|
|
||||||
|
Millimeter => (Length, d128!(10)),
|
||||||
|
Centimeter => (Length, d128!(100)),
|
||||||
|
Decimeter => (Length, d128!(1000)),
|
||||||
|
Meter => (Length, d128!(10000)),
|
||||||
|
Kilometer => (Length, d128!(10000000)),
|
||||||
|
Inch => (Length, d128!(254)),
|
||||||
|
Foot => (Length, d128!(3048)),
|
||||||
|
Yard => (Length, d128!(9144)),
|
||||||
|
Mile => (Length, d128!(16090000)),
|
||||||
|
NauticalMile => (Length, d128!(18520000)),
|
||||||
|
|
||||||
|
SquareMeter => (UnitType::Area, d128!(1)),
|
||||||
|
|
||||||
|
CubicMeter => (UnitType::Volume, d128!(1)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Unit {
|
||||||
|
pub fn category(&self) -> UnitType {
|
||||||
|
return get_info(self).0
|
||||||
|
}
|
||||||
|
pub fn weight(&self) -> d128 {
|
||||||
|
return get_info(self).1
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user