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::{ | use std::{ | ||||||
| 	collections::VecDeque, | 	collections::VecDeque, | ||||||
| 	env::args, | 	env::args, | ||||||
| 	fmt, | 	fmt::{ self, Display, Formatter }, | ||||||
| 	io::stdin, | 	io::stdin, | ||||||
| 	process::ExitCode, | 	process::ExitCode, | ||||||
| }; | }; | ||||||
| @ -70,19 +70,6 @@ enum CalcType { | |||||||
| 	Empty, | 	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 { | impl From<&str> for CalcType { | ||||||
| 	fn from(value: &str) -> Self { | 	fn from(value: &str) -> Self { | ||||||
| 		match value { | 		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( | fn eval( | ||||||
| 	input: &str, | 	input: &str, | ||||||
| 	initial_stack: VecDeque<f64>, | 	initial_stack: VecDeque<f64>, | ||||||
| ) -> Result<VecDeque<f64>, EvaluationError> { | ) -> Result<(VecDeque<f64>, bool), EvaluationError> { | ||||||
| 	let mut stack = initial_stack; | 	let mut stack = initial_stack; | ||||||
|  | 	let mut oper = false; | ||||||
| 
 | 
 | ||||||
| 	if input.is_empty() { | 	if input.is_empty() { | ||||||
| 		stack.clear(); | 		stack.clear(); | ||||||
| 		return Ok(stack); | 		return Ok((stack, oper)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Split the input into tokens.
 | 	// Split the input into tokens.
 | ||||||
| @ -122,7 +142,7 @@ fn eval( | |||||||
| 		let x: CalcType = match CalcType::from(tok) { | 		let x: CalcType = match CalcType::from(tok) { | ||||||
| 			Empty => { | 			Empty => { | ||||||
| 				return Err(EvaluationError { | 				return Err(EvaluationError { | ||||||
| 					message: format!("Invalid token: {}", tok), | 					message: format!("{}: Invalid token", tok), | ||||||
| 				}) | 				}) | ||||||
| 			}, | 			}, | ||||||
| 			x => x, | 			x => x, | ||||||
| @ -136,13 +156,28 @@ fn eval( | |||||||
| 
 | 
 | ||||||
| 	for op in &ops { | 	for op in &ops { | ||||||
| 		match op { | 		match op { | ||||||
| 			Val(v) => { | 			Val(_) => { | ||||||
| 				return Err(EvaluationError { message: format!( | 				return Err(EvaluationError { message: format!( | ||||||
| 					"{}: Unexpected value in the operator stack.", | 					"{}: 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) = ( | 				let (x, y) = ( | ||||||
| 					stack.pop_back().unwrap(), | 					stack.pop_back().unwrap(), | ||||||
| 					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
 | // Round a float to the given precision level
 | ||||||
| @ -183,15 +218,17 @@ fn main() -> ExitCode { | |||||||
| 		while let Ok(_) = stdin().read_line(&mut buf) { | 		while let Ok(_) = stdin().read_line(&mut buf) { | ||||||
| 			match eval(&buf.trim(), stack) { | 			match eval(&buf.trim(), stack) { | ||||||
| 				Ok(s) => { | 				Ok(s) => { | ||||||
| 					stack = s.clone(); | 					buf.clear(); | ||||||
|  | 					stack = s.0.clone(); | ||||||
| 
 | 
 | ||||||
| 					let val = match stack.iter().last() { | 					let val = match stack.iter().last() { | ||||||
| 						Some(v) => v, | 						Some(v) => v, | ||||||
| 						None => break, | 						None => break, | ||||||
| 					}; | 					}; | ||||||
| 
 | 
 | ||||||
|  | 					if s.1 == false { continue; } | ||||||
|  | 
 | ||||||
| 					println!("{}", round_precise(val, precision).to_string()); | 					println!("{}", round_precise(val, precision).to_string()); | ||||||
| 					buf.clear(); |  | ||||||
| 				}, | 				}, | ||||||
| 				Err(err) => { | 				Err(err) => { | ||||||
| 					eprintln!("{}: {}", argv[0], err.message); | 					eprintln!("{}: {}", argv[0], err.message); | ||||||
| @ -209,7 +246,7 @@ fn main() -> ExitCode { | |||||||
| 
 | 
 | ||||||
| 		match eval(&input, stack) { | 		match eval(&input, stack) { | ||||||
| 			Ok(s) => { | 			Ok(s) => { | ||||||
| 				stack = s.clone(); | 				stack = s.0.clone(); | ||||||
| 
 | 
 | ||||||
| 				let val = match stack.iter().last() { | 				let val = match stack.iter().last() { | ||||||
| 					Some(v) => v, | 					Some(v) => v, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user