match_class! macro

This commit is contained in:
Joey Hain
2019-04-01 13:38:06 -07:00
parent 0ce15e1ff5
commit 98889d5339
2 changed files with 93 additions and 0 deletions

View File

@@ -147,3 +147,90 @@ macro_rules! extend_class {
)*
}
}
/// Macro to match on the built-in class of a Python object.
///
/// Like `match`, `match_object!` is an expression, and so must have a default
/// arm that will be evaluated when the object was not an instance of any of
/// the classes specified in other arms.
///
/// # Examples
///
/// ```
/// use num_bigint::ToBigInt;
/// use num_traits::Zero;
///
/// use rustpython_vm::VirtualMachine;
/// use rustpython_vm::match_class;
/// use rustpython_vm::obj::objfloat::PyFloat;
/// use rustpython_vm::obj::objint::PyInt;
/// use rustpython_vm::pyobject::PyValue;
///
/// let vm = VirtualMachine::new();
/// let obj = PyInt::new(0).into_ref(&vm).into_object();
/// assert_eq!(
/// "int",
/// match_class!(obj.clone(),
/// PyInt => "int",
/// PyFloat => "float",
/// _ => "neither"
/// )
/// );
///
/// ```
///
/// With a binding to the downcasted type:
///
/// ```
/// use num_bigint::ToBigInt;
/// use num_traits::Zero;
///
/// use rustpython_vm::VirtualMachine;
/// use rustpython_vm::match_class;
/// use rustpython_vm::obj::objfloat::PyFloat;
/// use rustpython_vm::obj::objint::PyInt;
/// use rustpython_vm::pyobject::PyValue;
///
/// let vm = VirtualMachine::new();
/// let obj = PyInt::new(0).into_ref(&vm).into_object();
///
/// let int_value = match_class!(obj,
/// i @ PyInt => i.as_bigint().clone(),
/// f @ PyFloat => f.to_f64().to_bigint().unwrap(),
/// obj => panic!("non-numeric object {}", obj)
/// );
///
/// assert!(int_value.is_zero());
/// ```
#[macro_export]
macro_rules! match_class {
// The default arm.
($obj:expr, _ => $default:expr) => {
$default
};
// The default arm, binding the original object to the specified identifier.
($obj:expr, $binding:ident => $default:expr) => {{
let $binding = $obj;
$default
}};
// An arm taken when the object is an instance of the specified built-in
// class and binding the downcasted object to the specified identifier.
($obj:expr, $binding:ident @ $class:ty => $expr:expr, $($rest:tt)*) => {
match $obj.downcast::<$class>() {
Ok($binding) => $expr,
Err(_obj) => match_class!(_obj, $($rest)*),
}
};
// An arm taken when the object is an instance of the specified built-in
// class.
($obj:expr, $class:ty => $expr:expr, $($rest:tt)*) => {
if $obj.payload_is::<$class>() {
$expr
} else {
match_class!($obj, $($rest)*)
}
};
}

View File

@@ -16,6 +16,12 @@ pub struct PyFloat {
value: f64,
}
impl PyFloat {
pub fn to_f64(&self) -> f64 {
self.value
}
}
impl PyValue for PyFloat {
fn class(vm: &VirtualMachine) -> PyClassRef {
vm.ctx.float_type()