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;
#[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 })
}