mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Interpreter struct for managing thread-local vm stack
This commit is contained in:
16 files changed
+379
-303
No files matched your search
+21
-19
@@ -2,16 +2,18 @@
|
||||
|
||||
extern crate test;
|
||||
|
||||
use test::Bencher;
|
||||
|
||||
use rustpython_compiler::compile;
|
||||
use rustpython_vm::pyobject::PyResult;
|
||||
use rustpython_vm::VirtualMachine;
|
||||
use rustpython_vm::Interpreter;
|
||||
|
||||
const MINIDOM: &str = include_str!("./benchmarks/minidom.py");
|
||||
const NBODY: &str = include_str!("./benchmarks/nbody.py");
|
||||
const MANDELBROT: &str = include_str!("./benchmarks/mandelbrot.py");
|
||||
|
||||
#[bench]
|
||||
fn bench_tokenization(b: &mut test::Bencher) {
|
||||
fn bench_tokenization(b: &mut Bencher) {
|
||||
use rustpython_parser::lexer::{make_tokenizer, Tok};
|
||||
|
||||
let source = MINIDOM;
|
||||
@@ -26,7 +28,7 @@ fn bench_tokenization(b: &mut test::Bencher) {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_rustpy_parse_to_ast(b: &mut test::Bencher) {
|
||||
fn bench_rustpy_parse_to_ast(b: &mut Bencher) {
|
||||
use rustpython_parser::parser::parse_program;
|
||||
|
||||
let source = MINIDOM;
|
||||
@@ -36,7 +38,7 @@ fn bench_rustpy_parse_to_ast(b: &mut test::Bencher) {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_cpython_parse_to_ast(b: &mut test::Bencher) {
|
||||
fn bench_cpython_parse_to_ast(b: &mut Bencher) {
|
||||
let source = MINIDOM;
|
||||
|
||||
let gil = cpython::Python::acquire_gil();
|
||||
@@ -56,7 +58,7 @@ fn bench_cpython_parse_to_ast(b: &mut test::Bencher) {
|
||||
})
|
||||
}
|
||||
|
||||
fn bench_cpython(b: &mut test::Bencher, source: &str) {
|
||||
fn bench_cpython(b: &mut Bencher, source: &str) {
|
||||
let gil = cpython::Python::acquire_gil();
|
||||
let python = gil.python();
|
||||
|
||||
@@ -70,36 +72,36 @@ fn bench_cpython(b: &mut test::Bencher, source: &str) {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_cpython_nbody(b: &mut test::Bencher) {
|
||||
fn bench_cpython_nbody(b: &mut Bencher) {
|
||||
bench_cpython(b, NBODY)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_cpython_mandelbrot(b: &mut test::Bencher) {
|
||||
fn bench_cpython_mandelbrot(b: &mut Bencher) {
|
||||
bench_cpython(b, MANDELBROT)
|
||||
}
|
||||
|
||||
fn bench_rustpy(b: &mut test::Bencher, name: &str, source: &str) {
|
||||
fn bench_rustpy(b: &mut Bencher, name: &str, source: &str) {
|
||||
// NOTE: Take long time.
|
||||
let vm = VirtualMachine::default();
|
||||
Interpreter::default().enter(|vm| {
|
||||
let code = vm
|
||||
.compile(source, compile::Mode::Exec, name.to_owned())
|
||||
.unwrap();
|
||||
|
||||
let code = vm
|
||||
.compile(source, compile::Mode::Exec, name.to_owned())
|
||||
.unwrap();
|
||||
|
||||
b.iter(|| {
|
||||
let scope = vm.new_scope_with_builtins();
|
||||
let res: PyResult = vm.run_code_obj(code.clone(), scope);
|
||||
vm.unwrap_pyresult(res);
|
||||
b.iter(|| {
|
||||
let scope = vm.new_scope_with_builtins();
|
||||
let res: PyResult = vm.run_code_obj(code.clone(), scope);
|
||||
vm.unwrap_pyresult(res);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_rustpy_nbody(b: &mut test::Bencher) {
|
||||
fn bench_rustpy_nbody(b: &mut Bencher) {
|
||||
bench_rustpy(b, "nbody.py", NBODY)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_rustpy_mandelbrot(b: &mut test::Bencher) {
|
||||
fn bench_rustpy_mandelbrot(b: &mut Bencher) {
|
||||
bench_rustpy(b, "mandelbrot.py", MANDELBROT)
|
||||
}
|
||||
@@ -3,8 +3,10 @@ use std::collections::HashMap;
|
||||
use rustpython_vm as vm;
|
||||
|
||||
fn main() -> vm::pyobject::PyResult<()> {
|
||||
let vm = vm::VirtualMachine::new(vm::PySettings::default());
|
||||
vm::Interpreter::default().enter(run)
|
||||
}
|
||||
|
||||
fn run(vm: &vm::VirtualMachine) -> vm::pyobject::PyResult<()> {
|
||||
let scope = vm.new_scope_with_builtins();
|
||||
|
||||
// the file parameter is relevant to the directory where the crate's Cargo.toml is located, see $CARGO_MANIFEST_DIR:
|
||||
|
||||
+12
-12
@@ -2,19 +2,19 @@ use rustpython_compiler as compiler;
|
||||
use rustpython_vm as vm;
|
||||
|
||||
fn main() -> vm::pyobject::PyResult<()> {
|
||||
let vm = vm::VirtualMachine::new(vm::PySettings::default());
|
||||
vm::Interpreter::default().enter(|vm| {
|
||||
let scope = vm.new_scope_with_builtins();
|
||||
|
||||
let scope = vm.new_scope_with_builtins();
|
||||
let code_obj = vm
|
||||
.compile(
|
||||
r#"print("Hello World!")"#,
|
||||
compiler::compile::Mode::Exec,
|
||||
"<embedded>".to_owned(),
|
||||
)
|
||||
.map_err(|err| vm.new_syntax_error(&err))?;
|
||||
|
||||
let code_obj = vm
|
||||
.compile(
|
||||
r#"print("Hello World!")"#,
|
||||
compiler::compile::Mode::Exec,
|
||||
"<embedded>".to_owned(),
|
||||
)
|
||||
.map_err(|err| vm.new_syntax_error(&err))?;
|
||||
vm.run_code_obj(code_obj, scope)?;
|
||||
|
||||
vm.run_code_obj(code_obj, scope)?;
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@@ -59,14 +59,17 @@ fn on(b: bool) {
|
||||
}
|
||||
|
||||
fn main() -> vm::pyobject::PyResult<()> {
|
||||
vm::Interpreter::default().enter(run)
|
||||
}
|
||||
|
||||
fn run(vm: &vm::VirtualMachine) -> vm::pyobject::PyResult<()> {
|
||||
let mut input = String::with_capacity(50);
|
||||
let stdin = std::io::stdin();
|
||||
|
||||
let vm = vm::VirtualMachine::new(vm::PySettings::default());
|
||||
let scope: vm::scope::Scope = vm.new_scope_with_builtins();
|
||||
|
||||
// typing `quit()` is too long, let's make `on(False)` work instead.
|
||||
scope.globals.set_item("on", vm.ctx.new_function(on), &vm)?;
|
||||
scope.globals.set_item("on", vm.ctx.new_function(on), vm)?;
|
||||
|
||||
// let's include a fibonacci function, but let's be lazy and write it in Python
|
||||
add_python_function!(
|
||||
@@ -97,11 +100,11 @@ fn main() -> vm::pyobject::PyResult<()> {
|
||||
Ok(output) => {
|
||||
// store the last value in the "last" variable
|
||||
if !vm.is_none(&output) {
|
||||
scope.globals.set_item("last", output, &vm)?;
|
||||
scope.globals.set_item("last", output, vm)?;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
vm::exceptions::print_exception(&vm, e);
|
||||
vm::exceptions::print_exception(vm, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+52
-50
@@ -12,7 +12,7 @@ use rustpython_vm::{
|
||||
obj::{objint::PyInt, objtype},
|
||||
pyobject::{BorrowValue, ItemProtocol, PyResult},
|
||||
scope::Scope,
|
||||
util, InitParameter, PySettings, VirtualMachine,
|
||||
util, InitParameter, Interpreter, PySettings, VirtualMachine,
|
||||
};
|
||||
|
||||
use std::convert::TryInto;
|
||||
@@ -49,49 +49,51 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let vm = VirtualMachine::new(settings);
|
||||
let interp = Interpreter::new(settings);
|
||||
|
||||
let res = run_rustpython(&vm, &matches);
|
||||
interp.enter(move |vm| {
|
||||
let res = run_rustpython(vm, &matches);
|
||||
|
||||
#[cfg(feature = "flame-it")]
|
||||
{
|
||||
main_guard.end();
|
||||
if let Err(e) = write_profile(&matches) {
|
||||
error!("Error writing profile information: {}", e);
|
||||
#[cfg(feature = "flame-it")]
|
||||
{
|
||||
main_guard.end();
|
||||
if let Err(e) = write_profile(&matches) {
|
||||
error!("Error writing profile information: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See if any exception leaked out:
|
||||
if let Err(err) = res {
|
||||
if objtype::isinstance(&err, &vm.ctx.exceptions.system_exit) {
|
||||
let args = err.args();
|
||||
match args.borrow_value().len() {
|
||||
0 => return,
|
||||
1 => match_class!(match args.borrow_value()[0].clone() {
|
||||
i @ PyInt => {
|
||||
use num_traits::cast::ToPrimitive;
|
||||
process::exit(i.borrow_value().to_i32().unwrap_or(0));
|
||||
}
|
||||
arg => {
|
||||
if vm.is_none(&arg) {
|
||||
return;
|
||||
// See if any exception leaked out:
|
||||
if let Err(err) = res {
|
||||
if objtype::isinstance(&err, &vm.ctx.exceptions.system_exit) {
|
||||
let args = err.args();
|
||||
match args.borrow_value().len() {
|
||||
0 => return,
|
||||
1 => match_class!(match args.borrow_value()[0].clone() {
|
||||
i @ PyInt => {
|
||||
use num_traits::cast::ToPrimitive;
|
||||
process::exit(i.borrow_value().to_i32().unwrap_or(0));
|
||||
}
|
||||
if let Ok(s) = vm.to_str(&arg) {
|
||||
eprintln!("{}", s);
|
||||
arg => {
|
||||
if vm.is_none(&arg) {
|
||||
return;
|
||||
}
|
||||
if let Ok(s) = vm.to_str(&arg) {
|
||||
eprintln!("{}", s);
|
||||
}
|
||||
}
|
||||
}),
|
||||
_ => {
|
||||
if let Ok(r) = vm.to_repr(args.as_object()) {
|
||||
eprintln!("{}", r);
|
||||
}
|
||||
}
|
||||
}),
|
||||
_ => {
|
||||
if let Ok(r) = vm.to_repr(args.as_object()) {
|
||||
eprintln!("{}", r);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print_exception(&vm, err);
|
||||
}
|
||||
} else {
|
||||
print_exception(&vm, err);
|
||||
process::exit(1);
|
||||
}
|
||||
process::exit(1);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> {
|
||||
@@ -493,21 +495,21 @@ fn run_script(vm: &VirtualMachine, scope: Scope, script_file: &str) -> PyResult<
|
||||
|
||||
#[test]
|
||||
fn test_run_script() {
|
||||
let vm: VirtualMachine = Default::default();
|
||||
Interpreter::default().enter(|vm| {
|
||||
// test file run
|
||||
let r = run_script(
|
||||
vm,
|
||||
vm.new_scope_with_builtins(),
|
||||
"extra_tests/snippets/dir_main/__main__.py",
|
||||
);
|
||||
assert!(r.is_ok());
|
||||
|
||||
// test file run
|
||||
let r = run_script(
|
||||
&vm,
|
||||
vm.new_scope_with_builtins(),
|
||||
"extra_tests/snippets/dir_main/__main__.py",
|
||||
);
|
||||
assert!(r.is_ok());
|
||||
|
||||
// test module run
|
||||
let r = run_script(
|
||||
&vm,
|
||||
vm.new_scope_with_builtins(),
|
||||
"extra_tests/snippets/dir_main",
|
||||
);
|
||||
assert!(r.is_ok());
|
||||
// test module run
|
||||
let r = run_script(
|
||||
vm,
|
||||
vm.new_scope_with_builtins(),
|
||||
"extra_tests/snippets/dir_main",
|
||||
);
|
||||
assert!(r.is_ok());
|
||||
})
|
||||
}
|
||||
+32
-29
@@ -504,39 +504,41 @@ impl DictKey for &str {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Dict, DictKey, VirtualMachine};
|
||||
use super::{Dict, DictKey};
|
||||
use crate::Interpreter;
|
||||
|
||||
#[test]
|
||||
fn test_insert() {
|
||||
let vm: VirtualMachine = Default::default();
|
||||
let dict = Dict::default();
|
||||
assert_eq!(0, dict.len());
|
||||
Interpreter::default().enter(|vm| {
|
||||
let dict = Dict::default();
|
||||
assert_eq!(0, dict.len());
|
||||
|
||||
let key1 = vm.ctx.new_bool(true);
|
||||
let value1 = vm.ctx.new_str("abc");
|
||||
dict.insert(&vm, key1.clone(), value1.clone()).unwrap();
|
||||
assert_eq!(1, dict.len());
|
||||
let key1 = vm.ctx.new_bool(true);
|
||||
let value1 = vm.ctx.new_str("abc");
|
||||
dict.insert(&vm, key1.clone(), value1.clone()).unwrap();
|
||||
assert_eq!(1, dict.len());
|
||||
|
||||
let key2 = vm.ctx.new_str("x");
|
||||
let value2 = vm.ctx.new_str("def");
|
||||
dict.insert(&vm, key2.clone(), value2.clone()).unwrap();
|
||||
assert_eq!(2, dict.len());
|
||||
let key2 = vm.ctx.new_str("x");
|
||||
let value2 = vm.ctx.new_str("def");
|
||||
dict.insert(&vm, key2.clone(), value2.clone()).unwrap();
|
||||
assert_eq!(2, dict.len());
|
||||
|
||||
dict.insert(&vm, key1.clone(), value2.clone()).unwrap();
|
||||
assert_eq!(2, dict.len());
|
||||
dict.insert(&vm, key1.clone(), value2.clone()).unwrap();
|
||||
assert_eq!(2, dict.len());
|
||||
|
||||
dict.delete(&vm, key1.clone()).unwrap();
|
||||
assert_eq!(1, dict.len());
|
||||
dict.delete(&vm, key1.clone()).unwrap();
|
||||
assert_eq!(1, dict.len());
|
||||
|
||||
dict.insert(&vm, key1.clone(), value2.clone()).unwrap();
|
||||
assert_eq!(2, dict.len());
|
||||
dict.insert(&vm, key1.clone(), value2.clone()).unwrap();
|
||||
assert_eq!(2, dict.len());
|
||||
|
||||
assert_eq!(true, dict.contains(&vm, &key1).unwrap());
|
||||
assert_eq!(true, dict.contains(&vm, &"x").unwrap());
|
||||
assert_eq!(true, dict.contains(&vm, &key1).unwrap());
|
||||
assert_eq!(true, dict.contains(&vm, &"x").unwrap());
|
||||
|
||||
let val = dict.get(&vm, &"x").unwrap().unwrap();
|
||||
vm.bool_eq(val, value2)
|
||||
.expect("retrieved value must be equal to inserted value.");
|
||||
let val = dict.get(&vm, &"x").unwrap().unwrap();
|
||||
vm.bool_eq(val, value2)
|
||||
.expect("retrieved value must be equal to inserted value.");
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! hash_tests {
|
||||
@@ -556,12 +558,13 @@ mod tests {
|
||||
}
|
||||
|
||||
fn check_hash_equivalence(text: &str) {
|
||||
let vm: VirtualMachine = Default::default();
|
||||
let value1 = text;
|
||||
let value2 = vm.ctx.new_str(value1.to_owned());
|
||||
Interpreter::default().enter(|vm| {
|
||||
let value1 = text;
|
||||
let value2 = vm.ctx.new_str(value1.to_owned());
|
||||
|
||||
let hash1 = value1.key_hash(&vm).expect("Hash should not fail.");
|
||||
let hash2 = value2.key_hash(&vm).expect("Hash should not fail.");
|
||||
assert_eq!(hash1, hash2);
|
||||
let hash1 = value1.key_hash(&vm).expect("Hash should not fail.");
|
||||
let hash2 = value2.key_hash(&vm).expect("Hash should not fail.");
|
||||
assert_eq!(hash1, hash2);
|
||||
})
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -1,6 +1,6 @@
|
||||
use crate::pyobject::PyResult;
|
||||
use crate::scope::Scope;
|
||||
use crate::vm::VirtualMachine;
|
||||
use crate::VirtualMachine;
|
||||
use rustpython_compiler::compile;
|
||||
|
||||
pub fn eval(vm: &VirtualMachine, source: &str, scope: Scope, source_path: &str) -> PyResult {
|
||||
@@ -15,16 +15,16 @@ pub fn eval(vm: &VirtualMachine, source: &str, scope: Scope, source_path: &str)
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::eval;
|
||||
use super::VirtualMachine;
|
||||
use crate::pyobject::IdProtocol;
|
||||
use super::*;
|
||||
use crate::Interpreter;
|
||||
|
||||
#[test]
|
||||
fn test_print_42() {
|
||||
let source = String::from("print('Hello world')");
|
||||
let vm = VirtualMachine::default();
|
||||
let vars = vm.new_scope_with_builtins();
|
||||
let result = eval(&vm, &source, vars, "<unittest>").expect("this should pass");
|
||||
assert!(result.is(&vm.ctx.none()));
|
||||
Interpreter::default().enter(|vm| {
|
||||
let source = String::from("print('Hello world')");
|
||||
let vars = vm.new_scope_with_builtins();
|
||||
let result = eval(&vm, &source, vars, "<unittest>").expect("this should pass");
|
||||
assert!(vm.is_none(&result));
|
||||
})
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -71,6 +71,6 @@ mod version;
|
||||
mod vm;
|
||||
|
||||
// pub use self::pyobject::Executor;
|
||||
pub use self::vm::{InitParameter, PySettings, VirtualMachine};
|
||||
pub use self::vm::{InitParameter, Interpreter, PySettings, VirtualMachine};
|
||||
pub use rustpython_bytecode::*;
|
||||
pub use rustpython_common as common;
|
||||
+4
-4
@@ -93,13 +93,12 @@ macro_rules! py_namespace {
|
||||
/// use num_bigint::ToBigInt;
|
||||
/// use num_traits::Zero;
|
||||
///
|
||||
/// use rustpython_vm::VirtualMachine;
|
||||
/// use rustpython_vm::match_class;
|
||||
/// use rustpython_vm::obj::objfloat::PyFloat;
|
||||
/// use rustpython_vm::obj::objint::PyInt;
|
||||
/// use rustpython_vm::pyobject::PyValue;
|
||||
///
|
||||
/// let vm: VirtualMachine = Default::default();
|
||||
/// # rustpython_vm::Interpreter::default().enter(|vm| {
|
||||
/// let obj = PyInt::from(0).into_ref(&vm).into_object();
|
||||
/// assert_eq!(
|
||||
/// "int",
|
||||
@@ -109,6 +108,7 @@ macro_rules! py_namespace {
|
||||
/// _ => "neither",
|
||||
/// })
|
||||
/// );
|
||||
/// # });
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
@@ -118,13 +118,12 @@ macro_rules! py_namespace {
|
||||
/// use num_bigint::ToBigInt;
|
||||
/// use num_traits::Zero;
|
||||
///
|
||||
/// use rustpython_vm::VirtualMachine;
|
||||
/// use rustpython_vm::match_class;
|
||||
/// use rustpython_vm::obj::objfloat::PyFloat;
|
||||
/// use rustpython_vm::obj::objint::PyInt;
|
||||
/// use rustpython_vm::pyobject::{PyValue, BorrowValue};
|
||||
///
|
||||
/// let vm: VirtualMachine = Default::default();
|
||||
/// # rustpython_vm::Interpreter::default().enter(|vm| {
|
||||
/// let obj = PyInt::from(0).into_ref(&vm).into_object();
|
||||
///
|
||||
/// let int_value = match_class!(match obj {
|
||||
@@ -134,6 +133,7 @@ macro_rules! py_namespace {
|
||||
/// });
|
||||
///
|
||||
/// assert!(int_value.is_zero());
|
||||
/// # });
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! match_class {
|
||||
|
||||
+22
-21
@@ -1258,6 +1258,7 @@ fn char_is_printable(c: char) -> bool {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::Interpreter;
|
||||
|
||||
#[test]
|
||||
fn str_title() {
|
||||
@@ -1307,27 +1308,27 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn str_maketrans_and_translate() {
|
||||
let vm: VirtualMachine = Default::default();
|
||||
|
||||
let table = vm.ctx.new_dict();
|
||||
table.set_item("a", vm.ctx.new_str("🎅"), &vm).unwrap();
|
||||
table.set_item("b", vm.get_none(), &vm).unwrap();
|
||||
table.set_item("c", vm.ctx.new_str("xda"), &vm).unwrap();
|
||||
let translated = PyString::maketrans(
|
||||
table.into_object(),
|
||||
OptionalArg::Missing,
|
||||
OptionalArg::Missing,
|
||||
&vm,
|
||||
)
|
||||
.unwrap();
|
||||
let text = PyString::from("abc");
|
||||
let translated = text.translate(translated, &vm).unwrap();
|
||||
assert_eq!(translated, "🎅xda".to_owned());
|
||||
let translated = text.translate(vm.ctx.new_int(3), &vm);
|
||||
assert_eq!(
|
||||
translated.unwrap_err().lease_class().name,
|
||||
"TypeError".to_owned()
|
||||
);
|
||||
Interpreter::default().enter(|vm| {
|
||||
let table = vm.ctx.new_dict();
|
||||
table.set_item("a", vm.ctx.new_str("🎅"), &vm).unwrap();
|
||||
table.set_item("b", vm.get_none(), &vm).unwrap();
|
||||
table.set_item("c", vm.ctx.new_str("xda"), &vm).unwrap();
|
||||
let translated = PyString::maketrans(
|
||||
table.into_object(),
|
||||
OptionalArg::Missing,
|
||||
OptionalArg::Missing,
|
||||
&vm,
|
||||
)
|
||||
.unwrap();
|
||||
let text = PyString::from("abc");
|
||||
let translated = text.translate(translated, &vm).unwrap();
|
||||
assert_eq!(translated, "🎅xda".to_owned());
|
||||
let translated = text.translate(vm.ctx.new_int(3), &vm);
|
||||
assert_eq!(
|
||||
translated.unwrap_err().lease_class().name,
|
||||
"TypeError".to_owned()
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ where
|
||||
// CPython-compatible drop implementation
|
||||
let zelf = Self::into_ref(self.clone());
|
||||
if let Some(del_method) = zelf.inner.get_class_attr("__del__") {
|
||||
crate::vm::thread::with_vm(|vm| {
|
||||
crate::vm::thread::with_vm(&zelf, |vm| {
|
||||
if let Err(e) = vm.invoke(&del_method, vec![zelf.clone()]) {
|
||||
// exception in del will be ignored but printed
|
||||
print!("Exception ignored in: ",);
|
||||
|
||||
+32
-30
@@ -221,44 +221,46 @@ fn thread_start_new_thread(
|
||||
kwargs: OptionalArg<PyDictRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<u64> {
|
||||
let args = PyFuncArgs::from((
|
||||
Args::from(args.borrow_value().to_owned()),
|
||||
KwArgs::from(kwargs.map_or_else(Default::default, |k| k.to_attributes())),
|
||||
));
|
||||
let thread_vm = vm.new_thread();
|
||||
let mut thread_builder = thread::Builder::new();
|
||||
let stacksize = vm.state.stacksize.load();
|
||||
if stacksize != 0 {
|
||||
thread_builder = thread_builder.stack_size(stacksize);
|
||||
}
|
||||
let res = thread_builder.spawn(move || {
|
||||
let vm = &thread_vm;
|
||||
let prior_vm = crate::vm::thread::VM.with(|tvm| tvm.replace(vm as *const _));
|
||||
assert!(prior_vm.is_null());
|
||||
let args = Args::from(args.borrow_value().to_owned());
|
||||
let kwargs = KwArgs::from(kwargs.map_or_else(Default::default, |k| k.to_attributes()));
|
||||
if let Err(exc) = func.invoke(PyFuncArgs::from((args, kwargs)), vm) {
|
||||
// TODO: sys.unraisablehook
|
||||
let stderr = std::io::stderr();
|
||||
let mut stderr = stderr.lock();
|
||||
let repr = vm.to_repr(&func.into_object()).ok();
|
||||
let repr = repr
|
||||
.as_ref()
|
||||
.map_or("<object repr() failed>", |s| s.borrow_value());
|
||||
writeln!(stderr, "Exception ignored in thread started by: {}", repr)
|
||||
.and_then(|()| exceptions::write_exception(&mut stderr, vm, &exc))
|
||||
.ok();
|
||||
}
|
||||
SENTINELS.with(|sents| {
|
||||
for lock in sents.replace(Default::default()) {
|
||||
if lock.mu.is_locked() {
|
||||
unsafe { lock.mu.unlock() };
|
||||
}
|
||||
thread_builder
|
||||
.spawn(move || thread_vm.enter(move |vm| run_thread(func, args, vm)))
|
||||
.map(|handle| {
|
||||
vm.state.thread_count.fetch_add(1);
|
||||
thread_to_id(&handle.thread())
|
||||
})
|
||||
.map_err(|err| err.into_pyexception(vm))
|
||||
}
|
||||
|
||||
fn run_thread(func: PyCallable, args: PyFuncArgs, vm: &VirtualMachine) {
|
||||
if let Err(exc) = func.invoke(args, vm) {
|
||||
// TODO: sys.unraisablehook
|
||||
let stderr = std::io::stderr();
|
||||
let mut stderr = stderr.lock();
|
||||
let repr = vm.to_repr(&func.into_object()).ok();
|
||||
let repr = repr
|
||||
.as_ref()
|
||||
.map_or("<object repr() failed>", |s| s.borrow_value());
|
||||
writeln!(stderr, "Exception ignored in thread started by: {}", repr)
|
||||
.and_then(|()| exceptions::write_exception(&mut stderr, vm, &exc))
|
||||
.ok();
|
||||
}
|
||||
SENTINELS.with(|sents| {
|
||||
for lock in sents.replace(Default::default()) {
|
||||
if lock.mu.is_locked() {
|
||||
unsafe { lock.mu.unlock() };
|
||||
}
|
||||
});
|
||||
vm.state.thread_count.fetch_sub(1);
|
||||
}
|
||||
});
|
||||
res.map(|handle| {
|
||||
vm.state.thread_count.fetch_add(1);
|
||||
thread_to_id(&handle.thread())
|
||||
})
|
||||
.map_err(|err| err.into_pyexception(vm))
|
||||
vm.state.thread_count.fetch_sub(1);
|
||||
}
|
||||
|
||||
thread_local!(static SENTINELS: RefCell<Vec<PyLockRef>> = RefCell::default());
|
||||
|
||||
+83
-34
@@ -69,24 +69,39 @@ pub struct VirtualMachine {
|
||||
}
|
||||
|
||||
pub(crate) mod thread {
|
||||
use super::VirtualMachine;
|
||||
use std::cell::Cell;
|
||||
use super::{Interpreter, PyObjectRef, VirtualMachine};
|
||||
use itertools::Itertools;
|
||||
use std::cell::RefCell;
|
||||
use std::ptr::NonNull;
|
||||
use std::thread_local;
|
||||
|
||||
thread_local! {
|
||||
pub(crate) static VM: Cell<*const VirtualMachine> = Cell::new(std::ptr::null());
|
||||
pub(super) static VM_STACK: RefCell<Vec<NonNull<Interpreter>>> = Vec::with_capacity(1).into();
|
||||
}
|
||||
|
||||
pub(crate) fn with_vm<F, R>(f: F) -> R
|
||||
pub(crate) fn with_vm<F, R>(obj: &PyObjectRef, f: F) -> R
|
||||
where
|
||||
F: Fn(&VirtualMachine) -> R,
|
||||
{
|
||||
VM.with(|tvm| {
|
||||
// vm is guaranteed to be existing unless it is not null
|
||||
let pvm = tvm.get();
|
||||
debug_assert!(!pvm.is_null());
|
||||
let vm = unsafe { &*pvm };
|
||||
f(vm)
|
||||
let vm_owns_obj = |intp: NonNull<Interpreter>| {
|
||||
// SAFETY: all references in VM_STACK should be valid
|
||||
let vm = unsafe { &intp.as_ref().vm };
|
||||
crate::obj::objtype::isinstance(obj, &vm.ctx.types.object_type)
|
||||
};
|
||||
VM_STACK.with(|vms| {
|
||||
let intp = match vms.borrow().iter().copied().exactly_one() {
|
||||
Ok(x) => {
|
||||
debug_assert!(vm_owns_obj(x));
|
||||
x
|
||||
}
|
||||
Err(mut others) => others
|
||||
.find(|x| vm_owns_obj(*x))
|
||||
.expect("can't get a vm; none on stack"),
|
||||
};
|
||||
// SAFETY: all references in VM_STACK should be valid, and should not be changed or moved
|
||||
// at least until this function returns and the stack unwinds to an Interpreter::enter call
|
||||
let intp = unsafe { intp.as_ref() };
|
||||
f(&intp.vm)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -191,7 +206,7 @@ impl Default for PySettings {
|
||||
|
||||
impl VirtualMachine {
|
||||
/// Create a new `VirtualMachine` structure.
|
||||
pub fn new(settings: PySettings) -> VirtualMachine {
|
||||
fn new(settings: PySettings) -> VirtualMachine {
|
||||
flame_guard!("new VirtualMachine");
|
||||
let ctx = PyContext::new();
|
||||
|
||||
@@ -244,7 +259,6 @@ impl VirtualMachine {
|
||||
}),
|
||||
initialized: false,
|
||||
};
|
||||
thread::VM.with(|tvm| tvm.replace(&vm as *const _));
|
||||
|
||||
objmodule::init_module_dict(
|
||||
&vm,
|
||||
@@ -316,8 +330,8 @@ impl VirtualMachine {
|
||||
}
|
||||
|
||||
#[cfg(feature = "threading")]
|
||||
pub(crate) fn new_thread(&self) -> VirtualMachine {
|
||||
VirtualMachine {
|
||||
pub(crate) fn new_thread(&self) -> Interpreter {
|
||||
let vm = VirtualMachine {
|
||||
builtins: self.builtins.clone(),
|
||||
sys_module: self.sys_module.clone(),
|
||||
ctx: self.ctx.clone(),
|
||||
@@ -333,7 +347,8 @@ impl VirtualMachine {
|
||||
repr_guards: RefCell::default(),
|
||||
state: self.state.clone(),
|
||||
initialized: self.initialized,
|
||||
}
|
||||
};
|
||||
Interpreter { vm }
|
||||
}
|
||||
|
||||
pub fn run_code_obj(&self, code: PyCodeRef, scope: Scope) -> PyResult {
|
||||
@@ -1526,12 +1541,6 @@ impl VirtualMachine {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for VirtualMachine {
|
||||
fn default() -> Self {
|
||||
VirtualMachine::new(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReprGuard<'vm> {
|
||||
vm: &'vm VirtualMachine,
|
||||
id: usize,
|
||||
@@ -1561,29 +1570,69 @@ impl<'vm> Drop for ReprGuard<'vm> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Interpreter {
|
||||
vm: VirtualMachine,
|
||||
}
|
||||
|
||||
impl Interpreter {
|
||||
pub fn new(settings: PySettings) -> Self {
|
||||
Self {
|
||||
vm: VirtualMachine::new(settings),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_init<F>(settings: PySettings, init: F) -> Self
|
||||
where
|
||||
F: FnOnce(&mut VirtualMachine) -> InitParameter,
|
||||
{
|
||||
let mut vm = VirtualMachine::new(settings);
|
||||
let init = init(&mut vm);
|
||||
vm.initialize(init);
|
||||
Self { vm }
|
||||
}
|
||||
|
||||
pub fn enter<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&VirtualMachine) -> R,
|
||||
{
|
||||
thread::VM_STACK.with(|vms| vms.borrow_mut().push(self.into()));
|
||||
let ret = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&self.vm)));
|
||||
thread::VM_STACK.with(|vms| vms.borrow_mut().pop());
|
||||
ret.unwrap_or_else(|e| std::panic::resume_unwind(e))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Interpreter {
|
||||
fn default() -> Self {
|
||||
Self::new(PySettings::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::VirtualMachine;
|
||||
use super::Interpreter;
|
||||
use crate::obj::{objint, objstr};
|
||||
use num_bigint::ToBigInt;
|
||||
|
||||
#[test]
|
||||
fn test_add_py_integers() {
|
||||
let vm: VirtualMachine = Default::default();
|
||||
let a = vm.ctx.new_int(33_i32);
|
||||
let b = vm.ctx.new_int(12_i32);
|
||||
let res = vm._add(a, b).unwrap();
|
||||
let value = objint::get_value(&res);
|
||||
assert_eq!(*value, 45_i32.to_bigint().unwrap());
|
||||
Interpreter::default().enter(|vm| {
|
||||
let a = vm.ctx.new_int(33_i32);
|
||||
let b = vm.ctx.new_int(12_i32);
|
||||
let res = vm._add(a, b).unwrap();
|
||||
let value = objint::get_value(&res);
|
||||
assert_eq!(*value, 45_i32.to_bigint().unwrap());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiply_str() {
|
||||
let vm: VirtualMachine = Default::default();
|
||||
let a = vm.ctx.new_str(String::from("Hello "));
|
||||
let b = vm.ctx.new_int(4_i32);
|
||||
let res = vm._mul(a, b).unwrap();
|
||||
let value = objstr::borrow_value(&res);
|
||||
assert_eq!(value, String::from("Hello Hello Hello Hello "))
|
||||
Interpreter::default().enter(|vm| {
|
||||
let a = vm.ctx.new_str(String::from("Hello "));
|
||||
let b = vm.ctx.new_int(4_i32);
|
||||
let res = vm._mul(a, b).unwrap();
|
||||
let value = objstr::borrow_value(&res);
|
||||
assert_eq!(value, String::from("Hello Hello Hello Hello "))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -127,13 +127,14 @@ fn browser_request_animation_frame(func: PyCallable, vm: &VirtualMachine) -> PyR
|
||||
let stored_vm = weak_vm
|
||||
.upgrade()
|
||||
.expect("that the vm is valid from inside of request_animation_frame");
|
||||
let vm = &stored_vm.vm;
|
||||
let func = func.clone();
|
||||
let args = vec![vm.ctx.new_float(time)];
|
||||
let _ = vm.invoke(&func.into_object(), args);
|
||||
stored_vm.interp.enter(|vm| {
|
||||
let func = func.clone();
|
||||
let args = vec![vm.ctx.new_float(time)];
|
||||
let _ = vm.invoke(&func.into_object(), args);
|
||||
|
||||
let closure = f.borrow_mut().take();
|
||||
drop(closure);
|
||||
let closure = f.borrow_mut().take();
|
||||
drop(closure);
|
||||
})
|
||||
}) as Box<dyn Fn(f64)>));
|
||||
|
||||
let id = window()
|
||||
@@ -195,26 +196,32 @@ impl PyPromise {
|
||||
let stored_vm = &weak_vm
|
||||
.upgrade()
|
||||
.expect("that the vm is valid when the promise resolves");
|
||||
let vm = &stored_vm.vm;
|
||||
let ret = match prom.await {
|
||||
Ok(val) => {
|
||||
let res = prom.await;
|
||||
match res {
|
||||
Ok(val) => stored_vm.interp.enter(move |vm| {
|
||||
let args = if val.is_null() {
|
||||
vec![]
|
||||
} else {
|
||||
vec![convert::js_to_py(vm, val)]
|
||||
};
|
||||
vm.invoke(&on_fulfill.into_object(), PyFuncArgs::new(args, vec![]))
|
||||
}
|
||||
let res = vm.invoke(&on_fulfill.into_object(), PyFuncArgs::new(args, vec![]));
|
||||
convert::pyresult_to_jsresult(vm, res)
|
||||
}),
|
||||
Err(err) => {
|
||||
if let OptionalArg::Present(on_reject) = on_reject {
|
||||
let err = convert::js_to_py(vm, err);
|
||||
vm.invoke(&on_reject.into_object(), PyFuncArgs::new(vec![err], vec![]))
|
||||
stored_vm.interp.enter(move |vm| {
|
||||
let err = convert::js_to_py(vm, err);
|
||||
let res = vm.invoke(
|
||||
&on_reject.into_object(),
|
||||
PyFuncArgs::new(vec![err], vec![]),
|
||||
);
|
||||
convert::pyresult_to_jsresult(vm, res)
|
||||
})
|
||||
} else {
|
||||
return Err(err);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
};
|
||||
convert::pyresult_to_jsresult(vm, ret)
|
||||
}
|
||||
};
|
||||
|
||||
PyPromise::from_future(ret_future).into_ref(vm)
|
||||
@@ -233,10 +240,11 @@ impl PyPromise {
|
||||
let stored_vm = weak_vm
|
||||
.upgrade()
|
||||
.expect("that the vm is valid when the promise resolves");
|
||||
let vm = &stored_vm.vm;
|
||||
let err = convert::js_to_py(vm, err);
|
||||
let res = vm.invoke(&on_reject.into_object(), PyFuncArgs::new(vec![err], vec![]));
|
||||
convert::pyresult_to_jsresult(vm, res)
|
||||
stored_vm.interp.enter(move |vm| {
|
||||
let err = convert::js_to_py(vm, err);
|
||||
let res = vm.invoke(&on_reject.into_object(), PyFuncArgs::new(vec![err], vec![]));
|
||||
convert::pyresult_to_jsresult(vm, res)
|
||||
})
|
||||
};
|
||||
|
||||
PyPromise::from_future(ret_future).into_ref(vm)
|
||||
@@ -327,13 +335,14 @@ fn browser_load_module(module: PyStringRef, path: PyStringRef, vm: &VirtualMachi
|
||||
let stored_vm = &weak_vm
|
||||
.upgrade()
|
||||
.expect("that the vm is valid when the promise resolves");
|
||||
let vm = &stored_vm.vm;
|
||||
let resp_text = text.as_string().unwrap();
|
||||
let res = import_file(vm, module.borrow_value(), "WEB".to_owned(), resp_text);
|
||||
match res {
|
||||
Ok(_) => Ok(JsValue::null()),
|
||||
Err(err) => Err(convert::py_err_to_js_err(vm, &err)),
|
||||
}
|
||||
stored_vm.interp.enter(move |vm| {
|
||||
let resp_text = text.as_string().unwrap();
|
||||
let res = import_file(vm, module.borrow_value(), "WEB".to_owned(), resp_text);
|
||||
match res {
|
||||
Ok(_) => Ok(JsValue::null()),
|
||||
Err(err) => Err(convert::py_err_to_js_err(vm, &err)),
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Ok(PyPromise::from_future(future).into_object(vm))
|
||||
|
||||
+16
-15
@@ -83,23 +83,24 @@ pub fn py_to_js(vm: &VirtualMachine, py_obj: PyObjectRef) -> JsValue {
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
let vm = &stored_vm_from_wasm(&wasm_vm).vm;
|
||||
let mut py_func_args = PyFuncArgs::default();
|
||||
if let Some(ref args) = args {
|
||||
for arg in args.values() {
|
||||
py_func_args.args.push(js_to_py(vm, arg?));
|
||||
stored_vm_from_wasm(&wasm_vm).interp.enter(move |vm| {
|
||||
let mut py_func_args = PyFuncArgs::default();
|
||||
if let Some(ref args) = args {
|
||||
for arg in args.values() {
|
||||
py_func_args.args.push(js_to_py(vm, arg?));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ref kwargs) = kwargs {
|
||||
for pair in object_entries(kwargs) {
|
||||
let (key, val) = pair?;
|
||||
py_func_args
|
||||
.kwargs
|
||||
.insert(js_sys::JsString::from(key).into(), js_to_py(vm, val));
|
||||
if let Some(ref kwargs) = kwargs {
|
||||
for pair in object_entries(kwargs) {
|
||||
let (key, val) = pair?;
|
||||
py_func_args
|
||||
.kwargs
|
||||
.insert(js_sys::JsString::from(key).into(), js_to_py(vm, val));
|
||||
}
|
||||
}
|
||||
}
|
||||
let result = vm.invoke(&py_obj, py_func_args);
|
||||
pyresult_to_jsresult(vm, result)
|
||||
let result = vm.invoke(&py_obj, py_func_args);
|
||||
pyresult_to_jsresult(vm, result)
|
||||
})
|
||||
};
|
||||
let closure = Closure::wrap(Box::new(closure)
|
||||
as Box<dyn FnMut(Option<Array>, Option<Object>) -> Result<JsValue, JsValue>>);
|
||||
|
||||
+48
-46
@@ -9,7 +9,7 @@ use rustpython_compiler::compile;
|
||||
use rustpython_vm::common::rc::PyRc;
|
||||
use rustpython_vm::pyobject::{ItemProtocol, PyObjectRef, PyObjectWeak, PyValue};
|
||||
use rustpython_vm::scope::{NameProtocol, Scope};
|
||||
use rustpython_vm::{InitParameter, PySettings, VirtualMachine};
|
||||
use rustpython_vm::{InitParameter, Interpreter, PySettings, VirtualMachine};
|
||||
|
||||
use crate::browser_module::setup_browser_module;
|
||||
use crate::convert::{self, PyResultExt};
|
||||
@@ -18,7 +18,7 @@ use crate::wasm_builtins;
|
||||
use rustpython_compiler::mode::Mode;
|
||||
|
||||
pub(crate) struct StoredVirtualMachine {
|
||||
pub vm: VirtualMachine,
|
||||
pub interp: Interpreter,
|
||||
pub scope: RefCell<Scope>,
|
||||
/// you can put a Rc in here, keep it as a Weak, and it'll be held only for
|
||||
/// as long as the StoredVM is alive
|
||||
@@ -27,34 +27,37 @@ pub(crate) struct StoredVirtualMachine {
|
||||
|
||||
impl StoredVirtualMachine {
|
||||
fn new(id: String, inject_browser_module: bool) -> StoredVirtualMachine {
|
||||
let mut settings = PySettings::default();
|
||||
let settings = PySettings {
|
||||
// After js, browser modules injected, the VM will not be initialized.
|
||||
initialization_parameter: InitParameter::NoInitialize,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// After js, browser modules injected, the VM will not be initialized.
|
||||
settings.initialization_parameter = InitParameter::NoInitialize;
|
||||
let mut scope = None;
|
||||
let interp = Interpreter::new_with_init(settings, |vm| {
|
||||
vm.wasm_id = Some(id);
|
||||
|
||||
let mut vm: VirtualMachine = VirtualMachine::new(settings);
|
||||
js_module::setup_js_module(vm);
|
||||
if inject_browser_module {
|
||||
PyRc::get_mut(&mut vm.state).unwrap().stdlib_inits.insert(
|
||||
"_window".to_owned(),
|
||||
Box::new(|vm| {
|
||||
py_module!(vm, "_window", {
|
||||
"window" => js_module::PyJsValue::new(wasm_builtins::window()).into_ref(vm),
|
||||
})
|
||||
}),
|
||||
);
|
||||
setup_browser_module(vm);
|
||||
}
|
||||
|
||||
vm.wasm_id = Some(id);
|
||||
let scope = vm.new_scope_with_builtins();
|
||||
scope = Some(vm.new_scope_with_builtins());
|
||||
|
||||
js_module::setup_js_module(&mut vm);
|
||||
if inject_browser_module {
|
||||
PyRc::get_mut(&mut vm.state).unwrap().stdlib_inits.insert(
|
||||
"_window".to_owned(),
|
||||
Box::new(|vm| {
|
||||
py_module!(vm, "_window", {
|
||||
"window" => js_module::PyJsValue::new(wasm_builtins::window()).into_ref(vm),
|
||||
})
|
||||
}),
|
||||
);
|
||||
setup_browser_module(&mut vm);
|
||||
}
|
||||
|
||||
vm.initialize(InitParameter::InitializeInternal);
|
||||
InitParameter::InitializeInternal
|
||||
});
|
||||
|
||||
StoredVirtualMachine {
|
||||
vm,
|
||||
scope: RefCell::new(scope),
|
||||
interp,
|
||||
scope: RefCell::new(scope.unwrap()),
|
||||
held_objects: RefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
@@ -170,6 +173,13 @@ impl WASMVirtualMachine {
|
||||
Ok(self.with_unchecked(f))
|
||||
}
|
||||
|
||||
pub(crate) fn with_vm<F, R>(&self, f: F) -> Result<R, JsValue>
|
||||
where
|
||||
F: FnOnce(&VirtualMachine, &StoredVirtualMachine) -> R,
|
||||
{
|
||||
self.with(|stored| stored.interp.enter(|vm| f(vm, stored)))
|
||||
}
|
||||
|
||||
pub fn valid(&self) -> bool {
|
||||
STORED_VMS.with(|cell| cell.borrow().contains_key(&self.id))
|
||||
}
|
||||
@@ -201,19 +211,15 @@ impl WASMVirtualMachine {
|
||||
|
||||
#[wasm_bindgen(js_name = addToScope)]
|
||||
pub fn add_to_scope(&self, name: String, value: JsValue) -> Result<(), JsValue> {
|
||||
self.with(
|
||||
move |StoredVirtualMachine {
|
||||
ref vm, ref scope, ..
|
||||
}| {
|
||||
let value = convert::js_to_py(vm, value);
|
||||
scope.borrow_mut().store_name(&vm, &name, value);
|
||||
},
|
||||
)
|
||||
self.with_vm(move |vm, StoredVirtualMachine { ref scope, .. }| {
|
||||
let value = convert::js_to_py(vm, value);
|
||||
scope.borrow_mut().store_name(&vm, &name, value);
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = setStdout)]
|
||||
pub fn set_stdout(&self, stdout: JsValue) -> Result<(), JsValue> {
|
||||
self.with(move |StoredVirtualMachine { ref vm, .. }| {
|
||||
self.with_vm(|vm, _| {
|
||||
fn error() -> JsValue {
|
||||
TypeError::new("Unknown stdout option, please pass a function or 'console'").into()
|
||||
}
|
||||
@@ -249,7 +255,7 @@ impl WASMVirtualMachine {
|
||||
source: &str,
|
||||
imports: Option<Object>,
|
||||
) -> Result<(), JsValue> {
|
||||
self.with(|StoredVirtualMachine { ref vm, .. }| {
|
||||
self.with_vm(|vm, _| {
|
||||
let code = vm
|
||||
.compile(source, Mode::Exec, name.clone())
|
||||
.map_err(convert::syntax_err)?;
|
||||
@@ -284,7 +290,7 @@ impl WASMVirtualMachine {
|
||||
|
||||
#[wasm_bindgen(js_name = injectJSModule)]
|
||||
pub fn inject_js_module(&self, name: String, module: Object) -> Result<(), JsValue> {
|
||||
self.with(|StoredVirtualMachine { ref vm, .. }| {
|
||||
self.with_vm(|vm, _| {
|
||||
let py_module = vm.new_module(&name, vm.ctx.new_dict());
|
||||
for entry in convert::object_entries(&module) {
|
||||
let (key, value) = entry?;
|
||||
@@ -309,17 +315,13 @@ impl WASMVirtualMachine {
|
||||
mode: compile::Mode,
|
||||
source_path: Option<String>,
|
||||
) -> Result<JsValue, JsValue> {
|
||||
self.with(
|
||||
|StoredVirtualMachine {
|
||||
ref vm, ref scope, ..
|
||||
}| {
|
||||
let source_path = source_path.unwrap_or_else(|| "<wasm>".to_owned());
|
||||
let code = vm.compile(source, mode, source_path);
|
||||
let code = code.map_err(convert::syntax_err)?;
|
||||
let result = vm.run_code_obj(code, scope.borrow().clone());
|
||||
convert::pyresult_to_jsresult(vm, result)
|
||||
},
|
||||
)?
|
||||
self.with_vm(|vm, StoredVirtualMachine { ref scope, .. }| {
|
||||
let source_path = source_path.unwrap_or_else(|| "<wasm>".to_owned());
|
||||
let code = vm.compile(source, mode, source_path);
|
||||
let code = code.map_err(convert::syntax_err)?;
|
||||
let result = vm.run_code_obj(code, scope.borrow().clone());
|
||||
convert::pyresult_to_jsresult(vm, result)
|
||||
})?
|
||||
}
|
||||
|
||||
pub fn exec(&self, source: &str, source_path: Option<String>) -> Result<JsValue, JsValue> {
|
||||
|
||||
Reference in new issue
Block a user