use std::convert::TryFrom;
use proc_macro2::Span;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{Expr, Macro};
use crate::detail::infer_macro_kind_from_path;
use crate::macro_parsing::assertion::Assertion;
use crate::macro_parsing::assertion_macro::AssertionMacro;
pub enum MacroExpression {
Assertion(AssertionMacro),
Other(Macro),
}
impl Spanned for MacroExpression {
fn span(&self) -> Span {
match self {
MacroExpression::Assertion(ass) => ass.span,
MacroExpression::Other(mac) => mac.span(),
}
}
}
impl MacroExpression {
pub fn new_assertion(ass: AssertionMacro) -> Self {
Self::Assertion(ass)
}
pub fn new_other(other: Macro) -> Self {
Self::Other(other)
}
}
impl TryFrom<Macro> for MacroExpression {
type Error = syn::Error;
fn try_from(mac: Macro) -> Result<Self, Self::Error> {
let span = mac.span();
let mut macro_arguments = mac
.parse_body_with(Punctuated::<Expr, syn::Token![,]>::parse_terminated)?
.into_iter();
let create_compile_error = |err_msg| syn::Error::new(span, err_msg);
let macro_kind = infer_macro_kind_from_path(&mac.path);
if macro_kind.is_binary_assertion() {
let lhs = macro_arguments.next().ok_or_else(|| {
create_compile_error("Too few arguments: expected 2 or more, got 0")
})?;
let operator = macro_kind.binary_operator(span).expect(
"Getting the binary operator for a binary assertion should return Some result",
);
let rhs = macro_arguments.next().ok_or_else(|| {
create_compile_error("Too few arguments: expected 2 or more, got 1")
})?;
let info_args: Vec<Expr> = macro_arguments.collect();
Ok(Self::new_assertion(AssertionMacro::new(
Assertion::new_binary(lhs, operator, rhs),
span,
info_args,
)))
} else if macro_kind.is_assertion() {
let expr = macro_arguments.next().ok_or_else(|| {
create_compile_error("Too few arguments: expected 1 or more, got 0")
})?;
let info_args: Vec<Expr> = macro_arguments.collect();
Ok(Self::new_assertion(AssertionMacro::new(
Assertion::new_assert(expr),
span,
info_args,
)))
} else {
Ok(MacroExpression::new_other(mac))
}
}
}