Skip to content

Commit 304c410

Browse files
Merge pull request RustPython#117 from RustPython/objtyp
Add bytes object class
2 parents 4132f33 + bcf5e8a commit 304c410

File tree

16 files changed

+255
-48
lines changed

16 files changed

+255
-48
lines changed

tests/snippets/basic_types.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,11 @@
2525
x = 1
2626
assert type(x) is int
2727
assert type(x - 1) is int
28+
29+
a = bytes([1, 2, 3])
30+
print(a)
31+
try:
32+
bytes([object()])
33+
except TypeError:
34+
pass
35+

vm/src/builtins.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
322322
dict.insert(String::from("all"), ctx.new_rustfunc(builtin_all));
323323
dict.insert(String::from("any"), ctx.new_rustfunc(builtin_any));
324324
dict.insert(String::from("bool"), ctx.bool_type());
325+
dict.insert(String::from("bytes"), ctx.bytes_type());
325326
dict.insert(String::from("chr"), ctx.new_rustfunc(builtin_chr));
326327
dict.insert(String::from("compile"), ctx.new_rustfunc(builtin_compile));
327328
dict.insert(String::from("dict"), ctx.dict_type());

vm/src/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ mod frame;
2222
mod import;
2323
mod obj;
2424
mod objbool;
25-
mod objfunction;
26-
mod objobject;
27-
mod objsequence;
2825
pub mod pyobject;
2926
pub mod stdlib;
3027
mod sysmodule;

vm/src/obj/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
pub mod objbytes;
12
pub mod objdict;
23
pub mod objfloat;
4+
pub mod objfunction;
35
pub mod objint;
46
pub mod objlist;
7+
pub mod objobject;
8+
pub mod objsequence;
59
pub mod objstr;
10+
pub mod objtuple;
611
pub mod objtype;

vm/src/obj/objbytes.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use super::super::pyobject::{
2+
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
3+
};
4+
use super::super::vm::VirtualMachine;
5+
use super::objint;
6+
use super::objlist;
7+
use super::objtype;
8+
// Binary data support
9+
10+
// Fill bytes class methods:
11+
pub fn init(context: &PyContext) {
12+
let ref bytes_type = context.bytes_type;
13+
bytes_type.set_attr("__init__", context.new_rustfunc(bytes_init));
14+
bytes_type.set_attr("__str__", context.new_rustfunc(bytes_str));
15+
}
16+
17+
// __init__ (store value into objectkind)
18+
fn bytes_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
19+
arg_check!(
20+
vm,
21+
args,
22+
required = [(zelf, Some(vm.ctx.bytes_type())), (arg, None)]
23+
);
24+
let val = if objtype::isinstance(arg.clone(), vm.ctx.list_type()) {
25+
let mut data_bytes = vec![];
26+
for elem in objlist::get_elements(arg) {
27+
let v = match objint::to_int(vm, &elem) {
28+
Ok(int_ref) => int_ref,
29+
Err(err) => return Err(err),
30+
};
31+
data_bytes.push(v as u8);
32+
}
33+
data_bytes
34+
} else {
35+
return Err(vm.new_type_error("Cannot construct bytes".to_string()));
36+
};
37+
set_value(zelf, val);
38+
Ok(vm.get_none())
39+
}
40+
41+
pub fn get_value(obj: &PyObjectRef) -> Vec<u8> {
42+
if let PyObjectKind::Bytes { value } = &obj.borrow().kind {
43+
value.clone()
44+
} else {
45+
panic!("Inner error getting int {:?}", obj);
46+
}
47+
}
48+
49+
fn set_value(obj: &PyObjectRef, value: Vec<u8>) {
50+
obj.borrow_mut().kind = PyObjectKind::Bytes { value };
51+
}
52+
53+
fn bytes_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
54+
arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytes_type()))]);
55+
let data = get_value(obj);
56+
let data: Vec<String> = data.into_iter().map(|b| format!("\\x{:02x}", b)).collect();
57+
let data = data.join("");
58+
Ok(vm.new_str(format!("b'{}'", data)))
59+
}

