forked from Rust-related/RustPython
Add example, change some stuff in the demo to align with example
This commit is contained in:
3
wasm/.gitignore
vendored
3
wasm/.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
bin/
|
||||
pkg/
|
||||
dist/
|
||||
node_modules/
|
||||
|
||||
|
||||
2
wasm/demo/.gitignore
vendored
2
wasm/demo/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
dist/
|
||||
node_modules/
|
||||
6032
wasm/demo/package-lock.json
generated
6032
wasm/demo/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "app",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"description": "Bindings to the RustPython library for WebAssembly",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"codemirror": "^5.42.0"
|
||||
|
||||
10
wasm/demo/src/bootstrap.js
vendored
10
wasm/demo/src/bootstrap.js
vendored
@@ -1,10 +0,0 @@
|
||||
import './style.css';
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
|
||||
// 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);
|
||||
document.getElementById('error').textContent = e;
|
||||
});
|
||||
@@ -8,12 +8,12 @@
|
||||
<h1>RustPython Demo</h1>
|
||||
<p>
|
||||
RustPython is a Python interpreter writter in Rust. This demo is
|
||||
compiled from Rust to WebAssembly so it runs in the browser
|
||||
compiled from Rust to WebAssembly so it runs in the browser.
|
||||
</p>
|
||||
<p>Please input your python code below and click <kbd>Run</kbd>:</p>
|
||||
<p>
|
||||
Alternatively, open up your browser's devtools and play with
|
||||
<code>rp.eval_py('print("a")')</code>
|
||||
Please input your python code below and click <kbd>Run</kbd>, or you
|
||||
can up your browser's devtools and play with
|
||||
<code>rp.pyEval('print("a")')</code>
|
||||
</p>
|
||||
<textarea id="code">
|
||||
n1 = 0
|
||||
@@ -28,13 +28,14 @@ while count < until:
|
||||
n1, n2 = n2, n1 + n2
|
||||
count += 1
|
||||
|
||||
</textarea>
|
||||
</textarea
|
||||
>
|
||||
<button id="run-btn">Run ▷</button>
|
||||
<div id="error"></div>
|
||||
<h3>Standard Output</h3>
|
||||
<textarea id="console">Loading...</textarea>
|
||||
<textarea id="console" readonly>Loading...</textarea>
|
||||
|
||||
<p>Here's some info regarding the <code>rp.eval_py()</code> function</p>
|
||||
<p>Here's some info regarding the <code>rp.pyEval()</code> function</p>
|
||||
<ul>
|
||||
<li>
|
||||
You can return variables from python and get them returned to
|
||||
@@ -42,10 +43,22 @@ while count < until:
|
||||
with <code>json.dumps</code>.
|
||||
</li>
|
||||
<li>
|
||||
You can pass an object as the second argument to the function,
|
||||
and that will be available in python as the variable
|
||||
<code>js_vars</code>. Again, only values that can be serialized
|
||||
with <code>JSON.stringify()</code> will go through.
|
||||
You can pass an options object as the second argument to the
|
||||
function:
|
||||
<ul>
|
||||
<li>
|
||||
<code>stdout</code>: either a string with a css selector
|
||||
to a textarea element or a function that recieves a
|
||||
string when the <code>print</code> function is called in
|
||||
python. The default value is <code>console.log</code>.
|
||||
</li>
|
||||
<li>
|
||||
<code>vars</code>: an object that will be available in
|
||||
python as the variable <code>js_vars</code>. Again, only
|
||||
values that can be serialized with
|
||||
<code>JSON.stringify()</code> will go through.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -1,46 +1,10 @@
|
||||
import * as rp from '../../lib/pkg';
|
||||
import CodeMirror from 'codemirror';
|
||||
import 'codemirror/mode/python/python';
|
||||
import 'codemirror/addon/comment/comment';
|
||||
import './style.css';
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
|
||||
// so people can play around with it
|
||||
window.rp = rp;
|
||||
|
||||
const editor = CodeMirror.fromTextArea(document.getElementById('code'), {
|
||||
extraKeys: {
|
||||
'Ctrl-Enter': runCodeFromTextarea,
|
||||
'Cmd-Enter': runCodeFromTextarea,
|
||||
'Shift-Tab': 'indentLess',
|
||||
'Ctrl-/': 'toggleComment',
|
||||
'Cmd-/': 'toggleComment'
|
||||
},
|
||||
lineNumbers: true,
|
||||
mode: 'text/x-python',
|
||||
indentUnit: 4,
|
||||
autofocus: true
|
||||
// A dependency graph that contains any wasm must all be imported
|
||||
// asynchronously. This `index.js` file does the single async import, so
|
||||
// that no one else needs to worry about it again.
|
||||
import('./main.js').catch(e => {
|
||||
console.error('Error importing `main.js`:', e);
|
||||
document.getElementById('error').textContent = e;
|
||||
});
|
||||
|
||||
function runCodeFromTextarea() {
|
||||
const consoleElement = document.getElementById('console');
|
||||
const errorElement = document.getElementById('error');
|
||||
|
||||
// Clean the console and errors
|
||||
consoleElement.value = '';
|
||||
errorElement.textContent = '';
|
||||
|
||||
const code = editor.getValue();
|
||||
try {
|
||||
rp.eval_py(code, {
|
||||
stdout: '#console'
|
||||
});
|
||||
} catch (e) {
|
||||
errorElement.textContent = e;
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
document
|
||||
.getElementById('run-btn')
|
||||
.addEventListener('click', runCodeFromTextarea);
|
||||
|
||||
runCodeFromTextarea(); // Run once for demo
|
||||
|
||||
47
wasm/demo/src/main.js
Normal file
47
wasm/demo/src/main.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import * as rp from '../../lib/pkg';
|
||||
import CodeMirror from 'codemirror';
|
||||
import 'codemirror/mode/python/python';
|
||||
import 'codemirror/addon/comment/comment';
|
||||
|
||||
// so people can play around with it
|
||||
window.rp = rp;
|
||||
|
||||
const editor = CodeMirror.fromTextArea(document.getElementById('code'), {
|
||||
extraKeys: {
|
||||
'Ctrl-Enter': runCodeFromTextarea,
|
||||
'Cmd-Enter': runCodeFromTextarea,
|
||||
'Shift-Tab': 'indentLess',
|
||||
'Ctrl-/': 'toggleComment',
|
||||
'Cmd-/': 'toggleComment'
|
||||
},
|
||||
lineNumbers: true,
|
||||
mode: 'text/x-python',
|
||||
indentUnit: 4,
|
||||
autofocus: true
|
||||
});
|
||||
|
||||
function runCodeFromTextarea() {
|
||||
const consoleElement = document.getElementById('console');
|
||||
const errorElement = document.getElementById('error');
|
||||
|
||||
// Clean the console and errors
|
||||
consoleElement.value = '';
|
||||
errorElement.textContent = '';
|
||||
|
||||
const code = editor.getValue();
|
||||
try {
|
||||
const result = rp.pyEval(code, {
|
||||
stdout: '#console'
|
||||
});
|
||||
consoleElement.value += `\n${result}\n`;
|
||||
} catch (e) {
|
||||
errorElement.textContent = e;
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
document
|
||||
.getElementById('run-btn')
|
||||
.addEventListener('click', runCodeFromTextarea);
|
||||
|
||||
runCodeFromTextarea(); // Run once for demo
|
||||
@@ -3,10 +3,10 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: './src/bootstrap.js',
|
||||
entry: './src/index.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'bootstrap.js'
|
||||
path: path.join(__dirname, 'dist'),
|
||||
filename: 'index.js'
|
||||
},
|
||||
mode: 'development',
|
||||
module: {
|
||||
|
||||
@@ -3405,9 +3405,6 @@ run-queue@^1.0.0, run-queue@^1.0.3:
|
||||
dependencies:
|
||||
aproba "^1.1.1"
|
||||
|
||||
"rustpython_wasm@file:../lib/pkg":
|
||||
version "0.1.0"
|
||||
|
||||
safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
|
||||
12
wasm/example/index.html
Normal file
12
wasm/example/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<title>RustPython Basic Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="./dist/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
18
wasm/example/package.json
Normal file
18
wasm/example/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "rustpython-wasm-example",
|
||||
"version": "1.0.0",
|
||||
"//1": "`dependencies.rustpython_wasm` would be the version of the npm",
|
||||
"//2": "library in a real app",
|
||||
"dependencies": {
|
||||
"rustpython_wasm": "file:../lib/pkg/"
|
||||
},
|
||||
"devDependencies": {
|
||||
"raw-loader": "1.0.0",
|
||||
"webpack": "4.28.2",
|
||||
"webpack-cli": "^3.1.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
6
wasm/example/src/index.js
Normal file
6
wasm/example/src/index.js
Normal file
@@ -0,0 +1,6 @@
|
||||
// A dependency graph that contains any wasm must all be imported
|
||||
// asynchronously. This `index.js` file does the single async import, so
|
||||
// that no one else needs to worry about it again.
|
||||
import('./main.js').catch(e => {
|
||||
console.error('Error importing `main.js`:', e);
|
||||
});
|
||||
11
wasm/example/src/main.js
Normal file
11
wasm/example/src/main.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import * as py from 'rustpython_wasm';
|
||||
import pyCode from 'raw-loader!./main.py';
|
||||
|
||||
fetch('https://github-trending-api.now.sh/repositories')
|
||||
.then(r => r.json())
|
||||
.then(repos => {
|
||||
const result = py.pyEval(pyCode, {
|
||||
vars: { repos }
|
||||
});
|
||||
alert(result);
|
||||
});
|
||||
8
wasm/example/src/main.py
Normal file
8
wasm/example/src/main.py
Normal file
@@ -0,0 +1,8 @@
|
||||
repos = js_vars['repos']
|
||||
|
||||
star_sum = 0
|
||||
|
||||
for repo in repos:
|
||||
star_sum += repo['stars']
|
||||
|
||||
return 'Average github trending star count: ' + str(star_sum / len(repos))
|
||||
12
wasm/example/webpack.config.js
Normal file
12
wasm/example/webpack.config.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.js',
|
||||
mode: 'development',
|
||||
output: {
|
||||
path: path.join(__dirname, 'dist'),
|
||||
filename: 'app.js',
|
||||
publicPath: '/dist/'
|
||||
},
|
||||
devtool: 'cheap-module-eval-source-map'
|
||||
};
|
||||
2796
wasm/example/yarn.lock
Normal file
2796
wasm/example/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@
|
||||
name = "rustpython_wasm"
|
||||
version = "0.1.0"
|
||||
authors = ["Ryan Liddle <ryan@rmliddle.com>"]
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
@@ -5,7 +5,7 @@ extern crate rustpython_vm;
|
||||
extern crate wasm_bindgen;
|
||||
extern crate web_sys;
|
||||
|
||||
use js_sys::{Array, Object, Reflect, TypeError};
|
||||
use js_sys::{Object, Reflect, TypeError};
|
||||
use rustpython_vm::compile;
|
||||
use rustpython_vm::pyobject::{self, PyFuncArgs, PyObjectRef, PyResult};
|
||||
use rustpython_vm::VirtualMachine;
|
||||
@@ -74,7 +74,7 @@ where
|
||||
vm.run_code_obj(code_obj, vars)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[wasm_bindgen(js_name = pyEval)]
|
||||
pub fn eval_py(source: &str, options: Option<Object>) -> Result<JsValue, JsValue> {
|
||||
let options = options.unwrap_or_else(|| Object::new());
|
||||
let js_vars = {
|
||||
@@ -96,17 +96,6 @@ pub fn eval_py(source: &str, options: Option<Object>) -> Result<JsValue, JsValue
|
||||
Some(prop)
|
||||
}
|
||||
};
|
||||
let string_stdout = {
|
||||
let prop = Reflect::get(&options, &"stdoutString".into())?;
|
||||
let prop = Object::from(prop);
|
||||
if prop.is_undefined() {
|
||||
true
|
||||
} else if let Some(prop) = prop.as_bool() {
|
||||
prop
|
||||
} else {
|
||||
return Err(TypeError::new("stdoutString must be a boolean").into());
|
||||
}
|
||||
};
|
||||
let mut vm = VirtualMachine::new();
|
||||
|
||||
let print_fn: Box<(Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult)> = match stdout {
|
||||
@@ -121,17 +110,11 @@ pub fn eval_py(source: &str, options: Option<Object>) -> Result<JsValue, JsValue
|
||||
let func = js_sys::Function::from(val);
|
||||
Box::new(
|
||||
move |vm: &mut VirtualMachine, args: PyFuncArgs| -> PyResult {
|
||||
let arr = Array::new();
|
||||
for arg in args.args {
|
||||
let arg = if string_stdout {
|
||||
vm.to_pystr(&arg)?.into()
|
||||
} else {
|
||||
py_to_js(vm, arg)
|
||||
};
|
||||
arr.push(&arg);
|
||||
}
|
||||
func.apply(&JsValue::UNDEFINED, &arr)
|
||||
.map_err(|err| js_to_py(vm, err))?;
|
||||
func.call1(
|
||||
&JsValue::UNDEFINED,
|
||||
&wasm_builtins::format_print_args(vm, args)?.into(),
|
||||
)
|
||||
.map_err(|err| js_to_py(vm, err))?;
|
||||
Ok(vm.get_none())
|
||||
},
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ extern crate web_sys;
|
||||
|
||||
use crate::js_to_py;
|
||||
use js_sys::Array;
|
||||
use rustpython_vm::pyobject::{PyFuncArgs, PyResult};
|
||||
use rustpython_vm::pyobject::{PyFuncArgs, PyObjectRef, PyResult};
|
||||
use rustpython_vm::VirtualMachine;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{console, window, HtmlTextAreaElement};
|
||||
@@ -30,7 +30,7 @@ pub fn print_to_html(text: &str, selector: &str) -> Result<(), JsValue> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn builtin_print_html(vm: &mut VirtualMachine, args: PyFuncArgs, selector: &str) -> PyResult {
|
||||
pub fn format_print_args(vm: &mut VirtualMachine, args: PyFuncArgs) -> Result<String, PyObjectRef> {
|
||||
let mut output = String::new();
|
||||
let mut first = true;
|
||||
for a in args.args {
|
||||
@@ -42,6 +42,11 @@ pub fn builtin_print_html(vm: &mut VirtualMachine, args: PyFuncArgs, selector: &
|
||||
output.push_str(&vm.to_pystr(&a)?);
|
||||
output.push('\n');
|
||||
}
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn builtin_print_html(vm: &mut VirtualMachine, args: PyFuncArgs, selector: &str) -> PyResult {
|
||||
let output = format_print_args(vm, args)?;
|
||||
print_to_html(&output, selector).map_err(|err| js_to_py(vm, err))?;
|
||||
Ok(vm.get_none())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user