forked from bonsai/harakit
		
	rpn(1): better error handling
This commit is contained in:
		
							parent
							
								
									885f167afc
								
							
						
					
					
						commit
						4cb5e8e2b0
					
				
							
								
								
									
										83
									
								
								src/rpn.rs
									
									
									
									
									
								
							
							
						
						
									
										83
									
								
								src/rpn.rs
									
									
									
									
									
								
							| @ -45,7 +45,7 @@ | ||||
| use std::{ | ||||
| 	collections::VecDeque, | ||||
| 	env::args, | ||||
| 	fmt, | ||||
| 	fmt::{ self, Display, Formatter }, | ||||
| 	io::stdin, | ||||
| 	process::ExitCode, | ||||
| }; | ||||
| @ -70,19 +70,6 @@ enum CalcType { | ||||
| 	Empty, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| struct EvaluationError { pub message: String } | ||||
| 
 | ||||
| impl fmt::Display for EvaluationError { | ||||
| 	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
| 		write!(f, "{}", self.message) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // I’m no math nerd but I want the highest possible approximation of 0.9
 | ||||
| // repeating and it seems this can give it to me
 | ||||
| const PRECISION_MOD: f64 = 0.9 + f64::EPSILON * 100.0; | ||||
| 
 | ||||
| impl From<&str> for CalcType { | ||||
| 	fn from(value: &str) -> Self { | ||||
| 		match value { | ||||
| @ -103,15 +90,48 @@ impl From<&str> for CalcType { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl Display for CalcType { | ||||
| 	fn fmt(&self, f: &mut Formatter) -> fmt::Result { | ||||
| 		let y: String; | ||||
| 		write!(f, "{}", match self { | ||||
| 			Add => "addition", | ||||
| 			Subtract => "subtraction", | ||||
| 			Multiply => "multiplication", | ||||
| 			Divide => "division", | ||||
| 			Power => "exponentiation", | ||||
| 			Floor => "floor divion", | ||||
| 			Modulo => "modulus", | ||||
| 			Val(x) => { | ||||
| 				y = x.to_string(); &y | ||||
| 			}, | ||||
| 			Empty => "", | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| struct EvaluationError { pub message: String } | ||||
| 
 | ||||
| impl Display for EvaluationError { | ||||
| 	fn fmt(&self, f: &mut Formatter) -> fmt::Result { | ||||
| 		write!(f, "{}", self.message) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // I’m no math nerd but I want the highest possible approximation of 0.9
 | ||||
| // repeating and it seems this can give it to me
 | ||||
| const PRECISION_MOD: f64 = 0.9 + f64::EPSILON * 100.0; | ||||
| 
 | ||||
| fn eval( | ||||
| 	input: &str, | ||||
| 	initial_stack: VecDeque<f64>, | ||||
| ) -> Result<VecDeque<f64>, EvaluationError> { | ||||
| ) -> Result<(VecDeque<f64>, bool), EvaluationError> { | ||||
| 	let mut stack = initial_stack; | ||||
| 	let mut oper = false; | ||||
| 
 | ||||
| 	if input.is_empty() { | ||||
| 		stack.clear(); | ||||
| 		return Ok(stack); | ||||
| 		return Ok((stack, oper)); | ||||
| 	} | ||||
| 
 | ||||
| 	// Split the input into tokens.
 | ||||
| @ -122,7 +142,7 @@ fn eval( | ||||
| 		let x: CalcType = match CalcType::from(tok) { | ||||
| 			Empty => { | ||||
| 				return Err(EvaluationError { | ||||
| 					message: format!("Invalid token: {}", tok), | ||||
| 					message: format!("{}: Invalid token", tok), | ||||
| 				}) | ||||
| 			}, | ||||
| 			x => x, | ||||
| @ -136,13 +156,28 @@ fn eval( | ||||
| 
 | ||||
| 	for op in &ops { | ||||
| 		match op { | ||||
| 			Val(v) => { | ||||
| 			Val(_) => { | ||||
| 				return Err(EvaluationError { message: format!( | ||||
| 					"{}: Unexpected value in the operator stack.", | ||||
| 					v | ||||
| 					op, | ||||
| 				)}); | ||||
| 			}, | ||||
| 			_ => { | ||||
| 
 | ||||
| 				if stack.len() < 2 { | ||||
| 					return Err(EvaluationError { | ||||
| 						message: format!("{}: Unexpected operation.", op) | ||||
| 					}) | ||||
| 				} | ||||
| 
 | ||||
| 				if stack.len() > ops.len() + 1 { | ||||
| 					return Err( | ||||
| 						EvaluationError { message: format!("Syntax error.")} | ||||
| 					); | ||||
| 				} | ||||
| 
 | ||||
| 				oper = true; | ||||
| 
 | ||||
| 				let (x, y) = ( | ||||
| 					stack.pop_back().unwrap(), | ||||
| 					stack.pop_back().unwrap(), | ||||
| @ -162,7 +197,7 @@ fn eval( | ||||
| 		}; | ||||
| 	} | ||||
| 
 | ||||
| 	Ok(stack) | ||||
| 	Ok((stack, oper)) | ||||
| } | ||||
| 
 | ||||
| // Round a float to the given precision level
 | ||||
| @ -183,15 +218,17 @@ fn main() -> ExitCode { | ||||
| 		while let Ok(_) = stdin().read_line(&mut buf) { | ||||
| 			match eval(&buf.trim(), stack) { | ||||
| 				Ok(s) => { | ||||
| 					stack = s.clone(); | ||||
| 					buf.clear(); | ||||
| 					stack = s.0.clone(); | ||||
| 
 | ||||
| 					let val = match stack.iter().last() { | ||||
| 						Some(v) => v, | ||||
| 						None => break, | ||||
| 					}; | ||||
| 
 | ||||
| 					if s.1 == false { continue; } | ||||
| 
 | ||||
| 					println!("{}", round_precise(val, precision).to_string()); | ||||
| 					buf.clear(); | ||||
| 				}, | ||||
| 				Err(err) => { | ||||
| 					eprintln!("{}: {}", argv[0], err.message); | ||||
| @ -209,7 +246,7 @@ fn main() -> ExitCode { | ||||
| 
 | ||||
| 		match eval(&input, stack) { | ||||
| 			Ok(s) => { | ||||
| 				stack = s.clone(); | ||||
| 				stack = s.0.clone(); | ||||
| 
 | ||||
| 				let val = match stack.iter().last() { | ||||
| 					Some(v) => v, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user