mirror of https://github.com/rm-dr/daisy
Improved error formatting
parent
aca8fa072d
commit
39c52782ca
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue