1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
pub mod browser_module;
pub mod convert;
pub mod js_module;
pub mod vm_class;
pub mod wasm_builtins;
extern crate futures;
extern crate js_sys;
#[macro_use]
extern crate rustpython_vm;
extern crate rustpython_compiler;
extern crate wasm_bindgen;
extern crate wasm_bindgen_futures;
extern crate web_sys;
use js_sys::{Object, Reflect, TypeError};
use rustpython_compiler::compile::Mode;
use std::panic;
use wasm_bindgen::prelude::*;
pub use crate::convert::PyError;
pub use crate::vm_class::*;
const PY_EVAL_VM_ID: &str = "__py_eval_vm";
fn panic_hook(info: &panic::PanicInfo) {
use js_sys::WebAssembly::RuntimeError;
let window = match web_sys::window() {
Some(win) => win,
None => return,
};
let msg = &info.to_string();
let _ = Reflect::set(&window, &"__RUSTPYTHON_ERROR_MSG".into(), &msg.into());
let error = RuntimeError::new(&msg);
let _ = Reflect::set(&window, &"__RUSTPYTHON_ERROR".into(), &error);
let stack = match Reflect::get(&error, &"stack".into()) {
Ok(stack) => stack,
Err(_) => return,
};
let _ = Reflect::set(&window, &"__RUSTPYTHON_ERROR_STACK".into(), &stack);
}
#[wasm_bindgen(start)]
pub fn setup_console_error() {
std::panic::set_hook(Box::new(panic_hook));
}
fn run_py(source: &str, options: Option<Object>, mode: Mode) -> Result<JsValue, JsValue> {
let vm = VMStore::init(PY_EVAL_VM_ID.into(), Some(true));
let options = options.unwrap_or_else(Object::new);
let js_vars = {
let prop = Reflect::get(&options, &"vars".into())?;
if prop.is_undefined() {
None
} else if prop.is_object() {
Some(Object::from(prop))
} else {
return Err(TypeError::new("vars must be an object").into());
}
};
vm.set_stdout(Reflect::get(&options, &"stdout".into())?)?;
if let Some(js_vars) = js_vars {
vm.add_to_scope("js_vars".into(), js_vars.into())?;
}
vm.run(source, mode, None)
}
#[wasm_bindgen(js_name = pyEval)]
pub fn eval_py(source: &str, options: Option<Object>) -> Result<JsValue, JsValue> {
run_py(source, options, Mode::Eval)
}
#[wasm_bindgen(js_name = pyExec)]
pub fn exec_py(source: &str, options: Option<Object>) -> Result<(), JsValue> {
run_py(source, options, Mode::Exec).map(drop)
}
#[wasm_bindgen(js_name = pyExecSingle)]
pub fn exec_single_py(source: &str, options: Option<Object>) -> Result<JsValue, JsValue> {
run_py(source, options, Mode::Single)
}