diff --git a/src/user/bin/calc/calc.rs b/src/user/bin/calc/calc.rs index f424649..767ce18 100755 --- a/src/user/bin/calc/calc.rs +++ b/src/user/bin/calc/calc.rs @@ -1,8 +1,8 @@ use core::fmt; -use alloc::{boxed::Box, string::String, vec::Vec}; +use alloc::{boxed::Box, format, string::String, vec::Vec}; use alloc::string::ToString; use alloc::borrow::ToOwned; -use crate::{println, print, mknode, std}; +use crate::{println, print, mknode, std, serial_println}; use async_trait::async_trait; use crate::std::application::{ @@ -35,6 +35,7 @@ impl Interpreter { Node::Number(_) => return self.visit_number(node), Node::Operator(_) => return self.visit_operator(node), Node::Function(_) => return self.visit_function(node), + Node::Variable => panic!("substitution not used!"), } } @@ -195,16 +196,6 @@ impl Interpreter { } - - - - - - - - - - impl Parser { fn new(tokens: Vec) -> Result { let mut parser = Self { tokens, idx: -1, current: Token::Null }; @@ -217,9 +208,7 @@ impl Parser { let result = self.expr(); result } - - - + fn advance(&mut self) -> Result, Error> { self.idx += 1; if self.idx < self.tokens.len() as i32 { @@ -240,7 +229,10 @@ impl Parser { self.advance()?; return Ok(Node::Number(x)) }, - + Token::Variable => { + self.advance()?; + return Ok(Node::Variable) + }, Token::Bracket('(') => { self.advance()?; let expr = self.expr()?; @@ -381,7 +373,7 @@ impl Application for Calculator { match self.calculate_and_format(inp) { Ok(_) => (), Err(e) => { - println!("your input must be a valid mathematical expression contaning only numbers (including floats) and the operators: [ +, -, *, **, /, //, % ]"); + println!("your input must be a valid mathematical expression containing only numbers (including floats) and the operators: [ +, -, *, **, /, //, % ]"); println!("{:?}", e); return Err(ShellError::CommandFailed(String::from("failed"))) }, @@ -391,7 +383,7 @@ impl Application for Calculator { match self.calculate_and_format(args.into_iter().collect()) { Ok(x) => x, Err(e) => { - println!("your input must be a valid mathematical expression contaning only numbers (including floats) and the operators: [ +, -, *, **, /, //, % ]"); + println!("your input must be a valid mathematical expression containing only numbers (including floats) and the operators: [ +, -, *, **, /, //, % ]"); println!("{:?}", e); return Err(ShellError::CommandFailed(String::from("failed"))) }, @@ -417,7 +409,51 @@ impl Calculator { {}", equation, res); Ok(res) } - + + pub fn get_expr(&self, mut equation: String) -> Result { + equation.push('\n'); + let mut neweq = equation.clone(); + neweq.pop(); + + let tokens = tokenise(&equation).map_err(|e| format!( + "failed to tokenise: {:?}", + e + ))?; + + serial_println!("{:?}", tokens); + + let mut parser = Parser::new(tokens).unwrap(); + parser.parse().map_err(|e| format!("{:?}", e)) + } + + pub fn substitute(&self, equation: &mut Node, value: f64) { + match equation { + Node::BinaryOperation(x) => { + self.substitute(&mut x.left, value); + self.substitute(&mut x.right, value); + }, + Node::UnaryOperation(x) => { + self.substitute(&mut x.other, value); + }, + Node::Function(x) => { + self.substitute(&mut x.arg, value); + }, + Node::Variable => { + *equation = Node::Number(value); + } + _ => () + } + } + + pub fn evaluate(&self, equation: &Node) -> Result { + let mut interpreter = Interpreter::new().unwrap(); + let result = interpreter.visit(equation.clone()).unwrap(); + let return_res = if let Value::Number(x) = result { + x + } else { panic!("the value returned was not a float! THIS IS A BUG") }; + Ok(return_res) + } + fn calculate_inner(&self, mut equation: String) -> Result { equation.push('\n'); let mut neweq = equation.clone(); @@ -436,6 +472,7 @@ impl Calculator { } } + fn tokenise(equation: &str) -> Result, Error> { let mut tokens = Vec::new(); let mut current_num = "".to_string(); @@ -446,6 +483,16 @@ fn tokenise(equation: &str) -> Result, Error> { 'mainloop: for (x, character) in equation.chars().enumerate() { match character { + 'x' => { + if is_var { + tokens.push(Token::Func(current_string.clone())); + } + is_var = false; + current_string = "".to_string(); + tokens.push(Token::Variable); + continue; + } + 'a'..='z' => { is_var = true; current_string.push(character); @@ -468,7 +515,6 @@ fn tokenise(equation: &str) -> Result, Error> { tokens.push(Token::Number(current_num.parse::().unwrap())); current_num = "".to_string(); } else if current_string.len() != 0 { - } match character { '+' => tokens.push(Token::Operator(Operator::Add)), '-' => tokens.push(Token::Operator(Operator::Sub)), @@ -495,7 +541,7 @@ fn tokenise(equation: &str) -> Result, Error> { '\n' => break 'mainloop, ' ' => (), _ => { - return Err(Error::InvalidCharacter(x)) + return Err(Error::InvalidCharacter(character)) }, } } @@ -522,11 +568,12 @@ enum Token { Bracket(char), Null, Func(String), + Variable, } #[derive(Copy, Debug, Clone, PartialEq)] -enum Operator { +pub enum Operator { Add, Sub, Mul, @@ -539,7 +586,7 @@ enum Operator { #[derive(Debug)] enum Error { InvalidSyntax(usize), - InvalidCharacter(usize), + InvalidCharacter(char), LogicalError(String), Eof, Other(String), @@ -548,8 +595,9 @@ enum Error { #[derive(Debug, Clone, PartialEq)] -enum Node { +pub enum Node { Number(f64), + Variable, Operator(Operator), Function(Box), BinaryOperation(Box), @@ -558,20 +606,20 @@ enum Node { #[derive(Debug, Clone, PartialEq)] -struct BinaryOperation { +pub struct BinaryOperation { left: Node, operator: Node, right: Node, } #[derive(Debug, Clone, PartialEq)] -struct UnaryOperation { +pub struct UnaryOperation { operator: Node, other: Node, } #[derive(Debug, Clone, PartialEq)] -struct FunctionCall { +pub struct FunctionCall { name: String, arg: Node, } @@ -612,6 +660,7 @@ impl fmt::Display for Node { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Node::Number(x) => write!(f, "{}", x), + Node::Variable => write!(f, "x"), Node::Operator(x) => write!(f, "{}", x), Node::BinaryOperation(x) => { let inner = *x.clone(); diff --git a/src/user/bin/calc/mod.rs b/src/user/bin/calc/mod.rs index 9b3ef2f..488441b 100644 --- a/src/user/bin/calc/mod.rs +++ b/src/user/bin/calc/mod.rs @@ -1,4 +1,5 @@ -pub mod calc; +//pub mod calc; mod functions; +pub mod calc; pub use calc::*; diff --git a/src/user/bin/grapher.rs b/src/user/bin/grapher.rs index 0e54f2b..5034e50 100644 --- a/src/user/bin/grapher.rs +++ b/src/user/bin/grapher.rs @@ -22,6 +22,7 @@ const OFFSET_Y: i64 = 10; use core::f64::consts::E; use core::f64::consts::PI; +use crate::serial_println; #[derive(Clone)] pub struct Grapher { @@ -89,14 +90,14 @@ impl Application for Grapher { let mut offset_x: i64 = 0; let mut offset_y: i64 = 0; - let mut rerender = true; + let mut redraw_graph = true; while let c = Stdin::keystroke().await { let entry_widget = container.elements.get("entry_box").unwrap(); let mut entry = entry_widget.fetch::().unwrap(); - rerender = true; + redraw_graph = true; match c { KeyStroke::Char('\n') => { commandresult = entry.text.iter().collect(); @@ -105,24 +106,27 @@ impl Application for Grapher { offset_y = 0; }, KeyStroke::Char(Stdin::BACKSPACE) => { - rerender = false; + redraw_graph = false; entry.backspace() }, KeyStroke::Char('`') => { break; } - KeyStroke::Char(c) => entry.write_char(c), + KeyStroke::Char(c) => { + redraw_graph = false; + entry.write_char(c) + }, KeyStroke::Left => offset_x -= 1, KeyStroke::Right => offset_x += 1, KeyStroke::Up => offset_y -= 1, KeyStroke::Down => offset_y += 1, KeyStroke::Alt => break, _ => { - rerender = false; + redraw_graph = false; } } - if commandresult.len() > 0 && rerender { + if commandresult.len() > 0 && redraw_graph { self.reset_frame(); self.graph_equation(commandresult.clone(), (offset_x, offset_y)); let self_widget = container.elements.get("grapher").unwrap(); @@ -153,26 +157,40 @@ impl Grapher { fn graph_equation(&mut self, equation: String, offsets: (i64, i64)) { let cal = calc::Calculator::new(); - for x in -4000..4000 { - let x = x as f64 / 100.0; - - let new_eq = equation.chars().map(|c| { - match c { - 'x' => format!("({})", x + offsets.0 as f64), - 'e' => format!("({})", E), - 'π' => format!("({})", PI), - _ => c.to_string(), - } - }).collect::(); - - let fx = cal.calculate(new_eq); - if let Ok(y) = fx { - self.render_point(PointF64 { - x, - y: y + offsets.1 as f64, - }) + let ast = cal.get_expr(equation.chars().map(|c| { + match c { + 'e' => format!("({})", E), + 'π' => format!("({})", PI), + _ => c.to_string(), } - }; + }).collect::()); + + if let Ok(ast) = ast { + for x in -4000..4000 { + let x = x as f64 / 100.0; + + let mut cmd = ast.clone(); + cal.substitute(&mut cmd, x + offsets.0 as f64); + + // + // let new_eq = equation.chars().map(|c| { + // match c { + // 'x' => format!("({})", x + offsets.0 as f64), + // 'e' => format!("({})", E), + // 'π' => format!("({})", PI), + // _ => c.to_string(), + // } + // }).collect::(); + + let fx = cal.evaluate(&cmd); + if let Ok(y) = fx { + self.render_point(PointF64 { + x, + y: y + offsets.1 as f64, + }) + } + }; + } } diff --git a/src/user/bin/pong.rs b/src/user/bin/pong.rs index c96159c..e5e2ea5 100644 --- a/src/user/bin/pong.rs +++ b/src/user/bin/pong.rs @@ -131,10 +131,10 @@ impl Ball { (self.pos.y as i32 + self.vy) as usize ); for i in 0..5 { - if player1.pos.y + i == pos_next.y && player1.pos.x == pos_next.x { + if player1.pos.y + i - 2 == pos_next.y && player1.pos.x == pos_next.x { self.vx = -self.vx; break; - } else if player2.pos.y + i == pos_next.y && player2.pos.x == pos_next.x { + } else if player2.pos.y + i - 2 == pos_next.y && player2.pos.x == pos_next.x { self.vx = -self.vx; break; } diff --git a/src/user/bin/snake.rs b/src/user/bin/snake.rs index 189b98b..6a92b55 100644 --- a/src/user/bin/snake.rs +++ b/src/user/bin/snake.rs @@ -173,7 +173,7 @@ impl Game { false => ColorCode::new(Color::LightGreen, Color::Black), }; for point in s.tail.iter() { - frame[24 - point.y as usize][point.x as usize] = ColouredChar::coloured('@', curr_colour); + frame[24 - point.y as usize][point.x as usize] = ColouredChar::coloured('▓', curr_colour); } }