Add example, change some stuff in the demo to align with example

This commit is contained in:
coolreader18
2018-12-22 22:22:34 -06:00
parent ca30ebcf5d
commit 2ea9dca40c
21 changed files with 2964 additions and 6132 deletions

3
wasm/.gitignore vendored
View File

@@ -1,2 +1,5 @@
bin/
pkg/
dist/
node_modules/

View File

@@ -1,2 +0,0 @@
dist/
node_modules/

File diff suppressed because it is too large Load Diff

View File

@@ -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"

View File

@@ -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;
});

View File

@@ -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 &#9655;</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>

View File

@@ -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
View 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

View File

@@ -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: {

View File

@@ -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
View 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
View 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"
}

View 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
View 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
View 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))

View 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

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@
name = "rustpython_wasm"
version = "0.1.0"
authors = ["Ryan Liddle <ryan@rmliddle.com>"]
license = "MIT"
[lib]
crate-type = ["cdylib", "rlib"]

View File

@@ -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())
},
)

View File

@@ -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())
}