rustpython_vm/scope.rs
1use crate::{builtins::PyDictRef, function::ArgMapping, VirtualMachine};
2use std::fmt;
3
4#[derive(Clone)]
5pub struct Scope {
6 pub locals: ArgMapping,
7 pub globals: PyDictRef,
8}
9
10impl fmt::Debug for Scope {
11 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
12 // TODO: have a more informative Debug impl that DOESN'T recurse and cause a stack overflow
13 f.write_str("Scope")
14 }
15}
16
17impl Scope {
18 #[inline]
19 pub fn new(locals: Option<ArgMapping>, globals: PyDictRef) -> Scope {
20 let locals = locals.unwrap_or_else(|| ArgMapping::from_dict_exact(globals.clone()));
21 Scope { locals, globals }
22 }
23
24 pub fn with_builtins(
25 locals: Option<ArgMapping>,
26 globals: PyDictRef,
27 vm: &VirtualMachine,
28 ) -> Scope {
29 if !globals.contains_key("__builtins__", vm) {
30 globals
31 .set_item("__builtins__", vm.builtins.clone().into(), vm)
32 .unwrap();
33 }
34 Scope::new(locals, globals)
35 }
36
37 // pub fn get_locals(&self) -> &PyDictRef {
38 // match self.locals.first() {
39 // Some(dict) => dict,
40 // None => &self.globals,
41 // }
42 // }
43
44 // pub fn get_only_locals(&self) -> Option<PyDictRef> {
45 // self.locals.first().cloned()
46 // }
47
48 // pub fn new_child_scope_with_locals(&self, locals: PyDictRef) -> Scope {
49 // let mut new_locals = Vec::with_capacity(self.locals.len() + 1);
50 // new_locals.push(locals);
51 // new_locals.extend_from_slice(&self.locals);
52 // Scope {
53 // locals: new_locals,
54 // globals: self.globals.clone(),
55 // }
56 // }
57
58 // pub fn new_child_scope(&self, ctx: &Context) -> Scope {
59 // self.new_child_scope_with_locals(ctx.new_dict())
60 // }
61
62 // #[cfg_attr(feature = "flame-it", flame("Scope"))]
63 // pub fn load_name(&self, vm: &VirtualMachine, name: impl PyName) -> Option<PyObjectRef> {
64 // for dict in self.locals.iter() {
65 // if let Some(value) = dict.get_item_option(name.clone(), vm).unwrap() {
66 // return Some(value);
67 // }
68 // }
69
70 // // Fall back to loading a global after all scopes have been searched!
71 // self.load_global(vm, name)
72 // }
73
74 // #[cfg_attr(feature = "flame-it", flame("Scope"))]
75 // /// Load a local name. Only check the local dictionary for the given name.
76 // pub fn load_local(&self, vm: &VirtualMachine, name: impl PyName) -> Option<PyObjectRef> {
77 // self.get_locals().get_item_option(name, vm).unwrap()
78 // }
79
80 // #[cfg_attr(feature = "flame-it", flame("Scope"))]
81 // pub fn load_cell(&self, vm: &VirtualMachine, name: impl PyName) -> Option<PyObjectRef> {
82 // for dict in self.locals.iter().skip(1) {
83 // if let Some(value) = dict.get_item_option(name.clone(), vm).unwrap() {
84 // return Some(value);
85 // }
86 // }
87 // None
88 // }
89
90 // pub fn store_cell(&self, vm: &VirtualMachine, name: impl PyName, value: PyObjectRef) {
91 // // find the innermost outer scope that contains the symbol name
92 // if let Some(locals) = self
93 // .locals
94 // .iter()
95 // .rev()
96 // .find(|l| l.contains_key(name.clone(), vm))
97 // {
98 // // add to the symbol
99 // locals.set_item(name, value, vm).unwrap();
100 // } else {
101 // // somewhat limited solution -> fallback to the old rustpython strategy
102 // // and store the next outer scope
103 // // This case is usually considered as a failure case, but kept for the moment
104 // // to support the scope propagation for named expression assignments to so far
105 // // unknown names in comprehensions. We need to consider here more context
106 // // information for correct handling.
107 // self.locals
108 // .get(1)
109 // .expect("no outer scope for non-local")
110 // .set_item(name, value, vm)
111 // .unwrap();
112 // }
113 // }
114
115 // pub fn store_name(&self, vm: &VirtualMachine, key: impl PyName, value: PyObjectRef) {
116 // self.get_locals().set_item(key, value, vm).unwrap();
117 // }
118
119 // pub fn delete_name(&self, vm: &VirtualMachine, key: impl PyName) -> PyResult {
120 // self.get_locals().del_item(key, vm)
121 // }
122
123 // #[cfg_attr(feature = "flame-it", flame("Scope"))]
124 // /// Load a global name.
125 // pub fn load_global(&self, vm: &VirtualMachine, name: impl PyName) -> Option<PyObjectRef> {
126 // if let Some(value) = self.globals.get_item_option(name.clone(), vm).unwrap() {
127 // Some(value)
128 // } else {
129 // vm.builtins.get_attr(name, vm).ok()
130 // }
131 // }
132
133 // pub fn store_global(&self, vm: &VirtualMachine, name: impl PyName, value: PyObjectRef) {
134 // self.globals.set_item(name, value, vm).unwrap();
135 // }
136}
137
138// mod sealed {
139// pub trait Sealed {}
140// impl Sealed for &str {}
141// impl Sealed for super::PyStrRef {}
142// }
143// pub trait PyName:
144// sealed::Sealed + crate::dictdatatype::DictKey + Clone + ToPyObject
145// {
146// }
147// impl PyName for str {}
148// impl PyName for Py<PyStr> {}