#[macro_export]
macro_rules! error {
($diagnostic:expr) => {
$crate::error::Error(Box::new($diagnostic))
};
($diagnostic:expr, $fragment:expr) => {{
let mut diag = $diagnostic;
diag.with_fragment($fragment.into());
$crate::error::Error(Box::new(diag))
}};
}
#[macro_export]
macro_rules! return_error {
($diagnostic:expr) => {
return Err($crate::error::Error(Box::new($diagnostic)))
};
($diagnostic:expr, $fragment:expr) => {{
let mut diag = $diagnostic;
diag.with_fragment($fragment.into());
return Err($crate::error::Error(Box::new(diag)));
}};
}
#[macro_export]
macro_rules! err {
($diagnostic:expr) => {
Err($crate::error::Error(Box::new($diagnostic)))
};
($diagnostic:expr, $fragment:expr) => {{
let mut diag = $diagnostic;
diag.with_fragment($fragment.into());
Err($crate::error::Error(Box::new(diag)))
}};
}
#[cfg(test)]
pub mod tests {
use std::sync::Arc;
use crate::{
error::{Error, IntoDiagnostic, TypeError},
fragment::{Fragment, StatementColumn, StatementLine},
};
#[test]
fn test_error_macro() {
let err = error!(TypeError::NanNotAllowed.into_diagnostic());
assert!(matches!(err, Error(_)));
let diagnostic = err.diagnostic();
assert!(diagnostic.message.contains("NaN"));
}
#[test]
fn test_return_error_macro() {
fn test_fn() -> Result<(), Error> {
return_error!(TypeError::NanNotAllowed.into_diagnostic());
}
let result = test_fn();
assert!(result.is_err());
if let Err(err) = result {
let diagnostic = err.diagnostic();
assert!(diagnostic.message.contains("NaN"));
}
}
#[test]
fn test_err_macro() {
let result: Result<(), Error> = err!(TypeError::NanNotAllowed.into_diagnostic());
assert!(result.is_err());
if let Err(err) = result {
let diagnostic = err.diagnostic();
assert!(diagnostic.message.contains("NaN"));
}
}
#[test]
fn test_error_macro_with_fragment() {
let fragment = Fragment::Statement {
line: StatementLine(42),
column: StatementColumn(10),
text: Arc::from("test fragment"),
};
let err = error!(TypeError::NanNotAllowed.into_diagnostic(), fragment.clone());
assert!(matches!(err, Error(_)));
let diagnostic = err.diagnostic();
let fragment = diagnostic.fragment();
assert!(fragment.is_some());
if let Some(Fragment::Statement {
line,
column,
..
}) = fragment.as_ref()
{
assert_eq!(line.0, 42);
assert_eq!(column.0, 10);
}
}
#[test]
fn test_return_error_macro_with_fragment() {
fn test_fn() -> Result<(), Error> {
let fragment = Fragment::Statement {
line: StatementLine(100),
column: StatementColumn(25),
text: Arc::from("error location"),
};
return_error!(TypeError::NanNotAllowed.into_diagnostic(), fragment);
}
let result = test_fn();
assert!(result.is_err());
if let Err(err) = result {
let diagnostic = err.diagnostic();
let fragment = diagnostic.fragment();
assert!(fragment.is_some());
if let Some(Fragment::Statement {
line,
column,
..
}) = fragment.as_ref()
{
assert_eq!(line.0, 100);
assert_eq!(column.0, 25);
}
}
}
#[test]
fn test_err_macro_with_fragment() {
let fragment = Fragment::Statement {
line: StatementLine(200),
column: StatementColumn(50),
text: Arc::from("err fragment test"),
};
let result: Result<(), Error> = err!(TypeError::NanNotAllowed.into_diagnostic(), fragment);
assert!(result.is_err());
if let Err(err) = result {
let diagnostic = err.diagnostic();
let fragment = diagnostic.fragment();
assert!(fragment.is_some());
if let Some(Fragment::Statement {
line,
column,
..
}) = fragment.as_ref()
{
assert_eq!(line.0, 200);
assert_eq!(column.0, 50);
}
}
}
#[test]
fn test_macros_with_closure_fragment() {
let get_fragment = || Fragment::Statement {
line: StatementLine(300),
column: StatementColumn(75),
text: Arc::from("closure fragment"),
};
let err = error!(TypeError::NanNotAllowed.into_diagnostic(), get_fragment());
let diagnostic = err.diagnostic();
let fragment = diagnostic.fragment();
assert!(fragment.is_some());
assert_eq!(fragment.as_ref().unwrap().line().0, 300);
}
}