Skip to content

Commit abba4ae

Browse files
committed
implemented pow builtin
1 parent 416e48b commit abba4ae

File tree

3 files changed

+45
-3
lines changed

3 files changed

+45
-3
lines changed

tests/snippets/builtin_pow.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
assert pow(3,2) == 9
2+
assert pow(5,3, 100) == 25
3+
4+
#causes overflow
5+
# assert pow(41, 7, 2) == 1
6+
assert pow(7, 2, 49) == 0

vm/src/builtins.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,42 @@ fn builtin_locals(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
259259
// builtin_oct
260260
// builtin_open
261261
// builtin_ord
262-
// builtin_pow
262+
263+
fn builtin_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
264+
arg_check!(
265+
vm,
266+
args,
267+
required = [(x, None), (y, None)],
268+
optional=[(mod_value, Some(vm.ctx.int_type()))]
269+
);
270+
let pow_method_name = "__pow__".to_string();
271+
let result = match vm.get_attribute(x.clone(), &pow_method_name) {
272+
Ok(attrib) => vm.invoke(attrib, PyFuncArgs::new(vec![y.clone()], vec![])),
273+
Err(..) => Err(vm.new_type_error("unsupported operand type(s) for pow".to_string()))
274+
};
275+
//Check if the 3rd argument is defined and perform modulus on the result
276+
//this should be optimized in the future to perform a "power-mod" algorithm in
277+
//order to improve performance
278+
match mod_value {
279+
Some(mod_value) => {
280+
let mod_method_name = "__mod__".to_string();
281+
match vm.get_attribute(
282+
result.expect("result not defined").clone(),
283+
&mod_method_name
284+
) {
285+
Ok(value) => vm.invoke(
286+
value,
287+
PyFuncArgs::new(vec![mod_value.clone()], vec![])
288+
),
289+
Err(..) => Err(
290+
vm.new_type_error("unsupported operand type(s) for mod".to_string())
291+
)
292+
}
293+
}
294+
None => result
295+
}
296+
}
297+
263298

264299
pub fn builtin_print(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
265300
trace!("print called with {:?}", args);
@@ -350,6 +385,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
350385
dict.insert(String::from("len"), ctx.new_rustfunc(builtin_len));
351386
dict.insert(String::from("list"), ctx.list_type());
352387
dict.insert(String::from("locals"), ctx.new_rustfunc(builtin_locals));
388+
dict.insert(String::from("pow"), ctx.new_rustfunc(builtin_pow));
353389
dict.insert(String::from("print"), ctx.new_rustfunc(builtin_print));
354390
dict.insert(String::from("range"), ctx.new_rustfunc(builtin_range));
355391
dict.insert(String::from("repr"), ctx.new_rustfunc(builtin_repr));

vm/src/obj/objint.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ fn int_truediv(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
156156
} else if objtype::isinstance(i2, vm.ctx.float_type()) {
157157
Ok(vm.ctx.new_float(v1 as f64 / objfloat::get_value(i2)))
158158
} else {
159-
Err(vm.new_type_error(format!("Cannot multiply {:?} and {:?}", i, i2)))
159+
Err(vm.new_type_error(format!("Cannot divide {:?} and {:?}", i, i2)))
160160
}
161161
}
162162

@@ -188,7 +188,7 @@ fn int_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
188188
let v2 = objfloat::get_value(i2);
189189
Ok(vm.ctx.new_float((v1 as f64).powf(v2)))
190190
} else {
191-
Err(vm.new_type_error(format!("Cannot modulo {:?} and {:?}", i, i2)))
191+
Err(vm.new_type_error(format!("Cannot raise power {:?} and {:?}", i, i2)))
192192
}
193193
}
194194

0 commit comments

Comments
 (0)