diff --git a/tests/snippets/builtin_pow.py b/tests/snippets/builtin_pow.py new file mode 100644 index 000000000..cd8321da5 --- /dev/null +++ b/tests/snippets/builtin_pow.py @@ -0,0 +1,6 @@ +assert pow(3,2) == 9 +assert pow(5,3, 100) == 25 + +#causes overflow +# assert pow(41, 7, 2) == 1 +assert pow(7, 2, 49) == 0 diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 40735bba7..c4e17b5d7 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -290,7 +290,38 @@ fn builtin_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { // builtin_oct // builtin_open // builtin_ord -// builtin_pow + +fn builtin_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(x, None), (y, None)], + optional = [(mod_value, Some(vm.ctx.int_type()))] + ); + let pow_method_name = "__pow__".to_string(); + let result = match vm.get_attribute(x.clone(), &pow_method_name) { + Ok(attrib) => vm.invoke(attrib, PyFuncArgs::new(vec![y.clone()], vec![])), + Err(..) => Err(vm.new_type_error("unsupported operand type(s) for pow".to_string())), + }; + //Check if the 3rd argument is defined and perform modulus on the result + //this should be optimized in the future to perform a "power-mod" algorithm in + //order to improve performance + match mod_value { + Some(mod_value) => { + let mod_method_name = "__mod__".to_string(); + match vm.get_attribute( + result.expect("result not defined").clone(), + &mod_method_name, + ) { + Ok(value) => vm.invoke(value, PyFuncArgs::new(vec![mod_value.clone()], vec![])), + Err(..) => { + Err(vm.new_type_error("unsupported operand type(s) for mod".to_string())) + } + } + } + None => result, + } +} pub fn builtin_print(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { trace!("print called with {:?}", args); @@ -386,6 +417,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { dict.insert(String::from("list"), ctx.list_type()); dict.insert(String::from("locals"), ctx.new_rustfunc(builtin_locals)); dict.insert(String::from("next"), ctx.new_rustfunc(builtin_next)); + dict.insert(String::from("pow"), ctx.new_rustfunc(builtin_pow)); dict.insert(String::from("print"), ctx.new_rustfunc(builtin_print)); dict.insert(String::from("range"), ctx.new_rustfunc(builtin_range)); dict.insert(String::from("repr"), ctx.new_rustfunc(builtin_repr)); diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 7620fbb8d..061d4b39b 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -156,7 +156,7 @@ fn int_truediv(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } else if objtype::isinstance(i2, vm.ctx.float_type()) { Ok(vm.ctx.new_float(v1 as f64 / objfloat::get_value(i2))) } else { - Err(vm.new_type_error(format!("Cannot multiply {:?} and {:?}", i, i2))) + Err(vm.new_type_error(format!("Cannot divide {:?} and {:?}", i, i2))) } } @@ -188,7 +188,7 @@ fn int_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let v2 = objfloat::get_value(i2); Ok(vm.ctx.new_float((v1 as f64).powf(v2))) } else { - Err(vm.new_type_error(format!("Cannot modulo {:?} and {:?}", i, i2))) + Err(vm.new_type_error(format!("Cannot raise power {:?} and {:?}", i, i2))) } }