-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Improve wasm demo website #230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
b428f2e
Improve demo site
coolreader18 f8cce25
Formatting; move the `+ '\n'` hack to eval().
coolreader18 2ae1df5
Rename run_code() to run_from_textbox()
coolreader18 921efd4
Switch to using json.dumps for py_to_js()
coolreader18 3be6fee
Clarify names of wasm builtins
coolreader18 e78a251
Remove dependency on num_bigint
coolreader18 a796b13
Allow injecting JS variables into python with eval_py()
coolreader18 e77f223
Add documentation for eval_py() and update error message handling
coolreader18 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ __pycache__ | |
**/*.pytest_cache | ||
.*sw* | ||
.repl_history.txt | ||
wasm-pack.log |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
bin/ | ||
pkg/ |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
dist/ | ||
node_modules/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"singleQuote": true, | ||
"tabWidth": 4 | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
// 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)); | ||
import('./index.js').catch(e => | ||
console.error('Error importing `index.js`:', e) | ||
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,27 @@ | ||
import * as rp from "rustpython_wasm"; | ||
import * as rp from 'rustpython_wasm'; | ||
|
||
function runCodeFromTextarea(_) { | ||
const consoleElement = document.getElementById('console'); | ||
// Clean the console | ||
consoleElement.value = ''; | ||
|
||
const code = document.getElementById('code').value; | ||
try { | ||
if (!code.endsWith('\n')) { // HACK: if the code doesn't end with newline it crashes. | ||
rp.run_code(code + '\n'); | ||
return; | ||
} | ||
// so people can play around with it | ||
window.rp = rp; | ||
|
||
rp.run_code(code); | ||
function runCodeFromTextarea(_) { | ||
const consoleElement = document.getElementById('console'); | ||
const errorElement = document.getElementById('error'); | ||
|
||
} catch(e) { | ||
consoleElement.value = 'Execution failed. Please check if your Python code has any syntax error.'; | ||
console.error(e); | ||
} | ||
// Clean the console and errors | ||
consoleElement.value = ''; | ||
errorElement.textContent = ''; | ||
|
||
const code = document.getElementById('code').value; | ||
try { | ||
rp.run_from_textbox(code); | ||
} catch (e) { | ||
errorElement.textContent = e; | ||
console.error(e); | ||
} | ||
} | ||
|
||
document.getElementById('run-btn').addEventListener('click', runCodeFromTextarea); | ||
document | ||
.getElementById('run-btn') | ||
.addEventListener('click', runCodeFromTextarea); | ||
|
||
runCodeFromTextarea(); // Run once for demo |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,143 @@ | ||
mod wasm_builtins; | ||
|
||
extern crate js_sys; | ||
extern crate rustpython_vm; | ||
extern crate wasm_bindgen; | ||
extern crate web_sys; | ||
|
||
use rustpython_vm::VirtualMachine; | ||
use rustpython_vm::compile; | ||
use rustpython_vm::pyobject::AttributeProtocol; | ||
use rustpython_vm::pyobject::{self, PyObjectRef, PyResult}; | ||
use rustpython_vm::VirtualMachine; | ||
use wasm_bindgen::prelude::*; | ||
use web_sys::console; | ||
|
||
fn py_str_err(vm: &mut VirtualMachine, py_err: &PyObjectRef) -> String { | ||
vm.to_pystr(&py_err) | ||
.unwrap_or_else(|_| "Error, and error getting error message".into()) | ||
} | ||
|
||
fn py_to_js(vm: &mut VirtualMachine, py_obj: PyObjectRef) -> JsValue { | ||
let dumps = rustpython_vm::import::import( | ||
vm, | ||
std::path::PathBuf::default(), | ||
"json", | ||
&Some("dumps".into()), | ||
) | ||
.expect("Couldn't get json.dumps function"); | ||
match vm.invoke(dumps, pyobject::PyFuncArgs::new(vec![py_obj], vec![])) { | ||
Ok(value) => { | ||
let json = vm.to_pystr(&value).unwrap(); | ||
js_sys::JSON::parse(&json).unwrap_or(JsValue::UNDEFINED) | ||
} | ||
Err(_) => JsValue::UNDEFINED, | ||
} | ||
} | ||
|
||
fn js_to_py(vm: &mut VirtualMachine, js_val: JsValue) -> PyObjectRef { | ||
let json = match js_sys::JSON::stringify(&js_val) { | ||
Ok(json) => String::from(json), | ||
Err(_) => return vm.get_none(), | ||
}; | ||
|
||
let loads = rustpython_vm::import::import( | ||
vm, | ||
std::path::PathBuf::default(), | ||
"json", | ||
&Some("loads".into()), | ||
) | ||
.expect("Couldn't get json.loads function"); | ||
|
||
let py_json = vm.new_str(json); | ||
|
||
vm.invoke(loads, pyobject::PyFuncArgs::new(vec![py_json], vec![])) | ||
// can safely unwrap because we know it's valid JSON | ||
.unwrap() | ||
} | ||
|
||
fn eval<F>(vm: &mut VirtualMachine, source: &str, setup_scope: F) -> PyResult | ||
where | ||
F: Fn(&mut VirtualMachine, &PyObjectRef), | ||
{ | ||
// HACK: if the code doesn't end with newline it crashes. | ||
let mut source = source.to_string(); | ||
if !source.ends_with('\n') { | ||
source.push('\n'); | ||
} | ||
|
||
let code_obj = compile::compile(vm, &source, compile::Mode::Exec, None)?; | ||
|
||
let builtins = vm.get_builtin_scope(); | ||
let mut vars = vm.context().new_scope(Some(builtins)); | ||
|
||
setup_scope(vm, &mut vars); | ||
|
||
vm.run_code_obj(code_obj, vars) | ||
} | ||
|
||
#[wasm_bindgen] | ||
pub fn eval_py(source: &str, js_injections: Option<js_sys::Object>) -> Result<JsValue, JsValue> { | ||
if let Some(js_injections) = js_injections.clone() { | ||
if !js_injections.is_object() { | ||
return Err(js_sys::TypeError::new("The second argument must be an object").into()); | ||
} | ||
} | ||
|
||
let mut vm = VirtualMachine::new(); | ||
|
||
vm.ctx.set_attr( | ||
&vm.builtins, | ||
"print", | ||
vm.context() | ||
.new_rustfunc(wasm_builtins::builtin_print_console), | ||
); | ||
|
||
let res = eval(&mut vm, source, |vm, vars| { | ||
let injections = if let Some(js_injections) = js_injections.clone() { | ||
js_to_py(vm, js_injections.into()) | ||
} else { | ||
vm.new_dict() | ||
}; | ||
|
||
vm.ctx.set_item(vars, "js_vars", injections); | ||
}); | ||
|
||
res.map(|value| py_to_js(&mut vm, value)) | ||
.map_err(|err| py_str_err(&mut vm, &err).into()) | ||
} | ||
|
||
#[wasm_bindgen] | ||
pub fn run_code(source: &str) -> () { | ||
pub fn run_from_textbox(source: &str) -> Result<JsValue, JsValue> { | ||
//add hash in here | ||
console::log_1(&"Running RustPython".into()); | ||
console::log_1(&"Running code:".into()); | ||
console::log_1(&source.to_string().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); | ||
// We are monkey-patching the builtin print to use console.log | ||
// TODO: monkey-patch sys.stdout instead, after print actually uses sys.stdout | ||
vm.ctx.set_attr( | ||
coolreader18 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
&vm.builtins, | ||
"print", | ||
vm.context().new_rustfunc(wasm_builtins::builtin_print_html), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! I like this dual-function design of print_html + print_console |
||
); | ||
|
||
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) => console::log_1(&"Execution successful".into()), | ||
Err(_) => console::log_1(&"Execution failed".into()), | ||
match eval(&mut vm, source, |_, _| {}) { | ||
Ok(value) => { | ||
console::log_1(&"Execution successful".into()); | ||
match value.borrow().kind { | ||
pyobject::PyObjectKind::None => {} | ||
_ => { | ||
if let Ok(text) = vm.to_pystr(&value) { | ||
wasm_builtins::print_to_html(&text); | ||
} | ||
} | ||
} | ||
Ok(JsValue::UNDEFINED) | ||
} | ||
Err(err) => { | ||
console::log_1(&"Execution failed".into()); | ||
Err(py_str_err(&mut vm, &err).into()) | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.