Improve parser error handling
This commit is contained in:
parent
04c0dc35a6
commit
698c914633
30
src/lexer.rs
30
src/lexer.rs
|
@ -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];
|
||||
|
|
28
src/parse.rs
28
src/parse.rs
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue