gaybuild/src/error.rs
fef 192edca1a1
rt: add initial runtime implementation
Alright, so this is ugly.  I'm really not happy
with how it turned out for the most part, but
that's what refactoring is for.  For now, though,
i will sleep because i'm seriously tired.
2022-08-07 06:40:08 +02:00

183 lines
3.6 KiB
Rust

use std::fmt;
use crate::ast::tree::Type;
use crate::lex::token::Position;
/// 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.
pub struct Error {
e: Box<dyn ErrorDetails>,
}
impl Error {
pub fn syntax_error(pos: Position, msg: String) -> Error {
Error {
e: Box::new(SyntaxError::new(pos, msg)),
}
}
pub fn type_error(pos: Position, expected: Type, actual: Type) -> Error {
Error {
e: Box::new(TypeError::new(pos, expected, actual)),
}
}
pub fn runtime_error(pos: Position, msg: String) -> Error {
Error {
e: Box::new(RuntimeError::new(pos, msg)),
}
}
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)]
pub struct SyntaxError {
pos: Position,
msg: String,
}
#[derive(Debug)]
pub struct TypeError {
pos: Position,
msg: String,
}
#[derive(Debug)]
pub struct RuntimeError {
pos: Position,
msg: String,
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let e = &self.e;
write!(
f,
"{} in {}:{}:{}: {}",
e.name(),
e.file(),
e.line(),
e.col(),
e.msg()
)
}
}
impl SyntaxError {
pub fn new(pos: Position, msg: String) -> SyntaxError {
SyntaxError { pos, msg }
}
}
impl TypeError {
pub fn new(pos: Position, expected: Type, actual: Type) -> TypeError {
TypeError {
pos,
msg: format!("Expected type {}, got {} instead", expected, actual),
}
}
}
impl RuntimeError {
pub fn new(pos: Position, msg: String) -> RuntimeError {
RuntimeError { pos, msg }
}
}
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 {
&self.msg
}
fn name(&self) -> &str {
"TypeError"
}
}
impl ErrorDetails for RuntimeError {
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 {
"RuntimeError"
}
}