Add do_call macro, implement Bool builtins, add tests
* I noticed that `fn call(...)` in all objects was identical, so I made a macro for it. This should make things a little easier to read, since do_call is about 30 lines a pop. * Bool has a constructor now, and a to_int and to_float implementations * Add tests for constructors and add new bool tests Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
133
src/builtins.rs
133
src/builtins.rs
@@ -33,6 +33,39 @@ pub fn init_global_builtins() {
|
||||
//
|
||||
// This would probably be doable in a procedural macro.
|
||||
|
||||
macro_rules! impl_do_call {
|
||||
($name:ident) => {
|
||||
pub(crate) fn do_call(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
||||
match state {
|
||||
FunctionState::Begin => {
|
||||
// get the top item off the stack and call to_float on it
|
||||
let arg = vm.peek();
|
||||
let method = if let Some(method) =
|
||||
arg.borrow().get_vtable_attr(arg.clone(), stringify!($name))
|
||||
{
|
||||
method
|
||||
} else {
|
||||
// TODO builtins::do_call - throw exception when target doesn't have a
|
||||
// to_$name method
|
||||
// BLOCKED-ON: exceptions
|
||||
todo!(
|
||||
concat!("{} does not have a ", stringify!($name), " method"),
|
||||
arg.borrow().ty_name()
|
||||
);
|
||||
};
|
||||
vm.push(method.clone());
|
||||
method.borrow().call(vm, 0);
|
||||
|
||||
// resume execution
|
||||
FunctionResult::Yield(0)
|
||||
}
|
||||
FunctionState::Resume(0) => FunctionResult::Return,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -211,31 +244,7 @@ impl BaseObj {
|
||||
// Str implementations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
impl Str {
|
||||
pub(crate) fn do_call(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
||||
match state {
|
||||
FunctionState::Begin => {
|
||||
// get the top item off the stack and call to_str on it
|
||||
let arg = vm.peek();
|
||||
let method =
|
||||
if let Some(method) = arg.borrow().get_vtable_attr(arg.clone(), "to_str") {
|
||||
method
|
||||
} else {
|
||||
// TODO Str::do_call - throw exception when target doesn't have a to_str()
|
||||
// method
|
||||
// BLOCKED-ON: exceptions
|
||||
todo!("{} does not have a to_str() method", arg.borrow().ty_name());
|
||||
// NOTE - every object should have to_str, right?
|
||||
};
|
||||
vm.push(method.clone());
|
||||
method.borrow().call(vm, 0);
|
||||
|
||||
// resume execution
|
||||
FunctionResult::Yield(0)
|
||||
}
|
||||
FunctionState::Resume(0) => FunctionResult::Return,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
impl_do_call!(to_str);
|
||||
|
||||
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
||||
@@ -380,31 +389,7 @@ impl Int {
|
||||
Float::create(int_value as f64).into()
|
||||
}
|
||||
|
||||
pub(crate) fn do_call(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
||||
match state {
|
||||
FunctionState::Begin => {
|
||||
// Pop the argument and call `to_int` on it
|
||||
let arg = vm.peek();
|
||||
|
||||
let method =
|
||||
if let Some(method) = arg.borrow().get_vtable_attr(arg.clone(), "to_int") {
|
||||
method
|
||||
} else {
|
||||
// TODO Int::do_call - throw exception when arg doesn't have to_int()
|
||||
// method
|
||||
// BLOCKED-ON: exceptions
|
||||
todo!("{} does not have a to_int() method", arg.borrow().ty_name());
|
||||
};
|
||||
|
||||
vm.push(method.clone());
|
||||
method.borrow().call(vm, 0);
|
||||
|
||||
FunctionResult::Yield(0)
|
||||
}
|
||||
FunctionState::Resume(0) => FunctionResult::Return,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
impl_do_call!(to_int);
|
||||
|
||||
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
||||
@@ -522,33 +507,7 @@ macro_rules! float_bin_op_logical {
|
||||
}
|
||||
|
||||
impl Float {
|
||||
pub(crate) fn do_call(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
||||
match state {
|
||||
FunctionState::Begin => {
|
||||
// get the top item off the stack and call to_float on it
|
||||
let arg = vm.peek();
|
||||
let method =
|
||||
if let Some(method) = arg.borrow().get_vtable_attr(arg.clone(), "to_float") {
|
||||
method
|
||||
} else {
|
||||
// TODO Float::do_call - throw exception when target doesn't have a to_float()
|
||||
// method
|
||||
// BLOCKED-ON: exceptions
|
||||
todo!(
|
||||
"{} does not have a to_float() method",
|
||||
arg.borrow().ty_name()
|
||||
);
|
||||
};
|
||||
vm.push(method.clone());
|
||||
method.borrow().call(vm, 0);
|
||||
|
||||
// resume execution
|
||||
FunctionResult::Yield(0)
|
||||
}
|
||||
FunctionState::Resume(0) => FunctionResult::Return,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
impl_do_call!(to_float);
|
||||
|
||||
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
||||
@@ -590,3 +549,23 @@ impl Float {
|
||||
Float::create(-value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Bool {
|
||||
impl_do_call!(to_bool);
|
||||
|
||||
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
||||
// instantiation is done in the `__call__` function.
|
||||
FunctionResult::ReturnPush(Nil::create())
|
||||
}
|
||||
|
||||
pub(crate) fn to_int(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||
let bool_value = with_obj_downcast(vm.frame_stack()[0].clone(), Bool::bool_value);
|
||||
Int::create(bool_value as i64).into()
|
||||
}
|
||||
|
||||
pub(crate) fn to_float(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||
let bool_value = with_obj_downcast(vm.frame_stack()[0].clone(), Bool::bool_value);
|
||||
Float::create(bool_value as i64 as f64).into()
|
||||
}
|
||||
}
|
||||
|
||||
12
src/obj.rs
12
src/obj.rs
@@ -210,7 +210,17 @@ pub fn init_types() {
|
||||
__pos__ => BuiltinFunction::create("__pos__", Float::pos, 1),
|
||||
__neg__ => BuiltinFunction::create("__neg__", Float::neg, 1),
|
||||
},
|
||||
Bool { },
|
||||
Bool {
|
||||
// Conversion methods
|
||||
to_int => BuiltinFunction::create("to_int", Bool::to_int, 1),
|
||||
to_float => BuiltinFunction::create("to_float", Bool::to_float, 1),
|
||||
|
||||
// Constructor
|
||||
__call__ => BuiltinFunction::create("__call__", Bool::do_call, 2),
|
||||
__init__ => BuiltinFunction::create("__init__", Bool::init, 2),
|
||||
|
||||
// Operators
|
||||
},
|
||||
Nil { },
|
||||
BuiltinFunction { },
|
||||
UserFunction { },
|
||||
|
||||
Reference in New Issue
Block a user