diff --git a/src/main.rs b/src/main.rs index a0683ec3e..70adf1008 100644 --- a/src/main.rs +++ b/src/main.rs @@ -65,16 +65,11 @@ fn main() { } fn _run_string(vm: &VirtualMachine, source: &str, source_path: String) -> PyResult { - let code_obj = compile::compile( - source, - &compile::Mode::Exec, - source_path, - vm.ctx.code_type(), - ) - .map_err(|err| { - let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.to_string()) - })?; + let code_obj = + compile::compile(vm, source, &compile::Mode::Exec, source_path).map_err(|err| { + let syntax_error = vm.context().exceptions.syntax_error.clone(); + vm.new_exception(syntax_error, err.to_string()) + })?; // trace!("Code object: {:?}", code_obj.borrow()); let vars = vm.ctx.new_scope(); // Keep track of local variables vm.run_code_obj(code_obj, vars) @@ -115,12 +110,7 @@ fn run_script(vm: &VirtualMachine, script_file: &str) -> PyResult { } fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> Result<(), CompileError> { - match compile::compile( - source, - &compile::Mode::Single, - "".to_string(), - vm.ctx.code_type(), - ) { + match compile::compile(vm, source, &compile::Mode::Single, "".to_string()) { Ok(code) => { if let Err(err) = vm.run_code_obj(code, scope) { print_exception(vm, &err); diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 5ac00561c..c81ee79e9 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -24,6 +24,7 @@ use crate::pyobject::{ }; use crate::vm::VirtualMachine; +use crate::obj::objcode::PyCodeRef; #[cfg(not(target_arch = "wasm32"))] use crate::stdlib::io::io_open; @@ -112,22 +113,17 @@ fn builtin_chr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.new_str(txt)) } -fn builtin_compile(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!( - vm, - args, - required = [ - (source, None), - (filename, Some(vm.ctx.str_type())), - (mode, Some(vm.ctx.str_type())) - ] - ); - let source = objstr::get_value(source); +fn builtin_compile( + source: PyStringRef, + filename: PyStringRef, + mode: PyStringRef, + vm: &VirtualMachine, +) -> PyResult { // TODO: fix this newline bug: - let source = format!("{}\n", source); + let source = format!("{}\n", &source.value); let mode = { - let mode = objstr::get_value(mode); + let mode = &mode.value; if mode == "exec" { compile::Mode::Exec } else if mode == "eval" { @@ -141,9 +137,7 @@ fn builtin_compile(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { } }; - let filename = objstr::get_value(filename); - - compile::compile(&source, &mode, filename, vm.ctx.code_type()).map_err(|err| { + compile::compile(vm, &source, &mode, filename.value.to_string()).map_err(|err| { let syntax_error = vm.context().exceptions.syntax_error.clone(); vm.new_exception(syntax_error, err.to_string()) }) @@ -190,25 +184,23 @@ fn builtin_eval(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { let scope = make_scope(vm, globals, locals)?; // Determine code object: - let code_obj = if objtype::isinstance(source, &vm.ctx.code_type()) { - source.clone() + let code_obj = if let Ok(code_obj) = PyCodeRef::try_from_object(vm, source.clone()) { + code_obj } else if objtype::isinstance(source, &vm.ctx.str_type()) { let mode = compile::Mode::Eval; let source = objstr::get_value(source); // TODO: fix this newline bug: let source = format!("{}\n", source); - compile::compile(&source, &mode, "".to_string(), vm.ctx.code_type()).map_err( - |err| { - let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.to_string()) - }, - )? + compile::compile(vm, &source, &mode, "".to_string()).map_err(|err| { + let syntax_error = vm.context().exceptions.syntax_error.clone(); + vm.new_exception(syntax_error, err.to_string()) + })? } else { return Err(vm.new_type_error("code argument must be str or code object".to_string())); }; // Run the source: - vm.run_code_obj(code_obj.clone(), scope) + vm.run_code_obj(code_obj, scope) } /// Implements `exec` @@ -229,14 +221,12 @@ fn builtin_exec(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { let source = objstr::get_value(source); // TODO: fix this newline bug: let source = format!("{}\n", source); - compile::compile(&source, &mode, "".to_string(), vm.ctx.code_type()).map_err( - |err| { - let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.to_string()) - }, - )? - } else if objtype::isinstance(source, &vm.ctx.code_type()) { - source.clone() + compile::compile(vm, &source, &mode, "".to_string()).map_err(|err| { + let syntax_error = vm.context().exceptions.syntax_error.clone(); + vm.new_exception(syntax_error, err.to_string()) + })? + } else if let Ok(code_obj) = PyCodeRef::try_from_object(vm, source.clone()) { + code_obj } else { return Err(vm.new_type_error("source argument must be str or code object".to_string())); }; diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 46101cdf4..00bafe727 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -8,8 +8,9 @@ use crate::bytecode::{self, CallType, CodeObject, Instruction, Varargs}; use crate::error::CompileError; use crate::obj::objcode; -use crate::obj::objtype::PyClassRef; -use crate::pyobject::{PyObject, PyObjectRef}; +use crate::obj::objcode::PyCodeRef; +use crate::pyobject::PyValue; +use crate::VirtualMachine; use num_complex::Complex64; use rustpython_parser::{ast, parser}; @@ -24,11 +25,11 @@ struct Compiler { /// Compile a given sourcecode into a bytecode object. pub fn compile( + vm: &VirtualMachine, source: &str, mode: &Mode, source_path: String, - code_type: PyClassRef, -) -> Result { +) -> Result { let mut compiler = Compiler::new(); compiler.source_path = Some(source_path); compiler.push_new_code_object("".to_string()); @@ -50,10 +51,7 @@ pub fn compile( let code = compiler.pop_code_object(); trace!("Compilation completed: {:?}", code); - Ok(PyObject::new( - objcode::PyCode::new(code), - code_type.into_object(), - )) + Ok(objcode::PyCode::new(code).into_ref(vm)) } pub enum Mode { diff --git a/vm/src/eval.rs b/vm/src/eval.rs index 202286eb1..6c7b3ca54 100644 --- a/vm/src/eval.rs +++ b/vm/src/eval.rs @@ -8,12 +8,7 @@ use crate::pyobject::PyResult; use crate::vm::VirtualMachine; pub fn eval(vm: &VirtualMachine, source: &str, scope: Scope, source_path: &str) -> PyResult { - match compile::compile( - source, - &compile::Mode::Eval, - source_path.to_string(), - vm.ctx.code_type(), - ) { + match compile::compile(vm, source, &compile::Mode::Eval, source_path.to_string()) { Ok(bytecode) => { debug!("Code object: {:?}", bytecode); vm.run_code_obj(bytecode, scope) diff --git a/vm/src/function.rs b/vm/src/function.rs index a7581d3f2..17e767823 100644 --- a/vm/src/function.rs +++ b/vm/src/function.rs @@ -305,6 +305,13 @@ pub enum OptionalArg { } impl OptionalArg { + pub fn is_present(&self) -> bool { + match self { + Present(_) => true, + Missing => false, + } + } + pub fn into_option(self) -> Option { match self { Present(value) => Some(value), diff --git a/vm/src/import.rs b/vm/src/import.rs index ed5a6d094..936b89680 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -27,10 +27,10 @@ fn import_uncached_module(vm: &VirtualMachine, current_path: PathBuf, module: &s let source = util::read_file(file_path.as_path()) .map_err(|e| vm.new_exception(import_error.clone(), e.description().to_string()))?; let code_obj = compile::compile( + vm, &source, &compile::Mode::Exec, file_path.to_str().unwrap().to_string(), - vm.ctx.code_type(), ) .map_err(|err| { let syntax_error = vm.context().exceptions.syntax_error.clone(); diff --git a/vm/src/obj/objcode.rs b/vm/src/obj/objcode.rs index fda5603f0..7fe54bf51 100644 --- a/vm/src/obj/objcode.rs +++ b/vm/src/obj/objcode.rs @@ -7,9 +7,11 @@ use std::fmt; use crate::bytecode; use crate::function::PyFuncArgs; use crate::obj::objtype::PyClassRef; -use crate::pyobject::{IdProtocol, PyContext, PyObjectRef, PyResult, PyValue, TypeProtocol}; +use crate::pyobject::{IdProtocol, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol}; use crate::vm::VirtualMachine; +pub type PyCodeRef = PyRef; + pub struct PyCode { code: bytecode::CodeObject, } diff --git a/vm/src/obj/objfilter.rs b/vm/src/obj/objfilter.rs index 6fcf84fb4..e547d2c43 100644 --- a/vm/src/obj/objfilter.rs +++ b/vm/src/obj/objfilter.rs @@ -1,13 +1,13 @@ use crate::function::PyFuncArgs; -use crate::pyobject::{ - IdProtocol, PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol, -}; +use crate::pyobject::{IdProtocol, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol}; use crate::vm::VirtualMachine; // Required for arg_check! to use isinstance use super::objbool; use super::objiter; use crate::obj::objtype::PyClassRef; +pub type PyFilterRef = PyRef; + #[derive(Debug)] pub struct PyFilter { predicate: PyObjectRef, @@ -20,20 +20,19 @@ impl PyValue for PyFilter { } } -fn filter_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!( - vm, - args, - required = [(cls, None), (function, None), (iterable, None)] - ); - let iterator = objiter::get_iter(vm, iterable)?; - Ok(PyObject::new( - PyFilter { - predicate: function.clone(), - iterator, - }, - cls.clone(), - )) +fn filter_new( + cls: PyClassRef, + function: PyObjectRef, + iterable: PyObjectRef, + vm: &VirtualMachine, +) -> PyResult { + let iterator = objiter::get_iter(vm, &iterable)?; + + PyFilter { + predicate: function.clone(), + iterator, + } + .into_ref_with_type(vm, cls) } fn filter_next(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/vm/src/obj/objfloat.rs b/vm/src/obj/objfloat.rs index 1abeabba2..958d368a8 100644 --- a/vm/src/obj/objfloat.rs +++ b/vm/src/obj/objfloat.rs @@ -4,7 +4,7 @@ use super::objstr; use super::objtype; use crate::obj::objtype::PyClassRef; use crate::pyobject::{ - IntoPyObject, PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, + IntoPyObject, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, }; use crate::vm::VirtualMachine; use num_bigint::ToBigInt; @@ -155,7 +155,7 @@ impl PyFloatRef { } } - fn new_float(cls: PyObjectRef, arg: PyObjectRef, vm: &VirtualMachine) -> PyResult { + fn new_float(cls: PyClassRef, arg: PyObjectRef, vm: &VirtualMachine) -> PyResult { let value = if objtype::isinstance(&arg, &vm.ctx.float_type()) { get_value(&arg) } else if objtype::isinstance(&arg, &vm.ctx.int_type()) { @@ -193,7 +193,7 @@ impl PyFloatRef { let type_name = objtype::get_type_name(&arg.typ()); return Err(vm.new_type_error(format!("can't convert {} to float", type_name))); }; - Ok(PyObject::new(PyFloat { value }, cls.clone())) + PyFloat { value }.into_ref_with_type(vm, cls) } fn mod_(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { diff --git a/vm/src/obj/objmemory.rs b/vm/src/obj/objmemory.rs index c5926c4ab..7f53fb5ae 100644 --- a/vm/src/obj/objmemory.rs +++ b/vm/src/obj/objmemory.rs @@ -1,8 +1,9 @@ -use crate::function::PyFuncArgs; use crate::obj::objtype::PyClassRef; -use crate::pyobject::{PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol}; +use crate::pyobject::{PyContext, PyObjectRef, PyRef, PyResult, PyValue}; use crate::vm::VirtualMachine; +pub type PyMemoryViewRef = PyRef; + #[derive(Debug)] pub struct PyMemoryView { obj: PyObjectRef, @@ -14,15 +15,13 @@ impl PyValue for PyMemoryView { } } -pub fn new_memory_view(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(cls, None), (bytes_object, None)]); - vm.ctx.set_attr(cls, "obj", bytes_object.clone()); - Ok(PyObject::new( - PyMemoryView { - obj: bytes_object.clone(), - }, - cls.clone(), - )) +pub fn new_memory_view( + cls: PyClassRef, + bytes_object: PyObjectRef, + vm: &VirtualMachine, +) -> PyResult { + vm.ctx.set_attr(&cls, "obj", bytes_object.clone()); + PyMemoryView { obj: bytes_object }.into_ref_with_type(vm, cls) } pub fn init(ctx: &PyContext) { diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index e0ff9b20c..84ba73fe6 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -7,7 +7,7 @@ use crate::obj::objproperty::PropertyBuilder; use crate::obj::objtype::PyClassRef; use crate::pyobject::{ DictProtocol, IdProtocol, PyAttributes, PyContext, PyObject, PyObjectRef, PyResult, PyValue, - TypeProtocol, + TryFromObject, TypeProtocol, }; use crate::vm::VirtualMachine; @@ -22,7 +22,7 @@ impl PyValue for PyInstance { pub fn new_instance(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResult { // more or less __new__ operator - let cls = args.shift(); + let cls = PyClassRef::try_from_object(vm, args.shift())?; Ok(if cls.is(&vm.ctx.object) { PyObject::new_without_dict(PyInstance, cls) } else { diff --git a/vm/src/obj/objproperty.rs b/vm/src/obj/objproperty.rs index 7a9dd8447..c5459a9fb 100644 --- a/vm/src/obj/objproperty.rs +++ b/vm/src/obj/objproperty.rs @@ -200,7 +200,7 @@ impl<'a> PropertyBuilder<'a> { deleter: None, }; - PyObject::new(payload, self.ctx.property_type().into_object()) + PyObject::new(payload, self.ctx.property_type()) } else { let payload = PyReadOnlyProperty { getter: self.getter.expect( @@ -208,7 +208,7 @@ impl<'a> PropertyBuilder<'a> { ), }; - PyObject::new(payload, self.ctx.readonly_property_type().into_object()) + PyObject::new(payload, self.ctx.readonly_property_type()) } } } diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index ad9c7bf36..83d0f9f9f 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -163,12 +163,12 @@ pub fn get_item( if sequence.payload::().is_some() { Ok(PyObject::new( PyList::from(elements.to_vec().get_slice_items(vm, &subscript)?), - sequence.typ(), + sequence.type_pyref(), )) } else if sequence.payload::().is_some() { Ok(PyObject::new( PyTuple::from(elements.to_vec().get_slice_items(vm, &subscript)?), - sequence.typ(), + sequence.type_pyref(), )) } else { panic!("sequence get_item called for non-sequence") diff --git a/vm/src/obj/objslice.rs b/vm/src/obj/objslice.rs index d171b2527..3d955b3f2 100644 --- a/vm/src/obj/objslice.rs +++ b/vm/src/obj/objslice.rs @@ -1,7 +1,7 @@ use num_bigint::BigInt; use crate::function::PyFuncArgs; -use crate::pyobject::{PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol}; +use crate::pyobject::{PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol}; use crate::vm::VirtualMachine; use super::objint; @@ -57,14 +57,13 @@ fn slice_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { Ok((cls, Some(start), Some(stop), step)) } }?; - Ok(PyObject::new( - PySlice { - start: start.map(|x| objint::get_value(x).clone()), - stop: stop.map(|x| objint::get_value(x).clone()), - step: step.map(|x| objint::get_value(x).clone()), - }, - cls.clone(), - )) + PySlice { + start: start.map(|x| objint::get_value(x).clone()), + stop: stop.map(|x| objint::get_value(x).clone()), + step: step.map(|x| objint::get_value(x).clone()), + } + .into_ref_with_type(vm, cls.clone().downcast().unwrap()) + .map(|x| x.into_object()) } fn get_property_value(vm: &VirtualMachine, value: &Option) -> PyResult { diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 81f04603b..b48ba9941 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -241,11 +241,12 @@ pub fn type_new_class( bases.push(vm.ctx.object()); let name = objstr::get_value(name); new( - typ.clone(), + typ.clone().downcast().unwrap(), &name, bases, objdict::py_dict_to_attributes(dict), ) + .map(|x| x.into_object()) } pub fn type_call(class: PyClassRef, args: Args, kwargs: KwArgs, vm: &VirtualMachine) -> PyResult { @@ -365,14 +366,14 @@ fn linearise_mro(mut bases: Vec>) -> Option> { } pub fn new( - typ: PyObjectRef, + typ: PyClassRef, name: &str, bases: Vec, dict: HashMap, -) -> PyResult { +) -> PyResult { let mros = bases.into_iter().map(|x| _mro(&x)).collect(); let mro = linearise_mro(mros).unwrap(); - Ok(PyObject { + let new_type = PyObject { payload: PyClass { name: String::from(name), mro, @@ -380,7 +381,8 @@ pub fn new( dict: Some(RefCell::new(dict)), typ, } - .into_ref()) + .into_ref(); + Ok(new_type.downcast().unwrap()) } #[cfg(test)] @@ -401,23 +403,8 @@ mod tests { let object: PyClassRef = context.object.clone(); let type_type = &context.type_type; - let a = new( - type_type.clone().into_object(), - "A", - vec![object.clone()], - HashMap::new(), - ) - .unwrap(); - let b = new( - type_type.clone().into_object(), - "B", - vec![object.clone()], - HashMap::new(), - ) - .unwrap(); - - let a: PyClassRef = a.downcast().unwrap(); - let b: PyClassRef = b.downcast().unwrap(); + let a = new(type_type.clone(), "A", vec![object.clone()], HashMap::new()).unwrap(); + let b = new(type_type.clone(), "B", vec![object.clone()], HashMap::new()).unwrap(); assert_eq!( map_ids(linearise_mro(vec![ diff --git a/vm/src/obj/objzip.rs b/vm/src/obj/objzip.rs index 63df96f62..e628cb218 100644 --- a/vm/src/obj/objzip.rs +++ b/vm/src/obj/objzip.rs @@ -1,10 +1,12 @@ -use crate::function::PyFuncArgs; -use crate::pyobject::{PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol}; +use crate::function::{Args, PyFuncArgs}; +use crate::pyobject::{PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol}; use crate::vm::VirtualMachine; use super::objiter; use crate::obj::objtype::PyClassRef; +pub type PyZipRef = PyRef; + #[derive(Debug)] pub struct PyZip { iterators: Vec, @@ -16,15 +18,12 @@ impl PyValue for PyZip { } } -fn zip_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { - no_kwargs!(vm, args); - let cls = &args.args[0]; - let iterables = &args.args[1..]; +fn zip_new(cls: PyClassRef, iterables: Args, vm: &VirtualMachine) -> PyResult { let iterators = iterables - .iter() - .map(|iterable| objiter::get_iter(vm, iterable)) + .into_iter() + .map(|iterable| objiter::get_iter(vm, &iterable)) .collect::, _>>()?; - Ok(PyObject::new(PyZip { iterators }, cls.clone())) + PyZip { iterators }.into_ref_with_type(vm, cls) } fn zip_next(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 40a2d56e2..aec210e7a 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -152,14 +152,7 @@ pub struct PyContext { pub fn create_type(name: &str, type_type: &PyClassRef, base: &PyClassRef) -> PyClassRef { let dict = PyAttributes::new(); - let new_type = objtype::new( - type_type.clone().into_object(), - name, - vec![base.clone()], - dict, - ) - .unwrap(); - new_type.downcast().unwrap() + objtype::new(type_type.clone(), name, vec![base.clone()], dict).unwrap() } pub type PyNotImplementedRef = PyRef; @@ -212,13 +205,14 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) { let object_type_ptr = PyObjectRef::into_raw(object_type.clone()) as *mut PyObject; let type_type_ptr = PyObjectRef::into_raw(type_type.clone()) as *mut PyObject; + + let type_type: PyClassRef = type_type.downcast().unwrap(); + let object_type: PyClassRef = object_type.downcast().unwrap(); + ptr::write(&mut (*object_type_ptr).typ, type_type.clone()); ptr::write(&mut (*type_type_ptr).typ, type_type.clone()); - ( - type_type.downcast().unwrap(), - object_type.downcast().unwrap(), - ) + (type_type, object_type) } } @@ -265,7 +259,7 @@ impl PyContext { fn create_object(payload: T, cls: &PyClassRef) -> PyRef { PyRef { - obj: PyObject::new(payload, cls.clone().into_object()), + obj: PyObject::new(payload, cls.clone()), _payload: PhantomData, } } @@ -520,33 +514,27 @@ impl PyContext { } pub fn new_int>(&self, i: T) -> PyObjectRef { - PyObject::new(PyInt::new(i), self.int_type().into_object()) + PyObject::new(PyInt::new(i), self.int_type()) } pub fn new_float(&self, value: f64) -> PyObjectRef { - PyObject::new(PyFloat::from(value), self.float_type().into_object()) + PyObject::new(PyFloat::from(value), self.float_type()) } pub fn new_complex(&self, value: Complex64) -> PyObjectRef { - PyObject::new(PyComplex::from(value), self.complex_type().into_object()) + PyObject::new(PyComplex::from(value), self.complex_type()) } pub fn new_str(&self, s: String) -> PyObjectRef { - PyObject::new(objstr::PyString { value: s }, self.str_type().into_object()) + PyObject::new(objstr::PyString { value: s }, self.str_type()) } pub fn new_bytes(&self, data: Vec) -> PyObjectRef { - PyObject::new( - objbytes::PyBytes::new(data), - self.bytes_type().into_object(), - ) + PyObject::new(objbytes::PyBytes::new(data), self.bytes_type()) } pub fn new_bytearray(&self, data: Vec) -> PyObjectRef { - PyObject::new( - objbytearray::PyByteArray::new(data), - self.bytearray_type().into_object(), - ) + PyObject::new(objbytearray::PyByteArray::new(data), self.bytearray_type()) } pub fn new_bool(&self, b: bool) -> PyObjectRef { @@ -558,32 +546,25 @@ impl PyContext { } pub fn new_tuple(&self, elements: Vec) -> PyObjectRef { - PyObject::new(PyTuple::from(elements), self.tuple_type().into_object()) + PyObject::new(PyTuple::from(elements), self.tuple_type()) } pub fn new_list(&self, elements: Vec) -> PyObjectRef { - PyObject::new(PyList::from(elements), self.list_type().into_object()) + PyObject::new(PyList::from(elements), self.list_type()) } pub fn new_set(&self) -> PyObjectRef { // Initialized empty, as calling __hash__ is required for adding each object to the set // which requires a VM context - this is done in the objset code itself. - PyObject::new(PySet::default(), self.set_type().into_object()) + PyObject::new(PySet::default(), self.set_type()) } pub fn new_dict(&self) -> PyObjectRef { - PyObject::new(PyDict::default(), self.dict_type().into_object()) + PyObject::new(PyDict::default(), self.dict_type()) } pub fn new_class(&self, name: &str, base: PyClassRef) -> PyClassRef { - let typ = objtype::new( - self.type_type().into_object(), - name, - vec![base], - PyAttributes::new(), - ) - .unwrap(); - typ.downcast().unwrap() + objtype::new(self.type_type(), name, vec![base], PyAttributes::new()).unwrap() } pub fn new_scope(&self) -> Scope { @@ -596,7 +577,7 @@ impl PyContext { name: name.to_string(), dict, }, - self.module_type.clone().into_object(), + self.module_type.clone(), ) } @@ -606,12 +587,12 @@ impl PyContext { { PyObject::new( PyBuiltinFunction::new(f.into_func()), - self.builtin_function_or_method_type().into_object(), + self.builtin_function_or_method_type(), ) } pub fn new_frame(&self, code: PyObjectRef, scope: Scope) -> PyObjectRef { - PyObject::new(Frame::new(code, scope), self.frame_type().into_object()) + PyObject::new(Frame::new(code, scope), self.frame_type()) } pub fn new_property(&self, f: F) -> PyObjectRef @@ -622,7 +603,7 @@ impl PyContext { } pub fn new_code_object(&self, code: bytecode::CodeObject) -> PyObjectRef { - PyObject::new(objcode::PyCode::new(code), self.code_type().into_object()) + PyObject::new(objcode::PyCode::new(code), self.code_type()) } pub fn new_function( @@ -633,21 +614,18 @@ impl PyContext { ) -> PyObjectRef { PyObject::new( PyFunction::new(code_obj, scope, defaults), - self.function_type().into_object(), + self.function_type(), ) } pub fn new_bound_method(&self, function: PyObjectRef, object: PyObjectRef) -> PyObjectRef { - PyObject::new( - PyMethod::new(object, function), - self.bound_method_type().into_object(), - ) + PyObject::new(PyMethod::new(object, function), self.bound_method_type()) } pub fn new_instance(&self, class: PyClassRef, dict: Option) -> PyObjectRef { let dict = dict.unwrap_or_default(); PyObject { - typ: class.into_object(), + typ: class, dict: Some(RefCell::new(dict)), payload: objobject::PyInstance, } @@ -716,7 +694,7 @@ pub struct PyObject where T: ?Sized + PyObjectPayload, { - pub typ: PyObjectRef, + pub typ: PyClassRef, pub dict: Option>, // __dict__ member pub payload: T, } @@ -896,7 +874,7 @@ where T: ?Sized + PyObjectPayload, { fn type_ref(&self) -> &PyObjectRef { - &self.typ + self.typ.as_object() } } @@ -1124,7 +1102,7 @@ where T: PyValue + Sized, { fn into_pyobject(self, vm: &VirtualMachine) -> PyResult { - Ok(PyObject::new(self, T::class(vm).into_object())) + Ok(PyObject::new(self, T::class(vm))) } } @@ -1146,7 +1124,7 @@ impl PyObject where T: Sized + PyObjectPayload, { - pub fn new(payload: T, typ: PyObjectRef) -> PyObjectRef { + pub fn new(payload: T, typ: PyClassRef) -> PyObjectRef { PyObject { typ, dict: Some(RefCell::new(PyAttributes::new())), @@ -1155,7 +1133,7 @@ where .into_ref() } - pub fn new_without_dict(payload: T, typ: PyObjectRef) -> PyObjectRef { + pub fn new_without_dict(payload: T, typ: PyClassRef) -> PyObjectRef { PyObject { typ, dict: None, @@ -1187,7 +1165,7 @@ pub trait PyValue: fmt::Debug + Sized + 'static { fn into_ref(self, vm: &VirtualMachine) -> PyRef { PyRef { - obj: PyObject::new(self, Self::class(vm).into_object()), + obj: PyObject::new(self, Self::class(vm)), _payload: PhantomData, } } @@ -1196,7 +1174,7 @@ pub trait PyValue: fmt::Debug + Sized + 'static { let class = Self::class(vm); if objtype::issubclass(&cls, &class) { Ok(PyRef { - obj: PyObject::new(self, cls.obj), + obj: PyObject::new(self, cls), _payload: PhantomData, }) } else { diff --git a/vm/src/stdlib/re.rs b/vm/src/stdlib/re.rs index 57db3f0a8..4dab1b0c3 100644 --- a/vm/src/stdlib/re.rs +++ b/vm/src/stdlib/re.rs @@ -4,16 +4,13 @@ * This module fits the python re interface onto the rust regular expression * system. */ - -use std::path::PathBuf; - use regex::{Match, Regex}; use crate::function::PyFuncArgs; -use crate::import; use crate::obj::objstr; +use crate::obj::objstr::PyStringRef; use crate::obj::objtype::PyClassRef; -use crate::pyobject::{PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol}; +use crate::pyobject::{PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol}; use crate::vm::VirtualMachine; impl PyValue for Regex { @@ -55,7 +52,8 @@ fn re_match(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { (string, Some(vm.ctx.str_type())) ] ); - let regex = make_regex(vm, pattern)?; + let pattern_str = objstr::get_value(&pattern); + let regex = make_regex(vm, &pattern_str)?; let search_text = objstr::get_value(string); do_match(vm, ®ex, search_text) @@ -74,8 +72,8 @@ fn re_search(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { ] ); - // let pattern_str = objstr::get_value(&pattern); - let regex = make_regex(vm, pattern)?; + let pattern_str = objstr::get_value(&pattern); + let regex = make_regex(vm, &pattern_str)?; let search_text = objstr::get_value(string); do_search(vm, ®ex, search_text) @@ -93,10 +91,8 @@ fn do_search(vm: &VirtualMachine, regex: &Regex, search_text: String) -> PyResul } } -fn make_regex(vm: &VirtualMachine, pattern: &PyObjectRef) -> PyResult { - let pattern_str = objstr::get_value(pattern); - - match Regex::new(&pattern_str) { +fn make_regex(vm: &VirtualMachine, pattern: &str) -> PyResult { + match Regex::new(pattern) { Ok(regex) => Ok(regex), Err(err) => Err(vm.new_value_error(format!("Error in regex: {:?}", err))), } @@ -117,39 +113,24 @@ impl PyValue for PyMatch { /// Take a found regular expression and convert it to proper match object. fn create_match(vm: &VirtualMachine, match_value: &Match) -> PyResult { - // Return match object: - // TODO: implement match object - // TODO: how to refer to match object defined in this - let module = import::import_module(vm, PathBuf::default(), "re").unwrap(); - let match_class = vm.get_attribute(module, "Match").unwrap(); - // let mo = vm.invoke(match_class, PyFuncArgs::default())?; // let txt = vm.ctx.new_str(result.as_str().to_string()); // vm.ctx.set_attr(&mo, "str", txt); - let match_value = PyMatch { + Ok(PyMatch { start: match_value.start(), end: match_value.end(), - }; - - Ok(PyObject::new(match_value, match_class.clone())) + } + .into_ref(vm) + .into_object()) } /// Compile a regular expression into a Pattern object. /// See also: /// https://docs.python.org/3/library/re.html#re.compile -fn re_compile(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!( - vm, - args, - required = [(pattern, Some(vm.ctx.str_type()))] // TODO: flags=0 - ); +fn re_compile(pattern: PyStringRef, vm: &VirtualMachine) -> PyResult> { + let regex = make_regex(vm, &pattern.value)?; - let regex = make_regex(vm, pattern)?; - // TODO: retrieval of this module is akward: - let module = import::import_module(vm, PathBuf::default(), "re").unwrap(); - let pattern_class = vm.get_attribute(module, "Pattern").unwrap(); - - Ok(PyObject::new(regex, pattern_class.clone())) + Ok(regex.into_ref(vm)) } fn pattern_match(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 4a3cc3abc..cde574fbc 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -19,6 +19,7 @@ use crate::function::PyFuncArgs; use crate::obj::objbool; use crate::obj::objbuiltinfunc::PyBuiltinFunction; use crate::obj::objcode; +use crate::obj::objcode::PyCodeRef; use crate::obj::objframe; use crate::obj::objfunction::{PyFunction, PyMethod}; use crate::obj::objgenerator; @@ -72,8 +73,8 @@ impl VirtualMachine { } } - pub fn run_code_obj(&self, code: PyObjectRef, scope: Scope) -> PyResult { - let frame = self.ctx.new_frame(code, scope); + pub fn run_code_obj(&self, code: PyCodeRef, scope: Scope) -> PyResult { + let frame = self.ctx.new_frame(code.into_object(), scope); self.run_frame_full(frame) } diff --git a/wasm/lib/src/browser_module.rs b/wasm/lib/src/browser_module.rs index 710b18e63..a48cf3d34 100644 --- a/wasm/lib/src/browser_module.rs +++ b/wasm/lib/src/browser_module.rs @@ -7,12 +7,12 @@ use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; use wasm_bindgen_futures::{future_to_promise, JsFuture}; -use rustpython_vm::function::PyFuncArgs; +use rustpython_vm::function::{OptionalArg, PyFuncArgs}; use rustpython_vm::import::import_module; use rustpython_vm::obj::objtype::PyClassRef; use rustpython_vm::obj::{objint, objstr}; use rustpython_vm::pyobject::{ - PyContext, PyObject, PyObjectRef, PyResult, PyValue, TryFromObject, TypeProtocol, + PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, }; use rustpython_vm::VirtualMachine; @@ -45,8 +45,6 @@ impl FetchResponseFormat { fn browser_fetch(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(url, Some(vm.ctx.str_type()))]); - let promise_type = import_promise_type(vm)?; - let response_format = args.get_optional_kwarg_with_type("response_format", vm.ctx.str_type(), vm)?; let method = args.get_optional_kwarg_with_type("method", vm.ctx.str_type(), vm)?; @@ -102,7 +100,7 @@ fn browser_fetch(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { }) .and_then(JsFuture::from); - Ok(PyPromise::new_obj(promise_type, future_to_promise(future))) + Ok(PyPromise::from_future(future).into_ref(vm).into_object()) } fn browser_request_animation_frame(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -159,6 +157,8 @@ fn browser_cancel_animation_frame(vm: &VirtualMachine, args: PyFuncArgs) -> PyRe Ok(vm.get_none()) } +pub type PyPromiseRef = PyRef; + #[derive(Debug)] pub struct PyPromise { value: Promise, @@ -171,8 +171,15 @@ impl PyValue for PyPromise { } impl PyPromise { - pub fn new_obj(promise_type: PyClassRef, value: Promise) -> PyObjectRef { - PyObject::new(PyPromise { value }, promise_type.into_object()) + pub fn new(promise: Promise) -> PyPromise { + PyPromise { value: promise } + } + + pub fn from_future(future: F) -> PyPromise + where + F: Future + 'static, + { + PyPromise::new(future_to_promise(future)) } } @@ -193,26 +200,17 @@ pub fn import_promise_type(vm: &VirtualMachine) -> PyResult { } } -fn promise_then(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { - let promise_type = import_promise_type(vm)?; - arg_check!( - vm, - args, - required = [ - (zelf, Some(promise_type.clone())), - (on_fulfill, Some(vm.ctx.function_type())) - ], - optional = [(on_reject, Some(vm.ctx.function_type()))] - ); - - let on_fulfill = on_fulfill.clone(); - let on_reject = on_reject.cloned(); +fn promise_then( + zelf: PyPromiseRef, + on_fulfill: PyObjectRef, + on_reject: OptionalArg, + vm: &VirtualMachine, +) -> PyPromise { + let on_reject = on_reject.into_option(); let acc_vm = AccessibleVM::from(vm); - let promise = get_promise_value(zelf); - - let ret_future = JsFuture::from(promise).then(move |res| { + let ret_future = JsFuture::from(zelf.value.clone()).then(move |res| { let stored_vm = &acc_vm .upgrade() .expect("that the vm is valid when the promise resolves"); @@ -234,29 +232,13 @@ fn promise_then(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { convert::pyresult_to_jsresult(vm, ret) }); - let ret_promise = future_to_promise(ret_future); - - Ok(PyPromise::new_obj(promise_type, ret_promise)) + PyPromise::from_future(ret_future) } -fn promise_catch(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { - let promise_type = import_promise_type(vm)?; - arg_check!( - vm, - args, - required = [ - (zelf, Some(promise_type.clone())), - (on_reject, Some(vm.ctx.function_type())) - ] - ); - - let on_reject = on_reject.clone(); - +fn promise_catch(zelf: PyPromiseRef, on_reject: PyObjectRef, vm: &VirtualMachine) -> PyPromise { let acc_vm = AccessibleVM::from(vm); - let promise = get_promise_value(zelf); - - let ret_future = JsFuture::from(promise).then(move |res| match res { + let ret_future = JsFuture::from(zelf.value.clone()).then(move |res| match res { Ok(val) => Ok(val), Err(err) => { let stored_vm = acc_vm @@ -269,9 +251,7 @@ fn promise_catch(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { } }); - let ret_promise = future_to_promise(ret_future); - - Ok(PyPromise::new_obj(promise_type, ret_promise)) + PyPromise::from_future(ret_future) } fn browser_alert(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/wasm/lib/src/convert.rs b/wasm/lib/src/convert.rs index c7ba1c616..41f43778f 100644 --- a/wasm/lib/src/convert.rs +++ b/wasm/lib/src/convert.rs @@ -4,7 +4,7 @@ use wasm_bindgen::{closure::Closure, prelude::*, JsCast}; use rustpython_vm::function::PyFuncArgs; use rustpython_vm::obj::{objbytes, objint, objsequence, objtype}; -use rustpython_vm::pyobject::{DictProtocol, PyObjectRef, PyResult}; +use rustpython_vm::pyobject::{DictProtocol, PyObjectRef, PyResult, PyValue}; use rustpython_vm::VirtualMachine; use crate::browser_module; @@ -159,8 +159,10 @@ pub fn js_to_py(vm: &VirtualMachine, js_val: JsValue) -> PyObjectRef { if js_val.is_object() { if let Some(promise) = js_val.dyn_ref::() { // the browser module might not be injected - if let Ok(promise_type) = browser_module::import_promise_type(vm) { - return browser_module::PyPromise::new_obj(promise_type, promise.clone()); + if let Ok(_) = browser_module::import_promise_type(vm) { + return browser_module::PyPromise::new(promise.clone()) + .into_ref(vm) + .into_object(); } } if Array::is_array(&js_val) { diff --git a/wasm/lib/src/vm_class.rs b/wasm/lib/src/vm_class.rs index fd2181182..2d20bc37a 100644 --- a/wasm/lib/src/vm_class.rs +++ b/wasm/lib/src/vm_class.rs @@ -285,8 +285,7 @@ impl WASMVirtualMachine { ref vm, ref scope, .. }| { source.push('\n'); - let code = - compile::compile(&source, &mode, "".to_string(), vm.ctx.code_type()); + let code = compile::compile(vm, &source, &mode, "".to_string()); let code = code.map_err(|err| { let js_err = SyntaxError::new(&format!("Error parsing Python code: {}", err)); if let rustpython_vm::error::CompileError::Parse(ref parse_error) = err {