Skip to content

Commit f9538af

Browse files
committed
Add bytes object class
1 parent 8ed132c commit f9538af

File tree

7 files changed

+138
-0
lines changed

7 files changed

+138
-0
lines changed

tests/snippets/basic_types.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@
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+

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/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod objbytes;
12
pub mod objdict;
23
pub mod objfloat;
34
pub mod objint;

vm/src/obj/objbytes.rs

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

vm/src/obj/objint.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,63 @@ fn int_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
142142
}
143143
}
144144

145+
fn int_xor(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
146+
arg_check!(
147+
vm,
148+
args,
149+
required = [(i, Some(vm.ctx.int_type())), (i2, None)]
150+
);
151+
let v1 = get_value(i);
152+
if objtype::isinstance(i2.clone(), vm.ctx.int_type()) {
153+
let v2 = get_value(i2);
154+
Ok(vm.ctx.new_int(v1 ^ v2))
155+
} else {
156+
Err(vm.new_type_error(format!("Cannot xor {:?} and {:?}", i, i2)))
157+
}
158+
}
159+
160+
fn int_or(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
161+
arg_check!(
162+
vm,
163+
args,
164+
required = [(i, Some(vm.ctx.int_type())), (i2, None)]
165+
);
166+
let v1 = get_value(i);
167+
if objtype::isinstance(i2.clone(), vm.ctx.int_type()) {
168+
let v2 = get_value(i2);
169+
Ok(vm.ctx.new_int(v1 | v2))
170+
} else {
171+
Err(vm.new_type_error(format!("Cannot or {:?} and {:?}", i, i2)))
172+
}
173+
}
174+
175+
fn int_and(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
176+
arg_check!(
177+
vm,
178+
args,
179+
required = [(i, Some(vm.ctx.int_type())), (i2, None)]
180+
);
181+
let v1 = get_value(i);
182+
if objtype::isinstance(i2.clone(), vm.ctx.int_type()) {
183+
let v2 = get_value(i2);
184+
Ok(vm.ctx.new_int(v1 & v2))
185+
} else {
186+
Err(vm.new_type_error(format!("Cannot and {:?} and {:?}", i, i2)))
187+
}
188+
}
189+
145190
pub fn init(context: &PyContext) {
146191
let ref int_type = context.int_type;
147192
int_type.set_attr("__add__", context.new_rustfunc(int_add));
193+
int_type.set_attr("__and__", context.new_rustfunc(int_and));
148194
int_type.set_attr("__init__", context.new_rustfunc(int_init));
149195
int_type.set_attr("__mod__", context.new_rustfunc(int_mod));
150196
int_type.set_attr("__mul__", context.new_rustfunc(int_mul));
197+
int_type.set_attr("__or__", context.new_rustfunc(int_or));
151198
int_type.set_attr("__pow__", context.new_rustfunc(int_pow));
152199
int_type.set_attr("__repr__", context.new_rustfunc(str));
153200
int_type.set_attr("__str__", context.new_rustfunc(str));
154201
int_type.set_attr("__sub__", context.new_rustfunc(int_sub));
155202
int_type.set_attr("__truediv__", context.new_rustfunc(int_truediv));
203+
int_type.set_attr("__xor__", context.new_rustfunc(int_xor));
156204
}

