mirror of
				https://github.com/rm-dr/daisy
				synced 2025-11-04 04:31:50 -08:00 
			
		
		
		
	Improved error formatting
This commit is contained in:
		@@ -129,10 +129,11 @@ fn main() -> Result<(), std::io::Error> {
 | 
				
			|||||||
							},
 | 
												},
 | 
				
			||||||
							Err((l, e)) => {
 | 
												Err((l, e)) => {
 | 
				
			||||||
								write!(
 | 
													write!(
 | 
				
			||||||
									stdout, "{}{}{} {e:?}{}\r\n",
 | 
														stdout, "{}{}{} {}{}\r\n",
 | 
				
			||||||
									color::Fg(color::Red),
 | 
														color::Fg(color::Red),
 | 
				
			||||||
									" ".repeat(l.pos + 4),
 | 
														" ".repeat(l.pos + 4),
 | 
				
			||||||
									"^".repeat(l.len),
 | 
														"^".repeat(l.len),
 | 
				
			||||||
 | 
														e.to_message(),
 | 
				
			||||||
									color::Fg(color::Reset),
 | 
														color::Fg(color::Reset),
 | 
				
			||||||
								)?;
 | 
													)?;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -255,11 +255,37 @@ pub struct LineLocation {
 | 
				
			|||||||
/// If we cannot parse a string, one of these is returned.
 | 
					/// If we cannot parse a string, one of these is returned.
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub enum ParserError {
 | 
					pub enum ParserError {
 | 
				
			||||||
	MissingCloseParen,
 | 
						//MissingCloseParen,
 | 
				
			||||||
	ExtraCloseParen,
 | 
						ExtraCloseParen,
 | 
				
			||||||
	EmptyGroup,
 | 
						EmptyGroup,
 | 
				
			||||||
	Syntax,
 | 
						Syntax,
 | 
				
			||||||
	BadNumber 
 | 
						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")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ pub fn p_find_subs(
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Token::PreWord(_, s) => {
 | 
								Token::PreWord(_, s) => {
 | 
				
			||||||
				match &s[..] {
 | 
									let target = match &s[..] {
 | 
				
			||||||
					// Greek letters
 | 
										// Greek letters
 | 
				
			||||||
					"alpha"   => {Some("α")},
 | 
										"alpha"   => {Some("α")},
 | 
				
			||||||
					"beta"    => {Some("β")},
 | 
										"beta"    => {Some("β")},
 | 
				
			||||||
@@ -62,7 +62,15 @@ pub fn p_find_subs(
 | 
				
			|||||||
					"omega"   => {Some("ω")}
 | 
										"omega"   => {Some("ω")}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					_ => {None}
 | 
										_ => {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}
 | 
								_ => {None}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,7 @@ pub fn p_groupify(mut g: VecDeque<Token>) -> Result<Token, (LineLocation, Parser
 | 
				
			|||||||
		let t = g.pop_front().unwrap();
 | 
							let t = g.pop_front().unwrap();
 | 
				
			||||||
		let (l_now, v_now) = levels.last_mut().unwrap();
 | 
							let (l_now, v_now) = levels.last_mut().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		match &t {
 | 
							match t {
 | 
				
			||||||
			Token::PreOperator(_, _) => {
 | 
								Token::PreOperator(_, _) => {
 | 
				
			||||||
				v_now.push_back(t);
 | 
									v_now.push_back(t);
 | 
				
			||||||
				lookback(v_now)?;
 | 
									lookback(v_now)?;
 | 
				
			||||||
@@ -82,23 +82,25 @@ pub fn p_groupify(mut g: VecDeque<Token>) -> Result<Token, (LineLocation, Parser
 | 
				
			|||||||
			Token::PreNumber(l, s) => {
 | 
								Token::PreNumber(l, s) => {
 | 
				
			||||||
				let n = match s.parse() {
 | 
									let n = match s.parse() {
 | 
				
			||||||
					Ok(n) => n,
 | 
										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)?;
 | 
									lookback(v_now)?;
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Token::PreWord(l, s) => {
 | 
								Token::PreWord(l, s) => {
 | 
				
			||||||
 | 
									// This method must support both plain text and
 | 
				
			||||||
 | 
									// unicode versions of each word.
 | 
				
			||||||
				v_now.push_back(match &s[..] {
 | 
									v_now.push_back(match &s[..] {
 | 
				
			||||||
					"mod" => { Token::PreOperator(*l, Operator::ModuloLong) },
 | 
										"mod" => { Token::PreOperator(l, Operator::ModuloLong) },
 | 
				
			||||||
					"pi" => { Token::Constant(*l, 3.141592653, String::from("π")) },
 | 
										"π"|"pi" => { Token::Constant(l, 3.141592653, String::from("π")) },
 | 
				
			||||||
					_ => { return Err((*l, ParserError::Syntax)); }
 | 
										_ => { return Err((l, ParserError::Undefined(s))); }
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
				lookback(v_now)?;
 | 
									lookback(v_now)?;
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Token::PreGroupStart(l) => {
 | 
								Token::PreGroupStart(l) => {
 | 
				
			||||||
				levels.push((*l, VecDeque::with_capacity(8)));
 | 
									levels.push((l, VecDeque::with_capacity(8)));
 | 
				
			||||||
				i_level += 1;
 | 
									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 {
 | 
						if levels.len() != 1 {
 | 
				
			||||||
		let (l, _) = levels.pop().unwrap();
 | 
							let (l, _) = levels.pop().unwrap();
 | 
				
			||||||
		return Err((l, ParserError::MissingCloseParen))
 | 
							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();
 | 
						let (_, v) = levels.pop().unwrap();
 | 
				
			||||||
	return Ok(Token::PreGroup(LineLocation{pos:0, len:0}, v));
 | 
						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() {
 | 
						for (i, c) in input.chars().enumerate() {
 | 
				
			||||||
 | 
					 | 
				
			||||||
		match c {
 | 
							match c {
 | 
				
			||||||
			// The minus sign can be both a Negative and an Operator.
 | 
								// The minus sign can be both a Negative and an Operator.
 | 
				
			||||||
			// Needs special treatment.
 | 
								// Needs special treatment.
 | 
				
			||||||
@@ -82,8 +81,8 @@ pub fn p_tokenize(input: &String) -> VecDeque<Token> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// Operator
 | 
								// Operator
 | 
				
			||||||
			// Always one character
 | 
								// Always one character
 | 
				
			||||||
			'*'|'/'|'+'|
 | 
								'*'|'×'|'/'|'÷'|
 | 
				
			||||||
			'^'|'!'|'%'
 | 
								'+'|'^'|'!'|'%'
 | 
				
			||||||
			=> {
 | 
								=> {
 | 
				
			||||||
				if t.is_some() { g.push_back(update_line_location(t.unwrap(), i)); }
 | 
									if t.is_some() { g.push_back(update_line_location(t.unwrap(), i)); }
 | 
				
			||||||
				t = Some(Token::PreOperator(
 | 
									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;
 | 
						return g;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user