Skip to content

Commit a1b7c61

Browse files
committed
Implement sys._getframe() to the point where we can use it to get locals.
1 parent f6d7e2f commit a1b7c61

File tree

5 files changed

+84
-5
lines changed

5 files changed

+84
-5
lines changed

tests/snippets/getframe.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import sys
2+
3+
value = 189
4+
locals_dict = sys._getframe().f_locals
5+
assert locals_dict['value'] == 189
6+
foo = 'bar'
7+
assert locals_dict['foo'] == foo
8+
9+
def test_function():
10+
x = 17
11+
assert sys._getframe().f_locals is not locals_dict
12+
assert sys._getframe().f_locals['x'] == 17
13+
14+
test_function()
15+
16+
class TestClass():
17+
def __init__(self):
18+
assert sys._getframe().f_locals['self'] == self
19+
20+
TestClass()

vm/src/frame.rs

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ extern crate rustpython_parser;
33
use self::rustpython_parser::ast;
44
use std::collections::hash_map::HashMap;
55
use std::fmt;
6+
use std::mem;
67
use std::path::PathBuf;
78

89
use super::builtins;
@@ -38,6 +39,7 @@ enum Block {
3839
},
3940
}
4041

42+
#[derive(Clone)]
4143
pub struct Frame {
4244
pub code: bytecode::CodeObject,
4345
// We need 1 stack per frame
@@ -94,6 +96,8 @@ impl Frame {
9496
"<unknown>".to_string()
9597
};
9698

99+
let prev_frame = mem::replace(&mut vm.current_frame, Some(vm.ctx.new_frame(self.clone())));
100+
97101
// This is the name of the object being run:
98102
let run_obj_name = &self.code.obj_name.to_string();
99103

@@ -142,6 +146,7 @@ impl Frame {
142146
}
143147
};
144148

149+
vm.current_frame = prev_frame;
145150
value
146151
}
147152

vm/src/obj/objframe.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
33
*/
44

5+
use super::super::frame::Frame;
56
use super::super::pyobject::{
6-
AttributeProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol,
7+
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
78
};
89
use super::super::vm::VirtualMachine;
910
use super::objtype;
@@ -12,6 +13,7 @@ pub fn init(context: &PyContext) {
1213
let ref frame_type = context.frame_type;
1314
frame_type.set_attr("__new__", context.new_rustfunc(frame_new));
1415
frame_type.set_attr("__repr__", context.new_rustfunc(frame_repr));
16+
frame_type.set_attr("f_locals", context.new_property(frame_locals));
1517
}
1618

1719
fn frame_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -24,3 +26,24 @@ fn frame_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
2426
let repr = format!("<frame object at .. >");
2527
Ok(vm.new_str(repr))
2628
}
29+
30+
fn frame_locals(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
31+
arg_check!(vm, args, required = [(frame, Some(vm.ctx.frame_type()))]);
32+
let frame = get_value(frame);
33+
let py_scope = frame.locals.clone();
34+
let py_scope = py_scope.borrow();
35+
36+
if let PyObjectKind::Scope { scope } = &py_scope.kind {
37+
Ok(scope.locals.clone())
38+
} else {
39+
panic!("The scope isn't a scope!");
40+
}
41+
}
42+
43+
pub fn get_value(obj: &PyObjectRef) -> Frame {
44+
if let PyObjectKind::Frame { frame } = &obj.borrow().kind {
45+
frame.clone()
46+
} else {
47+
panic!("Inner error getting int {:?}", obj);
48+
}
49+
}

vm/src/pyobject.rs

+21
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,22 @@ impl PyContext {
459459
)
460460
}
461461

462+
pub fn new_frame(&self, frame: Frame) -> PyObjectRef {
463+
PyObject::new(PyObjectKind::Frame { frame: frame }, self.frame_type())
464+
}
465+
466+
pub fn new_property(&self, function: RustPyFunc) -> PyObjectRef {
467+
let fget = self.new_rustfunc(function);
468+
let py_obj = PyObject::new(
469+
PyObjectKind::Instance {
470+
dict: self.new_dict(),
471+
},
472+
self.property_type(),
473+
);
474+
py_obj.set_attr("fget", fget.clone());
475+
py_obj
476+
}
477+
462478
pub fn new_function(
463479
&self,
464480
code_obj: PyObjectRef,
@@ -782,6 +798,9 @@ pub enum PyObjectKind {
782798
Code {
783799
code: bytecode::CodeObject,
784800
},
801+
Frame {
802+
frame: Frame,
803+
},
785804
Function {
786805
code: PyObjectRef,
787806
scope: PyObjectRef,
@@ -856,6 +875,7 @@ impl fmt::Debug for PyObjectKind {
856875
} => write!(f, "class {:?}", name),
857876
&PyObjectKind::Instance { dict: _ } => write!(f, "instance"),
858877
&PyObjectKind::RustFunction { function: _ } => write!(f, "rust function"),
878+
&PyObjectKind::Frame { .. } => write!(f, "frame"),
859879
}
860880
}
861881
}
@@ -913,6 +933,7 @@ impl PyObject {
913933
PyObjectKind::Code { code: _ } => format!("<code>"),
914934
PyObjectKind::Function { .. } => format!("<func>"),
915935
PyObjectKind::Generator { .. } => format!("<generator>"),
936+
PyObjectKind::Frame { .. } => format!("<frame>"),
916937
PyObjectKind::BoundMethod { .. } => format!("<bound-method>"),
917938
PyObjectKind::RustFunction { function: _ } => format!("<rustfunc>"),
918939
PyObjectKind::Module { ref name, dict: _ } => format!("<module '{}'>", name),

vm/src/sysmodule.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use super::pyobject::{DictProtocol, PyContext, PyObjectRef};
1+
use super::pyobject::{DictProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult};
2+
use super::vm::VirtualMachine;
23
use std::env;
34

45
/*
@@ -11,6 +12,14 @@ fn argv(ctx: &PyContext) -> PyObjectRef {
1112
ctx.new_list(argv)
1213
}
1314

15+
fn getframe(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
16+
if let Some(frame) = &vm.current_frame {
17+
Ok(frame.clone())
18+
} else {
19+
panic!("Current frame is undefined!")
20+
}
21+
}
22+
1423
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
1524
let path_list = match env::var_os("PYTHONPATH") {
1625
Some(paths) => env::split_paths(&paths)
@@ -23,8 +32,9 @@ pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
2332
let sys_name = "sys".to_string();
2433
let sys_mod = ctx.new_module(&sys_name, ctx.new_scope(None));
2534
modules.set_item(&sys_name, sys_mod.clone());
26-
sys_mod.set_item(&"modules".to_string(), modules);
27-
sys_mod.set_item(&"argv".to_string(), argv(ctx));
28-
sys_mod.set_item(&"path".to_string(), path);
35+
sys_mod.set_item("modules", modules);
36+
sys_mod.set_item("argv", argv(ctx));
37+
sys_mod.set_item("path", path);
38+
sys_mod.set_item("_getframe", ctx.new_rustfunc(getframe));
2939
sys_mod
3040
}

0 commit comments

Comments
 (0)