Skip to content

Commit 2449c12

Browse files
Merge remote-tracking branch 'origin/master' into make_module_not_mk_module
Conflicts: vm/src/stdlib/weakref.rs
2 parents 0ff5155 + cf659b8 commit 2449c12

File tree

12 files changed

+163
-72
lines changed

12 files changed

+163
-72
lines changed

tests/snippets/list.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,22 @@
2929
assert x > y, "list __gt__ failed"
3030

3131

32-
assert [1,2,'a'].pop() == 'a', "list pop failed"
32+
x = [0, 1, 2]
33+
assert x.pop() == 2
34+
assert x == [0, 1]
35+
36+
def test_pop(lst, idx, value, new_lst):
37+
assert lst.pop(idx) == value
38+
assert lst == new_lst
39+
test_pop([0, 1, 2], -1, 2, [0, 1])
40+
test_pop([0, 1, 2], 0, 0, [1, 2])
41+
test_pop([0, 1, 2], 1, 1, [0, 2])
42+
test_pop([0, 1, 2], 2, 2, [0, 1])
3343
assert_raises(IndexError, lambda: [].pop())
44+
assert_raises(IndexError, lambda: [].pop(0))
45+
assert_raises(IndexError, lambda: [].pop(-1))
46+
assert_raises(IndexError, lambda: [0].pop(1))
47+
assert_raises(IndexError, lambda: [0].pop(-2))
3448

3549
recursive = []
3650
recursive.append(recursive)

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ pub mod objstr;
3131
pub mod objsuper;
3232
pub mod objtuple;
3333
pub mod objtype;
34+
pub mod objweakref;
3435
pub mod objzip;

vm/src/obj/objlist.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,18 @@ impl PyListRef {
203203
Err(vm.new_value_error(format!("'{}' is not in list", needle_str)))
204204
}
205205

