use bottomspeak_macros::CompilerError;
use codespan_reporting::diagnostic::{
Diagnostic as CodespanDiagnostic, Label, LabelStyle, Severity,
};
use core::range::Range;
#[macro_export]
macro_rules! diagnostic {
(
$kind:expr
$(,labels = [
($primary_label_span:expr, $primary_label_fmt:literal $($primary_label_arg:tt)*)
$(,($label_span:expr, $label_fmt:literal $($label_arg:tt)*))*
])?
$(,notes = [$(($notes_fmt:literal $($notes_arg:tt)*)),+])?$(,)?
) => {{
$crate::diagnostics::Diagnostic {
kind: $kind,
labels: vec![
$($crate::diagnostics::DiagnosticLabel { primary: true, msg: format!($primary_label_fmt $($primary_label_arg)*), range: $primary_label_span.into() },
$($crate::diagnostics::DiagnosticLabel { primary: false, msg: format!($label_fmt $($label_arg)*), range: $label_span.into() }),*)?
],
notes: vec![
$($(format!($notes_fmt $($notes_arg)*)),*)?
]
}
}};
}
#[derive(Debug, Clone)]
pub(crate) struct Diagnostic {
pub(crate) kind: ErrorKind,
pub(crate) labels: Vec<DiagnosticLabel>,
pub(crate) notes: Vec<String>,
}
impl Diagnostic {
pub(crate) fn to_codespan_diagnostic(&self) -> CodespanDiagnostic<usize> {
let labels = self
.labels
.iter()
.map(|label| {
let style = if label.primary {
LabelStyle::Primary
} else {
LabelStyle::Secondary
};
Label {
style,
file_id: 0,
range: label.range.into(),
message: label.msg.clone(),
}
})
.collect();
CodespanDiagnostic {
severity: self.kind.severity(),
code: Some(self.kind.code().to_string()),
message: self.kind.msg(),
labels,
notes: self.notes.clone(),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct DiagnosticLabel {
pub(crate) primary: bool,
pub(crate) msg: String,
pub(crate) range: Range<usize>,
}
pub(crate) trait CompilerError {
fn msg(&self) -> String;
fn code(&self) -> String;
fn severity(&self) -> Severity;
}
#[allow(dead_code)]
#[derive(CompilerError, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum ErrorKind {
#[msg(
"oh dear, {interp_title} made a mistake, why don't you be a good {praise_term} and go report it at `https://www.github.com/oughtum/bottomspeak-interp/issues/` for me~"
)]
#[code(0000)]
Bug {
interp_title: String,
praise_term: String,
},
#[msg(
"sorry {petname}, {interp_title} doesn't need the character `{char}`, could you be ever such a good {praise_term} and remove it for me~"
)]
#[code(0001)]
UnexpectedToken {
petname: String,
interp_title: String,
praise_term: String,
char: char,
},
#[msg(
"you seem to have an unfinished emoticon here, could you please add a `{char_to_add}` at the end for me, {petname}~"
)]
#[code(0002)]
UnfinishedEmoticon { petname: String, char_to_add: char },
#[msg(
"{interp_title} doesn't quite understand, did you mean to type one of these, {petname}? - `>w<`, `>//<`, `>.<`"
)]
#[code(0003)]
AmbiguousUnfinishedEmoticon {
interp_title: String,
petname: String,
},
#[msg(
"{interp_title} thinks your enthusiasm is adorable but keysmashes can't be longer than 127 characters, okay {petname}? mwah~"
)]
#[code(0004)]
OverlongKeysmash {
interp_title: String,
petname: String,
},
#[msg("come on, be a good {praise_term} and use your words for {interp_title}~")]
#[code(0005)]
EmptySource {
praise_term: String,
interp_title: String,
},
#[msg(
"subs need a name for their {interp_title} to call them by and so does this, can you add one for me {petname}?~"
)]
#[code(0006)]
UnnamedSub {
petname: String,
interp_title: String,
},
#[msg(
"{interp_title} isn't sure where you're trying to jump to, {petname}, could you be a good {praise_term} and add the name of the subroutine you want for me?~"
)]
#[code(0007)]
UnnamedJump {
interp_title: String,
petname: String,
praise_term: String,
},
#[msg(
"all good subs need to communicate when they want {interp_title} to stop, so why don't you add a little `>.<` at the end for me~"
)]
#[code(0008)]
SubWithoutReturn { interp_title: String },
#[msg(
"subroutines aren't allowed to be inside another subroutine, that's {interp_title}'s job~"
)]
#[code(0009)]
NestedSubroutine { interp_title: String },
#[msg(
"oh you're a very talkative {praise_term} aren't you? unfortunately {interp_title}'s stack isn't infinite, so I think my adorable {praise_term} should shush now~"
)]
#[code(0010)]
ReachedStackLimit {
praise_term: String,
interp_title: String,
},
#[msg(
"oh {petname}, there aren't enough values on the stack to {op}, could you try again for {interp_title}?~"
)]
#[code(0011)]
InsufficientElements {
op: String,
petname: String,
interp_title: String,
},
#[msg(
"sorry {petname}, unicode characters are in the range 0x000000-0x10FFFF, git it another go for {interp_title} okay?~"
)]
#[code(0012)]
InvalidCodepoint {
petname: String,
interp_title: String,
},
#[msg(
"{name} couldn't find any subroutine called `{interp_title}`, but I know you can do better for me next time {petname} <3"
)]
#[code(0013)]
UnresolvedSubroutine {
name: String,
interp_title: String,
petname: String,
},
}