1#[macro_export]
2macro_rules! define_compile_errors {
3 (
4 $(
5 $variant:ident {
6 error = $error_msg:literal,
7 label = $label_msg:literal,
8 fields = { $( $field_name:ident : $field_ty:ty ),* $(,)? }
9 }
10 ),* $(,)?
11 ) => {
12 #[derive(Debug, thiserror::Error)]
13 pub enum CompileError {
14 $(
15 #[error($error_msg)]
16 $variant { $( $field_name: $field_ty ),*, custom_label: Option<String> }
17 ),*
18 }
19
20 impl CompileError {
21 pub fn label(&self) -> &str {
22 match self {
23 $(
24 Self::$variant { custom_label, .. } => custom_label.as_deref().unwrap_or($label_msg),
25 )*
26 }
27 }
28
29 pub fn span(&self) -> &Range<usize> {
30 match self {
31 $(
32 Self::$variant { span, .. } => span,
33 )*
34 }
35 }
36 }
37 };
38}
39
40#[macro_export]
42macro_rules! bug {
43 ($($arg:tt)*) => {{
44 eprintln!(
45 "\n{}\n{}",
46 "Thanks for abusing the compiler <3 you've hunted a bug!",
47 format!("Please file a bug report at: {}", "https://github.com/blueshift-gg/sbpf/issues/new")
48 );
49
50 panic!("{}", format!("Internal error: {}\n", format!($($arg)*)));
51 }};
52}
53
54#[cfg(test)]
55mod tests {
56 use std::ops::Range;
57
58 #[test]
59 fn test_define_compile_errors_macro() {
60 define_compile_errors! {
61 TestError1 {
62 error = "Test error 1",
63 label = "test label 1",
64 fields = { span: Range<usize> }
65 },
66 TestError2 {
67 error = "Test error 2",
68 label = "test label 2",
69 fields = { span: Range<usize>, message: String }
70 }
71 }
72
73 let err1 = CompileError::TestError1 {
75 span: 0..10,
76 custom_label: None,
77 };
78 assert_eq!(err1.label(), "test label 1");
79 assert_eq!(err1.span(), &(0..10));
80 assert_eq!(err1.to_string(), "Test error 1");
81
82 let err2 = CompileError::TestError2 {
83 span: 5..15,
84 message: "custom message".to_string(),
85 custom_label: Some("custom".to_string()),
86 };
87 assert_eq!(err2.label(), "custom");
88 assert_eq!(err2.span(), &(5..15));
89 }
90}