vm/src/objfunction.rs renamed to vm/src/obj/objfunction.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use super::pyobject::{AttributeProtocol, PyContext, PyFuncArgs, PyResult};
2-
use super::vm::VirtualMachine;
1+
use super::super::pyobject::{AttributeProtocol, PyContext, PyFuncArgs, PyResult};
2+
use super::super::vm::VirtualMachine;
33

44
pub fn init(context: &PyContext) {
55
let ref function_type = context.function_type;

vm/src/obj/objint.rs

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,29 @@ fn int_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
1919
args,
2020
required = [(zelf, Some(vm.ctx.int_type())), (arg, None)]
2121
);
22-
let val = if objtype::isinstance(arg.clone(), vm.ctx.int_type()) {
23-
get_value(arg)
24-
} else if objtype::isinstance(arg.clone(), vm.ctx.float_type()) {
25-
objfloat::get_value(arg) as i32
26-
} else {
27-
return Err(vm.new_type_error("Cannot construct int".to_string()));
22+
23+
// Try to cast to int:
24+
let val = match to_int(vm, arg) {
25+
Ok(val) => val,
26+
Err(err) => return Err(err),
2827
};
28+
2929
set_value(zelf, val);
3030
Ok(vm.get_none())
3131
}
3232

33+
// Casting function:
34+
pub fn to_int(vm: &mut VirtualMachine, obj: &PyObjectRef) -> Result<i32, PyObjectRef> {
35+
let val = if objtype::isinstance(obj.clone(), vm.ctx.int_type()) {
36+
get_value(obj)
37+
} else if objtype::isinstance(obj.clone(), vm.ctx.float_type()) {
38+
objfloat::get_value(obj) as i32
39+
} else {
40+
return Err(vm.new_type_error("Cannot construct int".to_string()));
41+
};
42+
Ok(val)
43+
}
44+
3345
// Retrieve inner int value:
3446
pub fn get_value(obj: &PyObjectRef) -> i32 {
3547
if let PyObjectKind::Integer { value } = &obj.borrow().kind {
@@ -142,15 +154,63 @@ fn int_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
142154
}
143155
}
144156

157+
fn int_xor(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
158+
arg_check!(
159+
vm,
160+
args,
161+
required = [(i, Some(vm.ctx.int_type())), (i2, None)]
162+
);
163+
let v1 = get_value(i);
164+
if objtype::isinstance(i2.clone(), vm.ctx.int_type()) {
165+
let v2 = get_value(i2);
166+
Ok(vm.ctx.new_int(v1 ^ v2))
167+
} else {
168+
Err(vm.new_type_error(format!("Cannot xor {:?} and {:?}", i, i2)))
169+
}
170+
}
171+
172+
fn int_or(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
173+
arg_check!(
174+
vm,
175+
args,
176+
required = [(i, Some(vm.ctx.int_type())), (i2, None)]
177+
);
178+
let v1 = get_value(i);
179+
if objtype::isinstance(i2.clone(), vm.ctx.int_type()) {
180+
let v2 = get_value(i2);
181+
Ok(vm.ctx.new_int(v1 | v2))
182+
} else {
183+
Err(vm.new_type_error(format!("Cannot or {:?} and {:?}", i, i2)))
184+
}
185+
}
186+
187+
fn int_and(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
188+
arg_check!(
189+
vm,
190+
args,
191+
required = [(i, Some(vm.ctx.int_type())), (i2, None)]
192+
);
193+
let v1 = get_value(i);
194+
if objtype::isinstance(i2.clone(), vm.ctx.int_type()) {
195+
let v2 = get_value(i2);
196+
Ok(vm.ctx.new_int(v1 & v2))
197+
} else {
198+
Err(vm.new_type_error(format!("Cannot and {:?} and {:?}", i, i2)))
199+
}
200+
}
201+
145202
pub fn init(context: &PyContext) {
146203
let ref int_type = context.int_type;
147204
int_type.set_attr("__add__", context.new_rustfunc(int_add));
205+
int_type.set_attr("__and__", context.new_rustfunc(int_and));
148206
int_type.set_attr("__init__", context.new_rustfunc(int_init));
149207
int_type.set_attr("__mod__", context.new_rustfunc(int_mod));
150208
int_type.set_attr("__mul__", context.new_rustfunc(int_mul));
209+
int_type.set_attr("__or__", context.new_rustfunc(int_or));
151210
int_type.set_attr("__pow__", context.new_rustfunc(int_pow));
152211
int_type.set_attr("__repr__", context.new_rustfunc(str));
153212
int_type.set_attr("__str__", context.new_rustfunc(str));
154213
int_type.set_attr("__sub__", context.new_rustfunc(int_sub));
155214
int_type.set_attr("__truediv__", context.new_rustfunc(int_truediv));
215+
int_type.set_attr("__xor__", context.new_rustfunc(int_xor));
156216
}

