Merge remote-tracking branch 'origin/master' into joey/range-getitem-either

This commit is contained in:
Joey
2019-03-23 15:50:12 -07:00
22 changed files with 189 additions and 283 deletions

View File

@@ -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,
"<stdin>".to_string(),
vm.ctx.code_type(),
) {
match compile::compile(vm, source, &compile::Mode::Single, "<stdin>".to_string()) {
Ok(code) => {
if let Err(err) = vm.run_code_obj(code, scope) {
print_exception(vm, &err);

View File

@@ -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<PyCodeRef> {
// 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, "<string>".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, "<string>".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, "<string>".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, "<string>".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()));
};

View File

@@ -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<PyObjectRef, CompileError> {
) -> Result<PyCodeRef, CompileError> {
let mut compiler = Compiler::new();
compiler.source_path = Some(source_path);
compiler.push_new_code_object("<module>".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 {

View File

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

View File

@@ -305,6 +305,13 @@ pub enum OptionalArg<T> {
}
impl<T> OptionalArg<T> {
pub fn is_present(&self) -> bool {
match self {
Present(_) => true,
Missing => false,
}
}
pub fn into_option(self) -> Option<T> {
match self {
Present(value) => Some(value),

View File

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

View File

@@ -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<PyCode>;
pub struct PyCode {
code: bytecode::CodeObject,
}

View File

@@ -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<PyFilter>;
#[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<PyFilterRef> {
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 {

View File

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

View File

@@ -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<PyMemoryView>;
#[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<PyMemoryViewRef> {
vm.ctx.set_attr(&cls, "obj", bytes_object.clone());
PyMemoryView { obj: bytes_object }.into_ref_with_type(vm, cls)
}
pub fn init(ctx: &PyContext) {

View File

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

View File

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

View File

@@ -163,12 +163,12 @@ pub fn get_item(
if sequence.payload::<PyList>().is_some() {
Ok(PyObject::new(
PyList::from(elements.to_vec().get_slice_items(vm, &subscript)?),
sequence.typ(),
sequence.type_pyref(),
))
} else if sequence.payload::<PyTuple>().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")

View File

@@ -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<BigInt>) -> PyResult {

View File

@@ -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<Vec<PyClassRef>>) -> Option<Vec<PyClassRef>> {
}
pub fn new(
typ: PyObjectRef,
typ: PyClassRef,
name: &str,
bases: Vec<PyClassRef>,
dict: HashMap<String, PyObjectRef>,
) -> PyResult {
) -> PyResult<PyClassRef> {
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![

View File

@@ -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<PyZip>;
#[derive(Debug)]
pub struct PyZip {
iterators: Vec<PyObjectRef>,
@@ -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<PyZipRef> {
let iterators = iterables
.iter()
.map(|iterable| objiter::get_iter(vm, iterable))
.into_iter()
.map(|iterable| objiter::get_iter(vm, &iterable))
.collect::<Result<Vec<_>, _>>()?;
Ok(PyObject::new(PyZip { iterators }, cls.clone()))
PyZip { iterators }.into_ref_with_type(vm, cls)
}
fn zip_next(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {

View File

@@ -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<PyNotImplemented>;
@@ -212,13 +205,14 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
let object_type_ptr = PyObjectRef::into_raw(object_type.clone()) as *mut PyObject<PyClass>;
let type_type_ptr = PyObjectRef::into_raw(type_type.clone()) as *mut PyObject<PyClass>;
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<T: PyObjectPayload>(payload: T, cls: &PyClassRef) -> PyRef<T> {
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<T: Into<BigInt>>(&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<u8>) -> 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<u8>) -> 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>) -> 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>) -> 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<F, I, V>(&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<PyAttributes>) -> 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<T>
where
T: ?Sized + PyObjectPayload,
{
pub typ: PyObjectRef,
pub typ: PyClassRef,
pub dict: Option<RefCell<PyAttributes>>, // __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<T> PyObject<T>
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<Self> {
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 {

View File

@@ -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, &regex, 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, &regex, 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<Regex> {
let pattern_str = objstr::get_value(pattern);
match Regex::new(&pattern_str) {
fn make_regex(vm: &VirtualMachine, pattern: &str) -> PyResult<Regex> {
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<PyRef<Regex>> {
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 {

View File

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

View File

@@ -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<PyPromise>;
#[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<F>(future: F) -> PyPromise
where
F: Future<Item = JsValue, Error = JsValue> + 'static,
{
PyPromise::new(future_to_promise(future))
}
}
@@ -193,26 +200,17 @@ pub fn import_promise_type(vm: &VirtualMachine) -> PyResult<PyClassRef> {
}
}
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<PyObjectRef>,
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 {

View File

@@ -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::<Promise>() {
// 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) {

View File

@@ -285,8 +285,7 @@ impl WASMVirtualMachine {
ref vm, ref scope, ..
}| {
source.push('\n');
let code =
compile::compile(&source, &mode, "<wasm>".to_string(), vm.ctx.code_type());
let code = compile::compile(vm, &source, &mode, "<wasm>".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 {