diff --git a/tests/snippets/builtin_abs.py b/tests/snippets/builtin_abs.py new file mode 100644 index 000000000..1b744978e --- /dev/null +++ b/tests/snippets/builtin_abs.py @@ -0,0 +1,5 @@ +assert abs(-3) == 3 +assert abs(7) == 7 +assert abs(-3.21) == 3.21 +assert abs(6.25) == 6.25 + diff --git a/tests/snippets/builtin_divmod.py b/tests/snippets/builtin_divmod.py new file mode 100644 index 000000000..7bab71c99 --- /dev/null +++ b/tests/snippets/builtin_divmod.py @@ -0,0 +1,3 @@ +assert divmod(11, 3) == (3, 2) +assert divmod(8,11) == (0, 8) +assert divmod(0.873, 0.252) == (3.0, 0.11699999999999999) diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 297187d2e..630044e5e 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -45,7 +45,13 @@ fn dir_object(vm: &mut VirtualMachine, obj: &PyObjectRef) -> PyObjectRef { vm.ctx.new_list(members_pystr) } -// builtin_abs +fn builtin_abs(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(x, None)]); + match vm.get_attribute(x.clone(), &"__abs__") { + Ok(attrib) => vm.invoke(attrib, PyFuncArgs::new(vec![], vec![])), + Err(..) => Err(vm.new_type_error("bad operand for abs".to_string())), + } +} fn builtin_all(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { for item in args.args { @@ -122,7 +128,14 @@ fn builtin_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } -// builtin_divmod +fn builtin_divmod(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(x, None), (y, None)]); + match vm.get_attribute(x.clone(), &"__divmod__") { + Ok(attrib) => vm.invoke(attrib, PyFuncArgs::new(vec![y.clone()], vec![])), + Err(..) => Err(vm.new_type_error("unsupported operand type(s) for divmod".to_string())), + } +} + // builtin_enumerate fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -373,7 +386,6 @@ fn builtin_setattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { // builtin_slice // builtin_sorted // builtin_staticmethod - // builtin_sum // builtin_super // builtin_vars @@ -383,6 +395,7 @@ fn builtin_setattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { pub fn make_module(ctx: &PyContext) -> PyObjectRef { // scope[String::from("print")] = print; let mut dict = HashMap::new(); + dict.insert(String::from("abs"), ctx.new_rustfunc(builtin_abs)); dict.insert(String::from("all"), ctx.new_rustfunc(builtin_all)); dict.insert(String::from("any"), ctx.new_rustfunc(builtin_any)); dict.insert(String::from("bool"), ctx.bool_type()); @@ -390,6 +403,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { dict.insert(String::from("chr"), ctx.new_rustfunc(builtin_chr)); dict.insert(String::from("compile"), ctx.new_rustfunc(builtin_compile)); dict.insert(String::from("dict"), ctx.dict_type()); + dict.insert(String::from("divmod"), ctx.new_rustfunc(builtin_divmod)); dict.insert(String::from("dir"), ctx.new_rustfunc(builtin_dir)); dict.insert(String::from("eval"), ctx.new_rustfunc(builtin_eval)); dict.insert(String::from("float"), ctx.float_type()); diff --git a/vm/src/obj/objfloat.rs b/vm/src/obj/objfloat.rs index 376627ee4..affd18a95 100644 --- a/vm/src/obj/objfloat.rs +++ b/vm/src/obj/objfloat.rs @@ -61,6 +61,11 @@ fn float_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.ctx.new_bool(result)) } +fn float_abs(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(i, Some(vm.ctx.float_type()))]); + Ok(vm.ctx.new_float(get_value(i).abs())) +} + fn float_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, @@ -78,13 +83,45 @@ fn float_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +fn float_divmod(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(i, Some(vm.ctx.float_type())), (i2, None)] + ); + let args = PyFuncArgs::new(vec![i.clone(), i2.clone()], vec![]); + if objtype::isinstance(i2, vm.ctx.float_type()) || objtype::isinstance(i2, vm.ctx.int_type()) { + let r1 = float_floordiv(vm, args.clone()); + let r2 = float_mod(vm, args.clone()); + Ok(vm.ctx.new_tuple(vec![r1.unwrap(), r2.unwrap()])) + } else { + Err(vm.new_type_error(format!("Cannot divmod power {:?} and {:?}", i, i2))) + } +} + +fn float_floordiv(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(i, Some(vm.ctx.float_type())), (i2, None)] + ); + if objtype::isinstance(i2, vm.ctx.float_type()) { + Ok(vm.ctx.new_float((get_value(i) / get_value(i2)).floor())) + } else if objtype::isinstance(i2, vm.ctx.int_type()) { + Ok(vm + .ctx + .new_float((get_value(i) / objint::get_value(i2) as f64).floor())) + } else { + Err(vm.new_type_error(format!("Cannot floordiv {:?} and {:?}", i, i2))) + } +} + fn float_sub(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, args, required = [(i, Some(vm.ctx.float_type())), (i2, None)] ); - let v1 = get_value(i); if objtype::isinstance(i2, vm.ctx.float_type()) { Ok(vm.ctx.new_float(v1 - get_value(i2))) @@ -95,6 +132,23 @@ fn float_sub(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +fn float_mod(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(i, Some(vm.ctx.float_type())), (i2, None)] + ); + if objtype::isinstance(i2, vm.ctx.float_type()) { + Ok(vm.ctx.new_float(get_value(i) % get_value(i2))) + } else if objtype::isinstance(i2, vm.ctx.int_type()) { + Ok(vm + .ctx + .new_float(get_value(i) % objint::get_value(i2) as f64)) + } else { + Err(vm.new_type_error(format!("Cannot mod {:?} and {:?}", i, i2))) + } +} + fn float_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, @@ -117,8 +171,12 @@ fn float_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { pub fn init(context: &PyContext) { let ref float_type = context.float_type; float_type.set_attr("__eq__", context.new_rustfunc(float_eq)); + float_type.set_attr("__abs__", context.new_rustfunc(float_abs)); float_type.set_attr("__add__", context.new_rustfunc(float_add)); + float_type.set_attr("__divmod__", context.new_rustfunc(float_divmod)); + float_type.set_attr("__floordiv__", context.new_rustfunc(float_floordiv)); float_type.set_attr("__init__", context.new_rustfunc(float_init)); + float_type.set_attr("__mod__", context.new_rustfunc(float_mod)); float_type.set_attr("__pow__", context.new_rustfunc(float_pow)); float_type.set_attr("__sub__", context.new_rustfunc(float_sub)); float_type.set_attr("__repr__", context.new_rustfunc(float_repr)); diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 061d4b39b..22835fa6a 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -99,6 +99,11 @@ fn int_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.ctx.new_bool(result)) } +fn int_abs(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(i, Some(vm.ctx.int_type()))]); + Ok(vm.ctx.new_int(get_value(i).abs())) +} + fn int_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, @@ -115,6 +120,19 @@ fn int_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +fn int_floordiv(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(i, Some(vm.ctx.int_type())), (i2, None)] + ); + if objtype::isinstance(i2, vm.ctx.int_type()) { + Ok(vm.ctx.new_int(get_value(i) / get_value(i2))) + } else { + Err(vm.new_type_error(format!("Cannot floordiv {:?} and {:?}", i, i2))) + } +} + fn int_sub(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, @@ -139,6 +157,10 @@ fn int_mul(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { ); if objtype::isinstance(i2, vm.ctx.int_type()) { Ok(vm.ctx.new_int(get_value(i) * get_value(i2))) + } else if objtype::isinstance(i2, vm.ctx.float_type()) { + Ok(vm + .ctx + .new_float(get_value(i) as f64 * objfloat::get_value(i2))) } else { Err(vm.new_type_error(format!("Cannot multiply {:?} and {:?}", i, i2))) } @@ -192,6 +214,22 @@ fn int_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +fn int_divmod(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(i, Some(vm.ctx.int_type())), (i2, None)] + ); + let args = PyFuncArgs::new(vec![i.clone(), i2.clone()], vec![]); + if objtype::isinstance(i2, vm.ctx.int_type()) { + let r1 = int_floordiv(vm, args.clone()); + let r2 = int_mod(vm, args.clone()); + Ok(vm.ctx.new_tuple(vec![r1.unwrap(), r2.unwrap()])) + } else { + Err(vm.new_type_error(format!("Cannot divmod power {:?} and {:?}", i, i2))) + } +} + fn int_xor(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, @@ -240,8 +278,11 @@ fn int_and(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { pub fn init(context: &PyContext) { let ref int_type = context.int_type; int_type.set_attr("__eq__", context.new_rustfunc(int_eq)); + int_type.set_attr("__abs__", context.new_rustfunc(int_abs)); int_type.set_attr("__add__", context.new_rustfunc(int_add)); int_type.set_attr("__and__", context.new_rustfunc(int_and)); + int_type.set_attr("__divmod__", context.new_rustfunc(int_divmod)); + int_type.set_attr("__floordiv__", context.new_rustfunc(int_floordiv)); int_type.set_attr("__new__", context.new_rustfunc(int_new)); int_type.set_attr("__mod__", context.new_rustfunc(int_mod)); int_type.set_attr("__mul__", context.new_rustfunc(int_mul)); diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 2984ec7fa..9d90f97bd 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -443,6 +443,7 @@ impl VirtualMachine { // self.invoke('__neg__' match a.borrow().kind { PyObjectKind::Integer { value: ref value1 } => Ok(self.ctx.new_int(-*value1)), + PyObjectKind::Float { value: ref value1 } => Ok(self.ctx.new_float(-*value1)), _ => panic!("Not impl {:?}", a), } }