Skip to content

Commit ba78000

Browse files
authored
Merge pull request RustPython#129 from RustPython/objtyp
Implement dir on object
2 parents e060982 + 64b04d0 commit ba78000

File tree

5 files changed

+77
-14
lines changed

5 files changed

+77
-14
lines changed

vm/src/builtins.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,16 @@ fn dir_locals(vm: &mut VirtualMachine) -> PyObjectRef {
3232
get_locals(vm)
3333
}
3434

35-
fn dir_object(vm: &mut VirtualMachine, _obj: PyObjectRef) -> PyObjectRef {
36-
let d = vm.new_dict();
37-
// TODO: loop over dict of instance, next of class?
38-
// TODO: Implement dir for objects
39-
// for i in obj.iter_items() {
40-
// d.set_item(k, v);
41-
// }
42-
d
35+
fn dir_object(vm: &mut VirtualMachine, obj: &PyObjectRef) -> PyObjectRef {
36+
// Gather all members here:
37+
let attributes = objtype::get_attributes(obj);
38+
let mut members: Vec<String> = attributes.into_iter().map(|(n, _o)| n).collect();
39+
40+
// Sort members:
41+
members.sort();
42+
43+
let members_pystr = members.into_iter().map(|m| vm.ctx.new_str(m)).collect();
44+
vm.ctx.new_list(members_pystr)
4345
}
4446

4547
// builtin_abs
@@ -115,7 +117,7 @@ fn builtin_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
115117
Ok(dir_locals(vm))
116118
} else {
117119
let obj = args.args.into_iter().next().unwrap();
118-
Ok(dir_object(vm, obj))
120+
Ok(dir_object(vm, &obj))
119121
}
120122
}
121123

vm/src/obj/objbytes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn bytes_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
2424
let val = if objtype::isinstance(arg, vm.ctx.list_type()) {
2525
let mut data_bytes = vec![];
2626
for elem in objlist::get_elements(arg) {
27-
let v = match objint::to_int(vm, &elem) {
27+
let v = match objint::to_int(vm, &elem, 10) {
2828
Ok(int_ref) => int_ref,
2929
Err(err) => return Err(err),
3030
};

vm/src/obj/objint.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use super::super::pyobject::{
44
};
55
use super::super::vm::VirtualMachine;
66
use super::objfloat;
7+
use super::objstr;
78
use super::objtype;
89

910
fn int_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -22,8 +23,11 @@ fn int_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
2223
if !objtype::issubclass(cls, vm.ctx.int_type()) {
2324
return Err(vm.new_type_error(format!("{:?} is not a subtype of int", cls)));
2425
}
26+
27+
// TODO: extract kwargs:
28+
let base = 10;
2529
let val = match val_option {
26-
Some(val) => to_int(vm, val)?,
30+
Some(val) => to_int(vm, val, base)?,
2731
None => 0,
2832
};
2933
Ok(PyObject::new(
@@ -33,13 +37,29 @@ fn int_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
3337
}
3438

3539
// Casting function:
36-
pub fn to_int(vm: &mut VirtualMachine, obj: &PyObjectRef) -> Result<i32, PyObjectRef> {
40+
pub fn to_int(vm: &mut VirtualMachine, obj: &PyObjectRef, base: u32) -> Result<i32, PyObjectRef> {
3741
let val = if objtype::isinstance(obj, vm.ctx.int_type()) {
3842
get_value(obj)
3943
} else if objtype::isinstance(obj, vm.ctx.float_type()) {
4044
objfloat::get_value(obj) as i32
45+
} else if objtype::isinstance(obj, vm.ctx.str_type()) {
46+
let s = objstr::get_value(obj);
47+
match i32::from_str_radix(&s, base) {
48+
Ok(v) => v,
49+
Err(err) => {
50+
trace!("Error occured during int conversion {:?}", err);
51+
return Err(vm.new_value_error(format!(
52+
"invalid literal for int() with base {}: '{}'",
53+
base, s
54+
)));
55+
}
56+
}
4157
} else {
42-
return Err(vm.new_type_error("Cannot construct int".to_string()));
58+
let type_name = objtype::get_type_name(&obj.typ());
59+
return Err(vm.new_type_error(format!(
60+
"int() argument must be a string or a number, not '{}'",
61+
type_name
62+
)));
4363
};
4464
Ok(val)
4565
}

vm/src/obj/objtype.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::super::pyobject::{
55
use super::super::vm::VirtualMachine;
66
use super::objdict;
77
use super::objtype; // Required for arg_check! to use isinstance
8+
use std::collections::HashMap;
89

910
/*
1011
* The magical type type
@@ -54,6 +55,10 @@ fn _mro(cls: PyObjectRef) -> Option<Vec<PyObjectRef>> {
5455
}
5556
}
5657

58+
pub fn base_classes(obj: &PyObjectRef) -> Vec<PyObjectRef> {
59+
_mro(obj.typ()).unwrap()
60+
}
61+
5762
pub fn isinstance(obj: &PyObjectRef, cls: PyObjectRef) -> bool {
5863
let mro = _mro(obj.typ()).unwrap();
5964
mro.into_iter().any(|c| c.is(&cls))
@@ -161,6 +166,37 @@ pub fn get_attribute(vm: &mut VirtualMachine, obj: PyObjectRef, name: &str) -> P
161166
}
162167
}
163168

169+
pub fn get_attributes(obj: &PyObjectRef) -> HashMap<String, PyObjectRef> {
170+
// Gather all members here:
171+
let mut attributes: HashMap<String, PyObjectRef> = HashMap::new();
172+
173+
// Get class attributes:
174+
let mut base_classes = objtype::base_classes(obj);
175+
base_classes.reverse();
176+
for bc in base_classes {
177+
if let PyObjectKind::Class {
178+
name: _,
179+
dict,
180+
mro: _,
181+
} = &bc.borrow().kind
182+
{
183+
let elements = objdict::get_elements(dict);
184+
for (name, value) in elements {
185+
attributes.insert(name.to_string(), value.clone());
186+
}
187+
}
188+
}
189+
190+
// Get instance attributes:
191+
if let PyObjectKind::Instance { dict } = &obj.borrow().kind {
192+
let elements = objdict::get_elements(dict);
193+
for (name, value) in elements {
194+
attributes.insert(name.to_string(), value.clone());
195+
}
196+
}
197+
attributes
198+
}
199+
164200
fn take_next_base(
165201
mut bases: Vec<Vec<PyObjectRef>>,
166202
) -> Option<(PyObjectRef, Vec<Vec<PyObjectRef>>)> {

vm/src/vm.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,15 @@ impl VirtualMachine {
7373
}
7474

7575
pub fn new_type_error(&mut self, msg: String) -> PyObjectRef {
76-
let type_error = self.context().exceptions.type_error.clone();
76+
let type_error = self.ctx.exceptions.type_error.clone();
7777
self.new_exception(type_error, msg)
7878
}
7979

80+
pub fn new_value_error(&mut self, msg: String) -> PyObjectRef {
81+
let value_error = self.ctx.exceptions.value_error.clone();
82+
self.new_exception(value_error, msg)
83+
}
84+
8085
pub fn new_scope(&mut self) -> PyObjectRef {
8186
let parent_scope = self.current_frame_mut().locals.clone();
8287
self.ctx.new_scope(Some(parent_scope))

0 commit comments

Comments
 (0)