Skip to content

Commit d443c64

Browse files
authored
Merge pull request RustPython#136 from RustPython/objtyp
Objtyp
2 parents 903bf41 + de9c11c commit d443c64

File tree

8 files changed

+194
-65
lines changed

8 files changed

+194
-65
lines changed

tests/snippets/ast_snippet.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55
source = """
66
def foo():
77
print('bar')
8+
pass
89
"""
910
n = ast.parse(source)
1011
print(n)
1112
print(n.body)
1213
print(n.body[0].name)
1314
assert n.body[0].name == 'foo'
14-
print(n.body[0].body)
15-
print(n.body[0].body[0])
16-
print(n.body[0].body[0].value.func.id)
17-
assert n.body[0].body[0].value.func.id == 'print'
15+
foo = n.body[0]
16+
assert foo.lineno == 2
17+
print(foo.body)
18+
assert len(foo.body) == 2
19+
print(foo.body[0])
20+
print(foo.body[0].value.func.id)
21+
assert foo.body[0].value.func.id == 'print'
22+
assert foo.body[0].lineno == 3
23+
assert foo.body[1].lineno == 4

tests/snippets/iterations.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
3+
ls = [1, 2, 3]
4+
5+
i = iter(ls)
6+
assert i.__next__() == 1
7+
assert i.__next__() == 2
8+
assert next(i) == 3
9+
10+
assert next(i, 'w00t') == 'w00t'
11+

vm/src/builtins.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::collections::HashMap;
44
use std::io::{self, Write};
55

66
use super::compile;
7+
use super::obj::objiter;
78
use super::obj::objstr;
89
use super::obj::objtype;
910
use super::objbool;
@@ -221,7 +222,10 @@ fn builtin_issubclass(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
221222
Ok(vm.context().new_bool(objtype::issubclass(cls1, cls2)))
222223
}
223224

224-
// builtin_iter
225+
fn builtin_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
226+
arg_check!(vm, args, required = [(iter_target, None)]);
227+
objiter::get_iter(vm, iter_target)
228+
}
225229

226230
fn builtin_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
227231
arg_check!(vm, args, required = [(obj, None)]);
@@ -254,7 +258,30 @@ fn builtin_locals(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
254258
// builtin_max
255259
// builtin_memoryview
256260
// builtin_min
257-
// builtin_next
261+
262+
fn builtin_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
263+
arg_check!(
264+
vm,
265+
args,
266+
required = [(iterator, None)],
267+
optional = [(default_value, None)]
268+
);
269+
270+
match vm.call_method(iterator.clone(), "__next__", vec![]) {
271+
Ok(value) => Ok(value),
272+
Err(value) => {
273+
if objtype::isinstance(&value, vm.ctx.exceptions.stop_iteration.clone()) {
274+
match default_value {
275+
None => Err(value),
276+
Some(value) => Ok(value.clone()),
277+
}
278+
} else {
279+
Err(value)
280+
}
281+
}
282+
}
283+
}
284+
258285
// builtin_object
259286
// builtin_oct
260287
// builtin_open
@@ -378,9 +405,11 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
378405
String::from("issubclass"),
379406
ctx.new_rustfunc(builtin_issubclass),
380407
);
408+
dict.insert(String::from("iter"), ctx.new_rustfunc(builtin_iter));
381409
dict.insert(String::from("len"), ctx.new_rustfunc(builtin_len));
382410
dict.insert(String::from("list"), ctx.list_type());
383411
dict.insert(String::from("locals"), ctx.new_rustfunc(builtin_locals));
412+
dict.insert(String::from("next"), ctx.new_rustfunc(builtin_next));
384413
dict.insert(String::from("pow"), ctx.new_rustfunc(builtin_pow));
385414
dict.insert(String::from("print"), ctx.new_rustfunc(builtin_print));
386415
dict.insert(String::from("range"), ctx.new_rustfunc(builtin_range));

