mirror of
				https://github.com/rm-dr/daisy
				synced 2025-10-31 14:34:51 -07:00 
			
		
		
		
	Improved error formatting
This commit is contained in:
		| @ -129,10 +129,11 @@ fn main() -> Result<(), std::io::Error> { | ||||
| 							}, | ||||
| 							Err((l, e)) => { | ||||
| 								write!( | ||||
| 									stdout, "{}{}{} {e:?}{}\r\n", | ||||
| 									stdout, "{}{}{} {}{}\r\n", | ||||
| 									color::Fg(color::Red), | ||||
| 									" ".repeat(l.pos + 4), | ||||
| 									"^".repeat(l.len), | ||||
| 									e.to_message(), | ||||
| 									color::Fg(color::Reset), | ||||
| 								)?; | ||||
| 							} | ||||
|  | ||||
| @ -255,13 +255,39 @@ pub struct LineLocation { | ||||
| /// If we cannot parse a string, one of these is returned. | ||||
| #[derive(Debug)] | ||||
| pub enum ParserError { | ||||
| 	MissingCloseParen, | ||||
| 	//MissingCloseParen, | ||||
| 	ExtraCloseParen, | ||||
| 	EmptyGroup, | ||||
| 	Syntax, | ||||
| 	Undefined(String), | ||||
| 	BadNumber | ||||
| } | ||||
|  | ||||
| impl ParserError { | ||||
| 	pub fn to_message(&self) -> String { | ||||
| 		match self { | ||||
| 			//ParserError::MissingCloseParen => { | ||||
| 			//	String::from("This group is never closed") | ||||
| 			//}, | ||||
| 			ParserError::ExtraCloseParen => { | ||||
| 				String::from("Extra close parenthesis") | ||||
| 			}, | ||||
| 			ParserError::EmptyGroup => { | ||||
| 				String::from("Groups can't be empty") | ||||
| 			}, | ||||
| 			ParserError::Syntax => { | ||||
| 				String::from("Syntax") | ||||
| 			}, | ||||
| 			ParserError::Undefined(s) => { | ||||
| 				format!("\"{s}\" isn't defined") | ||||
| 			}, | ||||
| 			ParserError::BadNumber => { | ||||
| 				String::from("Invalid number") | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| /// Parse a user string. This is the only method that should be used | ||||
| /// outside this module. | ||||
|  | ||||
| @ -34,7 +34,7 @@ pub fn p_find_subs( | ||||
| 			}, | ||||
|  | ||||
| 			Token::PreWord(_, s) => { | ||||
| 				match &s[..] { | ||||
| 				let target = match &s[..] { | ||||
| 					// Greek letters | ||||
| 					"alpha"   => {Some("α")}, | ||||
| 					"beta"    => {Some("β")}, | ||||
| @ -62,7 +62,15 @@ pub fn p_find_subs( | ||||
| 					"omega"   => {Some("ω")} | ||||
|  | ||||
| 					_ => {None} | ||||
| 				}; | ||||
|  | ||||
| 				// Update preword contents too. | ||||
| 				// This makes sure future prints of this token | ||||
| 				// contain substituted text too. | ||||
| 				if target.is_some() {* | ||||
| 					s = String::from(target.unwrap()); | ||||
| 				} | ||||
| 				target | ||||
| 			}, | ||||
|  | ||||
| 			_ => {None} | ||||
|  | ||||
| @ -73,7 +73,7 @@ pub fn p_groupify(mut g: VecDeque<Token>) -> Result<Token, (LineLocation, Parser | ||||
| 		let t = g.pop_front().unwrap(); | ||||
| 		let (l_now, v_now) = levels.last_mut().unwrap(); | ||||
|  | ||||
| 		match &t { | ||||
| 		match t { | ||||
| 			Token::PreOperator(_, _) => { | ||||
| 				v_now.push_back(t); | ||||
| 				lookback(v_now)?; | ||||
| @ -82,23 +82,25 @@ pub fn p_groupify(mut g: VecDeque<Token>) -> Result<Token, (LineLocation, Parser | ||||
| 			Token::PreNumber(l, s) => { | ||||
| 				let n = match s.parse() { | ||||
| 					Ok(n) => n, | ||||
| 					Err(_) => return Err((*l, ParserError::BadNumber)) | ||||
| 					Err(_) => return Err((l, ParserError::BadNumber)) | ||||
| 				}; | ||||
| 				v_now.push_back(Token::Number(*l, n)); | ||||
| 				v_now.push_back(Token::Number(l, n)); | ||||
| 				lookback(v_now)?; | ||||
| 			}, | ||||
|  | ||||
| 			Token::PreWord(l, s) => { | ||||
| 				// This method must support both plain text and | ||||
| 				// unicode versions of each word. | ||||
| 				v_now.push_back(match &s[..] { | ||||
| 					"mod" => { Token::PreOperator(*l, Operator::ModuloLong) }, | ||||
| 					"pi" => { Token::Constant(*l, 3.141592653, String::from("π")) }, | ||||
| 					_ => { return Err((*l, ParserError::Syntax)); } | ||||
| 					"mod" => { Token::PreOperator(l, Operator::ModuloLong) }, | ||||
| 					"π"|"pi" => { Token::Constant(l, 3.141592653, String::from("π")) }, | ||||
| 					_ => { return Err((l, ParserError::Undefined(s))); } | ||||
| 				}); | ||||
| 				lookback(v_now)?; | ||||
| 			}, | ||||
|  | ||||
| 			Token::PreGroupStart(l) => { | ||||
| 				levels.push((*l, VecDeque::with_capacity(8))); | ||||
| 				levels.push((l, VecDeque::with_capacity(8))); | ||||
| 				i_level += 1; | ||||
| 			}, | ||||
|  | ||||
| @ -129,10 +131,28 @@ pub fn p_groupify(mut g: VecDeque<Token>) -> Result<Token, (LineLocation, Parser | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	// Error on missing parenthesis | ||||
| 	if levels.len() != 1 { | ||||
| 		let (l, _) = levels.pop().unwrap(); | ||||
| 		return Err((l, ParserError::MissingCloseParen)) | ||||
| 	} | ||||
| 	*/ | ||||
|  | ||||
| 	// Auto-close parenthesis | ||||
| 	while levels.len() != 1 { | ||||
| 		let (l, v) = levels.pop().unwrap(); | ||||
| 		let (_, v_now) = levels.last_mut().unwrap(); | ||||
|  | ||||
| 		// Catch empty groups | ||||
| 		if v.len() == 0 { | ||||
| 			return Err((l, ParserError::EmptyGroup)) | ||||
| 		} | ||||
|  | ||||
| 		v_now.push_back(Token::PreGroup(l, v)); | ||||
| 		lookback(v_now)?; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	let (_, v) = levels.pop().unwrap(); | ||||
| 	return Ok(Token::PreGroup(LineLocation{pos:0, len:0}, v)); | ||||
|  | ||||
| @ -33,7 +33,6 @@ pub fn p_tokenize(input: &String) -> VecDeque<Token> { | ||||
|  | ||||
|  | ||||
| 	for (i, c) in input.chars().enumerate() { | ||||
|  | ||||
| 		match c { | ||||
| 			// The minus sign can be both a Negative and an Operator. | ||||
| 			// Needs special treatment. | ||||
| @ -82,8 +81,8 @@ pub fn p_tokenize(input: &String) -> VecDeque<Token> { | ||||
|  | ||||
| 			// Operator | ||||
| 			// Always one character | ||||
| 			'*'|'/'|'+'| | ||||
| 			'^'|'!'|'%' | ||||
| 			'*'|'×'|'/'|'÷'| | ||||
| 			'+'|'^'|'!'|'%' | ||||
| 			=> { | ||||
| 				if t.is_some() { g.push_back(update_line_location(t.unwrap(), i)); } | ||||
| 				t = Some(Token::PreOperator( | ||||
| @ -136,7 +135,7 @@ pub fn p_tokenize(input: &String) -> VecDeque<Token> { | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	if t.is_some() { g.push_back(update_line_location(t.unwrap(), input.len())); } | ||||
| 	if t.is_some() { g.push_back(update_line_location(t.unwrap(), input.chars().count())); } | ||||
|  | ||||
| 	return g; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user