Improve parser error handling

This commit is contained in:
mars 2022-02-28 14:36:24 -07:00
parent 04c0dc35a6
commit 698c914633
2 changed files with 41 additions and 17 deletions

View File

@ -2,7 +2,7 @@ use logos::Logos;
use std::fmt::{Display, Formatter, Result as FmtResult};
#[rustfmt::skip]
#[derive(Logos, Debug, PartialEq)]
#[derive(Logos, Clone, Copy, Debug, PartialEq)]
pub enum Token {
// keywords
#[token("struct")] Struct,
@ -78,10 +78,10 @@ impl<'a> Display for TokenInfo<'a> {
let token_len = self.token_end - self.token_start;
if token_len > 1 {
write!(f, "{}^", "-".repeat(token_len - 2))?;
write!(f, "{}^\n", "-".repeat(token_len - 2))
} else {
write!(f, "\n")
}
Ok(())
}
}
@ -113,7 +113,27 @@ impl<'a> Lexer<'a> {
}
}
pub fn get_info(&self) -> TokenInfo<'a> {
pub fn eat_expect_id(&mut self) -> &'a str {
let tok = self.next();
if let Some(Token::Identifier) = tok {
self.slice()
} else {
self.panic_message("Expected identifier");
}
}
pub fn eat_expect(&mut self, expected: Token) {
let tok = self.next();
if tok != Some(expected) {
self.panic_message(&format!("Expected {:?}, got {:?}", expected, tok));
}
}
pub fn panic_message(&self, message: &str) -> ! {
panic!("{}\n{}", message, self.info());
}
pub fn info(&self) -> TokenInfo<'a> {
let from_start = &self.inner.source()[self.line_start..];
let line_end = from_start.find("\n").unwrap_or(from_start.len());
let line = &from_start[..line_end];

View File

@ -11,7 +11,10 @@ impl<'a> ParseTree<'a> {
let mut associated_struct = None;
while let Some(tok) = lexer.next() {
if let Some(_) = associated_struct {
assert_eq!(Token::Function, tok);
if tok != Token::Function {
lexer.panic_message("Expected fn");
}
declarations.push(Definition::build_function(associated_struct, lexer));
associated_struct = None;
} else {
@ -19,7 +22,7 @@ impl<'a> ParseTree<'a> {
Token::Struct => declarations.push(Definition::build_structure(lexer)),
Token::Function => declarations.push(Definition::build_function(None, lexer)),
Token::Identifier => associated_struct = Some(lexer.slice()),
_ => panic!("Expected associated struct identifier, fn, or struct"),
_ => lexer.panic_message("Expected associated struct identifier, fn or struct"),
}
}
}
@ -44,7 +47,7 @@ pub enum Definition<'a> {
impl<'a> Definition<'a> {
pub fn build_structure(lexer: &mut Lexer<'a>) -> Self {
let name = lexer.eat_id().unwrap();
assert_eq!(lexer.next(), Some(Token::BraceOpen));
lexer.eat_expect(Token::BraceOpen);
let mut members = Vec::new();
@ -59,7 +62,7 @@ impl<'a> Definition<'a> {
}
Err(Some(Token::Comma)) => {}
Err(Some(Token::BraceClose)) => break,
_ => panic!("Expected comma or closing brace"),
_ => lexer.panic_message("Expected comma or closing brace"),
}
}
@ -67,9 +70,9 @@ impl<'a> Definition<'a> {
}
pub fn build_function(associated_struct: Option<&'a str>, lexer: &mut Lexer<'a>) -> Self {
let name = lexer.eat_id().unwrap();
let name = lexer.eat_expect_id();
lexer.eat_expect(Token::ParanOpen);
assert_eq!(lexer.next(), Some(Token::ParanOpen));
let mut args = Vec::new();
loop {
@ -83,7 +86,7 @@ impl<'a> Definition<'a> {
}
Err(Some(Token::Comma)) => {}
Err(Some(Token::ParanClose)) => break,
_ => panic!("Expected comma, type, or closing paranthases"),
_ => lexer.panic_message("Expected comma, type, or closing parantheses"),
}
}
@ -91,9 +94,10 @@ impl<'a> Definition<'a> {
let mut return_type = None;
if let Some(Token::Identifier) = tok {
return_type = Some(lexer.slice());
assert_eq!(Some(Token::BraceOpen), lexer.next());
} else {
assert_eq!(Some(Token::BraceOpen), tok);
lexer.eat_expect(Token::BraceOpen);
} else if tok != Some(Token::BraceOpen) {
let info = lexer.info();
panic!("Expected open bracket:\n{}", info);
}
let signature = FunctionSignature {
@ -127,7 +131,7 @@ pub struct FunctionSignature<'a> {
impl<'a> FunctionSignature<'a> {
pub fn build(associated_struct: Option<&'a str>, lexer: &mut Lexer<'a>) -> Self {
assert_eq!(lexer.next(), Some(Token::ParanOpen));
lexer.eat_expect(Token::ParanOpen);
let mut args = Vec::new();
loop {
@ -141,7 +145,7 @@ impl<'a> FunctionSignature<'a> {
}
Err(Some(Token::Comma)) => {}
Err(Some(Token::ParanClose)) => break,
_ => panic!("Expected comma, type, or closing paranthases"),
_ => lexer.panic_message("Expected comma, type, or closing parantheses"),
}
}