error: refactor into unified error type

This is probably a bad idea.  Every stage in the
compiler pipeline will use the same type for
emitting errors now (good), but it's doing so
using a bunch of wrappers (bad, i think).
main
anna 2 years ago
parent 8710d08a19
commit c7fc83f844
Signed by: fef
GPG Key ID: EC22E476DC2D3D84

@ -1,8 +1,49 @@
use std::fmt;
use std::fmt::Formatter;
use crate::ast::tree::Type;
/// This is just a wrapper for the actual error types.
/// I have no idea whether this is good design (probably not),
/// but idc for now. Shouldn't be too hard to change the API
/// later on bc each component of the compiler has its own
/// wrappers for instantiating errors anyway.
#[derive(Debug)]
pub struct Error {
e: Box<dyn ErrorDetails>,
}
impl Error {
pub fn syntax_error(file: String, line: usize, col: usize, msg: String) -> Error {
Error {
e: Box::new(SyntaxError::new(file, line, col, msg))
}
}
pub fn type_error(file: String, line: usize, col: usize, expected: Type, actual: Type) -> Error {
Error {
e: Box::new(TypeError::new(file, line, col, expected, actual))
}
}
pub fn file(&self) -> &String {
self.e.file()
}
pub fn line(&self) -> usize {
self.e.line()
}
pub fn col(&self) -> usize {
self.e.col()
}
pub fn msg(&self) -> &String {
self.e.msg()
}
}
/// Anything that can go wrong while compiling and executing the build script.
pub trait Error {
trait ErrorDetails {
/// Name of the file that the error originated from.
fn file(&self) -> &String;
/// Line (starting from 1) of the first erroneous character.
@ -28,7 +69,14 @@ pub struct SyntaxError {
msg: String,
}
impl fmt::Display for dyn Error {
#[derive(Debug)]
pub struct TypeError {
pos: Position,
expected: Type,
actual: Type,
}
impl fmt::Display for dyn ErrorDetails {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{} in {}:{}:{}: {}", self.name(), self.file(), self.line(), self.col(), self.msg())
}
@ -43,7 +91,17 @@ impl SyntaxError {
}
}
impl Error for SyntaxError {
impl TypeError {
pub fn new(file: String, line: usize, col: usize, expected: Type, actual: Type) -> TypeError {
TypeError {
pos: Position { file, line, col },
expected,
actual,
}
}
}
impl ErrorDetails for SyntaxError {
fn file(&self) -> &String {
&self.pos.file
}
@ -64,3 +122,25 @@ impl Error for SyntaxError {
"SyntaxError"
}
}
impl ErrorDetails for TypeError {
fn file(&self) -> &String {
&self.pos.file
}
fn line(&self) -> usize {
self.pos.line
}
fn col(&self) -> usize {
self.pos.col
}
fn msg(&self) -> &String {
&format!("Expected type {}, got {} instead", self.expected, self.actual)
}
fn name(&self) -> &str {
"TypeError"
}
}

@ -6,7 +6,7 @@ use cursor::Cursor;
pub(crate) mod token;
use token::Token;
use crate::error::SyntaxError;
use crate::error::Error;
pub struct Lexer<'a> {
file: String,
@ -40,9 +40,9 @@ static KEYWORDS: [KeywordMap; 6] = [
];
impl Iterator for Lexer<'_> {
type Item = Result<Token, SyntaxError>;
type Item = Result<Token, Error>;
fn next(&mut self) -> Option<Result<Token, SyntaxError>> {
fn next(&mut self) -> Option<Result<Token, Error>> {
if self.offset > 0 {
let tmp = self.history[self.history.len() - self.offset].clone();
self.offset -= 1;
@ -110,7 +110,7 @@ impl<'a> Lexer<'a> {
}
}
pub fn peek(&mut self) -> Option<Result<Token, SyntaxError>> {
pub fn peek(&mut self) -> Option<Result<Token, Error>> {
let t = self.next()?;
self.prev();
Some(t)
@ -122,7 +122,7 @@ impl<'a> Lexer<'a> {
Some(prev)
}
pub fn expect_kind(&mut self, kind: token::Kind) -> Result<Token, SyntaxError> {
pub fn expect_kind(&mut self, kind: token::Kind) -> Result<Token, Error> {
match self.next() {
Some(Ok(t)) => if t.kind == kind {
Ok(t)
@ -134,14 +134,14 @@ impl<'a> Lexer<'a> {
}
}
pub fn require_next(&mut self) -> Result<Token, SyntaxError> {
pub fn require_next(&mut self) -> Result<Token, Error> {
match self.next() {
Some(t) => t,
None => self.syntax_error(String::from("Unexpected EOF")),
}
}
fn read_keyword_or_ident(&mut self) -> Result<Token, SyntaxError> {
fn read_keyword_or_ident(&mut self) -> Result<Token, Error> {
let current = self.cursor.current().unwrap();
for kw in &KEYWORDS {
// keywords are always at least 2 characters long as per the language spec
@ -154,7 +154,7 @@ impl<'a> Lexer<'a> {
self.read_ident()
}
fn read_ident(&mut self) -> Result<Token, SyntaxError> {
fn read_ident(&mut self) -> Result<Token, Error> {
for c in &mut self.cursor {
if !c.is_ascii_alphanumeric() && c != '_' {
self.cursor.prev();
@ -165,13 +165,13 @@ impl<'a> Lexer<'a> {
self.token_ok(token::Kind::Ident)
}
fn read_comment(&mut self) -> Result<Token, SyntaxError> {
fn read_comment(&mut self) -> Result<Token, Error> {
assert_eq!(self.cursor.current(), Some('#'));
self.cursor.seek_while(|c| c != '\n');
self.token_ok(token::Kind::Comment)
}
fn read_string_literal(&mut self) -> Result<Token, SyntaxError> {
fn read_string_literal(&mut self) -> Result<Token, Error> {
assert_eq!(self.cursor.current(), Some('"'));
self.cursor.chop();
let mut raw = String::new();
@ -188,7 +188,7 @@ impl<'a> Lexer<'a> {
self.token_ok(token::Kind::StringLiteral)
}
fn read_prefix_int_literal(&mut self) -> Result<Token, SyntaxError> {
fn read_prefix_int_literal(&mut self) -> Result<Token, Error> {
assert_eq!(self.cursor.next(), Some('0'));
match self.cursor.next() {
Some('x') => self.read_int_literal(16),
@ -199,7 +199,7 @@ impl<'a> Lexer<'a> {
}
}
fn read_int_literal(&mut self, base: usize) -> Result<Token, SyntaxError> {
fn read_int_literal(&mut self, base: usize) -> Result<Token, Error> {
assert!(base >= 2 && base <= 16);
for c in &mut self.cursor {
@ -246,8 +246,8 @@ impl<'a> Lexer<'a> {
true
}
fn syntax_error<T>(&mut self, msg: String) -> Result<T, SyntaxError> {
Err(SyntaxError::new(
fn syntax_error<T>(&mut self, msg: String) -> Result<T, Error> {
Err(Error::syntax_error(
self.file.clone(),
self.cursor.line(),
self.cursor.col(),

Loading…
Cancel
Save