feat(parser::ast_builder): ast_builder passes

This commit is contained in:
gbrochar 2023-08-02 22:18:52 +02:00
parent 484e82c847
commit b1eb997703
3 changed files with 473 additions and 44 deletions

View File

@ -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<Vec<f64>, Box<dyn Error>> {
pub fn parse(query: &str) -> Result<Node, Box<dyn Error>> {
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<f64>) {
@ -113,36 +113,4 @@ pub fn solve(equation: Vec<f64>) {
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_degree_0() {
let query = "5 * X^0 = 3 * X^0";
let result: Vec<f64> = 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<f64> = 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);
}
}

View File

@ -3,9 +3,9 @@ use std::process;
fn main() {
let args: Vec<String> = 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);
}

View File

@ -1,10 +1,471 @@
use super::Token;
#[derive(Debug, PartialEq, Clone)]
pub struct Rational {
numerator: i128,
denominator: i128,
}
#[derive(Debug, PartialEq, Clone)]
pub struct GaussianRational {
real: Rational,
imaginary: Rational,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Node {
Leaf(Vec<GaussianRational>),
Internal {
operator: Token,
lhs: Box<Node>,
rhs: Box<Node>,
}
}
/*
pub struct Node {
_lhs: Option<Box<Node>>,
_rhs: Option<Box<Node>>,
}
*/
pub fn build_ast(_tokens: Vec<Token>) -> Node {
Node { _lhs: None, _rhs: None }
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<GaussianRational> {
vec![zero(), one()]
}
fn minus_x() -> Vec<GaussianRational> {
vec![zero(), minus_one()]
}
fn insert_operator_node(mut tokens: Vec<Token>, 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<Token>) -> Vec<usize> {
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::<i128>().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<Token>) -> 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<Token>) -> 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);
}
}