Skip to content

Commit 58b905f

Browse files
Merge pull request RustPython#182 from rmliddle/wasm-steps
Exposes API for running Python via JS
2 parents 49f8552 + ad0f8dd commit 58b905f

File tree

9 files changed

+131
-30
lines changed

9 files changed

+131
-30
lines changed

README.md

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,14 @@ $ cargo run -- -c 'import statistics'
9898

9999
# Compiling to WebAssembly
100100

101+
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.
102+
101103
## Setup
102104

103-
Using `rustup` add the compile target `wasm32-unknown-emscripten`. To do so you will need to have [rustup](https://rustup.rs/) installed.
105+
To get started, install [wasm-bingden](https://rustwasm.github.io/wasm-bindgen/whirlwind-tour/basic-usage.html)
106+
and [wasm-webpack](https://rustwasm.github.io/wasm-pack/installer/). You will also need to have `npm` installed.
107+
108+
<!-- Using `rustup` add the compile target `wasm32-unknown-emscripten`. To do so you will need to have [rustup](https://rustup.rs/) installed.
104109
105110
```bash
106111
rustup target add wasm32-unknown-emscripten
@@ -114,41 +119,58 @@ cd emsdk-portable/
114119
./emsdk update
115120
./emsdk install sdk-incoming-64bit
116121
./emsdk activate sdk-incoming-64bit
117-
source ./emsdk_env.sh
118-
```
122+
``` -->
123+
124+
119125

120126
## Build
121127

122-
Move into the `wasm` directory. This contains a custom binary crate optimized for a web assembly build.
128+
Move into the `wasm` directory. This contains a custom library crate optimized for wasm build of RustPython.
123129

124130
```bash
125131
cd wasm
126132
```
127133

128134
From here run the build. This can take several minutes depending on the machine.
135+
136+
```
137+
wasm-pack build
138+
```
139+
140+
Upon successful build, cd in the the `/pkg` directory and run:
141+
129142
```
130-
cargo build --target=wasm32-unknown-emscripten --release
143+
npm link
131144
```
132145

133-
Upon successful build, the following files will be available:
146+
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).
134147

148+
Finally, run:
135149

136150
```
137-
target/wasm32-unknown-emscripten/release/rustpython_wasm.wasm
138-
target/wasm32-unknown-emscripten/release/rustpython_wasm.js
151+
npm install
139152
```
140153

141-
- `rustpython_wasm.wasm`: the wasm build for rustpython. It includes both an parser and virtual machine.
142-
- `rustpython_wasm.js`: the loading scripts for the above wasm file.
154+
and you will be able to run the files with:
155+
156+
```
157+
webpack-dev-server
158+
```
143159

144-
You will also find `index.html` in the `wasm` directory.
145-
From here, you can copy these 3 files into the static assets directory of your web server and you should be
146-
able to see the ouput in the web console of your browser.
160+
Open a browser console and see the output of rustpython_wasm. To verify this, modify the line in `app/index.js`
147161

162+
```js
163+
rp.run_code("print('Hello Python!')\n");
148164
```
149-
Hello RustPython!
165+
166+
To the following:
167+
168+
```js
169+
rp.run_code("assert(False)\n");
150170
```
151171

172+
and you should observe: `Execution failed` in your console output, indicating that the execution of RustPython has failed.
173+
152174
# Code style
153175

154176
The code style used is the default rustfmt codestyle. Please format your code accordingly.

wasm/Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
[package]
22
name = "rustpython_wasm"
33
version = "0.1.0"
4-
authors = ["rmliddle <[email protected]>"]
4+
authors = ["Ryan Liddle <[email protected]>"]
5+
6+
[lib]
7+
crate-type = ["cdylib", "rlib"]
58

69
[workspace]
710
members = []
811

912
[dependencies]
1013
rustpython_parser = {path = "../parser"}
1114
rustpython_vm = {path = "../vm"}
15+
cfg-if = "0.1.2"
16+
wasm-bindgen = "0.2"
17+
1218

1319
[profile.release]
14-
opt-level = 's'
20+
opt-level = "s"

wasm/app/bootstrap.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// A dependency graph that contains any wasm must all be imported
2+
// asynchronously. This `bootstrap.js` file does the single async import, so
3+
// that no one else needs to worry about it again.
4+
import("./index.js")
5+
.catch(e => console.error("Error importing `index.js`:", e));

wasm/app/index.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>RustPython Starter Application</title>
6+
</head>
7+
<body>
8+
<script src="./bootstrap.js"></script>
9+
</body>
10+
</html>

wasm/app/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import * as rp from "rustpython_wasm";
2+
3+
rp.run_code("print('Hello Python!')\n");

wasm/app/package.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "app",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"dependencies": {
7+
"hello-wasm-pack": "^0.1.0",
8+
"webpack": "^4.16.3",
9+
"webpack-cli": "^3.1.0",
10+
"webpack-dev-server": "^3.1.5",
11+
"copy-webpack-plugin": "^4.5.2"
12+
},
13+
"devDependencies": {},
14+
"scripts": {
15+
"test": "echo \"Error: no test specified\" && exit 1"
16+
},
17+
"repository": {
18+
"type": "git",
19+
"url": "git+https://github.com/RustPython/RustPython.git"
20+
},
21+
"author": "Ryan Liddle",
22+
"license": "MIT",
23+
"bugs": {
24+
"url": "https://github.com/RustPython/RustPython/issues"
25+
},
26+
"homepage": "https://github.com/RustPython/RustPython#readme"
27+
}

wasm/app/webpack.config.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const CopyWebpackPlugin = require("copy-webpack-plugin");
2+
const path = require('path');
3+
4+
module.exports = {
5+
entry: "./bootstrap.js",
6+
output: {
7+
path: path.resolve(__dirname, "dist"),
8+
filename: "bootstrap.js",
9+
},
10+
mode: "development",
11+
plugins: [
12+
new CopyWebpackPlugin(['index.html'])
13+
],
14+
};

wasm/index.html

Lines changed: 0 additions & 14 deletions
This file was deleted.

wasm/src/lib.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
extern crate rustpython_vm;
2+
extern crate wasm_bindgen;
3+
use rustpython_vm::compile;
4+
use rustpython_vm::VirtualMachine;
5+
use wasm_bindgen::prelude::*;
6+
7+
#[wasm_bindgen]
8+
extern "C" {
9+
// Use `js_namespace` here to bind `console.log(..)` instead of just
10+
// `log(..)`
11+
#[wasm_bindgen(js_namespace = console)]
12+
fn log(s: &str);
13+
}
14+
15+
#[wasm_bindgen]
16+
pub fn run_code(source: &str) -> () {
17+
//add hash in here
18+
log("Running RustPython");
19+
log(&source.to_string());
20+
let mut vm = VirtualMachine::new();
21+
let code_obj = compile::compile(&mut vm, &source.to_string(), compile::Mode::Exec, None);
22+
let builtins = vm.get_builtin_scope();
23+
let vars = vm.context().new_scope(Some(builtins));
24+
match vm.run_code_obj(code_obj.unwrap(), vars) {
25+
Ok(_value) => log("Execution successful"),
26+
Err(_) => log("Execution failed"),
27+
}
28+
}

0 commit comments

Comments
 (0)