vm/src/obj/objlist.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use super::super::objsequence::PySliceableSequence;
21
use super::super::pyobject::{
32
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
43
};
54
use super::super::vm::VirtualMachine;
5+
use super::objsequence::PySliceableSequence;
66
use super::objstr;
77
use super::objtype;
88

@@ -26,7 +26,7 @@ pub fn set_item(
2626
}
2727
}
2828

29-
pub fn get_elements(obj: PyObjectRef) -> Vec<PyObjectRef> {
29+
pub fn get_elements(obj: &PyObjectRef) -> Vec<PyObjectRef> {
3030
if let PyObjectKind::List { elements } = &obj.borrow().kind {
3131
elements.to_vec()
3232
} else {
@@ -42,8 +42,8 @@ fn list_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
4242
);
4343

4444
if objtype::isinstance(o2.clone(), vm.ctx.list_type()) {
45-
let e1 = get_elements(o.clone());
46-
let e2 = get_elements(o2.clone());
45+
let e1 = get_elements(o);
46+
let e2 = get_elements(o2);
4747
let elements = e1.iter().chain(e2.iter()).map(|e| e.clone()).collect();
4848
Ok(vm.ctx.new_list(elements))
4949
} else {
@@ -54,7 +54,7 @@ fn list_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5454
fn list_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5555
arg_check!(vm, args, required = [(o, Some(vm.ctx.list_type()))]);
5656

57-
let elements = get_elements(o.clone());
57+
let elements = get_elements(o);
5858
let mut str_parts = vec![];
5959
for elem in elements {
6060
match vm.to_str(elem) {
@@ -95,15 +95,10 @@ fn clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
9595
}
9696
}
9797

98-
fn len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
99-
trace!("list.len called with: {:?}", args);
98+
fn list_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
10099
arg_check!(vm, args, required = [(list, Some(vm.ctx.list_type()))]);
101-
let list_obj = list.borrow();
102-
if let PyObjectKind::List { ref elements } = list_obj.kind {
103-
Ok(vm.context().new_int(elements.len() as i32))
104-
} else {
105-
Err(vm.new_type_error("list.len is called with no list".to_string()))
106-
}
100+
let elements = get_elements(list);
101+
Ok(vm.context().new_int(elements.len() as i32))
107102
}
108103

109104
fn reverse(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -121,7 +116,7 @@ fn reverse(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
121116
pub fn init(context: &PyContext) {
122117
let ref list_type = context.list_type;
123118
list_type.set_attr("__add__", context.new_rustfunc(list_add));
124-
list_type.set_attr("__len__", context.new_rustfunc(len));
119+
list_type.set_attr("__len__", context.new_rustfunc(list_len));
125120
list_type.set_attr("__str__", context.new_rustfunc(list_str));
126121
list_type.set_attr("append", context.new_rustfunc(append));
127122
list_type.set_attr("clear", context.new_rustfunc(clear));

vm/src/objobject.rs renamed to vm/src/obj/objobject.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use super::obj::objdict;
2-
use super::obj::objtype;
3-
use super::pyobject::{
1+
use super::super::pyobject::{
42
AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef,
53
PyResult, TypeProtocol,
64
};
7-
use super::vm::VirtualMachine;
5+
use super::super::vm::VirtualMachine;
6+
use super::objdict;
7+
use super::objtype;
88

99
pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
1010
// more or less __new__ operator

vm/src/objsequence.rs renamed to vm/src/obj/objsequence.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use super::pyobject::{PyObject, PyObjectKind, PyObjectRef, PyResult};
2-
use super::vm::VirtualMachine;
1+
use super::super::pyobject::{PyObject, PyObjectKind, PyObjectRef, PyResult};
2+
use super::super::vm::VirtualMachine;
33
use std::marker::Sized;
44

55
pub trait PySliceableSequence {

vm/src/obj/objstr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use super::super::objsequence::PySliceableSequence;
21
use super::super::pyobject::{
32
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
43
};
54
use super::super::vm::VirtualMachine;
65
use super::objint;
6+
use super::objsequence::PySliceableSequence;
77
use super::objtype;
88

99
pub fn init(context: &PyContext) {

vm/src/obj/objtuple.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use super::super::pyobject::{
2+
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
3+
};
4+
use super::super::vm::VirtualMachine;
5+
use super::objstr;
6+
use super::objtype;
7+
8+
fn tuple_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
9+
arg_check!(vm, args, required = [(o, Some(vm.ctx.tuple_type()))]);
10+
11+
let elements = get_elements(o);
12+
let mut str_parts = vec![];
13+
for elem in elements {
14+
match vm.to_str(elem) {
15+
Ok(s) => str_parts.push(objstr::get_value(&s)),
16+
Err(err) => return Err(err),
17+
}
18+
}
19+
20+
let s = if str_parts.len() == 1 {
21+
format!("({},)", str_parts.join(", "))
22+
} else {
23+
format!("({})", str_parts.join(", "))
24+
};
25+
Ok(vm.new_str(s))
26+
}
27+
28+
pub fn get_elements(obj: &PyObjectRef) -> Vec<PyObjectRef> {
29+
if let PyObjectKind::Tuple { elements } = &obj.borrow().kind {
30+
elements.to_vec()
31+
} else {
32+
panic!("Cannot extract elements from non-tuple");
33+
}
34+
}
35+
36+
fn tuple_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
37+
arg_check!(vm, args, required = [(tuple, Some(vm.ctx.tuple_type()))]);
38+
let elements = get_elements(tuple);
39+
Ok(vm.context().new_int(elements.len() as i32))
40+
}
41+
42+
pub fn init(context: &PyContext) {
43+
let ref tuple_type = context.tuple_type;
44+
tuple_type.set_attr("__len__", context.new_rustfunc(tuple_len));
45+
tuple_type.set_attr("__str__", context.new_rustfunc(tuple_str));
46+
}

vm/src/obj/objtype.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,22 @@ pub fn type_call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
113113
debug!("type_call: {:?}", args);
114114
let typ = args.shift();
115115
let new = typ.get_attr("__new__").unwrap();
116-
let obj = vm.invoke(new, args.insert(typ.clone()))?;
116+
let obj = match vm.invoke(new, args.insert(typ.clone())) {
117+
Ok(res) => res,
118+
Err(err) => return Err(err),
119+
};
117120

118121
if let Some(init) = obj.typ().get_attr("__init__") {
119-
let _ = vm.invoke(init, args.insert(obj.clone())).unwrap();
122+
match vm.invoke(init, args.insert(obj.clone())) {
123+
Ok(res) => {
124+
// TODO: assert that return is none?
125+
if !isinstance(res, vm.get_none()) {
126+
// panic!("__init__ must return none");
127+
// return Err(vm.new_type_error("__init__ must return None".to_string()));
128+
}
129+
}
130+
Err(err) => return Err(err),
131+
}
120132
}
121133
Ok(obj)
122134
}

0 commit comments

Comments
 (0)