#[macro_export]
macro_rules! replace_expr {
($_t:tt $sub:expr) => {
$sub
};
}
#[macro_export]
macro_rules! count_tts {
($($tts:tt)*) => {0usize $(+ $crate::replace_expr!($tts 1usize))*};
}
#[macro_export]
macro_rules! type_check {
($vm:ident, $args:ident, $arg_count:ident, $arg_name:ident, $arg_type:expr) => {
if let Some(expected_type) = $arg_type {
let arg = &$args.args[$arg_count];
if !$crate::obj::objtype::isinstance(arg, &expected_type) {
use $crate::pyobject::TypeProtocol;
let arg_typ = arg.class();
let expected_type_name = $vm.to_pystr(&expected_type)?;
let actual_type = $vm.to_pystr(&arg_typ)?;
return Err($vm.new_type_error(format!(
"argument of type {} is required for parameter {} ({}) (got: {})",
expected_type_name,
$arg_count + 1,
stringify!($arg_name),
actual_type
)));
}
}
};
}
#[macro_export]
macro_rules! arg_check {
( $vm: ident, $args:ident ) => {
if $args.args.len() != 0 {
return Err($vm.new_type_error(format!(
"Expected no arguments (got: {})", $args.args.len())));
}
};
( $vm: ident, $args:ident, required=[$( ($arg_name:ident, $arg_type:expr) ),*] ) => {
$crate::arg_check!($vm, $args, required=[$( ($arg_name, $arg_type) ),*], optional=[]);
};
( $vm: ident, $args:ident, required=[$( ($arg_name:ident, $arg_type:expr) ),*], optional=[$( ($optional_arg_name:ident, $optional_arg_type:expr) ),*] ) => {
let mut arg_count = 0;
let minimum_arg_count = $crate::count_tts!($($arg_name)*);
let maximum_arg_count = minimum_arg_count + $crate::count_tts!($($optional_arg_name)*);
if $args.args.len() < minimum_arg_count || $args.args.len() > maximum_arg_count {
let expected_str = if minimum_arg_count == maximum_arg_count {
format!("{}", minimum_arg_count)
} else {
format!("{}-{}", minimum_arg_count, maximum_arg_count)
};
return Err($vm.new_type_error(format!(
"Expected {} arguments (got: {})",
expected_str,
$args.args.len()
)));
};
$(
$crate::type_check!($vm, $args, arg_count, $arg_name, $arg_type);
let $arg_name = &$args.args[arg_count];
#[allow(unused_assignments)]
{
arg_count += 1;
}
)*
$(
let $optional_arg_name = if arg_count < $args.args.len() {
$crate::type_check!($vm, $args, arg_count, $optional_arg_name, $optional_arg_type);
let ret = Some(&$args.args[arg_count]);
#[allow(unused_assignments)]
{
arg_count += 1;
}
ret
} else {
None
};
)*
};
}
#[macro_export]
macro_rules! no_kwargs {
( $vm: ident, $args:ident ) => {
if $args.kwargs.len() != 0 {
return Err($vm.new_type_error(format!(
"Expected no keyword arguments (got: {})",
$args.kwargs.len()
)));
}
};
}
#[macro_export]
macro_rules! py_module {
( $vm:expr, $module_name:expr, { $($name:expr => $value:expr),* $(,)* }) => {{
let module = $vm.ctx.new_module($module_name, $vm.ctx.new_dict());
$vm.set_attr(&module, "__name__", $vm.ctx.new_str($module_name.to_string())).unwrap();
$(
$vm.set_attr(&module, $name, $value).unwrap();
)*
module
}};
}
#[macro_export]
macro_rules! extend_module {
( $vm:expr, $module:expr, { $($name:expr => $value:expr),* $(,)* }) => {
$(
$vm.set_attr(&$module, $name, $value).unwrap();
)*
}
}
#[macro_export]
macro_rules! py_class {
( $ctx:expr, $class_name:expr, $class_base:expr, { $($name:expr => $value:expr),* $(,)* }) => {
{
let py_class = $ctx.new_class($class_name, $class_base);
$(
py_class.set_str_attr($name, $value);
)*
py_class
}
}
}
#[macro_export]
macro_rules! extend_class {
( $ctx:expr, $class:expr, { $($name:expr => $value:expr),* $(,)* }) => {
let class = $class;
$(
class.set_str_attr($name, $value);
)*
}
}
#[macro_export]
macro_rules! py_namespace {
( $vm:expr, { $($name:expr => $value:expr),* $(,)* }) => {
{
let namespace = $vm.ctx.new_namespace();
$(
$vm.set_attr(&namespace, $name, $value).unwrap();
)*
namespace
}
}
}
#[macro_export]
macro_rules! match_class {
($obj:expr, _ => $default:expr $(,)?) => {
$default
};
($obj:expr, $binding:ident => $default:expr $(,)?) => {{
let $binding = $obj;
$default
}};
($obj:expr, $binding:ident @ $class:ty => $expr:expr, $($rest:tt)*) => {
match $obj.downcast::<$class>() {
Ok($binding) => $expr,
Err(_obj) => $crate::match_class!(_obj, $($rest)*),
}
};
($obj:expr, $class:ty => $expr:expr, $($rest:tt)*) => {
if $obj.payload_is::<$class>() {
$expr
} else {
$crate::match_class!($obj, $($rest)*)
}
};
}