refactor
This commit is contained in:
parent
ba6f572d6b
commit
5b03990d38
1 changed files with 97 additions and 86 deletions
183
src/main.rs
183
src/main.rs
|
@ -1,8 +1,8 @@
|
|||
use std::io;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum Symbol {
|
||||
Number { value: u64 },
|
||||
Number(f64),
|
||||
LeftBracket,
|
||||
RightBracket,
|
||||
Add,
|
||||
|
@ -17,32 +17,32 @@ enum Node {
|
|||
Add { left: Box<Node>, right: Box<Node> },
|
||||
Sub { left: Box<Node>, right: Box<Node> },
|
||||
Mul { left: Box<Node>, right: Box<Node> },
|
||||
Number { value: u64 },
|
||||
Div { left: Box<Node>, right: Box<Node> },
|
||||
Number(f64),
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eval() {
|
||||
let node_to_eval = Node::Add {
|
||||
left: Box::new(Node::Add {
|
||||
left: Box::new(Node::Number { value: 1 }),
|
||||
right: Box::new(Node::Number { value: 1 }),
|
||||
left: Box::new(Node::Number(1.0)),
|
||||
right: Box::new(Node::Number(1.0)),
|
||||
}),
|
||||
right: Box::new(Node::Number { value: 3 }),
|
||||
right: Box::new(Node::Number(3.0)),
|
||||
};
|
||||
|
||||
let result = eval(&node_to_eval);
|
||||
|
||||
assert!(result == 5_i64);
|
||||
assert!((result - 5.0_f64).abs() < 0.00000000000000000001);
|
||||
}
|
||||
|
||||
fn eval(expr: &Node) -> i64 {
|
||||
fn eval(expr: &Node) -> f64 {
|
||||
match expr {
|
||||
Node::Add { left, right } => eval(left) + eval(right),
|
||||
Node::Sub { left, right } => eval(left) - eval(right),
|
||||
Node::Mul { left, right } => eval(left) * eval(right),
|
||||
Node::Number { value } => {
|
||||
Node::Div { left, right } => eval(left) / eval(right),
|
||||
Node::Number(value) => {
|
||||
// println!("Evaling number {value}");
|
||||
*value as i64
|
||||
*value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ fn eval(expr: &Node) -> i64 {
|
|||
#[derive(Debug)]
|
||||
enum ParseError {
|
||||
WrongTokenError { pos: usize },
|
||||
WrongNumberError { pos: usize },
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -58,16 +59,17 @@ fn main() {
|
|||
match tokenize(&user_input) {
|
||||
Ok(tokenized_input) => {
|
||||
// for el in &tokenized_input {
|
||||
// println!("lol {:?}", el);
|
||||
// println!("lol {:?}", el);
|
||||
// }
|
||||
let ast = ast(tokenized_input);
|
||||
// println!("{:?}", ast);
|
||||
// println!(" test {:?}", ast);
|
||||
match ast {
|
||||
Ok(ast) => {
|
||||
let evaled = eval(&ast);
|
||||
println!("{}", evaled);
|
||||
println!("{}\n", evaled);
|
||||
}
|
||||
_ => {
|
||||
// println!("lol");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +81,13 @@ fn main() {
|
|||
println!("^");
|
||||
println!("Syntax Error\n");
|
||||
}
|
||||
Err(ParseError::WrongNumberError { pos }) => {
|
||||
for _ in 0..pos {
|
||||
print!("-");
|
||||
}
|
||||
println!("^");
|
||||
println!("Your Number is invalid HERE\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,31 +105,11 @@ fn try_tokenizing() {
|
|||
let tokenized_input: Vec<Vec<Symbol>> = input.iter().map(|s| tokenize(s).unwrap()).collect();
|
||||
|
||||
let result: Vec<Vec<Symbol>> = vec![
|
||||
vec![
|
||||
Symbol::Number { value: 1 },
|
||||
Symbol::Add,
|
||||
Symbol::Number { value: 2 },
|
||||
],
|
||||
vec![
|
||||
Symbol::Number { value: 3 },
|
||||
Symbol::Sub,
|
||||
Symbol::Number { value: 4 },
|
||||
],
|
||||
vec![
|
||||
Symbol::Number { value: 5 },
|
||||
Symbol::Mul,
|
||||
Symbol::Number { value: 6 },
|
||||
],
|
||||
vec![
|
||||
Symbol::Number { value: 7 },
|
||||
Symbol::Div,
|
||||
Symbol::Number { value: 8 },
|
||||
],
|
||||
vec![
|
||||
Symbol::Number { value: 8 },
|
||||
Symbol::Exp,
|
||||
Symbol::Number { value: 9 },
|
||||
],
|
||||
vec![Symbol::Number(1.0), Symbol::Add, Symbol::Number(2.0)],
|
||||
vec![Symbol::Number(3.0), Symbol::Sub, Symbol::Number(4.0)],
|
||||
vec![Symbol::Number(5.0), Symbol::Mul, Symbol::Number(6.0)],
|
||||
vec![Symbol::Number(7.0), Symbol::Div, Symbol::Number(8.0)],
|
||||
vec![Symbol::Number(8.0), Symbol::Exp, Symbol::Number(9.0)],
|
||||
];
|
||||
assert!(tokenized_input == result);
|
||||
}
|
||||
|
@ -131,17 +120,16 @@ fn tokenize(input: &str) -> Result<Vec<Symbol>, ParseError> {
|
|||
|
||||
for (i, c) in input.chars().enumerate() {
|
||||
if !c.is_ascii_digit() && !acc.is_empty() {
|
||||
tokens.push(Symbol::Number {
|
||||
value: acc
|
||||
.parse()
|
||||
.map_err(|_| ParseError::WrongTokenError { pos: 1 })?,
|
||||
});
|
||||
acc.clear();
|
||||
if let Ok(num) = acc.parse() {
|
||||
tokens.push(Symbol::Number(num));
|
||||
acc.clear();
|
||||
} else {
|
||||
return Err(ParseError::WrongNumberError { pos: i });
|
||||
}
|
||||
};
|
||||
match c {
|
||||
'0'..='9' => {
|
||||
acc.push(c);
|
||||
continue;
|
||||
}
|
||||
' ' => continue,
|
||||
'(' => tokens.push(Symbol::LeftBracket),
|
||||
|
@ -156,63 +144,86 @@ fn tokenize(input: &str) -> Result<Vec<Symbol>, ParseError> {
|
|||
}
|
||||
}
|
||||
if !acc.is_empty() {
|
||||
tokens.push(Symbol::Number {
|
||||
value: acc
|
||||
.parse()
|
||||
.map_err(|_| ParseError::WrongTokenError { pos: 1 })?,
|
||||
});
|
||||
}
|
||||
if let Ok(num) = acc.parse() {
|
||||
tokens.push(Symbol::Number(num));
|
||||
} else {
|
||||
return Err(ParseError::WrongNumberError { pos: 0 });
|
||||
}
|
||||
};
|
||||
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
fn ast(input: Vec<Symbol>) -> Result<Node, ParseError> {
|
||||
fn ast(mut input: Vec<Symbol>) -> Result<Node, ParseError> {
|
||||
let mut stack = Vec::<Node>::new();
|
||||
// println!("{}", input.len());
|
||||
let length = input.len();
|
||||
let mut i = 0;
|
||||
|
||||
if length == 1 {
|
||||
if let Symbol::Number(num) = input[0] {
|
||||
return Ok(Node::Number(num));
|
||||
} else {
|
||||
return Err(ParseError::WrongTokenError { pos: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
while i < length {
|
||||
let s = &input[i];
|
||||
match s {
|
||||
Symbol::Number { value } => {
|
||||
stack.push(Node::Number { value: *value });
|
||||
}
|
||||
Symbol::Add => {
|
||||
let left = stack.pop();
|
||||
// increment
|
||||
let right = input.get(i + 1);
|
||||
i += 1;
|
||||
|
||||
match (left, right) {
|
||||
(Some(left), Some(right)) => {
|
||||
match right {
|
||||
Symbol::Number { value } => {
|
||||
stack.push(Node::Add {
|
||||
left: (Box::new(left)),
|
||||
right: (Box::new(Node::Number { value: *value })),
|
||||
});
|
||||
}
|
||||
_ => return Err(ParseError::WrongTokenError { pos: 1 }),
|
||||
}
|
||||
{}
|
||||
}
|
||||
_ => {
|
||||
return Err(ParseError::WrongTokenError { pos: 1 });
|
||||
}
|
||||
Symbol::Add | Symbol::Sub | Symbol::Mul | Symbol::Div => {
|
||||
if let Ok(n) = push_to_ast(&mut input, &mut i) {
|
||||
stack.push(n);
|
||||
} else {
|
||||
return Err(ParseError::WrongTokenError { pos: i });
|
||||
}
|
||||
}
|
||||
Symbol::Sub => {}
|
||||
Symbol::Mul => {}
|
||||
Symbol::Div => {}
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
i += 1;
|
||||
i += 1
|
||||
}
|
||||
if stack.len() != 1 {
|
||||
return Err(ParseError::WrongTokenError { pos: 1 });
|
||||
}
|
||||
Ok(stack[0].clone())
|
||||
}
|
||||
|
||||
fn push_to_ast(input: &mut [Symbol], index: &mut usize) -> Result<Node, ParseError> {
|
||||
let left = input.get(*index - 1);
|
||||
let op = input.get(*index);
|
||||
let right = input.get(*index + 1);
|
||||
*index += 1;
|
||||
|
||||
if let (Some(op), Some(l), Some(r)) = (op, left, right) {
|
||||
if let (Symbol::Number(le), Symbol::Number(ri)) = (l, r) {
|
||||
match op {
|
||||
Symbol::Add => {
|
||||
return Ok(Node::Add {
|
||||
left: Box::new(Node::Number(*le)),
|
||||
right: Box::new(Node::Number(*ri)),
|
||||
});
|
||||
}
|
||||
Symbol::Sub => {
|
||||
return Ok(Node::Sub {
|
||||
left: Box::new(Node::Number(*le)),
|
||||
right: Box::new(Node::Number(*ri)),
|
||||
});
|
||||
}
|
||||
Symbol::Mul => {
|
||||
return Ok(Node::Mul {
|
||||
left: Box::new(Node::Number(*le)),
|
||||
right: Box::new(Node::Number(*ri)),
|
||||
});
|
||||
}
|
||||
Symbol::Div => {
|
||||
return Ok(Node::Div {
|
||||
left: Box::new(Node::Number(*le)),
|
||||
right: Box::new(Node::Number(*ri)),
|
||||
});
|
||||
}
|
||||
_ => return Err(ParseError::WrongTokenError { pos: 16 }),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(ParseError::WrongTokenError { pos: 1 })
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue