Skip to content

Commit a450c0e

Browse files
committed
Add builtin type set
1 parent 77a4369 commit a450c0e

File tree

9 files changed

+146
-1
lines changed

9 files changed

+146
-1
lines changed

parser/src/ast.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ pub enum Expression {
165165
Dict {
166166
elements: Vec<(Expression, Expression)>,
167167
},
168+
Set {
169+
elements: Vec<Expression>,
170+
},
168171
ListComprehension {
169172
element: Box<Expression>,
170173
generators: Vec<Comprehension>,

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ fn handle_exception(vm: &mut VirtualMachine, result: PyResult) {
7979
Ok(_value) => {}
8080
Err(err) => {
8181
print_exception(vm, &err);
82+
std::process::exit(1);
8283
}
8384
}
8485
}

vm/src/builtins.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,9 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
512512
dict.insert(String::from("print"), ctx.new_rustfunc(builtin_print));
513513
dict.insert(String::from("range"), ctx.new_rustfunc(builtin_range));
514514
dict.insert(String::from("repr"), ctx.new_rustfunc(builtin_repr));
515+
dict.insert(String::from("set"), ctx.set_type());
515516
dict.insert(String::from("setattr"), ctx.new_rustfunc(builtin_setattr));
516-
dict.insert(String::from("str"), ctx.str_type()); // new_rustfunc(builtin_str));
517+
dict.insert(String::from("str"), ctx.str_type());
517518
dict.insert(String::from("tuple"), ctx.tuple_type());
518519
dict.insert(String::from("type"), ctx.type_type());
519520
dict.insert(String::from("object"), ctx.object());

vm/src/bytecode.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ pub enum Instruction {
134134
BuildList {
135135
size: usize,
136136
},
137+
BuildSet {
138+
size: usize,
139+
},
137140
BuildMap {
138141
size: usize,
139142
},

vm/src/compile.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,13 @@ impl Compiler {
802802
}
803803
self.emit(Instruction::BuildTuple { size: size });
804804
}
805+
ast::Expression::Set { elements } => {
806+
let size = elements.len();
807+
for element in elements {
808+
self.compile_expression(element);
809+
}
810+
self.emit(Instruction::BuildSet { size: size });
811+
}
805812
ast::Expression::Dict { elements } => {
806813
let size = elements.len();
807814
for (key, value) in elements {

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod objiter;
88
pub mod objlist;
99
pub mod objobject;
1010
pub mod objsequence;
11+
pub mod objset;
1112
pub mod objstr;
1213
pub mod objtuple;
1314
pub mod objtype;

vm/src/obj/objset.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Builtin set type with a sequence of unique items.
3+
*/
4+
5+
use super::super::pyobject::{
6+
AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef,
7+
PyResult, TypeProtocol,
8+
};
9+
use super::super::vm::VirtualMachine;
10+
use super::objiter;
11+
use super::objstr;
12+
use super::objtype;
13+
use std::collections::HashMap;
14+
15+
pub fn get_elements(obj: &PyObjectRef) -> HashMap<usize, PyObjectRef> {
16+
if let PyObjectKind::Set { elements } = &obj.borrow().kind {
17+
elements.clone()
18+
} else {
19+
panic!("Cannot extract set elements from non-set");
20+
}
21+
}
22+
23+
pub fn sequence_to_hashmap(iterable: &Vec<PyObjectRef>) -> HashMap<usize, PyObjectRef> {
24+
let mut elements = HashMap::new();
25+
for item in iterable {
26+
let key = item.get_id();
27+
elements.insert(key, item.clone());
28+
}
29+
elements
30+
}
31+
32+
/* Create a new object of sub-type of set */
33+
fn set_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
34+
arg_check!(
35+
vm,
36+
args,
37+
required = [(cls, None)],
38+
optional = [(iterable, None)]
39+
);
40+
41+
if !objtype::issubclass(cls, vm.ctx.set_type()) {
42+
return Err(vm.new_type_error(format!("{:?} is not a subtype of set", cls)));
43+
}
44+
45+
let elements = match iterable {
46+
None => HashMap::new(),
47+
Some(iterable) => {
48+
let mut elements = HashMap::new();
49+
let iterator = objiter::get_iter(vm, iterable)?;
50+
loop {
51+
match vm.call_method(&iterator, "__next__", vec![]) {
52+
Ok(v) => {
53+
// TODO: should we use the hash function here?
54+
let key = v.get_id();
55+
elements.insert(key, v);
56+
}
57+
_ => break,
58+
}
59+
}
60+
elements
61+
}
62+
};
63+
64+
Ok(PyObject::new(
65+
PyObjectKind::Set { elements: elements },
66+
cls.clone(),
67+
))
68+
}
69+
70+
fn set_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
71+
trace!("set.len called with: {:?}", args);
72+
arg_check!(vm, args, required = [(s, Some(vm.ctx.set_type()))]);
73+
let elements = get_elements(s);
74+
Ok(vm.context().new_int(elements.len() as i32))
75+
}
76+
77+
fn set_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
78+
arg_check!(vm, args, required = [(o, Some(vm.ctx.set_type()))]);
79+
80+
let elements = get_elements(o);
81+
let mut str_parts = vec![];
82+
for elem in elements.values() {
83+
let part = vm.to_repr(elem.clone())?;
84+
str_parts.push(objstr::get_value(&part));
85+
}
86+
87+
let s = format!("{{ {} }}", str_parts.join(", "));
88+
Ok(vm.new_str(s))
89+
}
90+
91+
pub fn init(context: &PyContext) {
92+
let ref set_type = context.set_type;
93+
set_type.set_attr("__len__", context.new_rustfunc(set_len));
94+
set_type.set_attr("__new__", context.new_rustfunc(set_new));
95+
set_type.set_attr("__repr__", context.new_rustfunc(set_repr));
96+
}