vm/src/exceptions.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub struct ExceptionZoo {
8989
pub name_error: PyObjectRef,
9090
pub runtime_error: PyObjectRef,
9191
pub not_implemented_error: PyObjectRef,
92+
pub stop_iteration: PyObjectRef,
9293
pub type_error: PyObjectRef,
9394
pub value_error: PyObjectRef,
9495
}
@@ -138,6 +139,12 @@ impl ExceptionZoo {
138139
&runtime_error,
139140
&dict_type,
140141
);
142+
let stop_iteration = create_type(
143+
&String::from("StopIteration"),
144+
&type_type,
145+
&exception_type,
146+
&dict_type,
147+
);
141148
let type_error = create_type(
142149
&String::from("TypeError"),
143150
&type_type,
@@ -159,6 +166,7 @@ impl ExceptionZoo {
159166
name_error: name_error,
160167
runtime_error: runtime_error,
161168
not_implemented_error: not_implemented_error,
169+
stop_iteration: stop_iteration,
162170
type_error: type_error,
163171
value_error: value_error,
164172
}

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod objdict;
33
pub mod objfloat;
44
pub mod objfunction;
55
pub mod objint;
6+
pub mod objiter;
67
pub mod objlist;
78
pub mod objobject;
89
pub mod objsequence;

vm/src/obj/objiter.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Various types to support iteration.
3+
*/
4+
5+
use super::super::pyobject::{
6+
AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult,
7+
TypeProtocol,
8+
};
9+
use super::super::vm::VirtualMachine;
10+
use super::objstr;
11+
use super::objtype; // Required for arg_check! to use isinstance
12+
13+
/*
14+
* This helper function is called at multiple places. First, it is called
15+
* in the vm when a for loop is entered. Next, it is used when the builtin
16+
* function 'iter' is called.
17+
*/
18+
pub fn get_iter(vm: &mut VirtualMachine, iter_target: &PyObjectRef) -> PyResult {
19+
// Check what we are going to iterate over:
20+
let iterated_obj = if objtype::isinstance(iter_target, vm.ctx.iter_type()) {
21+
// If object is already an iterator, return that one.
22+
return Ok(iter_target.clone());
23+
} else if objtype::isinstance(iter_target, vm.ctx.list_type()) {
24+
iter_target.clone()
25+
} else {
26+
let type_str = objstr::get_value(&vm.to_str(iter_target.typ()).unwrap());
27+
let type_error = vm.new_type_error(format!("Cannot iterate over {}", type_str));
28+
return Err(type_error);
29+
};
30+
31+
let iter_obj = PyObject::new(
32+
PyObjectKind::Iterator {
33+
position: 0,
34+
iterated_obj: iterated_obj,
35+
},
36+
vm.ctx.iter_type(),
37+
);
38+
39+
// We are all good here:
40+
Ok(iter_obj)
41+
}
42+
43+
// Sequence iterator:
44+
fn iter_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
45+
arg_check!(vm, args, required = [(iter_target, None)]);
46+
47+
get_iter(vm, iter_target)
48+
}
49+
50+
fn iter_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
51+
arg_check!(vm, args, required = [(iter, Some(vm.ctx.iter_type()))]);
52+
// Return self:
53+
Ok(iter.clone())
54+
}
55+
56+
fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
57+
arg_check!(vm, args, required = [(iter, Some(vm.ctx.iter_type()))]);
58+
59+
if let PyObjectKind::Iterator {
60+
ref mut position,
61+
iterated_obj: ref iterated_obj_ref,
62+
} = iter.borrow_mut().kind
63+
{
64+
let iterated_obj = &*iterated_obj_ref.borrow_mut();
65+
match iterated_obj.kind {
66+
PyObjectKind::List { ref elements } => {
67+
if *position < elements.len() {
68+
let obj_ref = elements[*position].clone();
69+
*position += 1;
70+
Ok(obj_ref)
71+
} else {
72+
let stop_iteration_type = vm.ctx.exceptions.stop_iteration.clone();
73+
let stop_iteration =
74+
vm.new_exception(stop_iteration_type, "End of iterator".to_string());
75+
Err(stop_iteration)
76+
}
77+
}
78+
_ => {
79+
panic!("NOT IMPL");
80+
}
81+
}
82+
} else {
83+
panic!("NOT IMPL");
84+
}
85+
}
86+
87+
pub fn init(context: &PyContext) {
88+
let ref iter_type = context.iter_type;
89+
iter_type.set_attr("__new__", context.new_rustfunc(iter_new));
90+
iter_type.set_attr("__iter__", context.new_rustfunc(iter_iter));
91+
iter_type.set_attr("__next__", context.new_rustfunc(iter_next));
92+
}