vm/src/pyobject.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::bytecode;
22
use super::exceptions;
3+
use super::obj::objbytes;
34
use super::obj::objdict;
45
use super::obj::objfloat;
56
use super::obj::objint;
@@ -52,6 +53,7 @@ pub struct PyContext {
5253
pub dict_type: PyObjectRef,
5354
pub int_type: PyObjectRef,
5455
pub float_type: PyObjectRef,
56+
pub bytes_type: PyObjectRef,
5557
pub bool_type: PyObjectRef,
5658
pub list_type: PyObjectRef,
5759
pub tuple_type: PyObjectRef,
@@ -114,6 +116,7 @@ impl PyContext {
114116
let list_type = create_type("list", &type_type, &object_type, &dict_type);
115117
let int_type = create_type("int", &type_type, &object_type, &dict_type);
116118
let float_type = create_type("float", &type_type, &object_type, &dict_type);
119+
let bytes_type = create_type("bytes", &type_type, &object_type, &dict_type);
117120
let tuple_type = create_type("tuple", &type_type, &object_type, &dict_type);
118121
let bool_type = create_type("bool", &type_type, &object_type, &dict_type);
119122
let exceptions = exceptions::ExceptionZoo::new(&type_type, &object_type, &dict_type);
@@ -126,6 +129,7 @@ impl PyContext {
126129
let context = PyContext {
127130
int_type: int_type,
128131
float_type: float_type,
132+
bytes_type: bytes_type,
129133
list_type: list_type,
130134
bool_type: bool_type,
131135
tuple_type: tuple_type,
@@ -146,6 +150,7 @@ impl PyContext {
146150
objfunction::init(&context);
147151
objint::init(&context);
148152
objfloat::init(&context);
153+
objbytes::init(&context);
149154
objstr::init(&context);
150155
objbool::init(&context);
151156
exceptions::init(&context);
@@ -162,6 +167,10 @@ impl PyContext {
162167
self.float_type.clone()
163168
}
164169

170+
pub fn bytes_type(&self) -> PyObjectRef {
171+
self.bytes_type.clone()
172+
}
173+
165174
pub fn list_type(&self) -> PyObjectRef {
166175
self.list_type.clone()
167176
}
@@ -547,6 +556,9 @@ pub enum PyObjectKind {
547556
Boolean {
548557
value: bool,
549558
},
559+
Bytes {
560+
value: Vec<u8>,
561+
},
550562
List {
551563
elements: Vec<PyObjectRef>,
552564
},
@@ -604,6 +616,7 @@ impl fmt::Debug for PyObjectKind {
604616
&PyObjectKind::String { ref value } => write!(f, "str \"{}\"", value),
605617
&PyObjectKind::Integer { ref value } => write!(f, "int {}", value),
606618
&PyObjectKind::Float { ref value } => write!(f, "float {}", value),
619+
&PyObjectKind::Bytes { ref value } => write!(f, "bytes {:?}", value),
607620
&PyObjectKind::Boolean { ref value } => write!(f, "boolean {}", value),
608621
&PyObjectKind::List { elements: _ } => write!(f, "list"),
609622
&PyObjectKind::Tuple { elements: _ } => write!(f, "tuple"),
@@ -651,6 +664,7 @@ impl PyObject {
651664
PyObjectKind::String { ref value } => value.clone(),
652665
PyObjectKind::Integer { ref value } => format!("{:?}", value),
653666
PyObjectKind::Float { ref value } => format!("{:?}", value),
667+
PyObjectKind::Bytes { ref value } => format!("b'{:?}'", value),
654668
PyObjectKind::Boolean { ref value } => format!("{:?}", value),
655669
PyObjectKind::List { ref elements } => format!(
656670
"[{}]",

vm/src/vm.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,18 @@ impl VirtualMachine {
360360
self.call_method(a, "__mod__".to_string(), vec![b])
361361
}
362362

363+
fn _xor(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
364+
self.call_method(a, "__xor__".to_string(), vec![b])
365+
}
366+
367+
fn _or(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
368+
self.call_method(a, "__or__".to_string(), vec![b])
369+
}
370+
371+
fn _and(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
372+
self.call_method(a, "__and__".to_string(), vec![b])
373+
}
374+
363375
fn execute_binop(&mut self, op: &bytecode::BinaryOperator) -> Option<PyResult> {
364376
let b_ref = self.pop_value();
365377
let a_ref = self.pop_value();
@@ -373,6 +385,9 @@ impl VirtualMachine {
373385
&bytecode::BinaryOperator::Divide => self._div(a_ref, b_ref),
374386
&bytecode::BinaryOperator::Subscript => self.subscript(a_ref, b_ref),
375387
&bytecode::BinaryOperator::Modulo => self._modulo(a_ref, b_ref),
388+
&bytecode::BinaryOperator::Xor => self._xor(a_ref, b_ref),
389+
&bytecode::BinaryOperator::Or => self._or(a_ref, b_ref),
390+
&bytecode::BinaryOperator::And => self._and(a_ref, b_ref),
376391
_ => panic!("NOT IMPL {:?}", op),
377392
};
378393
match result {

0 commit comments

Comments
 (0)