diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 6494bb9777..e91f434a54 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -31,7 +31,7 @@ use super::sysmodule; /// Top level container of a python virtual machine. In theory you could /// create more instances of this struct and have them operate fully isolated. pub struct VirtualMachine { - builtins: PyObjectRef, + pub builtins: PyObjectRef, pub sys_module: PyObjectRef, pub stdlib_inits: HashMap, pub ctx: PyContext, diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 112d62a724..c311ce6e65 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -15,6 +15,10 @@ rustpython_vm = {path = "../vm"} cfg-if = "0.1.2" wasm-bindgen = "0.2" +[dependencies.web-sys] +version = "0.3" +features = [ "console" ] + [profile.release] opt-level = "s" diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 6c5d39209e..5827d89df6 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -1,28 +1,34 @@ +mod wasm_builtins; + extern crate rustpython_vm; extern crate wasm_bindgen; -use rustpython_vm::compile; +extern crate web_sys; + use rustpython_vm::VirtualMachine; +use rustpython_vm::compile; +use rustpython_vm::pyobject::AttributeProtocol; use wasm_bindgen::prelude::*; - -#[wasm_bindgen] -extern "C" { - // Use `js_namespace` here to bind `console.log(..)` instead of just - // `log(..)` - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); -} +use web_sys::console; #[wasm_bindgen] pub fn run_code(source: &str) -> () { //add hash in here - log("Running RustPython"); - log(&source.to_string()); + console::log_1(&"Running RustPython".into()); + console::log_1(&"Running code:".into()); + console::log_1(&source.to_string().into()); + console::log_1(&"----- console -----".into()); + let mut vm = VirtualMachine::new(); + // We are monkey-patching the builtin print to use console.log + // TODO: moneky-patch sys.stdout instead, after print actually uses sys.stdout + vm.builtins.set_attr("print", vm.context().new_rustfunc(wasm_builtins::builtin_print)); + let code_obj = compile::compile(&mut vm, &source.to_string(), compile::Mode::Exec, None); + let builtins = vm.get_builtin_scope(); let vars = vm.context().new_scope(Some(builtins)); match vm.run_code_obj(code_obj.unwrap(), vars) { - Ok(_value) => log("Execution successful"), - Err(_) => log("Execution failed"), + Ok(_value) => console::log_1(&"Execution successful".into()), + Err(_) => console::log_1(&"Execution failed".into()), } } diff --git a/wasm/src/wasm_builtins.rs b/wasm/src/wasm_builtins.rs new file mode 100644 index 0000000000..6247c6518c --- /dev/null +++ b/wasm/src/wasm_builtins.rs @@ -0,0 +1,28 @@ +//! Builtin function specific to WASM build. +//! +//! This is required because some feature like I/O works differently in the browser comparing to +//! desktop. +//! Implements functions listed here: https://docs.python.org/3/library/builtins.html +//! +extern crate wasm_bindgen; +extern crate web_sys; + +use rustpython_vm::obj::objstr; +use rustpython_vm::VirtualMachine; +use rustpython_vm::pyobject::{ PyFuncArgs, PyResult }; +use web_sys::console; + +pub fn builtin_print(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + let mut first = true; + for a in args.args { + if first { + first = false; + } else { + console::log_1(&" ".into()) + } + let v = vm.to_str(&a)?; + let s = objstr::get_value(&v); + console::log_1(&format!("{}", s).into()) + } + Ok(vm.get_none()) +}