#![feature(decl_macro)]
use lark_collections::{seq, Seq};
use lark_debug_derive::DebugWith;
use lark_span::{FileName, Span};
use std::sync::Arc;
#[derive(Copy, Clone, Debug, DebugWith, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ErrorReported(pub Span<FileName>);
impl ErrorReported {
pub fn at_span(s: Span<FileName>) -> Self {
ErrorReported(s)
}
pub fn at_diagnostic(s: &Diagnostic) -> Self {
ErrorReported(s.span)
}
pub fn at_diagnostics(s: &[Diagnostic]) -> Self {
assert!(!s.is_empty());
Self::at_diagnostic(&s[0])
}
pub fn span(&self) -> Span<FileName> {
self.0
}
}
#[derive(Clone, Debug, DebugWith, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Diagnostic {
pub span: Span<FileName>,
pub label: String,
}
impl Diagnostic {
pub fn new(label: String, span: Span<FileName>) -> Self {
Diagnostic { label, span }
}
}
#[derive(Clone, Debug, DebugWith, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct WithError<T> {
pub value: T,
pub errors: Vec<Diagnostic>,
}
impl<T> WithError<T> {
pub fn ok(value: T) -> WithError<T> {
WithError {
value,
errors: vec![],
}
}
pub fn report_error<Cx>(cx: Cx, label: String, span: Span<FileName>) -> WithError<T>
where
T: ErrorSentinel<Cx>,
{
let diagnostic = Diagnostic::new(label, span);
WithError {
value: T::error_sentinel(cx, ErrorReported::at_diagnostic(&diagnostic)),
errors: vec![diagnostic],
}
}
pub fn accumulate_errors_into(self, vec: &mut Vec<Diagnostic>) -> T {
vec.extend(self.errors);
self.value
}
pub fn assert_no_errors(self) -> T {
assert!(
self.errors.is_empty(),
"expected no errors, found: {:#?}",
self.errors
);
self.into_value()
}
pub fn into_value(self) -> T {
self.value
}
pub fn into_result(self) -> Result<T, ErrorReported> {
if !self.errors.is_empty() {
Err(ErrorReported::at_diagnostics(&self.errors))
} else {
Ok(self.value)
}
}
pub fn map<U>(self, op: impl FnOnce(T) -> U) -> WithError<U> {
WithError {
value: op(self.value),
errors: self.errors,
}
}
}
pub macro or_return_sentinel($cx:expr, $v:expr) {
match $v {
Ok(v) => v,
Err(report) => {
log::debug!("or_return_sentinel: returning error sentinel");
return ErrorSentinel::error_sentinel($cx, report);
}
}
}
pub trait ResultExt<Ok, Cx> {
fn unwrap_or_error_sentinel(self, cx: Cx) -> Ok;
}
impl<Ok, Cx> ResultExt<Ok, Cx> for Result<Ok, ErrorReported>
where
Ok: ErrorSentinel<Cx>,
{
fn unwrap_or_error_sentinel(self, cx: Cx) -> Ok {
match self {
Ok(v) => v,
Err(report) => Ok::error_sentinel(cx, report),
}
}
}
pub trait ErrorSentinel<Cx> {
fn error_sentinel(cx: Cx, report: ErrorReported) -> Self;
}
impl<T, Cx> ErrorSentinel<Cx> for Result<T, ErrorReported> {
fn error_sentinel(_cx: Cx, report: ErrorReported) -> Self {
Err(report)
}
}
impl<T, Cx> ErrorSentinel<Cx> for Arc<T>
where
T: ErrorSentinel<Cx>,
{
fn error_sentinel(cx: Cx, report: ErrorReported) -> Self {
Arc::new(T::error_sentinel(cx, report))
}
}
impl<T, Cx> ErrorSentinel<Cx> for Vec<T>
where
T: ErrorSentinel<Cx>,
{
fn error_sentinel(cx: Cx, report: ErrorReported) -> Self {
vec![T::error_sentinel(cx, report)]
}
}
impl<T, Cx> ErrorSentinel<Cx> for Seq<T>
where
T: ErrorSentinel<Cx>,
{
fn error_sentinel(cx: Cx, report: ErrorReported) -> Self {
seq![T::error_sentinel(cx, report)]
}
}
impl<T, Cx> ErrorSentinel<Cx> for WithError<T>
where
T: ErrorSentinel<Cx>,
{
fn error_sentinel(cx: Cx, report: ErrorReported) -> WithError<T>
where
T: ErrorSentinel<Cx>,
{
WithError::ok(T::error_sentinel(cx, report))
}
}