feat(parser::ast_builder): ast_builder passes
This commit is contained in:
parent
484e82c847
commit
b1eb997703
42
src/lib.rs
42
src/lib.rs
|
@ -1,7 +1,7 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use crate::parser::tokenizer::tokenize;
|
use crate::parser::tokenizer::tokenize;
|
||||||
use crate::parser::sanitizer::sanitize_tokens;
|
use crate::parser::sanitizer::sanitize_tokens;
|
||||||
use crate::parser::ast_builder::build_ast;
|
use crate::parser::ast_builder::{build_ast, Node};
|
||||||
|
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
|
||||||
|
@ -15,15 +15,15 @@ struct _GaussianRational {
|
||||||
imaginary: _Rational,
|
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)?;
|
let tokens = tokenize(query)?;
|
||||||
println!("{:?}", tokens);
|
println!("{:?}", tokens);
|
||||||
let sanitized_tokens = sanitize_tokens(tokens)?;
|
let sanitized_tokens = sanitize_tokens(tokens)?;
|
||||||
println!("{:?}", sanitized_tokens);
|
println!("{:?}", sanitized_tokens);
|
||||||
let _ast = build_ast(sanitized_tokens);
|
let ast = build_ast(sanitized_tokens);
|
||||||
|
println!("{:?}", ast);
|
||||||
|
|
||||||
|
Ok(ast)
|
||||||
Ok(vec![])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_reduced_form(equation: &Vec<f64>) {
|
fn print_reduced_form(equation: &Vec<f64>) {
|
||||||
|
@ -113,36 +113,4 @@ pub fn solve(equation: Vec<f64>) {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ use std::process;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
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}");
|
println!("Error during parsing: {e}");
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
});
|
});
|
||||||
computorv1::solve(equation);
|
//computorv1::solve(equation);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,471 @@
|
||||||
use super::Token;
|
use super::Token;
|
||||||
|
|
||||||
pub struct Node {
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
_lhs: Option<Box<Node>>,
|
pub struct Rational {
|
||||||
_rhs: Option<Box<Node>>,
|
numerator: i128,
|
||||||
|
denominator: i128,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_ast(_tokens: Vec<Token>) -> Node {
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
Node { _lhs: None, _rhs: None }
|
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>>,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue