Skip to content

Commit 62842e6

Browse files
convert some builtins
1 parent e048037 commit 62842e6

File tree

4 files changed

+62
-75
lines changed

4 files changed

+62
-75
lines changed

tests/snippets/builtin_format.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@
77
assert format({}) == "{}"
88

99
assert_raises(TypeError, lambda: format({}, 'b'), 'format_spec not empty for dict')
10+
11+
class BadFormat:
12+
def __format__(self, spec):
13+
return 42
14+
assert_raises(TypeError, lambda: format(BadFormat()))

vm/src/builtins.rs

Lines changed: 53 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -6,96 +6,76 @@ use std::char;
66
use std::io::{self, Write};
77
use std::path::PathBuf;
88

9-
use num_traits::{Signed, ToPrimitive};
9+
use num_traits::Signed;
1010

1111
use crate::compile;
1212
use crate::import::import_module;
1313
use crate::obj::objbool;
1414
use crate::obj::objdict::PyDictRef;
15-
use crate::obj::objint;
15+
use crate::obj::objint::{self, PyIntRef};
1616
use crate::obj::objiter;
17-
use crate::obj::objstr::{self, PyStringRef};
17+
use crate::obj::objstr::{self, PyString, PyStringRef};
1818
use crate::obj::objtype::{self, PyClassRef};
1919

2020
use crate::frame::Scope;
2121
use crate::function::{Args, OptionalArg, PyFuncArgs};
2222
use crate::pyobject::{
23-
DictProtocol, IdProtocol, PyContext, PyObjectRef, PyResult, TryFromObject, TypeProtocol,
23+
DictProtocol, IdProtocol, PyContext, PyIterable, PyObjectRef, PyResult, PyValue, TryFromObject,
24+
TypeProtocol,
2425
};
2526
use crate::vm::VirtualMachine;
2627

2728
use crate::obj::objcode::PyCodeRef;
2829
#[cfg(not(target_arch = "wasm32"))]
2930
use crate::stdlib::io::io_open;
3031

31-
fn builtin_abs(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
32-
arg_check!(vm, args, required = [(x, None)]);
32+
fn builtin_abs(x: PyObjectRef, vm: &VirtualMachine) -> PyResult {
3333
match vm.get_method(x.clone(), "__abs__") {
3434
Ok(attrib) => vm.invoke(attrib, PyFuncArgs::new(vec![], vec![])),
3535
Err(..) => Err(vm.new_type_error("bad operand for abs".to_string())),
3636
}
3737
}
3838

39-
fn builtin_all(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
40-
arg_check!(vm, args, required = [(iterable, None)]);
41-
let items = vm.extract_elements(iterable)?;
42-
for item in items {
43-
let result = objbool::boolval(vm, item)?;
44-
if !result {
45-
return Ok(vm.new_bool(false));
39+
fn builtin_all(iterable: PyIterable<bool>, vm: &VirtualMachine) -> PyResult<bool> {
40+
for item in iterable.iter(vm)? {
41+
if !item? {
42+
return Ok(false);
4643
}
4744
}
48-
Ok(vm.new_bool(true))
45+
Ok(true)
4946
}
5047

51-
fn builtin_any(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
52-
arg_check!(vm, args, required = [(iterable, None)]);
53-
let iterator = objiter::get_iter(vm, iterable)?;
54-
55-
while let Some(item) = objiter::get_next_object(vm, &iterator)? {
56-
let result = objbool::boolval(vm, item)?;
57-
if result {
58-
return Ok(vm.new_bool(true));
48+
fn builtin_any(iterable: PyIterable<bool>, vm: &VirtualMachine) -> PyResult<bool> {
49+
for item in iterable.iter(vm)? {
50+
if item? {
51+
return Ok(true);
5952
}
6053
}
61-
62-
Ok(vm.new_bool(false))
54+
Ok(false)
6355
}
6456

6557
// builtin_ascii
6658

67-
fn builtin_bin(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
68-
arg_check!(vm, args, required = [(number, Some(vm.ctx.int_type()))]);
69-
70-
let n = objint::get_value(number);
71-
let s = if n.is_negative() {
72-
format!("-0b{:b}", n.abs())
59+
fn builtin_bin(x: PyIntRef, _vm: &VirtualMachine) -> String {
60+
let x = x.as_bigint();
61+
if x.is_negative() {
62+
format!("-0b{:b}", x.abs())
7363
} else {
74-
format!("0b{:b}", n)
75-
};
76-
77-
Ok(vm.new_str(s))
64+
format!("0b{:b}", x)
65+
}
7866
}
7967

8068
// builtin_breakpoint
8169

82-
fn builtin_callable(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
83-
arg_check!(vm, args, required = [(obj, None)]);
84-
let is_callable = objtype::class_has_attr(&obj.class(), "__call__");
85-
Ok(vm.new_bool(is_callable))
70+
fn builtin_callable(obj: PyObjectRef, _vm: &VirtualMachine) -> bool {
71+
objtype::class_has_attr(&obj.class(), "__call__")
8672
}
8773

88-
fn builtin_chr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
89-
arg_check!(vm, args, required = [(i, Some(vm.ctx.int_type()))]);
90-
91-
let code_point = objint::get_value(i).to_u32().unwrap();
92-
93-
let txt = match char::from_u32(code_point) {
74+
fn builtin_chr(i: u32, _vm: &VirtualMachine) -> String {
75+
match char::from_u32(i) {
9476
Some(value) => value.to_string(),
9577
None => '_'.to_string(),
96-
};
97-
98-
Ok(vm.new_str(txt))
78+
}
9979
}
10080

10181
fn builtin_compile(
@@ -128,13 +108,8 @@ fn builtin_compile(
128108
})
129109
}
130110

131-
fn builtin_delattr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
132-
arg_check!(
133-
vm,
134-
args,
135-
required = [(obj, None), (attr, Some(vm.ctx.str_type()))]
136-
);
137-
vm.del_attr(obj, attr.clone())
111+
fn builtin_delattr(obj: PyObjectRef, attr: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
112+
vm.del_attr(&obj, attr.into_object())
138113
}
139114

140115
fn builtin_dir(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -258,17 +233,26 @@ fn make_scope(
258233
Ok(Scope::new(locals, globals))
259234
}
260235

261-
fn builtin_format(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
262-
arg_check!(
263-
vm,
264-
args,
265-
required = [(obj, None)],
266-
optional = [(format_spec, Some(vm.ctx.str_type()))]
267-
);
268-
let format_spec = format_spec
269-
.cloned()
270-
.unwrap_or_else(|| vm.new_str("".to_string()));
271-
vm.call_method(obj, "__format__", vec![format_spec])
236+
fn builtin_format(
237+
value: PyObjectRef,
238+
format_spec: OptionalArg<PyStringRef>,
239+
vm: &VirtualMachine,
240+
) -> PyResult<PyStringRef> {
241+
let format_spec = format_spec.into_option().unwrap_or_else(|| {
242+
PyString {
243+
value: "".to_string(),
244+
}
245+
.into_ref(vm)
246+
});
247+
248+
vm.call_method(&value, "__format__", vec![format_spec.into_object()])?
249+
.downcast()
250+
.map_err(|obj| {
251+
vm.new_type_error(format!(
252+
"__format__ must return a str, not {}",
253+
obj.class().name
254+
))
255+
})
272256
}
273257

274258
fn catch_attr_exception<T>(ex: PyObjectRef, default: T, vm: &VirtualMachine) -> PyResult<T> {
@@ -644,14 +628,11 @@ fn builtin_sorted(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResult {
644628
Ok(lst)
645629
}
646630

647-
fn builtin_sum(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
648-
arg_check!(vm, args, required = [(iterable, None)]);
649-
let items = vm.extract_elements(iterable)?;
650-
631+
fn builtin_sum(iterable: PyIterable, start: OptionalArg, vm: &VirtualMachine) -> PyResult {
651632
// Start with zero and add at will:
652-
let mut sum = vm.ctx.new_int(0);
653-
for item in items {
654-
sum = vm._add(sum, item)?;
633+
let mut sum = start.into_option().unwrap_or_else(|| vm.ctx.new_int(0));
634+
for item in iterable.iter(vm)? {
635+
sum = vm._add(sum, item?)?;
655636
}
656637
Ok(sum)
657638
}

vm/src/function.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ where
308308
/// An argument that may or may not be provided by the caller.
309309
///
310310
/// This style of argument is not possible in pure Python.
311-
pub enum OptionalArg<T> {
311+
pub enum OptionalArg<T = PyObjectRef> {
312312
Present(T),
313313
Missing,
314314
}

vm/src/vm.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,8 +577,9 @@ impl VirtualMachine {
577577
self.call_method(&obj, "__setattr__", vec![attr_name, attr_value])
578578
}
579579

580-
pub fn del_attr(&self, obj: &PyObjectRef, attr_name: PyObjectRef) -> PyResult {
581-
self.call_method(&obj, "__delattr__", vec![attr_name])
580+
pub fn del_attr(&self, obj: &PyObjectRef, attr_name: PyObjectRef) -> PyResult<()> {
581+
self.call_method(&obj, "__delattr__", vec![attr_name])?;
582+
Ok(())
582583
}
583584

584585
// get_method should be used for internal access to magic methods (by-passing

0 commit comments

Comments
 (0)