@@ -18,7 +18,6 @@ use crate::frame::{Scope, ScopeRef};
18
18
use crate :: pyobject:: {
19
19
AttributeProtocol , IdProtocol , PyContext , PyFuncArgs , PyObjectRef , PyResult , TypeProtocol ,
20
20
} ;
21
- use std:: rc:: Rc ;
22
21
23
22
#[ cfg( not( target_arch = "wasm32" ) ) ]
24
23
use crate :: stdlib:: io:: io_open;
@@ -191,12 +190,11 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
191
190
vm,
192
191
args,
193
192
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( ) ) ) ]
198
194
) ;
199
195
196
+ let scope = make_scope ( vm, globals, locals) ?;
197
+
200
198
// Determine code object:
201
199
let code_obj = if objtype:: isinstance ( source, & vm. ctx . code_type ( ) ) {
202
200
source. clone ( )
@@ -215,8 +213,6 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
215
213
return Err ( vm. new_type_error ( "code argument must be str or code object" . to_string ( ) ) ) ;
216
214
} ;
217
215
218
- let scope = make_scope ( vm, locals) ;
219
-
220
216
// Run the source:
221
217
vm. run_code_obj ( code_obj. clone ( ) , scope)
222
218
}
@@ -228,12 +224,11 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
228
224
vm,
229
225
args,
230
226
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( ) ) ) ]
235
228
) ;
236
229
230
+ let scope = make_scope ( vm, globals, locals) ?;
231
+
237
232
// Determine code object:
238
233
let code_obj = if objtype:: isinstance ( source, & vm. ctx . str_type ( ) ) {
239
234
let mode = compile:: Mode :: Exec ;
@@ -252,26 +247,48 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
252
247
return Err ( vm. new_type_error ( "source argument must be str or code object" . to_string ( ) ) ) ;
253
248
} ;
254
249
255
- let scope = make_scope ( vm, locals) ;
256
-
257
250
// Run the code:
258
251
vm. run_code_obj ( code_obj, scope)
259
252
}
260
253
261
- fn make_scope ( vm : & mut VirtualMachine , locals : Option < & PyObjectRef > ) -> ScopeRef {
262
- // handle optional global and locals
263
- let locals = if let Some ( locals) = locals {
264
- locals. clone ( )
265
- } else {
266
- vm. new_dict ( )
254
+ fn make_scope (
255
+ vm : & mut VirtualMachine ,
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
+ return Err ( vm. new_type_error ( format ! (
272
+ "globals must be a {}, not {}" ,
273
+ expected_type_name, actual_type
274
+ ) ) ) ;
275
+ }
276
+ }
277
+ }
278
+ None => None ,
267
279
} ;
268
280
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) )
275
292
}
276
293
277
294
fn builtin_format ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
0 commit comments