This commit is contained in:
Charlie Root 2025-04-01 17:34:02 +02:00
commit 5b03990d38
Signed by: faukah
SSH key fingerprint: SHA256:Uj2AXqvtdCA4hn5Hq0ZonhIAyUqI1q4w2sMG3Z1TH7E

View file

@ -1,8 +1,8 @@
use std::io; use std::io;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
enum Symbol { enum Symbol {
Number { value: u64 }, Number(f64),
LeftBracket, LeftBracket,
RightBracket, RightBracket,
Add, Add,
@ -17,32 +17,32 @@ enum Node {
Add { left: Box<Node>, right: Box<Node> }, Add { left: Box<Node>, right: Box<Node> },
Sub { left: Box<Node>, right: Box<Node> }, Sub { left: Box<Node>, right: Box<Node> },
Mul { 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] #[test]
fn test_eval() { fn test_eval() {
let node_to_eval = Node::Add { let node_to_eval = Node::Add {
left: Box::new(Node::Add { left: Box::new(Node::Add {
left: Box::new(Node::Number { value: 1 }), left: Box::new(Node::Number(1.0)),
right: Box::new(Node::Number { value: 1 }), 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); let result = eval(&node_to_eval);
assert!((result - 5.0_f64).abs() < 0.00000000000000000001);
assert!(result == 5_i64);
} }
fn eval(expr: &Node) -> i64 { fn eval(expr: &Node) -> f64 {
match expr { match expr {
Node::Add { left, right } => eval(left) + eval(right), Node::Add { left, right } => eval(left) + eval(right),
Node::Sub { left, right } => eval(left) - eval(right), Node::Sub { left, right } => eval(left) - eval(right),
Node::Mul { 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}"); // println!("Evaling number {value}");
*value as i64 *value
} }
} }
} }
@ -50,6 +50,7 @@ fn eval(expr: &Node) -> i64 {
#[derive(Debug)] #[derive(Debug)]
enum ParseError { enum ParseError {
WrongTokenError { pos: usize }, WrongTokenError { pos: usize },
WrongNumberError { pos: usize },
} }
fn main() { fn main() {
@ -58,16 +59,17 @@ fn main() {
match tokenize(&user_input) { match tokenize(&user_input) {
Ok(tokenized_input) => { Ok(tokenized_input) => {
// for el in &tokenized_input { // for el in &tokenized_input {
// println!("lol {:?}", el); // println!("lol {:?}", el);
// } // }
let ast = ast(tokenized_input); let ast = ast(tokenized_input);
// println!("{:?}", ast); // println!(" test {:?}", ast);
match ast { match ast {
Ok(ast) => { Ok(ast) => {
let evaled = eval(&ast); let evaled = eval(&ast);
println!("{}", evaled); println!("{}\n", evaled);
} }
_ => { _ => {
// println!("lol");
continue; continue;
} }
} }
@ -79,6 +81,13 @@ fn main() {
println!("^"); println!("^");
println!("Syntax Error\n"); 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 tokenized_input: Vec<Vec<Symbol>> = input.iter().map(|s| tokenize(s).unwrap()).collect();
let result: Vec<Vec<Symbol>> = vec![ let result: Vec<Vec<Symbol>> = vec![
vec![ vec![Symbol::Number(1.0), Symbol::Add, Symbol::Number(2.0)],
Symbol::Number { value: 1 }, vec![Symbol::Number(3.0), Symbol::Sub, Symbol::Number(4.0)],
Symbol::Add, vec![Symbol::Number(5.0), Symbol::Mul, Symbol::Number(6.0)],
Symbol::Number { value: 2 }, vec![Symbol::Number(7.0), Symbol::Div, Symbol::Number(8.0)],
], vec![Symbol::Number(8.0), Symbol::Exp, Symbol::Number(9.0)],
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 },
],
]; ];
assert!(tokenized_input == result); assert!(tokenized_input == result);
} }
@ -131,17 +120,16 @@ fn tokenize(input: &str) -> Result<Vec<Symbol>, ParseError> {
for (i, c) in input.chars().enumerate() { for (i, c) in input.chars().enumerate() {
if !c.is_ascii_digit() && !acc.is_empty() { if !c.is_ascii_digit() && !acc.is_empty() {
tokens.push(Symbol::Number { if let Ok(num) = acc.parse() {
value: acc tokens.push(Symbol::Number(num));
.parse() acc.clear();
.map_err(|_| ParseError::WrongTokenError { pos: 1 })?, } else {
}); return Err(ParseError::WrongNumberError { pos: i });
acc.clear(); }
}; };
match c { match c {
'0'..='9' => { '0'..='9' => {
acc.push(c); acc.push(c);
continue;
} }
' ' => continue, ' ' => continue,
'(' => tokens.push(Symbol::LeftBracket), '(' => tokens.push(Symbol::LeftBracket),
@ -156,63 +144,86 @@ fn tokenize(input: &str) -> Result<Vec<Symbol>, ParseError> {
} }
} }
if !acc.is_empty() { if !acc.is_empty() {
tokens.push(Symbol::Number { if let Ok(num) = acc.parse() {
value: acc tokens.push(Symbol::Number(num));
.parse() } else {
.map_err(|_| ParseError::WrongTokenError { pos: 1 })?, return Err(ParseError::WrongNumberError { pos: 0 });
}); }
} };
Ok(tokens) 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(); let mut stack = Vec::<Node>::new();
// println!("{}", input.len()); // println!("{}", input.len());
let length = input.len(); let length = input.len();
let mut i = 0; 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 { while i < length {
let s = &input[i]; let s = &input[i];
match s { match s {
Symbol::Number { value } => { Symbol::Add | Symbol::Sub | Symbol::Mul | Symbol::Div => {
stack.push(Node::Number { value: *value }); if let Ok(n) = push_to_ast(&mut input, &mut i) {
} stack.push(n);
Symbol::Add => { } else {
let left = stack.pop(); return Err(ParseError::WrongTokenError { pos: i });
// 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::Sub => {} _ => {}
Symbol::Mul => {}
Symbol::Div => {}
_ => {
continue;
}
} }
i += 1; i += 1
} }
if stack.len() != 1 { if stack.len() != 1 {
return Err(ParseError::WrongTokenError { pos: 1 }); return Err(ParseError::WrongTokenError { pos: 1 });
} }
Ok(stack[0].clone()) 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 })
}