Skip to content

Commit 6abf151

Browse files
committed
Add nonlocal support.
1 parent d7275c7 commit 6abf151

File tree

4 files changed

+28
-2
lines changed

4 files changed

+28
-2
lines changed

tests/snippets/global_nonlocal.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,13 @@ def b():
1111
b()
1212
assert a == 4
1313

14+
def x():
15+
def y():
16+
nonlocal b
17+
b = 3
18+
b = 2
19+
y()
20+
return b
21+
22+
res = x()
23+
assert res == 3, str(res)

vm/src/bytecode.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub type Label = usize;
4141
#[derive(Debug, Clone, PartialEq)]
4242
pub enum NameScope {
4343
Local,
44+
NonLocal,
4445
Global,
4546
}
4647

vm/src/compile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,12 @@ impl Compiler {
179179
let role = self.lookup_name(name);
180180
match role {
181181
SymbolRole::Global => bytecode::NameScope::Global,
182+
SymbolRole::Nonlocal => bytecode::NameScope::NonLocal,
182183
_ => bytecode::NameScope::Local,
183184
}
184185
}
185186

186187
fn load_name(&mut self, name: &str) {
187-
// TODO: if global, do something else!
188188
let scope = self.scope_for_name(name);
189189
self.emit(Instruction::LoadName {
190190
name: name.to_string(),

vm/src/frame.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ pub trait NameProtocol {
129129
fn store_name(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef);
130130
fn delete_name(&self, vm: &VirtualMachine, name: &str);
131131
fn load_cell(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef>;
132+
fn store_cell(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef);
132133
fn load_global(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef>;
133134
fn store_global(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef);
134135
}
@@ -157,6 +158,16 @@ impl NameProtocol for Scope {
157158
None
158159
}
159160

161+
fn store_cell(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef) {
162+
self.locals
163+
.iter()
164+
.skip(1)
165+
.next()
166+
.unwrap()
167+
.set_item(name, value, vm)
168+
.unwrap();
169+
}
170+
160171
fn store_name(&self, vm: &VirtualMachine, key: &str, value: PyObjectRef) {
161172
self.get_locals().set_item(key, value, vm).unwrap();
162173
}
@@ -1037,8 +1048,11 @@ impl Frame {
10371048
bytecode::NameScope::Global => {
10381049
self.scope.store_global(vm, name, obj);
10391050
}
1051+
bytecode::NameScope::NonLocal => {
1052+
self.scope.store_cell(vm, name, obj);
1053+
}
10401054
bytecode::NameScope::Local => {
1041-
self.scope.store_name(&vm, name, obj);
1055+
self.scope.store_name(vm, name, obj);
10421056
}
10431057
}
10441058
Ok(None)
@@ -1057,6 +1071,7 @@ impl Frame {
10571071
) -> FrameResult {
10581072
let optional_value = match name_scope {
10591073
bytecode::NameScope::Global => self.scope.load_global(vm, name),
1074+
bytecode::NameScope::NonLocal => self.scope.load_cell(vm, name),
10601075
bytecode::NameScope::Local => self.scope.load_name(&vm, name),
10611076
};
10621077

0 commit comments

Comments
 (0)