vm/src/pyobject.rs

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::obj::objdict;
55
use super::obj::objfloat;
66
use super::obj::objfunction;
77
use super::obj::objint;
8+
use super::obj::objiter;
89
use super::obj::objlist;
910
use super::obj::objobject;
1011
use super::obj::objstr;
@@ -60,6 +61,7 @@ pub struct PyContext {
6061
pub false_value: PyObjectRef,
6162
pub list_type: PyObjectRef,
6263
pub tuple_type: PyObjectRef,
64+
pub iter_type: PyObjectRef,
6365
pub str_type: PyObjectRef,
6466
pub function_type: PyObjectRef,
6567
pub module_type: PyObjectRef,
@@ -123,6 +125,7 @@ impl PyContext {
123125
let float_type = create_type("float", &type_type, &object_type, &dict_type);
124126
let bytes_type = create_type("bytes", &type_type, &object_type, &dict_type);
125127
let tuple_type = create_type("tuple", &type_type, &object_type, &dict_type);
128+
let iter_type = create_type("iter", &type_type, &object_type, &dict_type);
126129
let bool_type = create_type("bool", &type_type, &int_type, &dict_type);
127130
let exceptions = exceptions::ExceptionZoo::new(&type_type, &object_type, &dict_type);
128131

@@ -142,6 +145,7 @@ impl PyContext {
142145
true_value: true_value,
143146
false_value: false_value,
144147
tuple_type: tuple_type,
148+
iter_type: iter_type,
145149
dict_type: dict_type,
146150
none: none,
147151
str_type: str_type,
@@ -164,6 +168,7 @@ impl PyContext {
164168
objbytes::init(&context);
165169
objstr::init(&context);
166170
objtuple::init(&context);
171+
objiter::init(&context);
167172
objbool::init(&context);
168173
exceptions::init(&context);
169174
context
@@ -190,6 +195,9 @@ impl PyContext {
190195
pub fn tuple_type(&self) -> PyObjectRef {
191196
self.tuple_type.clone()
192197
}
198+
pub fn iter_type(&self) -> PyObjectRef {
199+
self.iter_type.clone()
200+
}
193201
pub fn dict_type(&self) -> PyObjectRef {
194202
self.dict_type.clone()
195203
}
@@ -750,35 +758,6 @@ impl PyObject {
750758
}
751759
}
752760

753-
// Implement iterator protocol:
754-
pub fn nxt(&mut self) -> Option<PyObjectRef> {
755-
match self.kind {
756-
PyObjectKind::Iterator {
757-
ref mut position,
758-
iterated_obj: ref iterated_obj_ref,
759-
} => {
760-
let iterated_obj = &*iterated_obj_ref.borrow_mut();
761-
match iterated_obj.kind {
762-
PyObjectKind::List { ref elements } => {
763-
if *position < elements.len() {
764-
let obj_ref = elements[*position].clone();
765-
*position += 1;
766-
Some(obj_ref)
767-
} else {
768-
None
769-
}
770-
}
771-
_ => {
772-
panic!("NOT IMPL");
773-
}
774-
}
775-
}
776-
_ => {
777-
panic!("NOT IMPL");
778-
}
779-
}
780-
}
781-
782761
// Move this object into a reference object, transferring ownership.
783762
pub fn into_ref(self) -> PyObjectRef {
784763
Rc::new(RefCell::new(self))

0 commit comments

Comments
 (0)