diff --git a/src/lib.rs b/src/lib.rs index 4a92cb3..3b5a836 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ use std::error::Error; use crate::parser::tokenizer::tokenize; use crate::parser::sanitizer::sanitize_tokens; -use crate::parser::ast_builder::build_ast; +use crate::parser::ast_builder::{build_ast, Node}; pub mod parser; @@ -15,15 +15,15 @@ struct _GaussianRational { imaginary: _Rational, } -pub fn parse(query: &str) -> Result, Box> { +pub fn parse(query: &str) -> Result> { let tokens = tokenize(query)?; println!("{:?}", tokens); let sanitized_tokens = sanitize_tokens(tokens)?; println!("{:?}", sanitized_tokens); - let _ast = build_ast(sanitized_tokens); + let ast = build_ast(sanitized_tokens); + println!("{:?}", ast); - - Ok(vec![]) + Ok(ast) } fn print_reduced_form(equation: &Vec) { @@ -113,36 +113,4 @@ pub fn solve(equation: Vec) { #[cfg(test)] mod tests { use super::*; - - #[test] - fn parse_degree_0() { - let query = "5 * X^0 = 3 * X^0"; - let result: Vec = vec![2.]; - - assert_eq!(parse(query).unwrap(), result); - } - - #[test] - fn parse_degree_1() { - let query = "5 * X^0 + 3 * X^1 = 3 * X^0"; - let result: Vec = vec![2., 3.]; - - assert_eq!(parse(query).unwrap(), result); - } - - #[test] - fn parse_degree_2() { - let query = "5 * X^0 + 6 * X^1 + 8 * X^2 = 3 * X^0 - 2 * X^2"; - let result = vec![2., 6., 10.]; - - assert_eq!(parse(query).unwrap(), result); - } - - #[test] - fn parse_random_order() { - let query = "9.3 * X^3 + 4.3 * X^0 + 3.4 * X^2 - 1.5 * X^3 - 13.12 * X^1 = 1.4 * X^2 - 5.1 * X^3 + 1.4 * X^1 -6.3 * X^0"; - let result = vec![10.6, -14.52, 2., 12.9]; - - assert_eq!(parse(query).unwrap(), result); - } } diff --git a/src/main.rs b/src/main.rs index 9776ba8..535d588 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,9 +3,9 @@ use std::process; fn main() { let args: Vec = env::args().collect(); - let equation = computorv1::parse(&args[1]).unwrap_or_else(|e| { + let _equation = computorv1::parse(&args[1]).unwrap_or_else(|e| { println!("Error during parsing: {e}"); process::exit(1); }); - computorv1::solve(equation); + //computorv1::solve(equation); } diff --git a/src/parser/ast_builder.rs b/src/parser/ast_builder.rs index ffd67ec..9bb8038 100644 --- a/src/parser/ast_builder.rs +++ b/src/parser/ast_builder.rs @@ -1,10 +1,471 @@ use super::Token; -pub struct Node { - _lhs: Option>, - _rhs: Option>, +#[derive(Debug, PartialEq, Clone)] +pub struct Rational { + numerator: i128, + denominator: i128, } -pub fn build_ast(_tokens: Vec) -> Node { - Node { _lhs: None, _rhs: None } +#[derive(Debug, PartialEq, Clone)] +pub struct GaussianRational { + real: Rational, + imaginary: Rational, +} + + +#[derive(Debug, PartialEq, Clone)] +pub enum Node { + Leaf(Vec), + Internal { + operator: Token, + lhs: Box, + rhs: Box, + } +} + +/* + pub struct Node { + _lhs: Option>, + _rhs: Option>, + } + */ + +fn zero() -> GaussianRational { + GaussianRational { + real: Rational { + numerator: 0, + denominator: 1, + }, + imaginary: Rational { + numerator: 0, + denominator: 1, + } + } +} + +fn minus_one() -> GaussianRational { + GaussianRational { + real: Rational { + numerator: -1, + denominator: 1, + }, + imaginary: Rational { + numerator: 0, + denominator: 1, + } + } +} + +fn one() -> GaussianRational { + GaussianRational { + real: Rational { + numerator: 1, + denominator: 1, + }, + imaginary: Rational { + numerator: 0, + denominator: 1, + } + } +} + +fn i() -> GaussianRational { + GaussianRational { + real: Rational { + numerator: 0, + denominator: 1, + }, + imaginary: Rational { + numerator: 1, + denominator: 1, + } + } +} + +fn minus_i() -> GaussianRational { + GaussianRational { + real: Rational { + numerator: 0, + denominator: 1, + }, + imaginary: Rational { + numerator: -1, + denominator: 1, + } + } +} + +fn x() -> Vec { + vec![zero(), one()] +} + +fn minus_x() -> Vec { + vec![zero(), minus_one()] +} + +fn insert_operator_node(mut tokens: Vec, position: usize) -> Node { + let tokens_right = tokens.split_off(position + 1); + let token = tokens.pop().unwrap(); + Node::Internal { + operator: token, + lhs: Box::new(build_ast(tokens)), + rhs: Box::new(build_ast(tokens_right)), + } +} + +fn get_parentheses_map(tokens: &Vec) -> Vec { + let mut parentheses_map = vec![]; + let mut score = 0; + for token in tokens { + match token { + Token::OpenParenthesis() => score += 1, + Token::CloseParenthesis() => score -= 1, + _ => (), + } + parentheses_map.push(score); + } + parentheses_map +} + +fn parse_number(string: &String, sign: i128) -> GaussianRational { + let mut number = Rational { + numerator: 0, + denominator: 1, + }; + let mut is_floating = false; + + for c in string.chars() { + match c { + '.' => is_floating = true, + '0'..='9' => { + number.numerator = 10 * number.numerator + String::from(c).parse::().unwrap(); + if is_floating == true { + number.denominator *= 10; + } + } + _ => unreachable!(), + } + } + + number.numerator *= sign; + + GaussianRational { + real: number, + imaginary: Rational { + numerator: 0, + denominator: 1, + } + } +} + +fn check_parentheses(tokens: &Vec) -> bool { + let mut level = 0; + let mut count = 0; + for token in tokens { + match token { + Token::OpenParenthesis() => level += 1, + Token::CloseParenthesis() => level -= 1, + _ => (), + } + count += 1; + if level == 0 { + break; + } + } + + count == tokens.len() +} + +pub fn build_ast(mut tokens: Vec) -> Node { + //let mut tokens_copy = tokens.clone(); + //let mut not_done = true; + + // Lowest prio : equal + let split = tokens.iter().position(|x| x == &Token::Equal()); + if let Some(position) = split { + return insert_operator_node(tokens, position); + } + + while tokens.starts_with(&[Token::OpenParenthesis()]) && tokens.ends_with(&[Token::CloseParenthesis()]) && check_parentheses(&tokens) == true { + tokens = tokens.split_off(1); + tokens.pop(); + } + + let parentheses_map = get_parentheses_map(&tokens); + //let iter = zip(tokens, parentheses_map); + // Lowest prio : rightest minus or plus, also manages minus unary operator + let split = tokens.iter().enumerate().rposition(|(i, x)| parentheses_map[i] == 0 && (x == &Token::Addition() || x == &Token::Substraction())); + if let Some(position) = split { + let tokens_right = tokens.split_off(position + 1); + let token = tokens.pop().unwrap(); + if tokens.len() == 0 { + match &tokens_right[0] { + Token::Number(n) => return Node::Leaf(vec![parse_number(n, -1)]), + Token::ImaginaryUnit() => return Node::Leaf(vec![minus_i()]), + Token::Variable(_) => return Node::Leaf(minus_x()), + _ => (), + } + } + return Node::Internal { + operator: token, + lhs: Box::new(build_ast(tokens)), + rhs: Box::new(build_ast(tokens_right)), + } + } + + // Lowest prio : righest times or divide or modulo + let split = tokens.iter().enumerate().rposition(|(i, x)| parentheses_map[i] == 0 && (x == &Token::Multiplication() || x == &Token::Division() || x == &Token::Modulo())); + if let Some(position) = split { + return insert_operator_node(tokens, position); + } + // Lowest prio : exponentiation + let split = tokens.iter().enumerate().rposition(|(i, x)| parentheses_map[i] == 0 && x == &Token::Exponentiation()); + if let Some(position) = split { + return insert_operator_node(tokens, position); + } + + match &tokens[0] { + Token::Number(n) => return Node::Leaf(vec![parse_number(n, 1)]), + Token::ImaginaryUnit() => return Node::Leaf(vec![i()]), + Token::Variable(_) => return Node::Leaf(x()), + _ => (), + } + unreachable!(); +} + +#[cfg(test)] +mod tests { + use super::*; + + fn one_token() -> Token { + Token::Number(String::from("1")) + } + + fn two_token() -> Token { + Token::Number(String::from("2")) + } + + fn x_token() -> Token { + Token::Variable(String::from("x")) + } + + fn i_token() -> Token { + Token::ImaginaryUnit() + } + + fn open() -> Token { + Token::OpenParenthesis() + } + + fn close() -> Token { + Token::CloseParenthesis() + } + + fn plus() -> Token { + Token::Addition() + } + + fn minus() -> Token { + Token::Substraction() + } + + fn times() -> Token { + Token::Multiplication() + } + + fn divided_by() -> Token { + Token::Division() + } + + fn modulo() -> Token { + Token::Modulo() + } + + fn power() -> Token { + Token::Exponentiation() + } + + fn equals() -> Token { + Token::Equal() + } + + #[test] + fn one_equals_one() { + let tokens = vec![one_token(), equals(), one_token()]; + let results = Node::Internal { + operator: Token::Equal(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Leaf(vec![one()])) + }; + + assert_eq!(build_ast(tokens), results); + + } + + #[test] + fn one_plus_one() { + let tokens = vec![one_token(), plus(), one_token()]; + let results = Node::Internal { + operator: plus(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Leaf(vec![one()])) + }; + + assert_eq!(build_ast(tokens), results); + + let tokens = vec![one_token(), minus(), one_token()]; + let results = Node::Internal { + operator: minus(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Leaf(vec![one()])) + }; + + assert_eq!(build_ast(tokens), results); + } + + #[test] + fn one_times_one() { + let tokens = vec![one_token(), times(), one_token()]; + let results = Node::Internal { + operator: times(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Leaf(vec![one()])) + }; + assert_eq!(build_ast(tokens), results); + + let tokens = vec![one_token(), divided_by(), one_token()]; + let results = Node::Internal { + operator: divided_by(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Leaf(vec![one()])) + }; + assert_eq!(build_ast(tokens), results); + + let tokens = vec![one_token(), modulo(), one_token()]; + let results = Node::Internal { + operator: modulo(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Leaf(vec![one()])) + }; + assert_eq!(build_ast(tokens), results); + } + + #[test] + fn one_power_one() { + let tokens = vec![one_token(), power(), one_token()]; + let results = Node::Internal { + operator: power(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Leaf(vec![one()])) + }; + assert_eq!(build_ast(tokens), results); + } + + #[test] + fn left_priority() { + let tokens = vec![one_token(), plus(), one_token(), minus(), one_token()]; + let results = Node::Internal { + operator: minus(), + lhs: Box::new(Node::Internal { + operator: plus(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Leaf(vec![one()])) + }), + rhs: Box::new(Node::Leaf(vec![one()])) + }; + assert_eq!(build_ast(tokens), results); + } + + #[test] + fn operation_priority() { + let tokens = vec![one_token(), plus(), one_token(), times(), one_token()]; + let results = Node::Internal { + operator: plus(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Internal { + operator: times(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Leaf(vec![one()])) + }) + }; + assert_eq!(build_ast(tokens), results); + } + + #[test] + fn i_plus_i() { + let tokens = vec![i_token(), plus(), i_token()]; + let results = Node::Internal { + operator: plus(), + lhs: Box::new(Node::Leaf(vec![i()])), + rhs: Box::new(Node::Leaf(vec![i()])) + }; + + assert_eq!(build_ast(tokens), results); + } + + #[test] + fn x_plus_x() { + let tokens = vec![x_token(), plus(), x_token()]; + let results = Node::Internal { + operator: plus(), + lhs: Box::new(Node::Leaf(x())), + rhs: Box::new(Node::Leaf(x())) + }; + + assert_eq!(build_ast(tokens), results); + } + + #[test] + fn parentheses() { + let tokens = vec![one_token(), times(), open(), one_token(), plus(), one_token(), close()]; + let results = Node::Internal { + operator: times(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Internal { + operator: plus(), + lhs: Box::new(Node::Leaf(vec![one()])), + rhs: Box::new(Node::Leaf(vec![one()])) + }) + }; + assert_eq!(build_ast(tokens), results); + } + + #[test] + fn two_plus_two() { + let mut two = one(); + two.real.numerator = 2; + + let tokens = vec![two_token(), plus(), two_token()]; + let results = Node::Internal { + operator: plus(), + lhs: Box::new(Node::Leaf(vec![two.clone()])), + rhs: Box::new(Node::Leaf(vec![two.clone()])) + }; + + assert_eq!(build_ast(tokens), results); + + let tokens = vec![two_token(), minus(), one_token()]; + let results = Node::Internal { + operator: minus(), + lhs: Box::new(Node::Leaf(vec![two])), + rhs: Box::new(Node::Leaf(vec![one()])) + }; + + assert_eq!(build_ast(tokens), results); + } + + #[test] + fn negative_one() { + let tokens = vec![minus(), one_token()]; + let results = Node::Leaf(vec![minus_one()]); + assert_eq!(build_ast(tokens), results); + + let tokens = vec![minus(), x_token()]; + let results = Node::Leaf(minus_x()); + assert_eq!(build_ast(tokens), results); + + let tokens = vec![minus(), i_token()]; + let results = Node::Leaf(vec![minus_i()]); + assert_eq!(build_ast(tokens), results); + } }