Improve lexer errors a little

This commit is contained in:
jonathandturner 2016-03-02 09:16:36 -05:00
parent 2bba8dc429
commit 0fd1af9c8d
2 changed files with 46 additions and 13 deletions

View File

@ -20,7 +20,8 @@ mod parser;
// * Overloading // * Overloading
// * How it works // * How it works
// * Arity to 10? // * Arity to 10?
// * Better error handling in lexer // * Vectors
// * Errors with positions?
// * Remove empty box values? // * Remove empty box values?
fn showit<T: Display>(x: &mut T) -> () { fn showit<T: Display>(x: &mut T) -> () {

View File

@ -5,6 +5,34 @@ use std::iter::Peekable;
use std::str::Chars; use std::str::Chars;
use std::char; use std::char;
#[derive(Debug)]
pub enum LexError {
UnexpectedChar,
MalformedEscapeSequence,
MalformedNumber
}
impl Error for LexError {
fn description(&self) -> &str {
match *self {
LexError::UnexpectedChar => "Unexpected character in input",
LexError::MalformedEscapeSequence => "Unexpected values in escape sequence",
LexError::MalformedNumber => "Unexpected characters in number"
}
}
fn cause(&self) -> Option<&Error> {
None
}
}
impl fmt::Display for LexError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum ParseError { pub enum ParseError {
BadInput, BadInput,
@ -66,7 +94,8 @@ pub enum Expr { IntConst(i32), Identifier(String), StringConst(String), FnCall(S
#[derive(Debug)] #[derive(Debug)]
pub enum Token { IntConst(i32), Identifier(String), StringConst(String), LCurly, RCurly, LParen, RParen, LSquare, RSquare, pub enum Token { IntConst(i32), Identifier(String), StringConst(String), LCurly, RCurly, LParen, RParen, LSquare, RSquare,
Plus, Minus, Multiply, Divide, Semicolon, Colon, Comma, Period, Equals, True, False, Var, If, While, Plus, Minus, Multiply, Divide, Semicolon, Colon, Comma, Period, Equals, True, False, Var, If, While,
LessThan, GreaterThan, Bang, LessThanEqual, GreaterThanEqual, EqualTo, NotEqualTo, Pipe, Or, Ampersand, And, Fn } LessThan, GreaterThan, Bang, LessThanEqual, GreaterThanEqual, EqualTo, NotEqualTo, Pipe, Or, Ampersand, And, Fn,
LexErr(LexError) }
pub struct TokenIterator<'a> { pub struct TokenIterator<'a> {
char_stream: Peekable<Chars<'a>> char_stream: Peekable<Chars<'a>>
@ -94,7 +123,7 @@ impl<'a> Iterator for TokenIterator<'a> {
if let Ok(val) = out.parse::<i32>() { if let Ok(val) = out.parse::<i32>() {
return Some(Token::IntConst(val)); return Some(Token::IntConst(val));
} }
return None; return Some(Token::LexErr(LexError::MalformedNumber));
}, },
'A'...'Z' | 'a'...'z' | '_' => { 'A'...'Z' | 'a'...'z' | '_' => {
let mut result = Vec::new(); let mut result = Vec::new();
@ -140,6 +169,7 @@ impl<'a> Iterator for TokenIterator<'a> {
match nxt { match nxt {
'"' if !escape => break, '"' if !escape => break,
'\\' if !escape => escape = true, '\\' if !escape => escape = true,
'\\' if escape => {escape = false; result.push('\\'); },
't' if escape => {escape = false; result.push('\t'); }, 't' if escape => {escape = false; result.push('\t'); },
'n' if escape => {escape = false; result.push('\n'); }, 'n' if escape => {escape = false; result.push('\n'); },
'r' if escape => {escape = false; result.push('\r'); }, 'r' if escape => {escape = false; result.push('\r'); },
@ -153,11 +183,11 @@ impl<'a> Iterator for TokenIterator<'a> {
out_val += d1; out_val += d1;
} }
else { else {
println!("Warning: unexpected character in escaped value") return Some(Token::LexErr(LexError::MalformedEscapeSequence));
} }
} }
else { else {
println!("Warning: unexpected character in escaped value") return Some(Token::LexErr(LexError::MalformedEscapeSequence));
} }
} }
@ -165,7 +195,7 @@ impl<'a> Iterator for TokenIterator<'a> {
result.push(r); result.push(r);
} }
else { else {
println!("Warning: unexpected character in escaped value") return Some(Token::LexErr(LexError::MalformedEscapeSequence));
} }
} }
'u' if escape => { 'u' if escape => {
@ -178,11 +208,11 @@ impl<'a> Iterator for TokenIterator<'a> {
out_val += d1; out_val += d1;
} }
else { else {
println!("Warning: unexpected character in escaped value") return Some(Token::LexErr(LexError::MalformedEscapeSequence));
} }
} }
else { else {
println!("Warning: unexpected character in escaped value") return Some(Token::LexErr(LexError::MalformedEscapeSequence));
} }
} }
@ -190,7 +220,7 @@ impl<'a> Iterator for TokenIterator<'a> {
result.push(r); result.push(r);
} }
else { else {
println!("Warning: unexpected character in escaped value") return Some(Token::LexErr(LexError::MalformedEscapeSequence));
} }
} }
'U' if escape => { 'U' if escape => {
@ -203,11 +233,11 @@ impl<'a> Iterator for TokenIterator<'a> {
out_val += d1; out_val += d1;
} }
else { else {
println!("Warning: unexpected character in escaped value") return Some(Token::LexErr(LexError::MalformedEscapeSequence));
} }
} }
else { else {
println!("Warning: unexpected character in escaped value") return Some(Token::LexErr(LexError::MalformedEscapeSequence));
} }
} }
@ -215,9 +245,10 @@ impl<'a> Iterator for TokenIterator<'a> {
result.push(r); result.push(r);
} }
else { else {
println!("Warning: unexpected character in escaped value") return Some(Token::LexErr(LexError::MalformedEscapeSequence));
} }
} }
_ if escape => return Some(Token::LexErr(LexError::MalformedEscapeSequence)),
_ => { escape = false; result.push(nxt); }, _ => { escape = false; result.push(nxt); },
} }
} }
@ -276,7 +307,7 @@ impl<'a> Iterator for TokenIterator<'a> {
} }
}, },
' ' | '\n' | '\r' => (), ' ' | '\n' | '\r' => (),
_ => return None _ => return Some(Token::LexErr(LexError::UnexpectedChar))
} }
} }
@ -383,6 +414,7 @@ fn parse_primary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, Pa
Token::LParen => {parse_paren_expr(input)}, Token::LParen => {parse_paren_expr(input)},
Token::True => {Ok(Expr::True)}, Token::True => {Ok(Expr::True)},
Token::False => {Ok(Expr::False)}, Token::False => {Ok(Expr::False)},
Token::LexErr(le) => {println!("Error: {}", le); Err(ParseError::BadInput)}
_ => {println!("Can't parse: {:?}", token); Err(ParseError::BadInput)} _ => {println!("Can't parse: {:?}", token); Err(ParseError::BadInput)}
} }
} }