Skip to content

Commit b9adb4e

Browse files
committed
Add environment thingy
1 parent cdd0c29 commit b9adb4e

6 files changed

Lines changed: 103 additions & 32 deletions

File tree

src/main.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ fn run_script(script_file: &String) {
4747
Ok(source) => {
4848
let code_obj = compile::compile(&mut vm, &source, compile::Mode::Exec).unwrap();
4949
debug!("Code object: {:?}", code_obj.borrow());
50-
let vars = vm.new_dict(); // Keep track of local variables
50+
let builtins = vm.get_builtin_scope();
51+
let vars = vm.new_scope(Some(builtins)); // Keep track of local variables
5152
match vm.run_code_obj(code_obj, vars) {
5253
Ok(_value) => {
5354
}
@@ -69,7 +70,8 @@ fn run_shell() {
6970
crate_version!()
7071
);
7172
let mut vm = VirtualMachine::new();
72-
let vars = vm.new_dict(); // Keep track of local variables
73+
let builtins = vm.get_builtin_scope();
74+
let vars = vm.new_scope(Some(builtins)); // Keep track of local variables
7375
// Read a single line:
7476
loop {
7577
let mut input = String::new();

vm/src/builtins.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::io::{self, Write};
44

55
use super::compile;
66
use super::pyobject::DictProtocol;
7-
use super::pyobject::{Executor, PyContext, PyObject, PyObjectKind, PyObjectRef, PyResult};
7+
use super::pyobject::{Executor, PyContext, PyObject, PyObjectKind, PyObjectRef, PyResult, Scope};
88
use super::objbool;
99

1010

@@ -97,10 +97,12 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
9797
dict.insert(String::from("locals"), ctx.new_rustfunc(locals));
9898
dict.insert(String::from("compile"), ctx.new_rustfunc(builtin_compile));
9999
dict.insert("len".to_string(), ctx.new_rustfunc(len));
100+
let d2 = PyObject::new(PyObjectKind::Dict { elements: dict }, ctx.type_type.clone());
101+
let scope = PyObject::new(PyObjectKind::Scope { scope: Scope { locals: d2, parent: None} }, ctx.type_type.clone());
100102
let obj = PyObject::new(
101103
PyObjectKind::Module {
102104
name: "__builtins__".to_string(),
103-
dict: PyObject::new(PyObjectKind::Dict { elements: dict }, ctx.type_type.clone()),
105+
dict: scope,
104106
},
105107
ctx.type_type.clone(),
106108
);

vm/src/eval.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ use super::compile;
44
use super::pyobject::{Executor, PyObjectRef, PyResult};
55
use super::vm::VirtualMachine;
66

7-
pub fn eval(vm: &mut VirtualMachine, source: &String, locals: PyObjectRef) -> PyResult {
7+
pub fn eval(vm: &mut VirtualMachine, source: &String, scope: PyObjectRef) -> PyResult {
88
match compile::compile(vm, source, compile::Mode::Eval) {
99
Ok(bytecode) => {
1010
debug!("Code object: {:?}", bytecode);
11-
vm.run_code_obj(bytecode, locals)
11+
vm.run_code_obj(bytecode, scope)
1212
}
1313
Err(msg) => {
1414
panic!("Parsing went horribly wrong: {}", msg);
@@ -26,7 +26,7 @@ mod tests {
2626
fn test_print_42() {
2727
let source = String::from("print('Hello world')\n");
2828
let mut vm = VirtualMachine::new();
29-
let vars = vm.new_dict();
29+
let vars = vm.new_scope(None);
3030
let result = eval(&mut vm, &source, vars);
3131

3232
// TODO: check result?

vm/src/frame.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ pub struct Frame {
1919
// We need 1 stack per frame
2020
stack: Vec<PyObjectRef>, // The main data frame of the stack machine
2121
blocks: Vec<Block>, // Block frames, for controling loops and exceptions
22-
// pub globals: HashMap<String, PyObjectRef>, // Variables
2322
pub locals: PyObjectRef, // Variables
2423
pub lasti: usize, // index of last instruction ran
2524
// cmp_op: Vec<&'a Fn(NativeType, NativeType) -> bool>, // TODO: change compare to a function list
@@ -37,7 +36,6 @@ pub fn copy_code(code_obj: PyObjectRef) -> bytecode::CodeObject {
3736
impl Frame {
3837
pub fn new(
3938
code: PyObjectRef,
40-
callargs: HashMap<String, PyObjectRef>,
4139
globals: PyObjectRef,
4240
) -> Frame {
4341
//populate the globals and locals

vm/src/pyobject.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ pub struct PyContext {
4343
pub int_type: PyObjectRef,
4444
}
4545

46+
/*
47+
* So a scope is a linked list of scopes.
48+
* When a name is looked up, it is check in its scope.
49+
*/
50+
#[derive(Debug)]
51+
pub struct Scope {
52+
pub locals: PyObjectRef, // Variables
53+
pub parent: Option<PyObjectRef>, // Parent scope
54+
}
55+
4656
// Basic objects:
4757
impl PyContext {
4858
pub fn new() -> PyContext {
@@ -118,6 +128,7 @@ pub trait Executor {
118128
fn new_str(&self, s: String) -> PyObjectRef;
119129
fn new_bool(&self, b: bool) -> PyObjectRef;
120130
fn new_dict(&self) -> PyObjectRef;
131+
fn new_scope(&self, parent: Option<PyObjectRef>) -> PyObjectRef;
121132
fn new_exception(&self, msg: String) -> PyObjectRef;
122133
fn get_none(&self) -> PyObjectRef;
123134
fn get_type(&self) -> PyObjectRef;
@@ -141,6 +152,33 @@ impl Default for PyObject {
141152
}
142153
}
143154

155+
pub trait ParentProtocol {
156+
fn has_parent(&self) -> bool;
157+
fn get_parent(&self) -> PyObjectRef;
158+
}
159+
160+
impl ParentProtocol for PyObjectRef {
161+
fn has_parent(&self) -> bool {
162+
match self.borrow().kind {
163+
PyObjectKind::Scope { ref scope } => match scope.parent {
164+
Some(_) => true,
165+
None => false,
166+
},
167+
_ => panic!("Only scopes have parent (not {:?}", self),
168+
}
169+
}
170+
171+
fn get_parent(&self) -> PyObjectRef {
172+
match self.borrow().kind {
173+
PyObjectKind::Scope { ref scope } => match scope.parent {
174+
Some(ref value) => value.clone(),
175+
None => panic!("OMG"),
176+
},
177+
_ => panic!("TODO"),
178+
}
179+
}
180+
}
181+
144182
pub trait DictProtocol {
145183
fn contains_key(&self, k: &String) -> bool;
146184
fn get_item(&self, k: &String) -> PyObjectRef;
@@ -152,6 +190,7 @@ impl DictProtocol for PyObjectRef {
152190
match self.borrow().kind {
153191
PyObjectKind::Dict { ref elements } => elements.contains_key(k),
154192
PyObjectKind::Module { ref name, ref dict } => dict.contains_key(k),
193+
PyObjectKind::Scope { ref scope } => scope.locals.contains_key(k),
155194
_ => panic!("TODO"),
156195
}
157196
}
@@ -160,6 +199,7 @@ impl DictProtocol for PyObjectRef {
160199
match self.borrow().kind {
161200
PyObjectKind::Dict { ref elements } => elements[k].clone(),
162201
PyObjectKind::Module { ref name, ref dict } => dict.get_item(k),
202+
PyObjectKind::Scope { ref scope } => scope.locals.get_item(k),
163203
_ => panic!("TODO"),
164204
}
165205
}
@@ -168,7 +208,12 @@ impl DictProtocol for PyObjectRef {
168208
match self.borrow_mut().kind {
169209
PyObjectKind::Dict {
170210
elements: ref mut el,
171-
} => el.insert(k.to_string(), v),
211+
} => {
212+
el.insert(k.to_string(), v);
213+
},
214+
PyObjectKind::Scope { ref mut scope } => {
215+
scope.locals.set_item(k, v);
216+
},
172217
_ => panic!("TODO"),
173218
};
174219
}
@@ -223,6 +268,9 @@ pub enum PyObjectKind {
223268
Function {
224269
code: PyObjectRef,
225270
},
271+
Scope {
272+
scope: Scope,
273+
},
226274
Module {
227275
name: String,
228276
dict: PyObjectRef,
@@ -253,6 +301,7 @@ impl fmt::Debug for PyObjectKind {
253301
&PyObjectKind::Code { ref code } => write!(f, "code: {:?}", code),
254302
&PyObjectKind::Function { ref code } => write!(f, "function"),
255303
&PyObjectKind::Module { ref name, ref dict } => write!(f, "module"),
304+
&PyObjectKind::Scope { ref scope } => write!(f, "scope"),
256305
&PyObjectKind::None => write!(f, "None"),
257306
&PyObjectKind::Class { ref name } => write!(f, "class"),
258307
&PyObjectKind::RustFunction { ref function } => write!(f, "rust function"),

vm/src/vm.rs

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use super::objlist;
1616
use super::objstr;
1717
use super::objtuple;
1818
use super::pyobject::{DictProtocol, Executor, PyContext, PyObject, PyObjectKind, PyObjectRef,
19-
PyResult};
19+
PyResult, ParentProtocol, Scope};
2020

2121
// use objects::objects;
2222

@@ -33,8 +33,8 @@ impl Executor for VirtualMachine {
3333
self.invoke(f, Vec::new())
3434
}
3535

36-
fn run_code_obj(&mut self, code: PyObjectRef, locals: PyObjectRef) -> PyResult {
37-
let frame = Frame::new(code, HashMap::new(), locals);
36+
fn run_code_obj(&mut self, code: PyObjectRef, scope: PyObjectRef) -> PyResult {
37+
let frame = Frame::new(code, scope);
3838
self.run_frame(frame)
3939
}
4040

@@ -50,6 +50,15 @@ impl Executor for VirtualMachine {
5050
self.ctx.new_dict()
5151
}
5252

53+
fn new_scope(&self, parent: Option<PyObjectRef>) -> PyObjectRef {
54+
let locals = self.ctx.new_dict();
55+
let scope = Scope {
56+
locals: locals,
57+
parent: parent,
58+
};
59+
PyObject { kind: PyObjectKind::Scope { scope: scope }, typ: None }.into_ref()
60+
}
61+
5362
fn new_exception(&self, msg: String) -> PyObjectRef {
5463
self.new_str(msg)
5564
}
@@ -83,6 +92,16 @@ impl VirtualMachine {
8392
}
8493
}
8594

95+
pub fn get_builtin_scope(&mut self) -> PyObjectRef {
96+
let a2 = &*self.builtins.borrow();
97+
match a2.kind {
98+
PyObjectKind::Module { ref name, ref dict } => {
99+
dict.clone()
100+
},
101+
_ => { panic!("OMG"); }
102+
}
103+
}
104+
86105
// Container of the virtual machine state:
87106
pub fn to_str(&mut self, obj: PyObjectRef) -> String {
88107
obj.borrow().str()
@@ -165,22 +184,23 @@ impl VirtualMachine {
165184

166185
fn load_name(&mut self, name: &String) -> Option<PyResult> {
167186
// Lookup name in scope and put it onto the stack!
168-
if self.current_frame().locals.contains_key(name) {
169-
let obj = self.current_frame().locals.get_item(name);
170-
self.push_value(obj);
171-
None
172-
} else if self.builtins.contains_key(name) {
173-
let obj = self.builtins.get_item(name);
174-
self.push_value(obj);
175-
None
176-
} else {
177-
let name_error = PyObject::new(
178-
PyObjectKind::NameError {
179-
name: name.to_string(),
180-
},
181-
self.get_type(),
182-
);
183-
Some(Err(name_error))
187+
let mut scope = self.current_frame().locals.clone();
188+
loop {
189+
if scope.contains_key(name) {
190+
let obj = scope.get_item(name);
191+
self.push_value(obj);
192+
break None
193+
} else if scope.has_parent() {
194+
scope = scope.get_parent();
195+
} else {
196+
let name_error = PyObject::new(
197+
PyObjectKind::NameError {
198+
name: name.to_string(),
199+
},
200+
self.get_type(),
201+
);
202+
break Some(Err(name_error))
203+
}
184204
}
185205
}
186206

@@ -431,12 +451,12 @@ impl VirtualMachine {
431451
match f.kind {
432452
PyObjectKind::RustFunction { ref function } => f.call(self, args),
433453
PyObjectKind::Function { ref code } => {
434-
let mut locals = self.new_dict();
454+
let mut scope = self.new_scope(None);
435455
let code_object = copy_code(code.clone());
436456
for (name, value) in code_object.arg_names.iter().zip(args) {
437-
locals.set_item(name, value);
457+
scope.set_item(name, value);
438458
}
439-
let frame = Frame::new(code.clone(), HashMap::new(), locals);
459+
let frame = Frame::new(code.clone(), scope);
440460
self.run_frame(frame)
441461
}
442462
PyObjectKind::Class { name: _ } => self.new_instance(func_ref.clone(), args),

0 commit comments

Comments
 (0)