Skip to content

Commit 7e45d0b

Browse files
committed
Add del statement
1 parent f7fc9a8 commit 7e45d0b

File tree

7 files changed

+130
-17
lines changed

7 files changed

+130
-17
lines changed

parser/src/python.lalrpop

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,31 @@ SimpleStatement: ast::LocatedStatement = {
3939
SmallStatement: ast::LocatedStatement = {
4040
// <e:Expression> => ast::Statement::Expression { expression: e },
4141
ExpressionStatement,
42-
<loc:@L> "pass" => {
43-
ast::LocatedStatement {
44-
location: loc,
45-
node: ast::Statement::Pass,
46-
}
47-
},
42+
PassStatement,
43+
DelStatement,
4844
FlowStatement,
4945
ImportStatement,
5046
AssertStatement,
5147
};
5248

49+
PassStatement: ast::LocatedStatement = {
50+
<loc:@L> "pass" => {
51+
ast::LocatedStatement {
52+
location: loc,
53+
node: ast::Statement::Pass,
54+
}
55+
},
56+
};
57+
58+
DelStatement: ast::LocatedStatement = {
59+
<loc:@L> "del" <e:ExpressionList2> => {
60+
ast::LocatedStatement {
61+
location: loc,
62+
node: ast::Statement::Delete { targets: e },
63+
}
64+
},
65+
};
66+
5367
ExpressionStatement: ast::LocatedStatement = {
5468
<loc:@L> <expr:TestList> <suffix:AssignSuffix*> => {
5569
// Just an expression, no assignment:
@@ -664,7 +678,7 @@ TestSetComp: ast::Expression = {
664678
};
665679

666680
ExpressionList: ast::Expression = {
667-
<e: Comma<Expression>> => {
681+
<e: ExpressionList2> => {
668682
if e.len() == 1 {
669683
e.into_iter().next().unwrap()
670684
} else {
@@ -673,6 +687,14 @@ ExpressionList: ast::Expression = {
673687
},
674688
};
675689

690+
ExpressionList2: Vec<ast::Expression> = {
691+
<e1:Expression> <e2:("," Expression)*> ","? => {
692+
let mut l = vec![e1];
693+
l.extend(e2.into_iter().map(|x| x.1));
694+
l
695+
},
696+
};
697+
676698
#[inline]
677699
TestList: Vec<ast::Expression> = {
678700
<e1:Test> <e2: ("," Test)*> => {
@@ -831,6 +853,7 @@ extern {
831853
"class" => lexer::Tok::Class,
832854
"continue" => lexer::Tok::Break,
833855
"def" => lexer::Tok::Def,
856+
"del" => lexer::Tok::Del,
834857
"elif" => lexer::Tok::Elif,
835858
"else" => lexer::Tok::Else,
836859
"except" => lexer::Tok::Except,

tests/snippets/delete.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
a = 1
3+
del a
4+

vm/src/bytecode.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,17 @@ pub enum Instruction {
6363
StoreName {
6464
name: String,
6565
},
66+
DeleteName {
67+
name: String,
68+
},
6669
StoreSubscript,
70+
DeleteSubscript,
6771
StoreAttr {
6872
name: String,
6973
},
74+
DeleteAttr {
75+
name: String,
76+
},
7077
LoadConst {
7178
value: Constant,
7279
},

vm/src/compile.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ impl Compiler {
123123
self.emit(Instruction::ReturnValue);
124124
}
125125

126-
fn compile_statements(&mut self, statements: &[ast::LocatedStatement]) {
126+
fn compile_statements(&mut self, statements: &[ast::LocatedStatement]) -> Result<(),String> {
127127
for statement in statements {
128-
self.compile_statement(statement)
128+
self.compile_statement(statement)?
129129
}
130130
}
131131

@@ -562,9 +562,30 @@ impl Compiler {
562562
self.compile_op(op);
563563
self.compile_store(target);
564564
}
565-
ast::Statement::Delete { targets: _ } => {
566-
// TODO: Remove the given names from the scope
567-
// self.emit(Instruction::DeleteName);
565+
ast::Statement::Delete { targets } => {
566+
for target in targets {
567+
match target {
568+
ast::Expression::Identifier { name } => {
569+
self.emit(Instruction::DeleteName {
570+
name: name.to_string(),
571+
});
572+
}
573+
ast::Expression::Attribute { value, name } => {
574+
self.compile_expression(value);
575+
self.emit(Instruction::DeleteAttr {
576+
name: name.to_string(),
577+
});
578+
}
579+
ast::Expression::Subscript { a, b } => {
580+
self.compile_expression(a);
581+
self.compile_expression(b);
582+
self.emit(Instruction::DeleteSubscript);
583+
}
584+
_ => {
585+
panic!("Invalid delete statement");
586+
}
587+
}
588+
}
568589
}
569590
ast::Statement::Pass => {
570591
self.emit(Instruction::Pass);

vm/src/obj/objdict.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,31 @@ pub fn dict_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
8383
Ok(vm.new_bool(false))
8484
}
8585

86+
pub fn dict_delitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
87+
arg_check!(
88+
vm,
89+
args,
90+
required = [
91+
(dict, Some(vm.ctx.dict_type())),
92+
(needle, Some(vm.ctx.str_type()))
93+
]
94+
);
95+
96+
// What we are looking for:
97+
let needle = objstr::get_value(&needle);
98+
99+
// Delete the item:
100+
let mut dict_obj = dict.borrow_mut();
101+
if let PyObjectKind::Dict { ref mut elements } = dict_obj.kind {
102+
match elements.remove(&needle) {
103+
Some(_) => Ok(vm.get_none()),
104+
None => Err(vm.new_value_error(format!("Key not found: {}", needle))),
105+
}
106+
} else {
107+
panic!("Cannot extract dict elements");
108+
}
109+
}
110+
86111
pub fn create_type(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: PyObjectRef) {
87112
(*dict_type.borrow_mut()).kind = PyObjectKind::Class {
88113
name: String::from("dict"),
@@ -96,6 +121,7 @@ pub fn init(context: &PyContext) {
96121
let ref dict_type = context.dict_type;
97122
dict_type.set_attr("__len__", context.new_rustfunc(dict_len));
98123
dict_type.set_attr("__contains__", context.new_rustfunc(dict_contains));
124+
dict_type.set_attr("__delitem__", context.new_rustfunc(dict_delitem));
99125
dict_type.set_attr("__new__", context.new_rustfunc(dict_new));
100126
dict_type.set_attr("__repr__", context.new_rustfunc(dict_repr));
101127
}

vm/src/pyobject.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ impl TypeProtocol for PyObjectRef {
397397
fn typ(&self) -> PyObjectRef {
398398
match self.borrow().typ {
399399
Some(ref typ) => typ.clone(),
400-
None => panic!("Object doesn't have a type!"),
400+
None => panic!("Object {:?} doesn't have a type!", self),
401401
}
402402
}
403403
}

vm/src/vm.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,20 @@ impl VirtualMachine {
316316
None
317317
}
318318

319+
fn delete_name(&mut self, name: &str) -> Option<PyResult> {
320+
let locals = match self.current_frame().locals.borrow().kind {
321+
PyObjectKind::Scope { ref scope } => scope.locals.clone(),
322+
_ => panic!("We really expect our scope to be a scope!"),
323+
};
324+
325+
// Assume here that locals is a dict
326+
let name = self.ctx.new_str(name.to_string());
327+
match self.call_method(&locals, "__delitem__", vec![name]) {
328+
Ok(_) => None,
329+
err => Some(err),
330+
}
331+
}
332+
319333
fn load_name(&mut self, name: &str) -> Option<PyResult> {
320334
// Lookup name in scope and put it onto the stack!
321335
let mut scope = self.current_frame().locals.clone();
@@ -432,6 +446,15 @@ impl VirtualMachine {
432446
}
433447
}
434448

449+
fn execute_delete_subscript(&mut self) -> Option<PyResult> {
450+
let idx = self.pop_value();
451+
let obj = self.pop_value();
452+
match self.call_method(&obj, "__delitem__", vec![idx]) {
453+
Ok(_) => None,
454+
err => Some(err),
455+
}
456+
}
457+
435458
fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
436459
self.call_method(&a, "__sub__", vec![b])
437460
}
@@ -779,6 +802,15 @@ impl VirtualMachine {
779802
None
780803
}
781804

805+
fn delete_attr(&mut self, attr_name: &str) -> Option<PyResult> {
806+
let parent = self.pop_value();
807+
let name = self.ctx.new_str(attr_name.to_string());
808+
match self.call_method(&parent, "__delattr__", vec![name]) {
809+
Ok(_) => None,
810+
err => Some(err),
811+
}
812+
}
813+
782814
fn unwrap_constant(&self, value: &bytecode::Constant) -> PyObjectRef {
783815
match *value {
784816
bytecode::Constant::Integer { ref value } => self.ctx.new_int(*value),
@@ -823,11 +855,10 @@ impl VirtualMachine {
823855
ref symbol,
824856
} => self.import(name, symbol),
825857
bytecode::Instruction::LoadName { ref name } => self.load_name(name),
826-
bytecode::Instruction::StoreName { ref name } => {
827-
// take top of stack and assign in scope:
828-
self.store_name(name)
829-
}
858+
bytecode::Instruction::StoreName { ref name } => self.store_name(name),
859+
bytecode::Instruction::DeleteName { ref name } => self.delete_name(name),
830860
bytecode::Instruction::StoreSubscript => self.execute_store_subscript(),
861+
bytecode::Instruction::DeleteSubscript => self.execute_delete_subscript(),
831862
bytecode::Instruction::Pop => {
832863
// Pop value from stack and ignore.
833864
self.pop_value();
@@ -957,6 +988,7 @@ impl VirtualMachine {
957988
bytecode::Instruction::BinaryOperation { ref op } => self.execute_binop(op),
958989
bytecode::Instruction::LoadAttr { ref name } => self.load_attr(name),
959990
bytecode::Instruction::StoreAttr { ref name } => self.store_attr(name),
991+
bytecode::Instruction::DeleteAttr { ref name } => self.delete_attr(name),
960992
bytecode::Instruction::UnaryOperation { ref op } => self.execute_unop(op),
961993
bytecode::Instruction::CompareOperation { ref op } => self.execute_compare(op),
962994
bytecode::Instruction::ReturnValue => {

0 commit comments

Comments
 (0)