vm/src/pyobject.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use super::obj::objint;
99
use super::obj::objiter;
1010
use super::obj::objlist;
1111
use super::obj::objobject;
12+
use super::obj::objset;
1213
use super::obj::objstr;
1314
use super::obj::objtuple;
1415
use super::obj::objtype;
@@ -61,6 +62,7 @@ pub struct PyContext {
6162
pub false_value: PyObjectRef,
6263
pub list_type: PyObjectRef,
6364
pub tuple_type: PyObjectRef,
65+
pub set_type: PyObjectRef,
6466
pub iter_type: PyObjectRef,
6567
pub str_type: PyObjectRef,
6668
pub function_type: PyObjectRef,
@@ -122,6 +124,7 @@ impl PyContext {
122124
create_type("member_descriptor", &type_type, &object_type, &dict_type);
123125
let str_type = create_type("str", &type_type, &object_type, &dict_type);
124126
let list_type = create_type("list", &type_type, &object_type, &dict_type);
127+
let set_type = create_type("set", &type_type, &object_type, &dict_type);
125128
let int_type = create_type("int", &type_type, &object_type, &dict_type);
126129
let float_type = create_type("float", &type_type, &object_type, &dict_type);
127130
let bytes_type = create_type("bytes", &type_type, &object_type, &dict_type);
@@ -142,6 +145,7 @@ impl PyContext {
142145
float_type: float_type,
143146
bytes_type: bytes_type,
144147
list_type: list_type,
148+
set_type: set_type,
145149
bool_type: bool_type,
146150
true_value: true_value,
147151
false_value: false_value,
@@ -160,6 +164,7 @@ impl PyContext {
160164
};
161165
objtype::init(&context);
162166
objlist::init(&context);
167+
objset::init(&context);
163168
objtuple::init(&context);
164169
objobject::init(&context);
165170
objdict::init(&context);
@@ -190,6 +195,11 @@ impl PyContext {
190195
pub fn list_type(&self) -> PyObjectRef {
191196
self.list_type.clone()
192197
}
198+
199+
pub fn set_type(&self) -> PyObjectRef {
200+
self.set_type.clone()
201+
}
202+
193203
pub fn bool_type(&self) -> PyObjectRef {
194204
self.bool_type.clone()
195205
}
@@ -269,6 +279,11 @@ impl PyContext {
269279
PyObject::new(PyObjectKind::List { elements: elements }, self.list_type())
270280
}
271281

282+
pub fn new_set(&self, elements: Vec<PyObjectRef>) -> PyObjectRef {
283+
let elements = objset::sequence_to_hashmap(&elements);
284+
PyObject::new(PyObjectKind::Set { elements: elements }, self.set_type())
285+
}
286+
272287
pub fn new_dict(&self) -> PyObjectRef {
273288
PyObject::new(
274289
PyObjectKind::Dict {
@@ -611,6 +626,9 @@ pub enum PyObjectKind {
611626
Dict {
612627
elements: HashMap<String, PyObjectRef>,
613628
},
629+
Set {
630+
elements: HashMap<usize, PyObjectRef>,
631+
},
614632
Iterator {
615633
position: usize,
616634
iterated_obj: PyObjectRef,
@@ -663,6 +681,7 @@ impl fmt::Debug for PyObjectKind {
663681
&PyObjectKind::List { elements: _ } => write!(f, "list"),
664682
&PyObjectKind::Tuple { elements: _ } => write!(f, "tuple"),
665683
&PyObjectKind::Dict { elements: _ } => write!(f, "dict"),
684+
&PyObjectKind::Set { elements: _ } => write!(f, "set"),
666685
&PyObjectKind::Iterator {
667686
position: _,
668687
iterated_obj: _,
@@ -738,6 +757,14 @@ impl PyObject {
738757
.collect::<Vec<_>>()
739758
.join(", ")
740759
),
760+
PyObjectKind::Set { ref elements } => format!(
761+
"{{ {} }}",
762+
elements
763+
.iter()
764+
.map(|elem| elem.1.borrow().str())
765+
.collect::<Vec<_>>()
766+
.join(", ")
767+
),
741768
PyObjectKind::None => String::from("None"),
742769
PyObjectKind::Class {
743770
ref name,

vm/src/vm.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,12 @@ impl VirtualMachine {
869869
self.push_value(list_obj);
870870
None
871871
}
872+
bytecode::Instruction::BuildSet { size } => {
873+
let elements = self.pop_multiple(*size);
874+
let py_obj = self.context().new_set(elements);
875+
self.push_value(py_obj);
876+
None
877+
}
872878
bytecode::Instruction::BuildTuple { size } => {
873879
let elements = self.pop_multiple(*size);
874880
let list_obj = self.context().new_tuple(elements);

0 commit comments

Comments
 (0)