use crate::{GPosIdx, Id, WithPos};
pub type CalyxResult<T> = std::result::Result<T, Error>;
pub struct Error {
kind: Box<ErrorKind>,
pos: GPosIdx,
post_msg: Option<String>,
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.pos == GPosIdx::UNKNOWN {
write!(f, "{}", self.kind)?
} else {
write!(f, "{}", self.pos.format(self.kind.to_string()))?
}
if let Some(post) = &self.post_msg {
write!(f, "\n{}", post)?;
}
Ok(())
}
}
impl Error {
pub fn with_pos<T: WithPos>(mut self, pos: &T) -> Self {
self.pos = pos.copy_span();
self
}
pub fn with_post_msg(mut self, msg: Option<String>) -> Self {
self.post_msg = msg;
self
}
pub fn reserved_name(name: Id) -> Self {
Self {
kind: Box::new(ErrorKind::ReservedName(name)),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
pub fn malformed_control(msg: String) -> Self {
Self {
kind: Box::new(ErrorKind::MalformedControl(msg)),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
pub fn malformed_structure<S: ToString>(msg: S) -> Self {
Self {
kind: Box::new(ErrorKind::MalformedStructure(msg.to_string())),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
pub fn pass_assumption<S: ToString, M: ToString>(pass: S, msg: M) -> Self {
Self {
kind: Box::new(ErrorKind::PassAssumption(
pass.to_string(),
msg.to_string(),
)),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
pub fn undefined(name: Id, typ: String) -> Self {
Self {
kind: Box::new(ErrorKind::Undefined(name, typ)),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
pub fn already_bound(name: Id, typ: String) -> Self {
Self {
kind: Box::new(ErrorKind::AlreadyBound(name, typ)),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
pub fn unused<S: ToString>(group: Id, typ: S) -> Self {
Self {
kind: Box::new(ErrorKind::Unused(group, typ.to_string())),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
pub fn papercut(msg: String) -> Self {
Self {
kind: Box::new(ErrorKind::Papercut(msg)),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
pub fn misc(msg: String) -> Self {
Self {
kind: Box::new(ErrorKind::Misc(msg)),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
pub fn invalid_file(msg: String) -> Self {
Self {
kind: Box::new(ErrorKind::InvalidFile(msg)),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
pub fn write_error(msg: String) -> Self {
Self {
kind: Box::new(ErrorKind::WriteError(msg)),
pos: GPosIdx::UNKNOWN,
post_msg: None,
}
}
}
enum ErrorKind {
ReservedName(Id),
MalformedControl(String),
MalformedStructure(String),
PassAssumption(String, String),
Undefined(Id, String),
AlreadyBound(Id, String),
Unused(Id, String),
Papercut(String),
Misc(String),
InvalidFile(String),
WriteError(String),
}
impl std::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use ErrorKind::*;
match self {
Papercut(msg) => {
write!(f, "[Papercut] {}", msg)
}
Unused(name, typ) => {
write!(f, "Unused {typ} `{name}'")
}
AlreadyBound(name, bound_by) => {
write!(f, "Name `{name}' already bound by {bound_by}")
}
ReservedName(name) => {
write!(f, "Use of reserved keyword: {name}")
}
Undefined(name, typ) => {
write!(f, "Undefined {typ} name: {name}")
}
MalformedControl(msg) => write!(f, "Malformed Control: {msg}"),
PassAssumption(pass, msg) => {
write!(f, "Pass `{pass}` assumption violated: {msg}")
}
MalformedStructure(msg) => {
write!(f, "Malformed Structure: {msg}")
}
InvalidFile(msg) | WriteError(msg) | Misc(msg) => {
write!(f, "{msg}")
}
}
}
}
impl From<std::str::Utf8Error> for Error {
fn from(err: std::str::Utf8Error) -> Self {
Error::invalid_file(err.to_string())
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error::write_error(format!("IO Error: {}", e))
}
}