Skip to content

Commit 372f09a

Browse files
committed
Abstract rc linked list so we can just use a loop.
1 parent ddf4f55 commit 372f09a

File tree

1 file changed

+55
-31
lines changed

1 file changed

+55
-31
lines changed

vm/src/frame.rs

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,51 +30,84 @@ use crate::vm::VirtualMachine;
3030
* When a name is looked up, it is check in its scope.
3131
*/
3232
#[derive(Debug)]
33-
pub struct Locals {
34-
dict: PyObjectRef,
35-
parent: Option<Rc<Locals>>,
33+
struct RcListNode<T> {
34+
elem: T,
35+
next: Option<Rc<RcListNode<T>>>,
36+
}
37+
38+
#[derive(Debug, Clone)]
39+
struct RcList<T> {
40+
head: Option<Rc<RcListNode<T>>>,
41+
}
42+
43+
struct Iter<'a, T: 'a> {
44+
next: Option<&'a RcListNode<T>>,
45+
}
46+
47+
impl<T> RcList<T> {
48+
pub fn new() -> Self {
49+
RcList { head: None }
50+
}
51+
52+
pub fn insert(self, elem: T) -> Self {
53+
RcList {
54+
head: Some(Rc::new(RcListNode {
55+
elem,
56+
next: self.head,
57+
})),
58+
}
59+
}
60+
61+
pub fn iter(&self) -> Iter<T> {
62+
Iter {
63+
next: self.head.as_ref().map(|node| &**node),
64+
}
65+
}
66+
}
67+
68+
impl<'a, T> Iterator for Iter<'a, T> {
69+
type Item = &'a T;
70+
71+
fn next(&mut self) -> Option<Self::Item> {
72+
self.next.map(|node| {
73+
self.next = node.next.as_ref().map(|node| &**node);
74+
&node.elem
75+
})
76+
}
3677
}
3778

3879
#[derive(Debug, Clone)]
3980
pub struct Scope {
40-
pub locals: Option<Rc<Locals>>, // Variables
81+
locals: RcList<PyObjectRef>,
4182
pub globals: PyObjectRef,
42-
// TODO: pub locals: RefCell<PyAttributes>, // Variables
43-
// pub parent: Option<Rc<Scope>>, // Parent scope
4483
}
4584

4685
impl Scope {
4786
pub fn new(locals: Option<PyObjectRef>, globals: PyObjectRef) -> Scope {
4887
let locals = match locals {
49-
Some(dict) => Some(Rc::new(Locals {
50-
dict: dict,
51-
parent: None,
52-
})),
53-
None => None,
88+
Some(dict) => RcList::new().insert(dict),
89+
None => RcList::new(),
5490
};
5591
Scope { locals, globals }
5692
}
5793

5894
pub fn get_locals(&self) -> PyObjectRef {
59-
match self.locals {
60-
Some(ref locals) => locals.dict.clone(),
95+
match self.locals.iter().next() {
96+
Some(dict) => dict.clone(),
6197
None => self.globals.clone(),
6298
}
6399
}
64100

65101
pub fn get_only_locals(&self) -> Option<PyObjectRef> {
66-
match self.locals {
67-
Some(ref locals) => Some(locals.dict.clone()),
102+
match self.locals.iter().next() {
103+
Some(dict) => Some(dict.clone()),
68104
None => None,
69105
}
70106
}
71107

72108
pub fn child_scope_with_locals(&self, locals: PyObjectRef) -> Scope {
73109
Scope {
74-
locals: Some(Rc::new(Locals {
75-
dict: locals,
76-
parent: self.locals.clone(),
77-
})),
110+
locals: self.locals.clone().insert(locals),
78111
globals: self.globals.clone(),
79112
}
80113
}
@@ -93,18 +126,9 @@ pub trait AttributeProtocol2 {
93126

94127
impl AttributeProtocol2 for Scope {
95128
fn get_attr(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef> {
96-
// Lookup name in scope and put it onto the stack!
97-
let mut locals = self.locals.clone();
98-
loop {
99-
match locals {
100-
Some(new_locals) => {
101-
if let Some(value) = new_locals.dict.get_item(name) {
102-
return Some(value);
103-
} else {
104-
locals = new_locals.parent.clone()
105-
}
106-
}
107-
None => break,
129+
for dict in self.locals.iter() {
130+
if let Some(value) = dict.get_item(name) {
131+
return Some(value);
108132
}
109133
}
110134

0 commit comments

Comments
 (0)