You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
3.2 KiB
Rust

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.
trait ErrorDetails {
/// Name of the file that the error originated from.
fn file(&self) -> &String;
/// Line (starting from 1) of the first erroneous character.
fn line(&self) -> usize;
/// Column (starting from 1) of the first erroneous character.
fn col(&self) -> usize;
/// Human readable error message.
fn msg(&self) -> &String;
/// Human readable error name (mostly for internal use; see the `fmt::Display` impl).
fn name(&self) -> &str;
}
#[derive(Debug)]
struct Position {
file: String,
line: usize,
col: usize,
}
#[derive(Debug)]
pub struct SyntaxError {
pos: Position,
msg: String,
}
#[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())
}
}
impl SyntaxError {
pub fn new(file: String, line: usize, col: usize, msg: String) -> SyntaxError {
SyntaxError {
pos: Position { file, line, col },
msg,
}
}
}
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
}
fn line(&self) -> usize {
self.pos.line
}
fn col(&self) -> usize {
self.pos.col
}
fn msg(&self) -> &String {
&self.msg
}
fn name(&self) -> &str {
"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"
}
}