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)) => {
|
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,13 +255,39 @@ 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,
|
||||||
|
Undefined(String),
|
||||||
BadNumber
|
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
|
/// Parse a user string. This is the only method that should be used
|
||||||
/// outside this module.
|
/// outside this module.
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
Loading…
Reference in New Issue