Improved error formatting

pull/2/head
Mark 2023-03-25 20:47:33 -07:00
parent aca8fa072d
commit 39c52782ca
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
5 changed files with 69 additions and 15 deletions

View File

@ -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),
)?;
}

View File

@ -255,11 +255,37 @@ pub struct LineLocation {
/// If we cannot parse a string, one of these is returned.
#[derive(Debug)]
pub enum ParserError {
MissingCloseParen,
//MissingCloseParen,
ExtraCloseParen,
EmptyGroup,
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")
}
}
}
}

View File

@ -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}

View File

@ -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));

View File

@ -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;
}