From 430bc4bac2217c3fe5dc6c06e6eda28272cb93d6 Mon Sep 17 00:00:00 2001
From: coolreader18 <33094578+coolreader18@users.noreply.github.com>
Date: Sat, 23 Mar 2019 09:35:53 -0500
Subject: [PATCH 01/51] Fix vm.import when there are no frames on stack
---
vm/src/builtins.rs | 11 ++++++++---
vm/src/obj/objsuper.rs | 8 +++++---
vm/src/vm.rs | 30 +++++++++++++++++++-----------
3 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs
index 6d3d512a79..a81273e60c 100644
--- a/vm/src/builtins.rs
+++ b/vm/src/builtins.rs
@@ -700,9 +700,14 @@ fn builtin_import(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
]
);
let current_path = {
- let mut source_pathbuf = PathBuf::from(&vm.current_frame().code.source_path);
- source_pathbuf.pop();
- source_pathbuf
+ match vm.current_frame() {
+ Some(frame) => {
+ let mut source_pathbuf = PathBuf::from(&frame.code.source_path);
+ source_pathbuf.pop();
+ source_pathbuf
+ }
+ None => PathBuf::new(),
+ }
};
import_module(vm, current_path, &objstr::get_value(name))
diff --git a/vm/src/obj/objsuper.rs b/vm/src/obj/objsuper.rs
index 2b2be02414..43161ae6b7 100644
--- a/vm/src/obj/objsuper.rs
+++ b/vm/src/obj/objsuper.rs
@@ -129,13 +129,15 @@ fn super_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
let py_obj = if let Some(obj) = py_obj {
obj.clone()
} else {
- let frame = vm.current_frame();
+ let frame = vm.current_frame().expect("no current frame for super()");
if let Some(first_arg) = frame.code.arg_names.get(0) {
match vm.get_locals().get_item(first_arg) {
Some(obj) => obj.clone(),
_ => {
- return Err(vm
- .new_type_error(format!("super arguement {} was not supplied", first_arg)));
+ return Err(vm.new_type_error(format!(
+ "super arguement {} was not supplied",
+ first_arg
+ )));
}
}
} else {
diff --git a/vm/src/vm.rs b/vm/src/vm.rs
index 029588d130..05a115732b 100644
--- a/vm/src/vm.rs
+++ b/vm/src/vm.rs
@@ -91,19 +91,28 @@ impl VirtualMachine {
result
}
- pub fn current_frame(&self) -> Ref {
- Ref::map(self.frames.borrow(), |frames| {
- let index = frames.len() - 1;
- let current_frame = &frames[index];
- objframe::get_value(current_frame)
- })
+ pub fn current_frame(&self) -> Option[> {
+ let frames = self.frames.borrow();
+ if frames.is_empty() {
+ None
+ } else {
+ Some(Ref::map(self.frames.borrow(), |frames| {
+ objframe::get_value(frames.last().unwrap())
+ }))
+ }
}
pub fn current_scope(&self) -> Ref {
- let frame = self.current_frame();
+ let frame = self
+ .current_frame()
+ .expect("called current_scope but no frames on the stack");
Ref::map(frame, |f| &f.scope)
}
+ pub fn try_class(&self, module: &str, class: &str) -> PyResult {
+ self.get_attribute(self.import(module)?, class)
+ }
+
pub fn class(&self, module: &str, class: &str) -> PyObjectRef {
let module = self
.import(module)
@@ -246,10 +255,9 @@ impl VirtualMachine {
}
pub fn import(&self, module: &str) -> PyResult {
- let builtins_import = self.builtins.get_item("__import__");
- match builtins_import {
- Some(func) => self.invoke(func, vec![self.ctx.new_str(module.to_string())]),
- None => Err(self.new_exception(
+ match self.get_attribute(self.builtins.clone(), "__import__") {
+ Ok(func) => self.invoke(func, vec![self.ctx.new_str(module.to_string())]),
+ Err(_) => Err(self.new_exception(
self.ctx.exceptions.import_error.clone(),
"__import__ not found".to_string(),
)),
From a830d8e131bf5d4f5debbc054814bbbbe4777535 Mon Sep 17 00:00:00 2001
From: coolreader18 <33094578+coolreader18@users.noreply.github.com>
Date: Sat, 23 Mar 2019 09:36:15 -0500
Subject: [PATCH 02/51] Add PyDocument and PyElement
---
vm/src/function.rs | 1 +
wasm/lib/src/browser_module.rs | 113 ++++++++++++++++++++++++++-------
wasm/lib/src/convert.rs | 4 +-
wasm/lib/src/vm_class.rs | 1 -
4 files changed, 94 insertions(+), 25 deletions(-)
diff --git a/vm/src/function.rs b/vm/src/function.rs
index 7159427e56..3093b8c5f5 100644
--- a/vm/src/function.rs
+++ b/vm/src/function.rs
@@ -304,6 +304,7 @@ pub enum OptionalArg {
}
impl OptionalArg {
+ #[inline]
pub fn into_option(self) -> Option {
match self {
Present(value) => Some(value),
diff --git a/wasm/lib/src/browser_module.rs b/wasm/lib/src/browser_module.rs
index 7fc2a2476e..13f1404ab2 100644
--- a/wasm/lib/src/browser_module.rs
+++ b/wasm/lib/src/browser_module.rs
@@ -1,5 +1,3 @@
-use std::path::PathBuf;
-
use futures::Future;
use js_sys::Promise;
use num_traits::cast::ToPrimitive;
@@ -7,11 +5,13 @@ use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::{future_to_promise, JsFuture};
-use rustpython_vm::function::PyFuncArgs;
-use rustpython_vm::import::import_module;
-use rustpython_vm::obj::{objint, objstr};
+use rustpython_vm::function::{OptionalArg, PyFuncArgs};
+use rustpython_vm::obj::{
+ objint,
+ objstr::{self, PyStringRef},
+};
use rustpython_vm::pyobject::{
- AttributeProtocol, PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol,
+ PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
};
use rustpython_vm::VirtualMachine;
@@ -44,7 +44,7 @@ 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 promise_type = vm.try_class("browser", "Promise")?;
let response_format =
args.get_optional_kwarg_with_type("response_format", vm.ctx.str_type(), vm)?;
@@ -165,7 +165,7 @@ pub struct PyPromise {
impl PyValue for PyPromise {
fn class(vm: &VirtualMachine) -> PyObjectRef {
- vm.class(BROWSER_NAME, "Promise")
+ vm.class("browser", "Promise")
}
}
@@ -182,15 +182,8 @@ pub fn get_promise_value(obj: &PyObjectRef) -> Promise {
panic!("Inner error getting promise")
}
-pub fn import_promise_type(vm: &VirtualMachine) -> PyResult {
- match import_module(vm, PathBuf::default(), BROWSER_NAME)?.get_attr("Promise") {
- Some(promise) => Ok(promise),
- None => Err(vm.new_not_implemented_error("No Promise".to_string())),
- }
-}
-
fn promise_then(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
- let promise_type = import_promise_type(vm)?;
+ let promise_type = vm.try_class("browser", "Promise")?;
arg_check!(
vm,
args,
@@ -236,7 +229,7 @@ fn promise_then(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
}
fn promise_catch(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
- let promise_type = import_promise_type(vm)?;
+ let promise_type = vm.try_class("browser", "Promise")?;
arg_check!(
vm,
args,
@@ -270,6 +263,65 @@ fn promise_catch(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
Ok(PyPromise::new_obj(promise_type, ret_promise))
}
+#[derive(Debug)]
+struct PyDocument {
+ doc: web_sys::Document,
+}
+type PyDocumentRef = PyRef;
+
+impl PyValue for PyDocument {
+ fn class(vm: &VirtualMachine) -> PyObjectRef {
+ vm.class("browser", "Document")
+ }
+}
+
+fn document_query(zelf: PyDocumentRef, query: PyStringRef, vm: &VirtualMachine) -> PyResult {
+ let elem = zelf
+ .doc
+ .query_selector(&query.value)
+ .map_err(|err| convert::js_py_typeerror(vm, err))?;
+ let elem = match elem {
+ Some(elem) => PyElement { elem }.into_ref(vm).into_object(),
+ None => vm.get_none(),
+ };
+ Ok(elem)
+}
+
+#[derive(Debug)]
+struct PyElement {
+ elem: web_sys::Element,
+}
+type PyElementRef = PyRef;
+
+impl PyValue for PyElement {
+ fn class(vm: &VirtualMachine) -> PyObjectRef {
+ vm.class("browser", "Element")
+ }
+}
+
+fn elem_get_attr(
+ zelf: PyElementRef,
+ attr: PyStringRef,
+ default: OptionalArg,
+ vm: &VirtualMachine,
+) -> PyObjectRef {
+ match zelf.elem.get_attribute(&attr.value) {
+ Some(s) => vm.new_str(s),
+ None => default.into_option().unwrap_or_else(|| vm.get_none()),
+ }
+}
+
+fn elem_set_attr(
+ zelf: PyElementRef,
+ attr: PyStringRef,
+ value: PyStringRef,
+ vm: &VirtualMachine,
+) -> PyResult<()> {
+ zelf.elem
+ .set_attribute(&attr.value, &value.value)
+ .map_err(|err| convert::js_to_py(vm, err))
+}
+
fn browser_alert(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(message, Some(vm.ctx.str_type()))]);
@@ -315,19 +367,36 @@ fn browser_prompt(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
Ok(result)
}
-const BROWSER_NAME: &str = "browser";
-
pub fn make_module(ctx: &PyContext) -> PyObjectRef {
let promise = py_class!(ctx, "Promise", ctx.object(), {
"then" => ctx.new_rustfunc(promise_then),
- "catch" => ctx.new_rustfunc(promise_catch)
+ "catch" => ctx.new_rustfunc(promise_catch),
+ });
+
+ let document_class = py_class!(ctx, "Document", ctx.object(), {
+ "query" => ctx.new_rustfunc(document_query),
+ });
+
+ let document = PyObject::new(
+ PyDocument {
+ doc: window().document().expect("Document missing from window"),
+ },
+ document_class.clone(),
+ );
+
+ let element = py_class!(ctx, "Element", ctx.object(), {
+ "get_attr" => ctx.new_rustfunc(elem_get_attr),
+ "set_attr" => ctx.new_rustfunc(elem_set_attr),
});
- py_module!(ctx, BROWSER_NAME, {
+ py_module!(ctx, "browser", {
"fetch" => ctx.new_rustfunc(browser_fetch),
"request_animation_frame" => ctx.new_rustfunc(browser_request_animation_frame),
"cancel_animation_frame" => ctx.new_rustfunc(browser_cancel_animation_frame),
"Promise" => promise,
+ "Document" => document_class,
+ "document" => document,
+ "Element" => element,
"alert" => ctx.new_rustfunc(browser_alert),
"confirm" => ctx.new_rustfunc(browser_confirm),
"prompt" => ctx.new_rustfunc(browser_prompt),
@@ -337,5 +406,5 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
pub fn setup_browser_module(vm: &VirtualMachine) {
vm.stdlib_inits
.borrow_mut()
- .insert(BROWSER_NAME.to_string(), Box::new(make_module));
+ .insert("browser".to_string(), Box::new(make_module));
}
diff --git a/wasm/lib/src/convert.rs b/wasm/lib/src/convert.rs
index 122ff1763e..b7f9048e91 100644
--- a/wasm/lib/src/convert.rs
+++ b/wasm/lib/src/convert.rs
@@ -114,7 +114,7 @@ pub fn py_to_js(vm: &VirtualMachine, py_obj: PyObjectRef) -> JsValue {
}
}
// the browser module might not be injected
- if let Ok(promise_type) = browser_module::import_promise_type(vm) {
+ if let Ok(promise_type) = vm.try_class("browser", "Promise") {
if objtype::isinstance(&py_obj, &promise_type) {
return browser_module::get_promise_value(&py_obj).into();
}
@@ -158,7 +158,7 @@ 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) {
+ if let Ok(promise_type) = vm.try_class("browser", "Promise") {
return browser_module::PyPromise::new_obj(promise_type, promise.clone());
}
}
diff --git a/wasm/lib/src/vm_class.rs b/wasm/lib/src/vm_class.rs
index 9d80854f73..77822147a8 100644
--- a/wasm/lib/src/vm_class.rs
+++ b/wasm/lib/src/vm_class.rs
@@ -49,7 +49,6 @@ impl StoredVirtualMachine {
thread_local! {
static STORED_VMS: RefCell>> =
RefCell::default();
- static ACTIVE_VMS: RefCell> = RefCell::default();
}
#[wasm_bindgen(js_name = vmStore)]
From 2626a800ab486c74ae3a28e19a0ac1757e19fe64 Mon Sep 17 00:00:00 2001
From: Aviv Palivoda
Date: Sat, 23 Mar 2019 11:04:40 +0200
Subject: [PATCH 03/51] Support frozenset
---
tests/snippets/set.py | 85 ++++++++++++++++++
vm/src/obj/objset.rs | 204 ++++++++++++++++++++++++++++++------------
2 files changed, 233 insertions(+), 56 deletions(-)
diff --git a/tests/snippets/set.py b/tests/snippets/set.py
index a7a20b0efb..9e49dff89e 100644
--- a/tests/snippets/set.py
+++ b/tests/snippets/set.py
@@ -144,3 +144,88 @@ def __hash__(self):
assert a == set([1,2,4,5])
with assertRaises(TypeError):
a ^= 1
+
+# frozen set
+
+assert frozenset([1,2]) == frozenset([1,2])
+assert not frozenset([1,2,3]) == frozenset([1,2])
+
+assert frozenset([1,2,3]) >= frozenset([1,2])
+assert frozenset([1,2]) >= frozenset([1,2])
+assert not frozenset([1,3]) >= frozenset([1,2])
+
+assert frozenset([1,2,3]).issuperset(frozenset([1,2]))
+assert frozenset([1,2]).issuperset(frozenset([1,2]))
+assert not frozenset([1,3]).issuperset(frozenset([1,2]))
+
+assert frozenset([1,2,3]) > frozenset([1,2])
+assert not frozenset([1,2]) > frozenset([1,2])
+assert not frozenset([1,3]) > frozenset([1,2])
+
+assert frozenset([1,2]) <= frozenset([1,2,3])
+assert frozenset([1,2]) <= frozenset([1,2])
+assert not frozenset([1,3]) <= frozenset([1,2])
+
+assert frozenset([1,2]).issubset(frozenset([1,2,3]))
+assert frozenset([1,2]).issubset(frozenset([1,2]))
+assert not frozenset([1,3]).issubset(frozenset([1,2]))
+
+assert frozenset([1,2]) < frozenset([1,2,3])
+assert not frozenset([1,2]) < frozenset([1,2])
+assert not frozenset([1,3]) < frozenset([1,2])
+
+a = frozenset([1, 2, 3])
+assert len(a) == 3
+b = a.copy()
+assert b == a
+
+assert frozenset([1,2,3]).union(frozenset([4,5])) == frozenset([1,2,3,4,5])
+assert frozenset([1,2,3]).union(frozenset([1,2,3,4,5])) == frozenset([1,2,3,4,5])
+
+assert frozenset([1,2,3]) | frozenset([4,5]) == frozenset([1,2,3,4,5])
+assert frozenset([1,2,3]) | frozenset([1,2,3,4,5]) == frozenset([1,2,3,4,5])
+
+assert frozenset([1,2,3]).intersection(frozenset([1,2])) == frozenset([1,2])
+assert frozenset([1,2,3]).intersection(frozenset([5,6])) == frozenset([])
+
+assert frozenset([1,2,3]) & frozenset([4,5]) == frozenset([])
+assert frozenset([1,2,3]) & frozenset([1,2,3,4,5]) == frozenset([1,2,3])
+
+assert frozenset([1,2,3]).difference(frozenset([1,2])) == frozenset([3])
+assert frozenset([1,2,3]).difference(frozenset([5,6])) == frozenset([1,2,3])
+
+assert frozenset([1,2,3]) - frozenset([4,5]) == frozenset([1,2,3])
+assert frozenset([1,2,3]) - frozenset([1,2,3,4,5]) == frozenset([])
+
+assert frozenset([1,2,3]).symmetric_difference(frozenset([1,2])) == frozenset([3])
+assert frozenset([1,2,3]).symmetric_difference(frozenset([5,6])) == frozenset([1,2,3,5,6])
+
+assert frozenset([1,2,3]) ^ frozenset([4,5]) == frozenset([1,2,3,4,5])
+assert frozenset([1,2,3]) ^ frozenset([1,2,3,4,5]) == frozenset([4,5])
+
+assert_raises(TypeError, lambda: frozenset([[]]))
+
+# set and frozen set
+assert frozenset([1,2,3]).union(set([4,5])) == frozenset([1,2,3,4,5])
+assert set([1,2,3]).union(frozenset([4,5])) == set([1,2,3,4,5])
+
+assert frozenset([1,2,3]) | set([4,5]) == frozenset([1,2,3,4,5])
+assert set([1,2,3]) | frozenset([4,5]) == set([1,2,3,4,5])
+
+assert frozenset([1,2,3]).intersection(set([5,6])) == frozenset([])
+assert set([1,2,3]).intersection(frozenset([5,6])) == set([])
+
+assert frozenset([1,2,3]) & set([1,2,3,4,5]) == frozenset([1,2,3])
+assert set([1,2,3]) & frozenset([1,2,3,4,5]) == set([1,2,3])
+
+assert frozenset([1,2,3]).difference(set([5,6])) == frozenset([1,2,3])
+assert set([1,2,3]).difference(frozenset([5,6])) == set([1,2,3])
+
+assert frozenset([1,2,3]) - set([4,5]) == frozenset([1,2,3])
+assert set([1,2,3]) - frozenset([4,5]) == frozenset([1,2,3])
+
+assert frozenset([1,2,3]).symmetric_difference(set([1,2])) == frozenset([3])
+assert set([1,2,3]).symmetric_difference(frozenset([1,2])) == set([3])
+
+assert frozenset([1,2,3]) ^ set([4,5]) == frozenset([1,2,3,4,5])
+assert set([1,2,3]) ^ frozenset([4,5]) == set([1,2,3,4,5])
diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs
index 33a4455318..8bb338d407 100644
--- a/vm/src/obj/objset.rs
+++ b/vm/src/obj/objset.rs
@@ -9,13 +9,14 @@ use std::hash::{Hash, Hasher};
use crate::function::{OptionalArg, PyFuncArgs};
use crate::pyobject::{
- PyContext, PyIteratorValue, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
+ PyContext, PyIteratorValue, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
};
use crate::vm::{ReprGuard, VirtualMachine};
use super::objbool;
use super::objint;
use super::objiter;
+use super::objtype;
use super::objtype::PyClassRef;
#[derive(Default)]
@@ -24,6 +25,12 @@ pub struct PySet {
}
pub type PySetRef = PyRef;
+#[derive(Default)]
+pub struct PyFrozenSet {
+ elements: RefCell>,
+}
+pub type PyFrozenSetRef = PyRef;
+
impl fmt::Debug for PySet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// TODO: implement more detailed, non-recursive Debug formatter
@@ -31,14 +38,69 @@ impl fmt::Debug for PySet {
}
}
+impl fmt::Debug for PyFrozenSet {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // TODO: implement more detailed, non-recursive Debug formatter
+ f.write_str("frozenset")
+ }
+}
+
impl PyValue for PySet {
fn class(vm: &VirtualMachine) -> PyClassRef {
vm.ctx.set_type()
}
}
+impl PyValue for PyFrozenSet {
+ fn class(vm: &VirtualMachine) -> PyClassRef {
+ vm.ctx.frozenset_type()
+ }
+}
+
pub fn get_elements(obj: &PyObjectRef) -> HashMap {
- obj.payload::().unwrap().elements.borrow().clone()
+ if let Some(set) = obj.payload::() {
+ return set.elements.borrow().clone();
+ } else if let Some(frozenset) = obj.payload::() {
+ return frozenset.elements.borrow().clone();
+ }
+ panic!("Not frozenset or set");
+}
+
+macro_rules! validate_set_or_frozenset {
+ ( $vm:ident, $obj:expr ) => {
+ if !(objtype::issubclass(&$obj, &$vm.ctx.set_type())
+ || objtype::issubclass(&$obj, &$vm.ctx.frozenset_type()))
+ {
+ return Err($vm.new_type_error(format!(
+ "{} is not a subtype of set or frozenset a",
+ $obj.typ()
+ )));
+ }
+ };
+}
+
+fn create_set(
+ vm: &VirtualMachine,
+ elements: HashMap,
+ cls: PyClassRef,
+) -> PyResult {
+ if objtype::issubclass(&cls, &vm.ctx.set_type()) {
+ Ok(PyObject::new(
+ PySet {
+ elements: RefCell::new(elements),
+ },
+ PySet::class(vm).into_object(),
+ ))
+ } else if objtype::issubclass(&cls, &vm.ctx.frozenset_type()) {
+ Ok(PyObject::new(
+ PyFrozenSet {
+ elements: RefCell::new(elements),
+ },
+ PyFrozenSet::class(vm).into_object(),
+ ))
+ } else {
+ Err(vm.new_type_error(format!("{} is not a subtype of set or frozenset", cls)))
+ }
}
fn perform_action_with_hash(
@@ -152,11 +214,9 @@ fn set_clear(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
}
/* Create a new object of sub-type of set */
-fn set_new(
- cls: PyClassRef,
- iterable: OptionalArg,
- vm: &VirtualMachine,
-) -> PyResult {
+fn set_new(cls: PyClassRef, iterable: OptionalArg, vm: &VirtualMachine) -> PyResult {
+ validate_set_or_frozenset!(vm, cls);
+
let elements: HashMap = match iterable {
OptionalArg::Missing => HashMap::new(),
OptionalArg::Present(iterable) => {
@@ -169,25 +229,22 @@ fn set_new(
}
};
- PySet {
- elements: RefCell::new(elements),
- }
- .into_ref_with_type(vm, cls)
+ create_set(vm, elements, cls)
}
fn set_len(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
trace!("set.len called with: {:?}", args);
- arg_check!(vm, args, required = [(s, Some(vm.ctx.set_type()))]);
+ arg_check!(vm, args, required = [(s, None)]);
+ validate_set_or_frozenset!(vm, s.type_pyref());
let elements = get_elements(s);
Ok(vm.context().new_int(elements.len()))
}
-fn set_copy(obj: PySetRef, _vm: &VirtualMachine) -> PySet {
+fn set_copy(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
trace!("set.copy called with: {:?}", obj);
- let elements = obj.elements.borrow().clone();
- PySet {
- elements: RefCell::new(elements),
- }
+ validate_set_or_frozenset!(vm, obj.type_pyref());
+ let elements = get_elements(&obj).clone();
+ create_set(vm, elements, obj.type_pyref())
}
fn set_repr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -211,11 +268,8 @@ fn set_repr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
}
pub fn set_contains(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
- arg_check!(
- vm,
- args,
- required = [(set, Some(vm.ctx.set_type())), (needle, None)]
- );
+ arg_check!(vm, args, required = [(set, None), (needle, None)]);
+ validate_set_or_frozenset!(vm, &set.type_pyref());
for element in get_elements(set).iter() {
match vm._eq(needle.clone(), element.1.clone()) {
Ok(value) => {
@@ -281,14 +335,10 @@ fn set_compare_inner(
size_func: &Fn(usize, usize) -> bool,
swap: bool,
) -> PyResult {
- arg_check!(
- vm,
- args,
- required = [
- (zelf, Some(vm.ctx.set_type())),
- (other, Some(vm.ctx.set_type()))
- ]
- );
+ arg_check!(vm, args, required = [(zelf, None), (other, None)]);
+
+ validate_set_or_frozenset!(vm, zelf.type_pyref());
+ validate_set_or_frozenset!(vm, other.type_pyref());
let get_zelf = |swap: bool| -> &PyObjectRef {
if swap {
@@ -323,47 +373,48 @@ fn set_compare_inner(
Ok(vm.new_bool(true))
}
-fn set_union(zelf: PySetRef, other: PySetRef, _vm: &VirtualMachine) -> PySet {
- let mut elements = zelf.elements.borrow().clone();
- elements.extend(other.elements.borrow().clone());
+fn set_union(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
+ validate_set_or_frozenset!(vm, zelf.type_pyref());
+ validate_set_or_frozenset!(vm, other.type_pyref());
- PySet {
- elements: RefCell::new(elements),
- }
+ let mut elements = get_elements(&zelf).clone();
+ elements.extend(get_elements(&other).clone());
+
+ create_set(vm, elements, zelf.type_pyref())
}
-fn set_intersection(zelf: PySetRef, other: PySetRef, vm: &VirtualMachine) -> PyResult {
+fn set_intersection(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
set_combine_inner(zelf, other, vm, SetCombineOperation::Intersection)
}
-fn set_difference(zelf: PySetRef, other: PySetRef, vm: &VirtualMachine) -> PyResult {
+fn set_difference(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
set_combine_inner(zelf, other, vm, SetCombineOperation::Difference)
}
fn set_symmetric_difference(
- zelf: PySetRef,
- other: PySetRef,
+ zelf: PyObjectRef,
+ other: PyObjectRef,
vm: &VirtualMachine,
-) -> PyResult {
+) -> PyResult {
+ validate_set_or_frozenset!(vm, zelf.type_pyref());
+ validate_set_or_frozenset!(vm, other.type_pyref());
let mut elements = HashMap::new();
- for element in zelf.elements.borrow().iter() {
- let value = vm.call_method(other.as_object(), "__contains__", vec![element.1.clone()])?;
+ for element in get_elements(&zelf).iter() {
+ let value = vm.call_method(&other, "__contains__", vec![element.1.clone()])?;
if !objbool::get_value(&value) {
elements.insert(element.0.clone(), element.1.clone());
}
}
- for element in other.elements.borrow().iter() {
- let value = vm.call_method(zelf.as_object(), "__contains__", vec![element.1.clone()])?;
+ for element in get_elements(&other).iter() {
+ let value = vm.call_method(&zelf, "__contains__", vec![element.1.clone()])?;
if !objbool::get_value(&value) {
elements.insert(element.0.clone(), element.1.clone());
}
}
- Ok(PySet {
- elements: RefCell::new(elements),
- })
+ create_set(vm, elements, zelf.type_pyref())
}
enum SetCombineOperation {
@@ -372,15 +423,17 @@ enum SetCombineOperation {
}
fn set_combine_inner(
- zelf: PySetRef,
- other: PySetRef,
+ zelf: PyObjectRef,
+ other: PyObjectRef,
vm: &VirtualMachine,
op: SetCombineOperation,
-) -> PyResult {
+) -> PyResult {
+ validate_set_or_frozenset!(vm, zelf.type_pyref());
+ validate_set_or_frozenset!(vm, other.type_pyref());
let mut elements = HashMap::new();
- for element in zelf.elements.borrow().iter() {
- let value = vm.call_method(other.as_object(), "__contains__", vec![element.1.clone()])?;
+ for element in get_elements(&zelf).iter() {
+ let value = vm.call_method(&other, "__contains__", vec![element.1.clone()])?;
let should_add = match op {
SetCombineOperation::Intersection => objbool::get_value(&value),
SetCombineOperation::Difference => !objbool::get_value(&value),
@@ -390,9 +443,7 @@ fn set_combine_inner(
}
}
- Ok(PySet {
- elements: RefCell::new(elements),
- })
+ create_set(vm, elements, zelf.type_pyref())
}
fn set_pop(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -614,6 +665,46 @@ pub fn init(context: &PyContext) {
frozenset(iterable) -> frozenset object\n\n\
Build an immutable unordered collection of unique elements.";
+ context.set_attr(frozenset_type, "__new__", context.new_rustfunc(set_new));
+ context.set_attr(frozenset_type, "__eq__", context.new_rustfunc(set_eq));
+ context.set_attr(frozenset_type, "__ge__", context.new_rustfunc(set_ge));
+ context.set_attr(frozenset_type, "__gt__", context.new_rustfunc(set_gt));
+ context.set_attr(frozenset_type, "__le__", context.new_rustfunc(set_le));
+ context.set_attr(frozenset_type, "__lt__", context.new_rustfunc(set_lt));
+ context.set_attr(frozenset_type, "issubset", context.new_rustfunc(set_le));
+ context.set_attr(frozenset_type, "issuperset", context.new_rustfunc(set_ge));
+ context.set_attr(frozenset_type, "union", context.new_rustfunc(set_union));
+ context.set_attr(frozenset_type, "__or__", context.new_rustfunc(set_union));
+ context.set_attr(
+ frozenset_type,
+ "intersection",
+ context.new_rustfunc(set_intersection),
+ );
+ context.set_attr(
+ frozenset_type,
+ "__and__",
+ context.new_rustfunc(set_intersection),
+ );
+ context.set_attr(
+ frozenset_type,
+ "difference",
+ context.new_rustfunc(set_difference),
+ );
+ context.set_attr(
+ frozenset_type,
+ "__sub__",
+ context.new_rustfunc(set_difference),
+ );
+ context.set_attr(
+ frozenset_type,
+ "symmetric_difference",
+ context.new_rustfunc(set_symmetric_difference),
+ );
+ context.set_attr(
+ frozenset_type,
+ "__xor__",
+ context.new_rustfunc(set_symmetric_difference),
+ );
context.set_attr(
frozenset_type,
"__contains__",
@@ -630,4 +721,5 @@ pub fn init(context: &PyContext) {
"__repr__",
context.new_rustfunc(frozenset_repr),
);
+ context.set_attr(frozenset_type, "copy", context.new_rustfunc(set_copy));
}
From dc05d5f94b43985245e5af0a505d0d0ce4e2a350 Mon Sep 17 00:00:00 2001
From: Aviv Palivoda
Date: Sat, 23 Mar 2019 11:06:18 +0200
Subject: [PATCH 04/51] Remove Refcell around PyFrozenSet elements
---
vm/src/obj/objset.rs | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs
index 8bb338d407..1d69d3bdef 100644
--- a/vm/src/obj/objset.rs
+++ b/vm/src/obj/objset.rs
@@ -27,7 +27,7 @@ pub type PySetRef = PyRef;
#[derive(Default)]
pub struct PyFrozenSet {
- elements: RefCell>,
+ elements: HashMap,
}
pub type PyFrozenSetRef = PyRef;
@@ -61,7 +61,7 @@ pub fn get_elements(obj: &PyObjectRef) -> HashMap {
if let Some(set) = obj.payload::() {
return set.elements.borrow().clone();
} else if let Some(frozenset) = obj.payload::() {
- return frozenset.elements.borrow().clone();
+ return frozenset.elements.clone();
}
panic!("Not frozenset or set");
}
@@ -93,9 +93,7 @@ fn create_set(
))
} else if objtype::issubclass(&cls, &vm.ctx.frozenset_type()) {
Ok(PyObject::new(
- PyFrozenSet {
- elements: RefCell::new(elements),
- },
+ PyFrozenSet { elements: elements },
PyFrozenSet::class(vm).into_object(),
))
} else {
From 0aabe88c5dc1aceea51a579e3bb9c5551bd17949 Mon Sep 17 00:00:00 2001
From: coolreader18 <33094578+coolreader18@users.noreply.github.com>
Date: Sat, 23 Mar 2019 14:04:14 -0500
Subject: [PATCH 05/51] Put `browser` class methods into `impl` blocks
---
vm/src/vm.rs | 7 +-
wasm/lib/src/browser_module.rs | 235 +++++++++++++++------------------
wasm/lib/src/convert.rs | 14 +-
3 files changed, 121 insertions(+), 135 deletions(-)
diff --git a/vm/src/vm.rs b/vm/src/vm.rs
index 76b06ddfcd..9cf4b98e09 100644
--- a/vm/src/vm.rs
+++ b/vm/src/vm.rs
@@ -111,7 +111,10 @@ impl VirtualMachine {
}
pub fn try_class(&self, module: &str, class: &str) -> PyResult {
- let class = self.get_attribute(self.import(module)?, class)?.downcast().expect("not a class");
+ let class = self
+ .get_attribute(self.import(module)?, class)?
+ .downcast()
+ .expect("not a class");
Ok(class)
}
@@ -122,7 +125,7 @@ impl VirtualMachine {
let class = self
.get_attribute(module.clone(), class)
.unwrap_or_else(|_| panic!("module {} has no class {}", module, class));
- class.downcast().expect("not a class");
+ class.downcast().expect("not a class")
}
/// Create a new python string object.
diff --git a/wasm/lib/src/browser_module.rs b/wasm/lib/src/browser_module.rs
index 0be52c43d6..ce2d3d6c14 100644
--- a/wasm/lib/src/browser_module.rs
+++ b/wasm/lib/src/browser_module.rs
@@ -7,6 +7,7 @@ use wasm_bindgen_futures::{future_to_promise, JsFuture};
use rustpython_vm::function::{OptionalArg, PyFuncArgs};
use rustpython_vm::obj::{
+ objfunction::PyFunction,
objint,
objstr::{self, PyStringRef},
objtype::PyClassRef,
@@ -45,8 +46,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 = vm.try_class("browser", "Promise")?;
-
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 +101,9 @@ fn browser_fetch(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
})
.and_then(JsFuture::from);
- Ok(PyPromise::new_obj(promise_type, future_to_promise(future)))
+ Ok(PyPromise::new(future_to_promise(future))
+ .into_ref(vm)
+ .into_object())
}
fn browser_request_animation_frame(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -163,6 +164,7 @@ fn browser_cancel_animation_frame(vm: &VirtualMachine, args: PyFuncArgs) -> PyRe
pub struct PyPromise {
value: Promise,
}
+pub type PyPromiseRef = PyRef;
impl PyValue for PyPromise {
fn class(vm: &VirtualMachine) -> PyClassRef {
@@ -171,156 +173,135 @@ 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(value: Promise) -> PyPromise {
+ PyPromise { value }
}
-}
-
-pub fn get_promise_value(obj: &PyObjectRef) -> Promise {
- if let Some(promise) = obj.payload::() {
- return promise.value.clone();
+ pub fn value(&self) -> Promise {
+ self.value.clone()
}
- panic!("Inner error getting promise")
-}
-fn promise_then(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
- let promise_type = vm.try_class("browser", "Promise")?;
- 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();
-
- let acc_vm = AccessibleVM::from(vm);
-
- let promise = get_promise_value(zelf);
+ fn then(
+ zelf: PyPromiseRef,
+ on_fulfill: PyRef,
+ on_reject: OptionalArg>,
+ vm: &VirtualMachine,
+ ) -> PyResult {
+ let acc_vm = AccessibleVM::from(vm);
- let ret_future = JsFuture::from(promise).then(move |res| {
- let stored_vm = &acc_vm
- .upgrade()
- .expect("that the vm is valid when the promise resolves");
- let vm = &stored_vm.vm;
- let ret = match res {
- Ok(val) => {
- let val = convert::js_to_py(vm, val);
- vm.invoke(on_fulfill, PyFuncArgs::new(vec![val], vec![]))
- }
- Err(err) => {
- if let Some(on_reject) = on_reject {
- let err = convert::js_to_py(vm, err);
- vm.invoke(on_reject, PyFuncArgs::new(vec![err], vec![]))
- } else {
- return Err(err);
+ 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");
+ let vm = &stored_vm.vm;
+ let ret = match res {
+ Ok(val) => {
+ let val = convert::js_to_py(vm, val);
+ vm.invoke(on_fulfill.into_object(), PyFuncArgs::new(vec![val], vec![]))
}
- }
- };
- convert::pyresult_to_jsresult(vm, ret)
- });
-
- let ret_promise = future_to_promise(ret_future);
-
- Ok(PyPromise::new_obj(promise_type, ret_promise))
-}
-
-fn promise_catch(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
- let promise_type = vm.try_class("browser", "Promise")?;
- arg_check!(
- vm,
- args,
- required = [
- (zelf, Some(promise_type.clone())),
- (on_reject, Some(vm.ctx.function_type()))
- ]
- );
+ 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![]))
+ } else {
+ return Err(err);
+ }
+ }
+ };
+ convert::pyresult_to_jsresult(vm, ret)
+ });
- let on_reject = on_reject.clone();
+ let ret_promise = future_to_promise(ret_future);
- let acc_vm = AccessibleVM::from(vm);
+ Ok(PyPromise::new(ret_promise).into_ref(vm))
+ }
- let promise = get_promise_value(zelf);
+ fn catch(
+ zelf: PyPromiseRef,
+ on_reject: PyRef,
+ vm: &VirtualMachine,
+ ) -> PyResult {
+ let acc_vm = AccessibleVM::from(vm);
- let ret_future = JsFuture::from(promise).then(move |res| match res {
- Ok(val) => Ok(val),
- Err(err) => {
- let stored_vm = acc_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, PyFuncArgs::new(vec![err], vec![]));
- convert::pyresult_to_jsresult(vm, 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
+ .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)
+ }
+ });
- let ret_promise = future_to_promise(ret_future);
+ let ret_promise = future_to_promise(ret_future);
- Ok(PyPromise::new_obj(promise_type, ret_promise))
+ Ok(PyPromise::new(ret_promise).into_ref(vm))
+ }
}
#[derive(Debug)]
-struct PyDocument {
+struct Document {
doc: web_sys::Document,
}
-type PyDocumentRef = PyRef;
+type DocumentRef = PyRef;
-impl PyValue for PyDocument {
- fn class(vm: &VirtualMachine) -> PyObjectRef {
+impl PyValue for Document {
+ fn class(vm: &VirtualMachine) -> PyClassRef {
vm.class("browser", "Document")
}
}
-fn document_query(zelf: PyDocumentRef, query: PyStringRef, vm: &VirtualMachine) -> PyResult {
- let elem = zelf
- .doc
- .query_selector(&query.value)
- .map_err(|err| convert::js_py_typeerror(vm, err))?;
- let elem = match elem {
- Some(elem) => PyElement { elem }.into_ref(vm).into_object(),
- None => vm.get_none(),
- };
- Ok(elem)
+impl Document {
+ fn query(zelf: DocumentRef, query: PyStringRef, vm: &VirtualMachine) -> PyResult {
+ let elem = zelf
+ .doc
+ .query_selector(&query.value)
+ .map_err(|err| convert::js_py_typeerror(vm, err))?;
+ let elem = match elem {
+ Some(elem) => Element { elem }.into_ref(vm).into_object(),
+ None => vm.get_none(),
+ };
+ Ok(elem)
+ }
}
#[derive(Debug)]
-struct PyElement {
+struct Element {
elem: web_sys::Element,
}
-type PyElementRef = PyRef;
+type ElementRef = PyRef;
-impl PyValue for PyElement {
- fn class(vm: &VirtualMachine) -> PyObjectRef {
+impl PyValue for Element {
+ fn class(vm: &VirtualMachine) -> PyClassRef {
vm.class("browser", "Element")
}
}
-fn elem_get_attr(
- zelf: PyElementRef,
- attr: PyStringRef,
- default: OptionalArg,
- vm: &VirtualMachine,
-) -> PyObjectRef {
- match zelf.elem.get_attribute(&attr.value) {
- Some(s) => vm.new_str(s),
- None => default.into_option().unwrap_or_else(|| vm.get_none()),
+impl Element {
+ fn get_attr(
+ zelf: ElementRef,
+ attr: PyStringRef,
+ default: OptionalArg,
+ vm: &VirtualMachine,
+ ) -> PyObjectRef {
+ match zelf.elem.get_attribute(&attr.value) {
+ Some(s) => vm.new_str(s),
+ None => default.into_option().unwrap_or_else(|| vm.get_none()),
+ }
}
-}
-fn elem_set_attr(
- zelf: PyElementRef,
- attr: PyStringRef,
- value: PyStringRef,
- vm: &VirtualMachine,
-) -> PyResult<()> {
- zelf.elem
- .set_attribute(&attr.value, &value.value)
- .map_err(|err| convert::js_to_py(vm, err))
+ fn set_attr(
+ zelf: ElementRef,
+ attr: PyStringRef,
+ value: PyStringRef,
+ vm: &VirtualMachine,
+ ) -> PyResult<()> {
+ zelf.elem
+ .set_attribute(&attr.value, &value.value)
+ .map_err(|err| convert::js_to_py(vm, err))
+ }
}
fn browser_alert(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -370,24 +351,24 @@ fn browser_prompt(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
pub fn make_module(ctx: &PyContext) -> PyObjectRef {
let promise = py_class!(ctx, "Promise", ctx.object(), {
- "then" => ctx.new_rustfunc(promise_then),
- "catch" => ctx.new_rustfunc(promise_catch),
+ "then" => ctx.new_rustfunc(PyPromise::then),
+ "catch" => ctx.new_rustfunc(PyPromise::catch),
});
let document_class = py_class!(ctx, "Document", ctx.object(), {
- "query" => ctx.new_rustfunc(document_query),
+ "query" => ctx.new_rustfunc(Document::query),
});
let document = PyObject::new(
- PyDocument {
+ Document {
doc: window().document().expect("Document missing from window"),
},
- document_class.clone(),
+ document_class.clone().into_object(),
);
let element = py_class!(ctx, "Element", ctx.object(), {
- "get_attr" => ctx.new_rustfunc(elem_get_attr),
- "set_attr" => ctx.new_rustfunc(elem_set_attr),
+ "get_attr" => ctx.new_rustfunc(Element::get_attr),
+ "set_attr" => ctx.new_rustfunc(Element::set_attr),
});
py_module!(ctx, "browser", {
diff --git a/wasm/lib/src/convert.rs b/wasm/lib/src/convert.rs
index 9c9e9f902e..ecdb4b1102 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;
@@ -115,9 +115,9 @@ pub fn py_to_js(vm: &VirtualMachine, py_obj: PyObjectRef) -> JsValue {
}
}
// the browser module might not be injected
- if let Ok(promise_type) = vm.try_class("browser", "Promise") {
- if objtype::isinstance(&py_obj, &promise_type) {
- return browser_module::get_promise_value(&py_obj).into();
+ if vm.try_class("browser", "Promise").is_ok() {
+ if let Some(py_prom) = py_obj.payload::() {
+ return py_prom.value().into();
}
}
@@ -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) = vm.try_class("browser", "Promise") {
- return browser_module::PyPromise::new_obj(promise_type, promise.clone());
+ if vm.try_class("browser", "Promise").is_ok() {
+ return browser_module::PyPromise::new(promise.clone())
+ .into_ref(vm)
+ .into_object();
}
}
if Array::is_array(&js_val) {
From 590b659548a090d08bb51bca46a4457cc560e9a8 Mon Sep 17 00:00:00 2001
From: Aviv Palivoda
Date: Sat, 23 Mar 2019 23:24:57 +0200
Subject: [PATCH 06/51] Change validate_set_or_frozenset to a function
---
vm/src/obj/objset.rs | 44 ++++++++++++++++++++------------------------
1 file changed, 20 insertions(+), 24 deletions(-)
diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs
index 1d69d3bdef..300dc9bca9 100644
--- a/vm/src/obj/objset.rs
+++ b/vm/src/obj/objset.rs
@@ -66,17 +66,13 @@ pub fn get_elements(obj: &PyObjectRef) -> HashMap {
panic!("Not frozenset or set");
}
-macro_rules! validate_set_or_frozenset {
- ( $vm:ident, $obj:expr ) => {
- if !(objtype::issubclass(&$obj, &$vm.ctx.set_type())
- || objtype::issubclass(&$obj, &$vm.ctx.frozenset_type()))
- {
- return Err($vm.new_type_error(format!(
- "{} is not a subtype of set or frozenset a",
- $obj.typ()
- )));
- }
- };
+fn validate_set_or_frozenset(vm: &VirtualMachine, cls: PyClassRef) -> PyResult<()> {
+ if !(objtype::issubclass(&cls, &vm.ctx.set_type())
+ || objtype::issubclass(&cls, &vm.ctx.frozenset_type()))
+ {
+ return Err(vm.new_type_error(format!("{} is not a subtype of set or frozenset", cls)));
+ }
+ Ok(())
}
fn create_set(
@@ -213,7 +209,7 @@ fn set_clear(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
/* Create a new object of sub-type of set */
fn set_new(cls: PyClassRef, iterable: OptionalArg, vm: &VirtualMachine) -> PyResult {
- validate_set_or_frozenset!(vm, cls);
+ validate_set_or_frozenset(vm, cls.clone())?;
let elements: HashMap = match iterable {
OptionalArg::Missing => HashMap::new(),
@@ -227,20 +223,20 @@ fn set_new(cls: PyClassRef, iterable: OptionalArg, vm: &VirtualMach
}
};
- create_set(vm, elements, cls)
+ create_set(vm, elements, cls.clone())
}
fn set_len(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
trace!("set.len called with: {:?}", args);
arg_check!(vm, args, required = [(s, None)]);
- validate_set_or_frozenset!(vm, s.type_pyref());
+ validate_set_or_frozenset(vm, s.type_pyref())?;
let elements = get_elements(s);
Ok(vm.context().new_int(elements.len()))
}
fn set_copy(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
trace!("set.copy called with: {:?}", obj);
- validate_set_or_frozenset!(vm, obj.type_pyref());
+ validate_set_or_frozenset(vm, obj.type_pyref())?;
let elements = get_elements(&obj).clone();
create_set(vm, elements, obj.type_pyref())
}
@@ -267,7 +263,7 @@ fn set_repr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
pub fn set_contains(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(set, None), (needle, None)]);
- validate_set_or_frozenset!(vm, &set.type_pyref());
+ validate_set_or_frozenset(vm, set.type_pyref())?;
for element in get_elements(set).iter() {
match vm._eq(needle.clone(), element.1.clone()) {
Ok(value) => {
@@ -335,8 +331,8 @@ fn set_compare_inner(
) -> PyResult {
arg_check!(vm, args, required = [(zelf, None), (other, None)]);
- validate_set_or_frozenset!(vm, zelf.type_pyref());
- validate_set_or_frozenset!(vm, other.type_pyref());
+ validate_set_or_frozenset(vm, zelf.type_pyref())?;
+ validate_set_or_frozenset(vm, other.type_pyref())?;
let get_zelf = |swap: bool| -> &PyObjectRef {
if swap {
@@ -372,8 +368,8 @@ fn set_compare_inner(
}
fn set_union(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
- validate_set_or_frozenset!(vm, zelf.type_pyref());
- validate_set_or_frozenset!(vm, other.type_pyref());
+ validate_set_or_frozenset(vm, zelf.type_pyref())?;
+ validate_set_or_frozenset(vm, other.type_pyref())?;
let mut elements = get_elements(&zelf).clone();
elements.extend(get_elements(&other).clone());
@@ -394,8 +390,8 @@ fn set_symmetric_difference(
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult {
- validate_set_or_frozenset!(vm, zelf.type_pyref());
- validate_set_or_frozenset!(vm, other.type_pyref());
+ validate_set_or_frozenset(vm, zelf.type_pyref())?;
+ validate_set_or_frozenset(vm, other.type_pyref())?;
let mut elements = HashMap::new();
for element in get_elements(&zelf).iter() {
@@ -426,8 +422,8 @@ fn set_combine_inner(
vm: &VirtualMachine,
op: SetCombineOperation,
) -> PyResult {
- validate_set_or_frozenset!(vm, zelf.type_pyref());
- validate_set_or_frozenset!(vm, other.type_pyref());
+ validate_set_or_frozenset(vm, zelf.type_pyref())?;
+ validate_set_or_frozenset(vm, other.type_pyref())?;
let mut elements = HashMap::new();
for element in get_elements(&zelf).iter() {
From 6fa059fd6c00eb4095c834a39dcfe43965b9a1b6 Mon Sep 17 00:00:00 2001
From: ben
Date: Sat, 23 Mar 2019 18:52:53 +1300
Subject: [PATCH 07/51] Make PyObject.typ a PyClassRef
---
src/main.rs | 22 +++-------
vm/src/builtins.rs | 56 +++++++++++--------------
vm/src/compile.rs | 14 +++----
vm/src/eval.rs | 7 +---
vm/src/function.rs | 7 ++++
vm/src/import.rs | 2 +-
vm/src/obj/objcode.rs | 4 +-
vm/src/obj/objfilter.rs | 33 ++++++++-------
vm/src/obj/objfloat.rs | 6 +--
vm/src/obj/objmemory.rs | 21 +++++-----
vm/src/obj/objobject.rs | 4 +-
vm/src/obj/objproperty.rs | 4 +-
vm/src/obj/objsequence.rs | 4 +-
vm/src/obj/objslice.rs | 6 ++-
vm/src/obj/objtype.rs | 31 ++++----------
vm/src/obj/objzip.rs | 17 ++++----
vm/src/pyobject.rs | 86 +++++++++++++++------------------------
vm/src/stdlib/re.rs | 49 +++++++---------------
vm/src/vm.rs | 5 ++-
wasm/lib/src/vm_class.rs | 3 +-
20 files changed, 154 insertions(+), 227 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index a0683ec3ed..70adf10080 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 5ac00561c6..c81ee79e92 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 46101cdf46..00bafe7278 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 202286eb13..6c7b3ca549 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 a7581d3f25..17e7678233 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 ed5a6d094b..936b896805 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 fda5603f00..7fe54bf513 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 6fcf84fb4d..e547d2c43e 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 1abeabba2a..958d368a89 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 c5926c4abd..7f53fb5ae6 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 e0ff9b20cd..84ba73fe68 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 7a9dd8447e..c5459a9fb2 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 ad9c7bf361..83d0f9f9f8 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 4a7124fdfd..9df435290f 100644
--- a/vm/src/obj/objslice.rs
+++ b/vm/src/obj/objslice.rs
@@ -1,7 +1,9 @@
use num_bigint::BigInt;
use crate::function::PyFuncArgs;
-use crate::pyobject::{PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol};
+use crate::pyobject::{
+ FromPyObjectRef, PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol,
+};
use crate::vm::VirtualMachine;
use super::objint;
@@ -61,7 +63,7 @@ fn slice_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
stop: stop.map(|x| objint::get_value(x).clone()),
step: step.map(|x| objint::get_value(x).clone()),
},
- cls.clone(),
+ PyClassRef::from_pyobj(&cls),
))
}
diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs
index 81f04603bb..1b53226c9d 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(),
+ PyClassRef::from_pyobj(typ),
&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(PyClassRef::from_pyobj(&new_type))
}
#[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 63df96f62f..e628cb218a 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 41a1ca6f34..deeb4f370c 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::from_pyobj(&type_type);
+ let object_type = PyClassRef::from_pyobj(&object_type);
+
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 57db3f0a80..4dab1b0c3f 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
- );
-
- 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();
+fn re_compile(pattern: PyStringRef, vm: &VirtualMachine) -> PyResult> {
+ let regex = make_regex(vm, &pattern.value)?;
- 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 4a3cc3abc0..cde574fbcd 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/vm_class.rs b/wasm/lib/src/vm_class.rs
index fd2181182f..2d20bc37a5 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 {
From 00540dec35c130a0aeff0841728cbe26c85bd55b Mon Sep 17 00:00:00 2001
From: ben
Date: Sun, 24 Mar 2019 08:12:07 +1300
Subject: [PATCH 08/51] Fix wasm, to reflect that PyObject.typ is now a
PyClassRef
---
wasm/lib/src/browser_module.rs | 72 ++++++++++++----------------------
wasm/lib/src/convert.rs | 8 ++--
2 files changed, 31 insertions(+), 49 deletions(-)
diff --git a/wasm/lib/src/browser_module.rs b/wasm/lib/src/browser_module.rs
index 710b18e639..a48cf3d342 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 c7ba1c6161..41f43778fa 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) {
From faf1925a25f64c4158942ded1e4db5253bc3bd44 Mon Sep 17 00:00:00 2001
From: ben
Date: Sun, 24 Mar 2019 09:08:03 +1300
Subject: [PATCH 09/51] Remove usages of PyClassRef::from_pyobj
---
vm/src/obj/objslice.rs | 19 ++++++++-----------
vm/src/obj/objtype.rs | 4 ++--
vm/src/pyobject.rs | 4 ++--
3 files changed, 12 insertions(+), 15 deletions(-)
diff --git a/vm/src/obj/objslice.rs b/vm/src/obj/objslice.rs
index 9df435290f..d68ae2255f 100644
--- a/vm/src/obj/objslice.rs
+++ b/vm/src/obj/objslice.rs
@@ -1,9 +1,7 @@
use num_bigint::BigInt;
use crate::function::PyFuncArgs;
-use crate::pyobject::{
- FromPyObjectRef, PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol,
-};
+use crate::pyobject::{PyContext, PyObjectRef, PyResult, PyValue, TypeProtocol};
use crate::vm::VirtualMachine;
use super::objint;
@@ -57,14 +55,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()),
- },
- PyClassRef::from_pyobj(&cls),
- ))
+ 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 1b53226c9d..b48ba99413 100644
--- a/vm/src/obj/objtype.rs
+++ b/vm/src/obj/objtype.rs
@@ -241,7 +241,7 @@ pub fn type_new_class(
bases.push(vm.ctx.object());
let name = objstr::get_value(name);
new(
- PyClassRef::from_pyobj(typ),
+ typ.clone().downcast().unwrap(),
&name,
bases,
objdict::py_dict_to_attributes(dict),
@@ -382,7 +382,7 @@ pub fn new(
typ,
}
.into_ref();
- Ok(PyClassRef::from_pyobj(&new_type))
+ Ok(new_type.downcast().unwrap())
}
#[cfg(test)]
diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs
index deeb4f370c..80eba36da3 100644
--- a/vm/src/pyobject.rs
+++ b/vm/src/pyobject.rs
@@ -206,8 +206,8 @@ 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::from_pyobj(&type_type);
- let object_type = PyClassRef::from_pyobj(&object_type);
+ 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());
From 017a9ef856fb0f1d9efa4d2ba607078485fddff3 Mon Sep 17 00:00:00 2001
From: jgirardet
Date: Sat, 23 Mar 2019 23:04:45 +0100
Subject: [PATCH 10/51] add bytes.__add__ + bytes tests
---
tests/snippets/bytes.py | 23 +++++++++++++++++++++++
vm/src/obj/objbytes.rs | 15 ++++++++++++++-
2 files changed, 37 insertions(+), 1 deletion(-)
create mode 100644 tests/snippets/bytes.py
diff --git a/tests/snippets/bytes.py b/tests/snippets/bytes.py
new file mode 100644
index 0000000000..7dae0b5249
--- /dev/null
+++ b/tests/snippets/bytes.py
@@ -0,0 +1,23 @@
+# comp
+a = b"abcd"
+b = b"ab"
+c = b"abcd"
+
+assert a > b
+assert a >= b
+assert b < a
+assert b <= a
+assert a == c
+
+# hash not implemented for iterator
+# assert hash(iter(a)) == hash(iter(b"abcd"))
+
+assert repr(a) == "b'abcd'"
+assert len(a) == 4
+
+assert a + b == b"abcdab"
+try:
+ b"ab" + "ab"
+ assert false
+except TypeError:
+ assert True
diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs
index 8d64cc5076..e7fd126e58 100644
--- a/vm/src/obj/objbytes.rs
+++ b/vm/src/obj/objbytes.rs
@@ -67,7 +67,8 @@ pub fn init(context: &PyContext) {
"__repr__" => context.new_rustfunc(bytes_repr),
"__len__" => context.new_rustfunc(bytes_len),
"__iter__" => context.new_rustfunc(bytes_iter),
- "__doc__" => context.new_str(bytes_doc.to_string())
+ "__doc__" => context.new_str(bytes_doc.to_string()),
+ "__add__" => context.new_rustfunc(PyBytesRef::add),
});
}
@@ -201,3 +202,15 @@ fn bytes_iter(obj: PyBytesRef, _vm: &VirtualMachine) -> PyIteratorValue {
iterated_obj: obj.into_object(),
}
}
+
+impl PyBytesRef {
+ fn add(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
+ if objtype::isinstance(&other, &vm.ctx.bytes_type()) {
+ let rhs = get_value(&other);
+ let elements: Vec = self.value.iter().chain(rhs.iter()).cloned().collect();
+ Ok(vm.ctx.new_bytes(elements))
+ } else {
+ Err(vm.new_type_error(format!("Cannot add {} and {}", self.as_object(), other)))
+ }
+ }
+}
From a5558e0e32971c8b6c2a5754250e9a81152e31fa Mon Sep 17 00:00:00 2001
From: Joey
Date: Sat, 23 Mar 2019 15:05:12 -0700
Subject: [PATCH 11/51] Introduce Either extractor and convert
range.__getitem__
---
vm/src/obj/objrange.rs | 115 ++++++++++++++++++-----------------------
vm/src/obj/objslice.rs | 4 +-
vm/src/pyobject.rs | 44 ++++++++++++++++
3 files changed, 98 insertions(+), 65 deletions(-)
diff --git a/vm/src/obj/objrange.rs b/vm/src/obj/objrange.rs
index db4ded48dd..8d526227a3 100644
--- a/vm/src/obj/objrange.rs
+++ b/vm/src/obj/objrange.rs
@@ -7,14 +7,13 @@ use num_traits::{One, Signed, ToPrimitive, Zero};
use crate::function::{OptionalArg, PyFuncArgs};
use crate::pyobject::{
- PyContext, PyIteratorValue, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
+ Either2, PyContext, PyIteratorValue, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
};
use crate::vm::VirtualMachine;
use super::objint::{self, PyInt, PyIntRef};
-use super::objslice::PySlice;
-use super::objtype;
-use super::objtype::PyClassRef;
+use super::objslice::PySliceRef;
+use super::objtype::{self, PyClassRef};
#[derive(Debug, Clone)]
pub struct PyRange {
@@ -169,7 +168,7 @@ pub fn init(context: &PyContext) {
"__bool__" => context.new_rustfunc(range_bool),
"__contains__" => context.new_rustfunc(range_contains),
"__doc__" => context.new_str(range_doc.to_string()),
- "__getitem__" => context.new_rustfunc(range_getitem),
+ "__getitem__" => context.new_rustfunc(PyRangeRef::getitem),
"__iter__" => context.new_rustfunc(range_iter),
"__len__" => context.new_rustfunc(range_len),
"__new__" => context.new_rustfunc(range_new),
@@ -212,6 +211,53 @@ impl PyRangeRef {
}
.into_ref_with_type(vm, cls)
}
+
+ fn getitem(self, subscript: Either2, vm: &VirtualMachine) -> PyResult {
+ match subscript {
+ Either2::A(index) => {
+ if let Some(value) = self.get(index.value.clone()) {
+ Ok(PyInt::new(value).into_ref(vm).into_object())
+ } else {
+ Err(vm.new_index_error("range object index out of range".to_string()))
+ }
+ }
+ Either2::B(slice) => {
+ let new_start = if let Some(int) = slice.start.clone() {
+ if let Some(i) = self.get(int) {
+ i
+ } else {
+ self.start.clone()
+ }
+ } else {
+ self.start.clone()
+ };
+
+ let new_end = if let Some(int) = slice.stop.clone() {
+ if let Some(i) = self.get(int) {
+ i
+ } else {
+ self.stop.clone()
+ }
+ } else {
+ self.stop.clone()
+ };
+
+ let new_step = if let Some(int) = slice.step.clone() {
+ int * self.step.clone()
+ } else {
+ self.step.clone()
+ };
+
+ Ok(PyRange {
+ start: new_start,
+ stop: new_end,
+ step: new_step,
+ }
+ .into_ref(vm)
+ .into_object())
+ }
+ }
+ }
}
fn range_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -252,65 +298,6 @@ fn range_len(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
}
}
-fn range_getitem(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
- arg_check!(
- vm,
- args,
- required = [(zelf, Some(vm.ctx.range_type())), (subscript, None)]
- );
-
- let range = get_value(zelf);
-
- if let Some(i) = subscript.payload::() {
- if let Some(int) = range.get(i.value.clone()) {
- Ok(vm.ctx.new_int(int))
- } else {
- Err(vm.new_index_error("range object index out of range".to_string()))
- }
- } else if let Some(PySlice {
- ref start,
- ref stop,
- ref step,
- }) = subscript.payload()
- {
- let new_start = if let Some(int) = start {
- if let Some(i) = range.get(int) {
- i
- } else {
- range.start.clone()
- }
- } else {
- range.start.clone()
- };
-
- let new_end = if let Some(int) = stop {
- if let Some(i) = range.get(int) {
- i
- } else {
- range.stop
- }
- } else {
- range.stop
- };
-
- let new_step = if let Some(int) = step {
- int * range.step
- } else {
- range.step
- };
-
- Ok(PyRange {
- start: new_start,
- stop: new_end,
- step: new_step,
- }
- .into_ref(vm)
- .into_object())
- } else {
- Err(vm.new_type_error("range indices must be integer or slice".to_string()))
- }
-}
-
fn range_repr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);
diff --git a/vm/src/obj/objslice.rs b/vm/src/obj/objslice.rs
index 4a7124fdfd..d171b2527b 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, PyResult, PyValue, TypeProtocol};
+use crate::pyobject::{PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol};
use crate::vm::VirtualMachine;
use super::objint;
@@ -21,6 +21,8 @@ impl PyValue for PySlice {
}
}
+pub type PySliceRef = PyRef;
+
fn slice_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
no_kwargs!(vm, args);
let (cls, start, stop, step): (
diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs
index 41a1ca6f34..a90a4ebc08 100644
--- a/vm/src/pyobject.rs
+++ b/vm/src/pyobject.rs
@@ -1218,6 +1218,50 @@ impl PyObjectPayload for T {
}
}
+pub enum Either2 {
+ A(A),
+ B(B),
+}
+
+/// This allows a builtin method to accept arguments that may be one of two
+/// types, raising a `TypeError` if it is neither.
+///
+/// # Example
+///
+/// ```
+/// fn do_something(arg: Either2, vm: &VirtualMachine) {
+/// match arg {
+/// Either2::A(int)=> {
+/// // do something with int
+/// }
+/// Either2::B(string) => {
+/// // do something with string
+/// }
+/// }
+/// }
+/// ```
+impl TryFromObject for Either2, PyRef>
+where
+ A: PyValue,
+ B: PyValue,
+{
+ fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult {
+ // TODO: downcast could probably be reworked a bit to make these clones not necessary
+ obj.clone()
+ .downcast::()
+ .map(Either2::A)
+ .or_else(|| obj.clone().downcast::().map(Either2::B))
+ .ok_or_else(|| {
+ vm.new_type_error(format!(
+ "must be {} or {}, not {}",
+ A::class(vm),
+ B::class(vm),
+ obj.type_pyref()
+ ))
+ })
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
From b6f1ecdb4be116d6242ed05541725adedf9a175c Mon Sep 17 00:00:00 2001
From: Joey
Date: Sat, 23 Mar 2019 15:49:31 -0700
Subject: [PATCH 12/51] Fix example
---
vm/src/pyobject.rs | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs
index a90a4ebc08..40a2d56e25 100644
--- a/vm/src/pyobject.rs
+++ b/vm/src/pyobject.rs
@@ -1229,6 +1229,10 @@ pub enum Either2 {
/// # Example
///
/// ```
+/// use rustpython_vm::VirtualMachine;
+/// use rustpython_vm::obj::{objstr::PyStringRef, objint::PyIntRef};
+/// use rustpython_vm::pyobject::Either2;
+///
/// fn do_something(arg: Either2, vm: &VirtualMachine) {
/// match arg {
/// Either2::A(int)=> {
From 3c15d892c5b99f903c5389dc1e5beb6e76b488c3 Mon Sep 17 00:00:00 2001
From: Joey
Date: Sat, 23 Mar 2019 15:57:06 -0700
Subject: [PATCH 13/51] Avoid some cloning
---
vm/src/pyobject.rs | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs
index aec210e7a8..befa798926 100644
--- a/vm/src/pyobject.rs
+++ b/vm/src/pyobject.rs
@@ -700,16 +700,23 @@ where
}
impl PyObject {
- pub fn downcast(self: Rc) -> Option> {
+ /// Attempt to downcast this reference to a subclass.
+ ///
+ /// If the downcast fails, the original ref is returned in as `Err` so
+ /// another downcast can be attempted without unnecessary cloning.
+ ///
+ /// Note: The returned `Result` is _not_ a `PyResult`, even though the
+ /// types are compatible.
+ pub fn downcast(self: Rc) -> Result, PyObjectRef> {
if self.payload_is::() {
- Some({
+ Ok({
PyRef {
obj: self,
_payload: PhantomData,
}
})
} else {
- None
+ Err(self)
}
}
}
@@ -1228,12 +1235,10 @@ where
B: PyValue,
{
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult {
- // TODO: downcast could probably be reworked a bit to make these clones not necessary
- obj.clone()
- .downcast::()
+ obj.downcast::()
.map(Either2::A)
- .or_else(|| obj.clone().downcast::().map(Either2::B))
- .ok_or_else(|| {
+ .or_else(|obj| obj.clone().downcast::().map(Either2::B))
+ .map_err(|obj| {
vm.new_type_error(format!(
"must be {} or {}, not {}",
A::class(vm),
From dc681015771d32d3b9b3e08c12d6942f4e5591b8 Mon Sep 17 00:00:00 2001
From: ben
Date: Sun, 24 Mar 2019 12:07:29 +1300
Subject: [PATCH 14/51] Refactor type_new_class to use more specific ref types
---
vm/src/obj/objtype.rs | 51 +++++++++++++-----------------------------
vm/src/stdlib/types.rs | 30 +++++++++++++------------
2 files changed, 32 insertions(+), 49 deletions(-)
diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs
index b48ba99413..9d3c9fe490 100644
--- a/vm/src/obj/objtype.rs
+++ b/vm/src/obj/objtype.rs
@@ -4,16 +4,17 @@ use std::fmt;
use crate::function::{Args, KwArgs, PyFuncArgs};
use crate::pyobject::{
- IdProtocol, PyAttributes, PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue,
- TypeProtocol,
+ IdProtocol, PyAttributes, PyContext, PyIterable, PyObject, PyObjectRef, PyRef, PyResult,
+ PyValue, TypeProtocol,
};
use crate::vm::VirtualMachine;
use super::objdict;
use super::objlist::PyList;
use super::objproperty::PropertyBuilder;
-use super::objstr::{self, PyStringRef};
+use super::objstr::PyStringRef;
use super::objtuple::PyTuple;
+use crate::obj::objdict::PyDictRef;
#[derive(Clone, Debug)]
pub struct PyClass {
@@ -203,24 +204,10 @@ pub fn get_type_name(typ: &PyObjectRef) -> String {
pub fn type_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
debug!("type.__new__ {:?}", args);
if args.args.len() == 2 {
- arg_check!(
- vm,
- args,
- required = [(_typ, Some(vm.ctx.type_type())), (obj, None)]
- );
- Ok(obj.typ())
+ Ok(args.args[1].typ())
} else if args.args.len() == 4 {
- arg_check!(
- vm,
- args,
- required = [
- (typ, Some(vm.ctx.type_type())),
- (name, Some(vm.ctx.str_type())),
- (bases, None),
- (dict, Some(vm.ctx.dict_type()))
- ]
- );
- type_new_class(vm, typ, name, bases, dict)
+ let (typ, name, bases, dict) = args.bind(vm)?;
+ type_new_class(vm, typ, name, bases, dict).map(|x| x.into_object())
} else {
Err(vm.new_type_error(format!(": type_new: {:?}", args)))
}
@@ -228,25 +215,19 @@ pub fn type_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
pub fn type_new_class(
vm: &VirtualMachine,
- typ: &PyObjectRef,
- name: &PyObjectRef,
- bases: &PyObjectRef,
- dict: &PyObjectRef,
-) -> PyResult {
- let mut bases: Vec = vm
- .extract_elements(bases)?
- .iter()
- .map(|x| x.clone().downcast().unwrap())
- .collect();
+ typ: PyClassRef,
+ name: PyStringRef,
+ bases: PyIterable,
+ dict: PyDictRef,
+) -> PyResult {
+ let mut bases: Vec = bases.iter(vm)?.collect::, _>>()?;
bases.push(vm.ctx.object());
- let name = objstr::get_value(name);
new(
- typ.clone().downcast().unwrap(),
- &name,
+ typ.clone(),
+ &name.value,
bases,
- objdict::py_dict_to_attributes(dict),
+ objdict::py_dict_to_attributes(dict.as_object()),
)
- .map(|x| x.into_object())
}
pub fn type_call(class: PyClassRef, args: Args, kwargs: KwArgs, vm: &VirtualMachine) -> PyResult {
diff --git a/vm/src/stdlib/types.rs b/vm/src/stdlib/types.rs
index 09aeb0dacc..8a5ab2939c 100644
--- a/vm/src/stdlib/types.rs
+++ b/vm/src/stdlib/types.rs
@@ -2,25 +2,27 @@
* Dynamic type creation and names for built in types.
*/
-use crate::function::PyFuncArgs;
+use crate::function::OptionalArg;
+use crate::obj::objdict::PyDict;
+use crate::obj::objstr::PyStringRef;
use crate::obj::objtype;
-use crate::pyobject::{PyContext, PyObjectRef, PyResult, TypeProtocol};
+use crate::obj::objtype::PyClassRef;
+use crate::pyobject::{PyContext, PyIterable, PyObjectRef, PyResult, PyValue, TryFromObject};
use crate::VirtualMachine;
-fn types_new_class(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
- arg_check!(
- vm,
- args,
- required = [(name, Some(vm.ctx.str_type()))],
- optional = [(bases, None), (_kwds, None), (_exec_body, None)]
- );
+fn types_new_class(
+ name: PyStringRef,
+ bases: OptionalArg>,
+ vm: &VirtualMachine,
+) -> PyResult {
+ // TODO kwds and exec_body parameter
- let bases: PyObjectRef = match bases {
- Some(bases) => bases.clone(),
- None => vm.ctx.new_tuple(vec![]),
+ let bases = match bases {
+ OptionalArg::Present(bases) => bases,
+ OptionalArg::Missing => PyIterable::try_from_object(vm, vm.ctx.new_tuple(vec![]))?,
};
- let dict = vm.ctx.new_dict();
- objtype::type_new_class(vm, &vm.ctx.type_type().into_object(), name, &bases, &dict)
+ let dict = PyDict::default().into_ref(vm);
+ objtype::type_new_class(vm, vm.ctx.type_type(), name, bases, dict)
}
pub fn make_module(ctx: &PyContext) -> PyObjectRef {
From 1997fb84108151790504ff76efe46cb7fd1f3502 Mon Sep 17 00:00:00 2001
From: jgirardet
Date: Sun, 24 Mar 2019 01:15:36 +0100
Subject: [PATCH 15/51] add bytes.__contains__ + fix err in __add__
---
tests/snippets/bytes.py | 15 +++++++++-----
vm/src/obj/objbytes.rs | 46 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/tests/snippets/bytes.py b/tests/snippets/bytes.py
index 7dae0b5249..d26fd26d89 100644
--- a/tests/snippets/bytes.py
+++ b/tests/snippets/bytes.py
@@ -16,8 +16,13 @@
assert len(a) == 4
assert a + b == b"abcdab"
-try:
- b"ab" + "ab"
- assert false
-except TypeError:
- assert True
+
+# contains
+assert b"ab" in b"abcd"
+assert b"cd" in b"abcd"
+assert b"abcd" in b"abcd"
+assert b"a" in b"abcd"
+assert b"d" in b"abcd"
+assert b"dc" not in b"abcd"
+assert 97 in b"abcd"
+assert 150 not in b"abcd"
diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs
index e7fd126e58..2a4b0114b5 100644
--- a/vm/src/obj/objbytes.rs
+++ b/vm/src/obj/objbytes.rs
@@ -69,6 +69,7 @@ pub fn init(context: &PyContext) {
"__iter__" => context.new_rustfunc(bytes_iter),
"__doc__" => context.new_str(bytes_doc.to_string()),
"__add__" => context.new_rustfunc(PyBytesRef::add),
+ "__contains__" => context.new_rustfunc(PyBytesRef::contains),
});
}
@@ -203,6 +204,28 @@ fn bytes_iter(obj: PyBytesRef, _vm: &VirtualMachine) -> PyIteratorValue {
}
}
+fn compare_slice(a: &[u8], b: &[u8]) -> bool {
+ for (i, j) in a.iter().zip(b.iter()) {
+ if i != j {
+ return false;
+ }
+ }
+ return true;
+}
+
+fn compare_vec(a: &Vec, b: &Vec) -> bool {
+ let a_len = a.len();
+ let b_len = b.len();
+ for (n, i) in a.iter().enumerate() {
+ if n + b_len <= a_len && *i == b[0] {
+ if compare_slice(&a[n..n + b_len], b) {
+ return true;
+ }
+ }
+ }
+ false
+}
+
impl PyBytesRef {
fn add(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if objtype::isinstance(&other, &vm.ctx.bytes_type()) {
@@ -210,7 +233,28 @@ impl PyBytesRef {
let elements: Vec = self.value.iter().chain(rhs.iter()).cloned().collect();
Ok(vm.ctx.new_bytes(elements))
} else {
- Err(vm.new_type_error(format!("Cannot add {} and {}", self.as_object(), other)))
+ Err(vm.new_not_implemented_error("".to_string()))
+ }
+ }
+
+ fn contains(self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
+ if objtype::isinstance(&needle, &vm.ctx.bytes_type()) {
+ if compare_vec(&self.value, &get_value(&needle)) {
+ return Ok(true);
+ } else {
+ return Ok(false);
+ }
+ } else if objtype::isinstance(&needle, &vm.ctx.int_type()) {
+ let c = self
+ .value
+ .contains(&objint::get_value(&needle).to_u8().unwrap());
+ if c == true {
+ return Ok(true);
+ } else {
+ return Ok(false);
+ }
+ } else {
+ Err(vm.new_type_error(format!("Cannot add {:?} and {:?}", self, needle)))
}
}
}
From db8e6486469b5d10e05155af1894db29e71db041 Mon Sep 17 00:00:00 2001
From: ben
Date: Sun, 24 Mar 2019 13:41:37 +1300
Subject: [PATCH 16/51] Make PyFunction.code a PyCodeRef, PyGenerator.frame a
FrameRef, and other improvements to increase use of specific ref types.
---
vm/src/frame.rs | 12 +++---
vm/src/obj/objcode.rs | 83 +++++++++++++-------------------------
vm/src/obj/objfunction.rs | 24 ++++++-----
vm/src/obj/objgenerator.rs | 72 +++++++++++++--------------------
vm/src/pyobject.rs | 9 ++---
vm/src/stdlib/dis.rs | 19 ++++-----
vm/src/stdlib/json.rs | 2 +-
vm/src/sysmodule.rs | 32 ++++-----------
vm/src/vm.rs | 35 +++++++---------
9 files changed, 107 insertions(+), 181 deletions(-)
diff --git a/vm/src/frame.rs b/vm/src/frame.rs
index 79fdfc1f57..f2a54a6325 100644
--- a/vm/src/frame.rs
+++ b/vm/src/frame.rs
@@ -11,7 +11,7 @@ use crate::bytecode;
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::objdict;
use crate::obj::objdict::PyDict;
use crate::obj::objint::PyInt;
@@ -22,7 +22,7 @@ use crate::obj::objstr;
use crate::obj::objtype;
use crate::obj::objtype::PyClassRef;
use crate::pyobject::{
- DictProtocol, IdProtocol, PyContext, PyObjectRef, PyResult, PyValue, TryFromObject,
+ DictProtocol, IdProtocol, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
TypeProtocol,
};
use crate::vm::VirtualMachine;
@@ -186,6 +186,8 @@ enum BlockType {
},
}
+pub type FrameRef = PyRef;
+
pub struct Frame {
pub code: bytecode::CodeObject,
// We need 1 stack per frame
@@ -211,7 +213,7 @@ pub enum ExecutionResult {
pub type FrameResult = Result