From 72d53fe80760bc827d39ced3d650c144a21bb47d Mon Sep 17 00:00:00 2001 From: rmliddle Date: Sun, 28 Oct 2018 13:23:00 +1100 Subject: [PATCH 1/4] move to wasm-bindgen + supporting application --- wasm/Cargo.toml | 10 ++++++++-- wasm/app/bootstrap.js | 5 +++++ wasm/app/index.html | 10 ++++++++++ wasm/app/index.js | 3 +++ wasm/app/package.json | 27 +++++++++++++++++++++++++++ wasm/app/webpack.config.js | 14 ++++++++++++++ wasm/src/lib.rs | 28 ++++++++++++++++++++++++++++ 7 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 wasm/app/bootstrap.js create mode 100644 wasm/app/index.html create mode 100644 wasm/app/index.js create mode 100644 wasm/app/package.json create mode 100644 wasm/app/webpack.config.js create mode 100644 wasm/src/lib.rs diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 9bb6be29f..11b60624f 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "rustpython_wasm" version = "0.1.0" -authors = ["rmliddle "] +authors = ["Ryan Liddle "] + +[lib] +crate-type = ["cdylib", "rlib"] [workspace] members = [] @@ -9,6 +12,9 @@ members = [] [dependencies] rustpython_parser = {path = "../parser"} rustpython_vm = {path = "../vm"} +cfg-if = "0.1.2" +wasm-bindgen = "0.2" + [profile.release] -opt-level = 's' \ No newline at end of file +opt-level = "s" \ No newline at end of file diff --git a/wasm/app/bootstrap.js b/wasm/app/bootstrap.js new file mode 100644 index 000000000..726fd1b62 --- /dev/null +++ b/wasm/app/bootstrap.js @@ -0,0 +1,5 @@ +// A dependency graph that contains any wasm must all be imported +// asynchronously. This `bootstrap.js` file does the single async import, so +// that no one else needs to worry about it again. +import("./index.js") + .catch(e => console.error("Error importing `index.js`:", e)); \ No newline at end of file diff --git a/wasm/app/index.html b/wasm/app/index.html new file mode 100644 index 000000000..069a09a70 --- /dev/null +++ b/wasm/app/index.html @@ -0,0 +1,10 @@ + + + + + Hello wasm-pack! + + + + + \ No newline at end of file diff --git a/wasm/app/index.js b/wasm/app/index.js new file mode 100644 index 000000000..10797d688 --- /dev/null +++ b/wasm/app/index.js @@ -0,0 +1,3 @@ +import * as rp from "rustpython_wasm"; + +rp.run_code("print('Hello Python!')\n"); diff --git a/wasm/app/package.json b/wasm/app/package.json new file mode 100644 index 000000000..a1f9c4191 --- /dev/null +++ b/wasm/app/package.json @@ -0,0 +1,27 @@ +{ + "name": "app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "dependencies": { + "hello-wasm-pack": "^0.1.0", + "webpack": "^4.16.3", + "webpack-cli": "^3.1.0", + "webpack-dev-server": "^3.1.5", + "copy-webpack-plugin": "^4.5.2" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/RustPython/RustPython.git" + }, + "author": "Ryan Liddle", + "license": "MIT", + "bugs": { + "url": "https://github.com/RustPython/RustPython/issues" + }, + "homepage": "https://github.com/RustPython/RustPython#readme" +} diff --git a/wasm/app/webpack.config.js b/wasm/app/webpack.config.js new file mode 100644 index 000000000..531def733 --- /dev/null +++ b/wasm/app/webpack.config.js @@ -0,0 +1,14 @@ +const CopyWebpackPlugin = require("copy-webpack-plugin"); +const path = require('path'); + +module.exports = { + entry: "./bootstrap.js", + output: { + path: path.resolve(__dirname, "dist"), + filename: "bootstrap.js", + }, + mode: "development", + plugins: [ + new CopyWebpackPlugin(['index.html']) + ], +}; \ No newline at end of file diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs new file mode 100644 index 000000000..d7916baef --- /dev/null +++ b/wasm/src/lib.rs @@ -0,0 +1,28 @@ +extern crate rustpython_vm; +extern crate wasm_bindgen; +use wasm_bindgen::prelude::*; +use rustpython_vm::VirtualMachine; +use rustpython_vm::compile; + +#[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); +} + +#[wasm_bindgen] +pub fn run_code(source: &str) -> () { + //add hash in here + log("Running RustPython"); + log(&source.to_string()); + let mut vm = VirtualMachine::new(); + 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") + } +} \ No newline at end of file From 958ee94bdc1313fe15bf6e004c4154f756572bd9 Mon Sep 17 00:00:00 2001 From: rmliddle Date: Sun, 28 Oct 2018 13:25:36 +1100 Subject: [PATCH 2/4] HTML update --- wasm/app/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wasm/app/index.html b/wasm/app/index.html index 069a09a70..786497a22 100644 --- a/wasm/app/index.html +++ b/wasm/app/index.html @@ -2,7 +2,7 @@ - Hello wasm-pack! + RustPython Starter Application From 27b5796b92b2ed579e58e3f53aa641821a3f59b4 Mon Sep 17 00:00:00 2001 From: rmliddle Date: Sun, 28 Oct 2018 13:30:18 +1100 Subject: [PATCH 3/4] formatting fixes --- wasm/Cargo.toml | 2 +- wasm/app/bootstrap.js | 2 +- wasm/app/index.html | 2 +- wasm/app/webpack.config.js | 2 +- wasm/index.html | 14 -------------- wasm/src/lib.rs | 8 ++++---- 6 files changed, 8 insertions(+), 22 deletions(-) delete mode 100644 wasm/index.html diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 11b60624f..112d62a72 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -17,4 +17,4 @@ wasm-bindgen = "0.2" [profile.release] -opt-level = "s" \ No newline at end of file +opt-level = "s" diff --git a/wasm/app/bootstrap.js b/wasm/app/bootstrap.js index 726fd1b62..7934d627e 100644 --- a/wasm/app/bootstrap.js +++ b/wasm/app/bootstrap.js @@ -2,4 +2,4 @@ // asynchronously. This `bootstrap.js` file does the single async import, so // that no one else needs to worry about it again. import("./index.js") - .catch(e => console.error("Error importing `index.js`:", e)); \ No newline at end of file + .catch(e => console.error("Error importing `index.js`:", e)); diff --git a/wasm/app/index.html b/wasm/app/index.html index 786497a22..00f0d2407 100644 --- a/wasm/app/index.html +++ b/wasm/app/index.html @@ -7,4 +7,4 @@ - \ No newline at end of file + diff --git a/wasm/app/webpack.config.js b/wasm/app/webpack.config.js index 531def733..80ad8142d 100644 --- a/wasm/app/webpack.config.js +++ b/wasm/app/webpack.config.js @@ -11,4 +11,4 @@ module.exports = { plugins: [ new CopyWebpackPlugin(['index.html']) ], -}; \ No newline at end of file +}; diff --git a/wasm/index.html b/wasm/index.html deleted file mode 100644 index 13313d61b..000000000 --- a/wasm/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - RustPython/Wasm - - - - - \ No newline at end of file diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index d7916baef..6c5d39209 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -1,8 +1,8 @@ extern crate rustpython_vm; extern crate wasm_bindgen; -use wasm_bindgen::prelude::*; -use rustpython_vm::VirtualMachine; use rustpython_vm::compile; +use rustpython_vm::VirtualMachine; +use wasm_bindgen::prelude::*; #[wasm_bindgen] extern "C" { @@ -23,6 +23,6 @@ pub fn run_code(source: &str) -> () { 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") + Err(_) => log("Execution failed"), } -} \ No newline at end of file +} From ad0f8dd674d1cc6d80612aa2381cc035c7e8dd05 Mon Sep 17 00:00:00 2001 From: rmliddle Date: Fri, 2 Nov 2018 18:17:06 +1100 Subject: [PATCH 4/4] Readme changes for compliation with wasm-pack --- README.md | 60 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 3517adf77..1e5654d66 100644 --- a/README.md +++ b/README.md @@ -66,9 +66,14 @@ $ cargo test --all # Compiling to WebAssembly +At this stage RustPython only has preliminary support for web assembly. The instructions here are intended for developers or those wishing to run a toy example. + ## Setup -Using `rustup` add the compile target `wasm32-unknown-emscripten`. To do so you will need to have [rustup](https://rustup.rs/) installed. +To get started, install [wasm-bingden](https://rustwasm.github.io/wasm-bindgen/whirlwind-tour/basic-usage.html) +and [wasm-webpack](https://rustwasm.github.io/wasm-pack/installer/). You will also need to have `npm` installed. + + + + ## Build -Move into the `wasm` directory. This contains a custom binary crate optimized for a web assembly build. +Move into the `wasm` directory. This contains a custom library crate optimized for wasm build of RustPython. ```bash cd wasm ``` From here run the build. This can take several minutes depending on the machine. -``` -cargo build --target=wasm32-unknown-emscripten --release -``` - -Upon successful build, the following files will be available: - ``` -target/wasm32-unknown-emscripten/release/rustpython_wasm.wasm -target/wasm32-unknown-emscripten/release/rustpython_wasm.js +wasm-pack build ``` -- `rustpython_wasm.wasm`: the wasm build for rustpython. It includes both an parser and virtual machine. -- `rustpython_wasm.js`: the loading scripts for the above wasm file. - -You will also find `index.html` in the `wasm` directory. -From here, you can copy these 3 files into the static assets directory of your web server and you should be -able to see the ouput in the web console of your browser. +Upon successful build, cd in the the `/pkg` directory and run: ``` -Hello RustPython! +npm link ``` +Now move back out into the `/app` directory. The files here have been adapted from [wasm-pack-template](https://github.com/rustwasm/wasm-pack-template). + +Finally, run: + +``` +npm install +``` + +and you will be able to run the files with: + +``` +webpack-dev-server +``` + +Open a browser console and see the output of rustpython_wasm. To verify this, modify the line in `app/index.js` + +```js +rp.run_code("print('Hello Python!')\n"); +``` + +To the following: + +```js +rp.run_code("assert(False)\n"); +``` + +and you should observe: `Execution failed` in your console output, indicating that the execution of RustPython has failed. + # Code style The code style used is the default rustfmt codestyle. Please format your code accordingly.