use std::fmt; use syn::{ext::*, spanned::*, *}; macro_rules! syn_error { ($src:expr, $($fmt:expr),+) => {{ return Err(syn::Error::new($src.span(), format!($($fmt),*))); }}; } macro_rules! syn_assert { ($cond:expr, $src:expr, $($fmt:expr),+) => {{ if !$cond { syn_error!($src, $($fmt),+); } }}; } pub(crate) use {syn_assert, syn_error}; pub fn wrap_expr_block(expr: &Expr) -> Block { // return the expr if it's a block, otherwise wrap it in a block match expr { Expr::Block(block) if block.label.is_none() => block.block.clone(), expr => parse_quote!({ #expr }), } } pub fn expr_ident(expr: &Expr) -> Result<&Ident> { match expr { Expr::Path(path) => path.path.require_ident(), _ => syn_error!(expr, "expected ident"), } } pub fn pat_ident(pat: &Pat) -> Result { Ok(match pat { Pat::Ident(ident) => match ident.subpat { Some((_, ref subpat)) => syn_error!(subpat, "unexpected subpattern"), None => ident.ident.clone(), }, Pat::Wild(wild) => Ident::new("_", wild.span()), _ => syn_error!(pat, "expected ident"), }) } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum LuaType { Any, Nil, Boolean, Lightuserdata, Number, Integer, String, Table, Function, Userdata, Thread, Cdata, } impl fmt::Display for LuaType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { LuaType::Any => write!(f, "any"), LuaType::Nil => write!(f, "nil"), LuaType::Boolean => write!(f, "boolean"), LuaType::Lightuserdata => write!(f, "lightuserdata"), LuaType::Number => write!(f, "number"), LuaType::Integer => write!(f, "integer"), LuaType::String => write!(f, "string"), LuaType::Table => write!(f, "table"), LuaType::Function => write!(f, "function"), LuaType::Userdata => write!(f, "userdata"), LuaType::Thread => write!(f, "thread"), LuaType::Cdata => write!(f, "cdata"), } } } impl TryFrom<&Ident> for LuaType { type Error = Error; fn try_from(value: &Ident) -> Result { Ok(match format!("{}", value.unraw()).as_str() { "any" => Self::Any, "nil" => Self::Nil, "boolean" => Self::Boolean, "lightuserdata" => Self::Lightuserdata, "number" => Self::Number, "integer" => Self::Integer, "string" => Self::String, "table" => Self::Table, "function" => Self::Function, "userdata" => Self::Userdata, "thread" => Self::Thread, "cdata" => Self::Cdata, _ => syn_error!(value, "invalid lua type"), }) } } impl TryFrom<&Type> for LuaType { type Error = Error; fn try_from(value: &Type) -> Result { match value { Type::Infer(_) => Ok(Self::Any), Type::Path(path) if path.qself.is_none() => path.path.require_ident()?.try_into(), _ => syn_error!(value, "invalid lua type"), } } }