luby/crates/luaify/src/utils.rs
2025-06-17 11:23:59 +10:00

114 lines
3.2 KiB
Rust

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 unwrap_expr_ident(expr: &Expr) -> Result<&Ident> {
match expr {
Expr::Path(path) => path.path.require_ident(),
_ => syn_error!(expr, "expected ident"),
}
}
pub fn unwrap_pat_ident(pat: &Pat) -> Result<Ident> {
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<Self> {
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<Self> {
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"),
}
}
}