206-
fn pop(self, vm: &mut VirtualMachine) -> PyResult {
206+
fn pop(self, i: OptionalArg<isize>, vm: &mut VirtualMachine) -> PyResult {
207+
let mut i = i.into_option().unwrap_or(-1);
207208
let mut elements = self.elements.borrow_mut();
208-
if let Some(result) = elements.pop() {
209-
Ok(result)
210-
} else {
209+
if i < 0 {
210+
i += elements.len() as isize;
211+
}
212+
if elements.is_empty() {
211213
Err(vm.new_index_error("pop from empty list".to_string()))
214+
} else if i < 0 || i as usize >= elements.len() {
215+
Err(vm.new_index_error("pop index out of range".to_string()))
216+
} else {
217+
Ok(elements.remove(i as usize))
212218
}
213219
}
214220

vm/src/obj/objweakref.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use crate::function::PyRef;
2+
use crate::obj::objtype::PyClassRef;
3+
use crate::pyobject::PyObjectPayload2;
4+
use crate::pyobject::{PyContext, PyObject, PyObjectRef, PyResult};
5+
use crate::vm::VirtualMachine;
6+
7+
use std::rc::{Rc, Weak};
8+
9+
#[derive(Debug)]
10+
pub struct PyWeak {
11+
referent: Weak<PyObject>,
12+
}
13+
14+
impl PyWeak {
15+
pub fn downgrade(obj: PyObjectRef) -> PyWeak {
16+
PyWeak {
17+
referent: Rc::downgrade(&obj),
18+
}
19+
}
20+
21+
pub fn upgrade(&self) -> Option<PyObjectRef> {
22+
self.referent.upgrade()
23+
}
24+
}
25+
26+
impl PyObjectPayload2 for PyWeak {
27+
fn required_type(ctx: &PyContext) -> PyObjectRef {
28+
ctx.weakref_type()
29+
}
30+
}
31+
32+
pub type PyWeakRef = PyRef<PyWeak>;
33+
34+
impl PyWeakRef {
35+
// TODO callbacks
36+
fn create(cls: PyClassRef, referent: PyObjectRef, vm: &mut VirtualMachine) -> PyResult<Self> {
37+
Self::new_with_type(vm, PyWeak::downgrade(referent), cls)
38+
}
39+
40+
fn call(self, vm: &mut VirtualMachine) -> PyObjectRef {
41+
self.referent.upgrade().unwrap_or_else(|| vm.get_none())
42+
}
43+
}
44+
45+
pub fn init(context: &PyContext) {
46+
extend_class!(context, &context.weakref_type, {
47+
"__new__" => context.new_rustfunc(PyWeakRef::create),
48+
"__call__" => context.new_rustfunc(PyWeakRef::call)
49+
});
50+
}

vm/src/pyobject.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::collections::HashMap;
33
use std::fmt;
44
use std::iter;
55
use std::ops::RangeInclusive;
6-
use std::rc::{Rc, Weak};
6+
use std::rc::Rc;
77

88
use num_bigint::BigInt;
99
use num_bigint::ToBigInt;
@@ -43,6 +43,7 @@ use crate::obj::objstr;
4343
use crate::obj::objsuper;
4444
use crate::obj::objtuple::{self, PyTuple};
4545
use crate::obj::objtype::{self, PyClass};
46+
use crate::obj::objweakref;
4647
use crate::obj::objzip;
4748
use crate::vm::VirtualMachine;
4849

@@ -67,9 +68,6 @@ Basically reference counting, but then done by rust.
6768
/// to the python object by 1.
6869
pub type PyObjectRef = Rc<PyObject>;
6970

70-
/// Same as PyObjectRef, except for being a weak reference.
71-
pub type PyObjectWeakRef = Weak<PyObject>;
72-
7371
/// Use this type for function which return a python object or and exception.
7472
/// Both the python object and the python exception are `PyObjectRef` types
7573
/// since exceptions are also python objects.
@@ -141,6 +139,7 @@ pub struct PyContext {
141139
pub readonly_property_type: PyObjectRef,
142140
pub module_type: PyObjectRef,
143141
pub bound_method_type: PyObjectRef,
142+
pub weakref_type: PyObjectRef,
144143
pub object: PyObjectRef,
145144
pub exceptions: exceptions::ExceptionZoo,
146145
}
@@ -185,6 +184,7 @@ impl PyContext {
185184
let readonly_property_type =
186185
create_type("readonly_property", &type_type, &object_type, &dict_type);
187186
let super_type = create_type("super", &type_type, &object_type, &dict_type);
187+
let weakref_type = create_type("ref", &type_type, &object_type, &dict_type);
188188
let generator_type = create_type("generator", &type_type, &object_type, &dict_type);
189189
let bound_method_type = create_type("method", &type_type, &object_type, &dict_type);
190190
let str_type = create_type("str", &type_type, &object_type, &dict_type);
@@ -284,6 +284,7 @@ impl PyContext {
284284
generator_type,
285285
module_type,
286286
bound_method_type,
287+
weakref_type,
287288
type_type,
288289
exceptions,
289290
};
@@ -316,6 +317,7 @@ impl PyContext {
316317
objbool::init(&context);
317318
objcode::init(&context);
318319
objframe::init(&context);
320+
objweakref::init(&context);
319321
objnone::init(&context);
320322
objmodule::init(&context);
321323
exceptions::init(&context);
@@ -450,6 +452,10 @@ impl PyContext {
450452
self.bound_method_type.clone()
451453
}
452454

455+
pub fn weakref_type(&self) -> PyObjectRef {
456+
self.weakref_type.clone()
457+
}
458+
453459
pub fn type_type(&self) -> PyObjectRef {
454460
self.type_type.clone()
455461
}
@@ -465,6 +471,7 @@ impl PyContext {
465471
pub fn not_implemented(&self) -> PyObjectRef {
466472
self.not_implemented.clone()
467473
}
474+
468475
pub fn object(&self) -> PyObjectRef {
469476
self.object.clone()
470477
}
@@ -1481,7 +1488,6 @@ into_py_native_func_tuple!((a, A), (b, B), (c, C), (d, D), (e, E));
14811488
/// of rust data for a particular python object. Determine the python type
14821489
/// by using for example the `.typ()` method on a python object.
14831490
pub enum PyObjectPayload {
1484-
WeakRef { referent: PyObjectWeakRef },
14851491
AnyRustValue { value: Box<dyn std::any::Any> },
14861492
}
14871493

@@ -1510,7 +1516,6 @@ impl PyObjectPayload2 for PyIteratorValue {
15101516
impl fmt::Debug for PyObjectPayload {
15111517
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15121518
match self {
1513-
PyObjectPayload::WeakRef { .. } => write!(f, "weakref"),
15141519
PyObjectPayload::AnyRustValue { value } => value.fmt(f),
15151520
}
15161521
}
@@ -1532,11 +1537,8 @@ impl PyObject {
15321537
}
15331538

15341539
pub fn payload<T: PyObjectPayload2>(&self) -> Option<&T> {
1535-
if let PyObjectPayload::AnyRustValue { ref value } = self.payload {
1536-
value.downcast_ref()
1537-
} else {
1538-
None
1539-
}
1540+
let PyObjectPayload::AnyRustValue { ref value } = self.payload;
1541+
value.downcast_ref()
15401542
}
15411543
}
15421544

vm/src/stdlib/re.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,20 +191,19 @@ fn match_end(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
191191

192192
/// Retrieve inner rust regex from python object:
193193
fn get_regex<'a>(obj: &'a PyObjectRef) -> &'a Regex {
194-
if let PyObjectPayload::AnyRustValue { ref value } = obj.payload {
195-
if let Some(regex) = value.downcast_ref::<Regex>() {
196-
return regex;
197-
}
194+
// TODO: Regex shouldn't be stored in payload directly, create newtype wrapper
195+
let PyObjectPayload::AnyRustValue { ref value } = obj.payload;
196+
if let Some(regex) = value.downcast_ref::<Regex>() {
197+
return regex;
198198
}
199199
panic!("Inner error getting regex {:?}", obj);
200200
}
201201

202202
/// Retrieve inner rust match from python object:
203203
fn get_match<'a>(obj: &'a PyObjectRef) -> &'a PyMatch {
204-
if let PyObjectPayload::AnyRustValue { ref value } = obj.payload {
205-
if let Some(value) = value.downcast_ref::<PyMatch>() {
206-
return value;
207-
}
204+
let PyObjectPayload::AnyRustValue { ref value } = obj.payload;
205+
if let Some(value) = value.downcast_ref::<PyMatch>() {
206+
return value;
208207
}
209208
panic!("Inner error getting match {:?}", obj);
210209
}

vm/src/stdlib/socket.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,9 @@ impl Socket {
127127
}
128128

129129
fn get_socket<'a>(obj: &'a PyObjectRef) -> impl DerefMut<Target = Socket> + 'a {
130-
if let PyObjectPayload::AnyRustValue { ref value } = obj.payload {
131-
if let Some(socket) = value.downcast_ref::<RefCell<Socket>>() {
132-
return socket.borrow_mut();
133-
}
130+
let PyObjectPayload::AnyRustValue { ref value } = obj.payload;
131+
if let Some(socket) = value.downcast_ref::<RefCell<Socket>>() {
132+
return socket.borrow_mut();
134133
}
135134
panic!("Inner error getting socket {:?}", obj);
136135
}

vm/src/stdlib/weakref.rs

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,10 @@
55
//! - [rust weak struct](https://doc.rust-lang.org/std/rc/struct.Weak.html)
66
//!
77
8-
use crate::pyobject::{
9-
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyObjectWeakRef, PyResult,
10-
TypeProtocol,
11-
};
12-
use crate::VirtualMachine;
13-
use std::rc::Rc;
8+
use super::super::pyobject::{PyContext, PyObjectRef};
149

1510
pub fn make_module(ctx: &PyContext) -> PyObjectRef {
16-
let py_ref_class = py_class!(ctx, "ref", ctx.object(), {
17-
"__new__" => ctx.new_rustfunc(ref_new),
18-
"__call__" => ctx.new_rustfunc(ref_call)
19-
});
20-
2111
py_module!(ctx, "_weakref", {
22-
"ref" => py_ref_class
12+
"ref" => ctx.weakref_type()
2313
})
2414
}
25-
26-
fn ref_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
27-
// TODO: check first argument for subclass of `ref`.
28-
arg_check!(vm, args, required = [(cls, None), (referent, None)]);
29-
let referent = Rc::downgrade(referent);
30-
Ok(PyObject::new(
31-
PyObjectPayload::WeakRef { referent },
32-
cls.clone(),
33-
))
34-
}
35-
36-
/// Dereference the weakref, and check if we still refer something.
37-
fn ref_call(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
38-
// TODO: check first argument for subclass of `ref`.
39-
arg_check!(vm, args, required = [(cls, None)]);
40-
let referent = get_value(cls);
41-
let py_obj = if let Some(obj) = referent.upgrade() {
42-
obj
43-
} else {
44-
vm.get_none()
45-
};
46-
Ok(py_obj)
47-
}
48-
49-
fn get_value(obj: &PyObjectRef) -> PyObjectWeakRef {
50-
if let PyObjectPayload::WeakRef { referent } = &obj.payload {
51-
referent.clone()
52-
} else {
53-
panic!("Inner error getting weak ref {:?}", obj);
54-
}
55-
}

wasm/demo/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"description": "Bindings to the RustPython library for WebAssembly",
55
"main": "index.js",
66
"dependencies": {
7-
"codemirror": "^5.42.0"
7+
"codemirror": "^5.42.0",
8+
"xterm": "^3.8.0"
89
},
910
"devDependencies": {
1011
"@wasm-tool/wasm-pack-plugin": "0.2.0",

wasm/demo/src/index.ejs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
<h3>Standard Output</h3>
3131
<textarea id="console" readonly>Loading...</textarea>
3232

33+
<h3>Interactive shell</h3>
34+
<div id="terminal"></div>
35+
3336
<p>Here's some info regarding the <code>rp.pyEval()</code> function</p>
3437
<ul>
3538
<li>

wasm/demo/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import './style.css';
22
import 'codemirror/lib/codemirror.css';
3+
import 'xterm/dist/xterm.css';
34

45
// A dependency graph that contains any wasm must all be imported
56
// asynchronously. This `index.js` file does the single async import, so

0 commit comments

Comments
 (0)