@@ -5,6 +5,7 @@ extern crate rustpython_vm;
55extern crate wasm_bindgen;
66extern crate web_sys;
77
8+ use js_sys:: Reflect ;
89use rustpython_vm:: compile;
910use rustpython_vm:: pyobject:: { self , PyObjectRef , PyResult } ;
1011use rustpython_vm:: VirtualMachine ;
@@ -33,7 +34,31 @@ fn py_to_js(vm: &mut VirtualMachine, py_obj: PyObjectRef) -> JsValue {
3334 }
3435}
3536
36- fn eval ( vm : & mut VirtualMachine , source : & str ) -> PyResult {
37+ fn js_to_py ( vm : & mut VirtualMachine , js_val : JsValue ) -> PyObjectRef {
38+ let json = match js_sys:: JSON :: stringify ( & js_val) {
39+ Ok ( json) => String :: from ( json) ,
40+ Err ( _) => return vm. get_none ( ) ,
41+ } ;
42+
43+ let loads = rustpython_vm:: import:: import (
44+ vm,
45+ std:: path:: PathBuf :: default ( ) ,
46+ "json" ,
47+ & Some ( "loads" . into ( ) ) ,
48+ )
49+ . expect ( "Couldn't get json.loads function" ) ;
50+
51+ let py_json = vm. new_str ( json) ;
52+
53+ vm. invoke ( loads, pyobject:: PyFuncArgs :: new ( vec ! [ py_json] , vec ! [ ] ) )
54+ // can safely unwrap because we know it's valid JSON
55+ . unwrap ( )
56+ }
57+
58+ fn eval < F > ( vm : & mut VirtualMachine , source : & str , setup_scope : F ) -> PyResult
59+ where
60+ F : Fn ( & mut VirtualMachine , & PyObjectRef ) ,
61+ {
3762 // HACK: if the code doesn't end with newline it crashes.
3863 let mut source = source. to_string ( ) ;
3964 if !source. ends_with ( '\n' ) {
@@ -43,13 +68,15 @@ fn eval(vm: &mut VirtualMachine, source: &str) -> PyResult {
4368 let code_obj = compile:: compile ( vm, & source, compile:: Mode :: Exec , None ) ?;
4469
4570 let builtins = vm. get_builtin_scope ( ) ;
46- let vars = vm. context ( ) . new_scope ( Some ( builtins) ) ;
71+ let mut vars = vm. context ( ) . new_scope ( Some ( builtins) ) ;
72+
73+ setup_scope ( vm, & mut vars) ;
4774
4875 vm. run_code_obj ( code_obj, vars)
4976}
5077
5178#[ wasm_bindgen]
52- pub fn eval_py ( source : & str ) -> Result < JsValue , JsValue > {
79+ pub fn eval_py ( source : & str , js_injections : Option < js_sys :: Object > ) -> Result < JsValue , JsValue > {
5380 let mut vm = VirtualMachine :: new ( ) ;
5481
5582 vm. ctx . set_attr (
@@ -59,8 +86,30 @@ pub fn eval_py(source: &str) -> Result<JsValue, JsValue> {
5986 . new_rustfunc ( wasm_builtins:: builtin_print_console) ,
6087 ) ;
6188
62- eval ( & mut vm, source)
63- . map ( |value| py_to_js ( & mut vm, value) )
89+ let res = eval ( & mut vm, source, |vm, vars| {
90+ let injections = vm. new_dict ( ) ;
91+
92+ if let Some ( js_injections) = js_injections. clone ( ) {
93+ for pair in js_sys:: try_iter ( & js_sys:: Object :: entries ( & js_injections) )
94+ . unwrap ( )
95+ . unwrap ( )
96+ {
97+ let pair = pair. unwrap ( ) ;
98+ let key = Reflect :: get ( & pair, & "0" . into ( ) ) . unwrap ( ) ;
99+ let val = Reflect :: get ( & pair, & "1" . into ( ) ) . unwrap ( ) ;
100+ let py_val = js_to_py ( vm, val) ;
101+ vm. ctx . set_item (
102+ & injections,
103+ & String :: from ( js_sys:: JsString :: from ( key) ) ,
104+ py_val,
105+ ) ;
106+ }
107+ }
108+
109+ vm. ctx . set_item ( vars, "js_vars" , injections) ;
110+ } ) ;
111+
112+ res. map ( |value| py_to_js ( & mut vm, value) )
64113 . map_err ( |err| py_str_err ( & mut vm, & err) . into ( ) )
65114}
66115
@@ -81,7 +130,7 @@ pub fn run_from_textbox(source: &str) -> Result<JsValue, JsValue> {
81130 vm. context ( ) . new_rustfunc ( wasm_builtins:: builtin_print_html) ,
82131 ) ;
83132
84- match eval ( & mut vm, source) {
133+ match eval ( & mut vm, source, |_ , _| { } ) {
85134 Ok ( value) => {
86135 console:: log_1 ( & "Execution successful" . into ( ) ) ;
87136 match value. borrow ( ) . kind {
0 commit comments