use crate::frontend::{ast, parser};
use crate::ir;
use petgraph::stable_graph::NodeIndex;
use std::rc::Rc;
#[allow(clippy::large_enum_variant)]
pub enum Error {
ParseError(pest_consume::Error<parser::Rule>),
ReservedName(ir::Id),
UnknownPass(String),
InvalidFile(String),
WriteError(String),
MalformedControl(String),
MalformedStructure(String),
MismatchedPortWidths(ast::Port, u64, ast::Port, u64),
PassAssumption(String, String),
Undefined(ir::Id, String),
AlreadyBound(ir::Id, String),
UnusedGroup(ir::Id),
SignatureResolutionFailed(ir::Id, ir::Id),
MissingImplementation(&'static str, ir::Id),
Papercut(String, ir::Id),
ImpossibleLatencyAnnotation(String, u64, u64),
Impossible(String), NotSubcomponent,
#[allow(unused)]
Misc(String),
}
pub type CalyxResult<T> = std::result::Result<T, Error>;
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Span {
input: Rc<str>,
start: usize,
end: usize,
}
impl Span {
pub fn new(span: pest::Span, input: Rc<str>) -> Span {
Span {
input,
start: span.start(),
end: span.end(),
}
}
pub fn format(&self, err_msg: &str) -> String {
let lines = self.input.split('\n');
let mut buf: String = String::new();
let mut pos: usize = 0;
let mut linum: usize = 1;
for l in lines {
let new_pos = pos + l.len() + 1;
if self.start > pos && self.end < pos + (l.len()) {
let linum_text = format!("{} ", linum);
let linum_space: String = " ".repeat(linum_text.len());
let mark: String = "^".repeat(self.end - self.start);
let space: String = " ".repeat(self.start - pos);
buf += "\n";
buf += &format!("{}|{}\n", linum_text, l);
buf +=
&format!("{}|{}{} {}", linum_space, space, mark, err_msg);
break;
}
pos = new_pos;
linum += 1;
}
buf
}
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use Error::*;
match self {
Papercut(msg, id) => {
write!(f, "{}", id.fmt_err(&("[Papercut] ".to_string() + msg)))
}
ImpossibleLatencyAnnotation(grp_name, ann_val, inferred_val) => {
let msg1 = format!("Annotated latency: {}", ann_val);
let msg2 = format!("Inferred latency: {}", inferred_val);
write!(
f,
"Impossible \"static\" latency annotation for group {}.\n{}\n{}",
grp_name,
msg1,
msg2
)
}
UnusedGroup(name) => {
write!(
f,
"{}",
name.fmt_err("Group not used in control")
)
}
AlreadyBound(name, bound_by) => {
let msg = format!("Name already bound by {}", bound_by.to_string());
write!(f, "{}", name.fmt_err(&msg))
}
ReservedName(name) => {
let msg = format!("Use of reserved keyword: {}", name.to_string());
write!(f, "{}", name.fmt_err(&msg))
}
Undefined(name, typ) => {
let msg = format!("Undefined {} name: {}", typ, name.to_string());
write!(
f,
"{}",
name.fmt_err(&msg)
)
}
UnknownPass(pass) => {
write!(
f,
"Unknown pass: {}. Use the flag `--list-passes` to view known passes.",
pass,
)
},
InvalidFile(err) => write!(f, "{}", err),
ParseError(err) => write!(f, "Calyx Parser: {}", err),
WriteError(msg) => write!(f, "{}", msg),
MismatchedPortWidths(port1, w1, port2, w2) => {
let msg1 = format!("This port has width: {}", w1);
let msg2 = format!("This port has width: {}", w2);
write!(f, "{}\nwhich doesn't match the width of '{}':{}",
port1.port_name().fmt_err(&msg1),
port2.port_name().to_string(),
port2.port_name().fmt_err(&msg2))
}
SignatureResolutionFailed(id, param_name) => {
let msg = format!("Failed to resolve: {}", param_name.to_string());
write!(f, "{}\nwhich is used here:{}", id.fmt_err(&msg), param_name.fmt_err(""))
}
MalformedControl(msg) => write!(f, "Malformed Control: {}", msg),
PassAssumption(pass, msg) => write!(f, "Pass `{}` requires: {}", pass, msg),
MalformedStructure(msg) => write!(f, "Malformed Structure: {}", msg),
NotSubcomponent => write!(f, "Not a subcomponent"),
Misc(msg) => write!(f, "{}", msg),
Impossible(msg) => write!(f, "Impossible: {}\nThis error should never occur. Report report this as a bug.", msg),
MissingImplementation(name, id) => write!(f, "Mising {} implementation for `{}`", name, id.to_string())
}
}
}
impl From<std::str::Utf8Error> for Error {
fn from(err: std::str::Utf8Error) -> Self {
Error::InvalidFile(err.to_string())
}
}
impl From<pest_consume::Error<parser::Rule>> for Error {
fn from(e: pest_consume::Error<parser::Rule>) -> Self {
Error::ParseError(e)
}
}
impl From<std::io::Error> for Error {
fn from(_e: std::io::Error) -> Self {
Error::WriteError("IO Error".to_string())
}
}
pub trait Extract<T, R> {
fn extract(&self, id: &ir::Id) -> CalyxResult<R>;
}
impl Extract<NodeIndex, NodeIndex> for Option<NodeIndex> {
fn extract(&self, id: &ir::Id) -> CalyxResult<NodeIndex> {
match self {
Some(t) => Ok(*t),
None => Err(Error::Undefined(id.clone(), "component".to_string())),
}
}
}