Skip to content

Commit a796b13

Browse files
committed
Allow injecting JS variables into python with eval_py()
eval_py(`return js_vars["a"]`, { a: 9 }) == 9
1 parent e78a251 commit a796b13

1 file changed

Lines changed: 55 additions & 6 deletions

File tree

wasm/src/lib.rs

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ extern crate rustpython_vm;
55
extern crate wasm_bindgen;
66
extern crate web_sys;
77

8+
use js_sys::Reflect;
89
use rustpython_vm::compile;
910
use rustpython_vm::pyobject::{self, PyObjectRef, PyResult};
1011
use 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

Comments
 (0)