Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit38c43e0

Browse files
Merge pull requestRustPython#590 from RustPython/exec
Proper construction of scope for exec/eval.
2 parents839f906 +c4953ee commit38c43e0

File tree

4 files changed

+97
-26
lines changed

4 files changed

+97
-26
lines changed

‎tests/snippets/test_exec.py‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
exec("def square(x):\n return x * x\n")
2+
assert16==square(4)
3+
4+
d= {}
5+
exec("def square(x):\n return x * x\n", {},d)
6+
assert16==d['square'](4)
7+
8+
exec("assert 2 == x", {}, {'x':2})
9+
exec("assert 2 == x", {'x':2}, {})
10+
exec("assert 4 == x", {'x':2}, {'x':4})
11+
12+
exec("assert max(1, 2) == 2", {}, {})
13+
14+
exec("assert max(1, 5, square(5)) == 25",None)
15+
16+
#
17+
# These doesn't work yet:
18+
#
19+
# Local environment shouldn't replace global environment:
20+
#
21+
# exec("assert max(1, 5, square(5)) == 25", None, {})
22+
#
23+
# Closures aren't available if local scope is replaced:
24+
#
25+
# def g():
26+
# seven = "seven"
27+
# def f():
28+
# try:
29+
# exec("seven", None, {})
30+
# except NameError:
31+
# pass
32+
# else:
33+
# raise NameError("seven shouldn't be in scope")
34+
# f()
35+
# g()
36+
37+
try:
38+
exec("",1)
39+
exceptTypeError:
40+
pass
41+
else:
42+
raiseTypeError("exec should fail unless globals is a dict or None")

‎vm/src/builtins.rs‎

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use crate::frame::{Scope, ScopeRef};
1818
usecrate::pyobject::{
1919
AttributeProtocol,IdProtocol,PyContext,PyFuncArgs,PyObjectRef,PyResult,TypeProtocol,
2020
};
21-
use std::rc::Rc;
2221

2322
#[cfg(not(target_arch ="wasm32"))]
2423
usecrate::stdlib::io::io_open;
@@ -191,12 +190,11 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
191190
vm,
192191
args,
193192
required =[(source,None)],
194-
optional =[
195-
(_globals,Some(vm.ctx.dict_type())),
196-
(locals,Some(vm.ctx.dict_type()))
197-
]
193+
optional =[(globals,None),(locals,Some(vm.ctx.dict_type()))]
198194
);
199195

196+
let scope =make_scope(vm, globals, locals)?;
197+
200198
// Determine code object:
201199
let code_obj =if objtype::isinstance(source,&vm.ctx.code_type()){
202200
source.clone()
@@ -215,8 +213,6 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
215213
returnErr(vm.new_type_error("code argument must be str or code object".to_string()));
216214
};
217215

218-
let scope =make_scope(vm, locals);
219-
220216
// Run the source:
221217
vm.run_code_obj(code_obj.clone(), scope)
222218
}
@@ -228,12 +224,11 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
228224
vm,
229225
args,
230226
required =[(source,None)],
231-
optional =[
232-
(_globals,Some(vm.ctx.dict_type())),
233-
(locals,Some(vm.ctx.dict_type()))
234-
]
227+
optional =[(globals,None),(locals,Some(vm.ctx.dict_type()))]
235228
);
236229

230+
let scope =make_scope(vm, globals, locals)?;
231+
237232
// Determine code object:
238233
let code_obj =if objtype::isinstance(source,&vm.ctx.str_type()){
239234
let mode = compile::Mode::Exec;
@@ -252,26 +247,48 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
252247
returnErr(vm.new_type_error("source argument must be str or code object".to_string()));
253248
};
254249

255-
let scope =make_scope(vm, locals);
256-
257250
// Run the code:
258251
vm.run_code_obj(code_obj, scope)
259252
}
260253

261-
fnmake_scope(vm:&mutVirtualMachine,locals:Option<&PyObjectRef>) ->ScopeRef{
262-
// handle optional global and locals
263-
let locals =ifletSome(locals) = locals{
264-
locals.clone()
265-
}else{
266-
vm.new_dict()
254+
fnmake_scope(
255+
vm:&mutVirtualMachine,
256+
globals:Option<&PyObjectRef>,
257+
locals:Option<&PyObjectRef>,
258+
) ->PyResult<ScopeRef>{
259+
let dict_type = vm.ctx.dict_type();
260+
let globals =match globals{
261+
Some(arg) =>{
262+
if arg.is(&vm.get_none()){
263+
None
264+
}else{
265+
if vm.isinstance(arg,&dict_type)?{
266+
Some(arg)
267+
}else{
268+
let arg_typ = arg.typ();
269+
let actual_type = vm.to_pystr(&arg_typ)?;
270+
let expected_type_name = vm.to_pystr(&dict_type)?;
271+
returnErr(vm.new_type_error(format!(
272+
"globals must be a {}, not {}",
273+
expected_type_name, actual_type
274+
)));
275+
}
276+
}
277+
}
278+
None =>None,
267279
};
268280

269-
// TODO: handle optional globals
270-
// Construct new scope:
271-
Rc::new(Scope{
272-
locals,
273-
parent:None,
274-
})
281+
let current_scope = vm.current_scope();
282+
let parent =match globals{
283+
Some(dict) =>Some(Scope::new(dict.clone(),Some(vm.get_builtin_scope()))),
284+
None => current_scope.parent.clone(),
285+
};
286+
let locals =match locals{
287+
Some(dict) => dict.clone(),
288+
None => current_scope.locals.clone(),
289+
};
290+
291+
Ok(Scope::new(locals, parent))
275292
}
276293

277294
fnbuiltin_format(vm:&mutVirtualMachine,args:PyFuncArgs) ->PyResult{

‎vm/src/frame.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ pub struct Scope {
3535
}
3636
pubtypeScopeRef =Rc<Scope>;
3737

38+
implScope{
39+
pubfnnew(locals:PyObjectRef,parent:Option<ScopeRef>) ->ScopeRef{
40+
Rc::new(Scope{ locals, parent})
41+
}
42+
}
43+
3844
#[derive(Clone,Debug)]
3945
structBlock{
4046
/// The type of block.

‎vm/src/vm.rs‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ impl VirtualMachine {
9090
result
9191
}
9292

93+
pubfncurrent_scope(&self) ->&ScopeRef{
94+
let current_frame =&self.frames[self.frames.len() -1];
95+
let frame = objframe::get_value(current_frame);
96+
&frame.scope
97+
}
98+
9399
/// Create a new python string object.
94100
pubfnnew_str(&self,s:String) ->PyObjectRef{
95101
self.ctx.new_str(s)
@@ -218,7 +224,7 @@ impl VirtualMachine {
218224
&self.ctx
219225
}
220226

221-
pubfnget_builtin_scope(&mutself) ->ScopeRef{
227+
pubfnget_builtin_scope(&self) ->ScopeRef{
222228
let a2 =&*self.builtins;
223229
match a2.payload{
224230
PyObjectPayload::Module{ref scope, ..} => scope.clone(),

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp