forked from Rust-related/RustPython
Merge pull request #1618 from RustPython/coolreader18/misc-changes
Some miscellaneous changes (print fix, bytes/bytearray fixes, mappingproxy iter)
This commit is contained in:
14
Lib/_sre.py
vendored
14
Lib/_sre.py
vendored
@@ -70,6 +70,16 @@ class SRE_Pattern(object):
|
||||
else:
|
||||
return None
|
||||
|
||||
def fullmatch(self, string):
|
||||
"""If the whole string matches the regular expression pattern, return a
|
||||
corresponding match object. Return None if the string does not match the
|
||||
pattern; note that this is different from a zero-length match."""
|
||||
match = self.match(string)
|
||||
if match and match.start() == 0 and match.end() == len(string):
|
||||
return match
|
||||
else:
|
||||
return None
|
||||
|
||||
def search(self, string, pos=0, endpos=sys.maxsize):
|
||||
"""Scan through string looking for a location where this regular
|
||||
expression produces a match, and return a corresponding MatchObject
|
||||
@@ -123,7 +133,7 @@ class SRE_Pattern(object):
|
||||
last_pos == state.string_position and n > 0):
|
||||
# the above ignores empty matches on latest position
|
||||
if callable(filter):
|
||||
sublist.append(list(filter(SRE_Match(self, state))))
|
||||
sublist.extend(filter(SRE_Match(self, state)))
|
||||
else:
|
||||
sublist.append(filter)
|
||||
last_pos = state.string_position
|
||||
@@ -334,6 +344,8 @@ class SRE_Match(object):
|
||||
class _State(object):
|
||||
|
||||
def __init__(self, string, start, end, flags):
|
||||
if isinstance(string, bytes):
|
||||
string = string.decode()
|
||||
self.string = string
|
||||
if start < 0:
|
||||
start = 0
|
||||
|
||||
10
src/main.rs
10
src/main.rs
@@ -279,7 +279,7 @@ fn get_paths(env_variable_name: &str) -> Vec<String> {
|
||||
|
||||
#[cfg(feature = "flame-it")]
|
||||
fn write_profile(matches: &ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
|
||||
use std::fs::File;
|
||||
use std::{fs, io};
|
||||
|
||||
enum ProfileFormat {
|
||||
Html,
|
||||
@@ -306,12 +306,14 @@ fn write_profile(matches: &ArgMatches) -> Result<(), Box<dyn std::error::Error>>
|
||||
ProfileFormat::Speedscope => "flamescope.json".as_ref(),
|
||||
});
|
||||
|
||||
let profile_output: Box<dyn std::io::Write> = if profile_output == "-" {
|
||||
Box::new(std::io::stdout())
|
||||
let profile_output: Box<dyn io::Write> = if profile_output == "-" {
|
||||
Box::new(io::stdout())
|
||||
} else {
|
||||
Box::new(File::create(profile_output)?)
|
||||
Box::new(fs::File::create(profile_output)?)
|
||||
};
|
||||
|
||||
let profile_output = io::BufWriter::new(profile_output);
|
||||
|
||||
match profile_format {
|
||||
ProfileFormat::Html => flame::dump_html(profile_output)?,
|
||||
ProfileFormat::Text => flame::dump_text_to_writer(profile_output)?,
|
||||
|
||||
@@ -271,6 +271,9 @@ assert bytearray(b"").join(
|
||||
) == bytearray(b"jiljlkmoomkaaaa")
|
||||
with assert_raises(TypeError):
|
||||
bytearray(b"").join((b"km", "kl"))
|
||||
assert bytearray(b"abc").join((
|
||||
bytearray(b"123"), bytearray(b"xyz")
|
||||
)) == bytearray(b"123abcxyz")
|
||||
|
||||
|
||||
# endswith startswith
|
||||
|
||||
@@ -270,6 +270,8 @@ assert (
|
||||
with assert_raises(TypeError):
|
||||
b"".join((b"km", "kl"))
|
||||
|
||||
assert b"abc".join((b"123", b"xyz")) == b"123abcxyz"
|
||||
|
||||
|
||||
# endswith startswith
|
||||
assert b"abcde".endswith(b"de")
|
||||
@@ -612,3 +614,9 @@ assert b'\xe4\xb8\xad\xe6\x96\x87\xe5\xad\x97'.decode('utf-8') == '中文字'
|
||||
# mod
|
||||
assert b'rust%bpython%b' % (b' ', b'!') == b'rust python!'
|
||||
assert b'x=%i y=%f' % (1, 2.5) == b'x=1 y=2.500000'
|
||||
|
||||
class A:
|
||||
def __bytes__(self):
|
||||
return b"bytess"
|
||||
|
||||
assert bytes(A()) == b"bytess"
|
||||
|
||||
@@ -131,3 +131,13 @@ for i in [0, 1, 2, 'spam', 4]:
|
||||
wrap.send(i)
|
||||
|
||||
assert l == ['>> 0', '>> 1', '>> 2', '***', '>> 4']
|
||||
|
||||
def a():
|
||||
yield
|
||||
|
||||
g = a()
|
||||
|
||||
next(g)
|
||||
assert_raises(TypeError, g.throw, TypeError)
|
||||
assert_raises(StopIteration, next, g)
|
||||
assert_raises(TypeError, g.throw, TypeError)
|
||||
|
||||
@@ -52,3 +52,5 @@ class ReturnInt(metaclass=MCReturnInt):
|
||||
|
||||
|
||||
assert isinstance("a", ReturnInt) is True
|
||||
|
||||
assert isinstance(1, ((int, float,), str))
|
||||
|
||||
@@ -25,8 +25,8 @@ use crate::obj::objstr::{PyString, PyStringRef};
|
||||
use crate::obj::objtype::{self, PyClassRef};
|
||||
use crate::pyhash;
|
||||
use crate::pyobject::{
|
||||
Either, IdProtocol, IntoPyObject, ItemProtocol, PyIterable, PyObjectRef, PyResult, PyValue,
|
||||
TryFromObject, TypeProtocol,
|
||||
Either, IdProtocol, ItemProtocol, PyIterable, PyObjectRef, PyResult, PyValue, TryFromObject,
|
||||
TypeProtocol,
|
||||
};
|
||||
use crate::scope::Scope;
|
||||
use crate::stdlib::ast;
|
||||
@@ -598,13 +598,13 @@ pub struct PrintOptions {
|
||||
}
|
||||
|
||||
trait Printer {
|
||||
fn write(&mut self, vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<()>;
|
||||
fn write(&mut self, vm: &VirtualMachine, obj: PyStringRef) -> PyResult<()>;
|
||||
fn flush(&mut self, vm: &VirtualMachine) -> PyResult<()>;
|
||||
}
|
||||
|
||||
impl Printer for &'_ PyObjectRef {
|
||||
fn write(&mut self, vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<()> {
|
||||
vm.call_method(self, "write", vec![obj])?;
|
||||
fn write(&mut self, vm: &VirtualMachine, obj: PyStringRef) -> PyResult<()> {
|
||||
vm.call_method(self, "write", vec![obj.into_object()])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -615,14 +615,13 @@ impl Printer for &'_ PyObjectRef {
|
||||
}
|
||||
|
||||
impl Printer for std::io::StdoutLock<'_> {
|
||||
fn write(&mut self, vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<()> {
|
||||
let s = vm.to_str(&obj)?;
|
||||
write!(self, "{}", s.as_str()).unwrap();
|
||||
fn write(&mut self, _vm: &VirtualMachine, s: PyStringRef) -> PyResult<()> {
|
||||
write!(self, "{}", s).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn flush(&mut self, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
<Self as std::io::Write>::flush(self).unwrap();
|
||||
<Self as io::Write>::flush(self).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -643,10 +642,7 @@ pub fn builtin_print(objects: Args, options: PrintOptions, vm: &VirtualMachine)
|
||||
|
||||
let sep = options
|
||||
.sep
|
||||
.as_ref()
|
||||
.map_or(" ", |sep| sep.as_str())
|
||||
.into_pyobject(vm)
|
||||
.unwrap();
|
||||
.unwrap_or_else(|| PyString::from(" ").into_ref(vm));
|
||||
|
||||
let mut first = true;
|
||||
for object in objects {
|
||||
@@ -656,15 +652,12 @@ pub fn builtin_print(objects: Args, options: PrintOptions, vm: &VirtualMachine)
|
||||
printer.write(vm, sep.clone())?;
|
||||
}
|
||||
|
||||
printer.write(vm, object)?;
|
||||
printer.write(vm, vm.to_str(&object)?)?;
|
||||
}
|
||||
|
||||
let end = options
|
||||
.end
|
||||
.as_ref()
|
||||
.map_or("\n", |end| end.as_str())
|
||||
.into_pyobject(vm)
|
||||
.unwrap();
|
||||
.unwrap_or_else(|| PyString::from("\n").into_ref(vm));
|
||||
printer.write(vm, end)?;
|
||||
|
||||
if options.flush.to_bool() {
|
||||
|
||||
@@ -390,9 +390,9 @@ impl ExceptionZoo {
|
||||
let assertion_error = create_type("AssertionError", &type_type, &exception_type);
|
||||
let attribute_error = create_type("AttributeError", &type_type, &exception_type);
|
||||
let import_error = create_type("ImportError", &type_type, &exception_type);
|
||||
let index_error = create_type("IndexError", &type_type, &exception_type);
|
||||
let key_error = create_type("KeyError", &type_type, &exception_type);
|
||||
let lookup_error = create_type("LookupError", &type_type, &exception_type);
|
||||
let index_error = create_type("IndexError", &type_type, &lookup_error);
|
||||
let key_error = create_type("KeyError", &type_type, &lookup_error);
|
||||
let name_error = create_type("NameError", &type_type, &exception_type);
|
||||
let runtime_error = create_type("RuntimeError", &type_type, &exception_type);
|
||||
let reference_error = create_type("ReferenceError", &type_type, &exception_type);
|
||||
|
||||
@@ -569,17 +569,35 @@ pub fn single_or_tuple_any<T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>>(
|
||||
message: fn(&PyObjectRef) -> String,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<bool> {
|
||||
match_class!(match obj {
|
||||
obj @ T => predicate(obj),
|
||||
tuple @ PyTuple => {
|
||||
for obj in tuple.elements.iter() {
|
||||
let inner_val = PyRef::<T>::try_from_object(vm, obj.clone())?;
|
||||
if predicate(inner_val)? {
|
||||
return Ok(true);
|
||||
// TODO: figure out some way to have recursive calls without... this
|
||||
use std::marker::PhantomData;
|
||||
struct Checker<'vm, T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>> {
|
||||
predicate: F,
|
||||
message: fn(&PyObjectRef) -> String,
|
||||
vm: &'vm VirtualMachine,
|
||||
t: PhantomData<T>,
|
||||
}
|
||||
impl<T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>> Checker<'_, T, F> {
|
||||
fn check(&self, obj: PyObjectRef) -> PyResult<bool> {
|
||||
match_class!(match obj {
|
||||
obj @ T => (self.predicate)(obj),
|
||||
tuple @ PyTuple => {
|
||||
for obj in tuple.elements.iter() {
|
||||
if self.check(obj.clone())? {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
obj => Err(self.vm.new_type_error((self.message)(&obj))),
|
||||
})
|
||||
}
|
||||
obj => Err(vm.new_type_error(message(&obj))),
|
||||
})
|
||||
}
|
||||
let checker = Checker {
|
||||
predicate,
|
||||
message,
|
||||
vm,
|
||||
t: PhantomData,
|
||||
};
|
||||
checker.check(obj)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use num_traits::Zero;
|
||||
|
||||
use crate::function::PyFuncArgs;
|
||||
use crate::pyobject::{
|
||||
IntoPyObject, PyContext, PyObjectRef, PyResult, TryFromObject, TypeProtocol,
|
||||
IdProtocol, IntoPyObject, PyContext, PyObjectRef, PyResult, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
@@ -29,6 +29,12 @@ impl TryFromObject for bool {
|
||||
|
||||
/// Convert Python bool into Rust bool.
|
||||
pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
|
||||
if obj.is(&vm.ctx.true_value) {
|
||||
return Ok(true);
|
||||
}
|
||||
if obj.is(&vm.ctx.false_value) {
|
||||
return Ok(false);
|
||||
}
|
||||
let rs_bool = match vm.get_method(obj.clone(), "__bool__") {
|
||||
Some(method_or_err) => {
|
||||
// If descriptor returns Error, propagate it further
|
||||
|
||||
@@ -187,6 +187,11 @@ impl PyByteArrayRef {
|
||||
self.inner.borrow_mut().setitem(needle, value, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__delitem__")]
|
||||
fn delitem(self, needle: Either<i32, PySliceRef>, vm: &VirtualMachine) -> PyResult<()> {
|
||||
self.inner.borrow_mut().delitem(needle, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "isalnum")]
|
||||
fn isalnum(self, vm: &VirtualMachine) -> bool {
|
||||
self.inner.borrow().isalnum(vm)
|
||||
@@ -285,7 +290,7 @@ impl PyByteArrayRef {
|
||||
}
|
||||
|
||||
#[pymethod(name = "join")]
|
||||
fn join(self, iter: PyIterable, vm: &VirtualMachine) -> PyResult {
|
||||
fn join(self, iter: PyIterable<PyByteInner>, vm: &VirtualMachine) -> PyResult {
|
||||
self.inner.borrow().join(iter, vm)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::ops::Range;
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
use num_integer::Integer;
|
||||
use num_traits::ToPrimitive;
|
||||
use num_traits::{One, Signed, ToPrimitive, Zero};
|
||||
|
||||
use super::objbytearray::{PyByteArray, PyByteArrayRef};
|
||||
use super::objbytes::{PyBytes, PyBytesRef};
|
||||
@@ -86,15 +86,20 @@ impl ByteInnerNewOptions {
|
||||
);
|
||||
}
|
||||
obj => {
|
||||
// TODO: only support this method in the bytes() constructor
|
||||
if let Some(bytes_method) = vm.get_method(obj.clone(), "__bytes__") {
|
||||
let bytes = vm.invoke(&bytes_method?, vec![])?;
|
||||
return PyByteInner::try_from_object(vm, bytes);
|
||||
}
|
||||
let elements = vm.extract_elements(&obj).or_else(|_| {
|
||||
Err(vm.new_type_error(format!(
|
||||
"cannot convert '{}' object to bytes",
|
||||
obj.class().name
|
||||
)))
|
||||
});
|
||||
})?;
|
||||
|
||||
let mut data_bytes = vec![];
|
||||
for elem in elements? {
|
||||
for elem in elements {
|
||||
let v = objint::to_int(vm, &elem, &BigInt::from(10))?;
|
||||
if let Some(i) = v.to_u8() {
|
||||
data_bytes.push(i);
|
||||
@@ -472,6 +477,140 @@ impl PyByteInner {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delitem(
|
||||
&mut self,
|
||||
needle: Either<i32, PySliceRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
match needle {
|
||||
Either::A(int) => {
|
||||
if let Some(idx) = self.elements.get_pos(int) {
|
||||
self.elements.remove(idx);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_index_error("index out of range".to_string()))
|
||||
}
|
||||
}
|
||||
Either::B(slice) => self.delslice(slice, vm),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: deduplicate this with the code in objlist
|
||||
fn delslice(&mut self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let start = slice.start_index(vm)?;
|
||||
let stop = slice.stop_index(vm)?;
|
||||
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
|
||||
|
||||
if step.is_zero() {
|
||||
Err(vm.new_value_error("slice step cannot be zero".to_string()))
|
||||
} else if step.is_positive() {
|
||||
let range = self.elements.get_slice_range(&start, &stop);
|
||||
if range.start < range.end {
|
||||
#[allow(clippy::range_plus_one)]
|
||||
match step.to_i32() {
|
||||
Some(1) => {
|
||||
self._del_slice(range);
|
||||
Ok(())
|
||||
}
|
||||
Some(num) => {
|
||||
self._del_stepped_slice(range, num as usize);
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
self._del_slice(range.start..range.start + 1);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no del to do
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
// calculate the range for the reverse slice, first the bounds needs to be made
|
||||
// exclusive around stop, the lower number
|
||||
let start = start.as_ref().map(|x| {
|
||||
if *x == (-1).to_bigint().unwrap() {
|
||||
self.elements.len() + BigInt::one() //.to_bigint().unwrap()
|
||||
} else {
|
||||
x + 1
|
||||
}
|
||||
});
|
||||
let stop = stop.as_ref().map(|x| {
|
||||
if *x == (-1).to_bigint().unwrap() {
|
||||
self.elements.len().to_bigint().unwrap()
|
||||
} else {
|
||||
x + 1
|
||||
}
|
||||
});
|
||||
let range = self.elements.get_slice_range(&stop, &start);
|
||||
if range.start < range.end {
|
||||
match (-step).to_i32() {
|
||||
Some(1) => {
|
||||
self._del_slice(range);
|
||||
Ok(())
|
||||
}
|
||||
Some(num) => {
|
||||
self._del_stepped_slice_reverse(range, num as usize);
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
self._del_slice(range.end - 1..range.end);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no del to do
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _del_slice(&mut self, range: Range<usize>) {
|
||||
self.elements.drain(range);
|
||||
}
|
||||
|
||||
fn _del_stepped_slice(&mut self, range: Range<usize>, step: usize) {
|
||||
// no easy way to delete stepped indexes so here is what we'll do
|
||||
let mut deleted = 0;
|
||||
let elements = &mut self.elements;
|
||||
let mut indexes = range.clone().step_by(step).peekable();
|
||||
|
||||
for i in range.clone() {
|
||||
// is this an index to delete?
|
||||
if indexes.peek() == Some(&i) {
|
||||
// record and move on
|
||||
indexes.next();
|
||||
deleted += 1;
|
||||
} else {
|
||||
// swap towards front
|
||||
elements.swap(i - deleted, i);
|
||||
}
|
||||
}
|
||||
// then drain (the values to delete should now be contiguous at the end of the range)
|
||||
elements.drain((range.end - deleted)..range.end);
|
||||
}
|
||||
|
||||
fn _del_stepped_slice_reverse(&mut self, range: Range<usize>, step: usize) {
|
||||
// no easy way to delete stepped indexes so here is what we'll do
|
||||
let mut deleted = 0;
|
||||
let elements = &mut self.elements;
|
||||
let mut indexes = range.clone().rev().step_by(step).peekable();
|
||||
|
||||
for i in range.clone().rev() {
|
||||
// is this an index to delete?
|
||||
if indexes.peek() == Some(&i) {
|
||||
// record and move on
|
||||
indexes.next();
|
||||
deleted += 1;
|
||||
} else {
|
||||
// swap towards back
|
||||
elements.swap(i + deleted, i);
|
||||
}
|
||||
}
|
||||
// then drain (the values to delete should now be contiguous at teh start of the range)
|
||||
elements.drain(range.start..(range.start + deleted));
|
||||
}
|
||||
|
||||
pub fn isalnum(&self, _vm: &VirtualMachine) -> bool {
|
||||
!self.elements.is_empty()
|
||||
&& self
|
||||
@@ -692,11 +831,14 @@ impl PyByteInner {
|
||||
Ok(total)
|
||||
}
|
||||
|
||||
pub fn join(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult {
|
||||
pub fn join(&self, iter: PyIterable<PyByteInner>, vm: &VirtualMachine) -> PyResult {
|
||||
let mut refs = vec![];
|
||||
for v in iter.iter(vm)? {
|
||||
let v = v?;
|
||||
refs.extend(PyByteInner::try_from_object(vm, v)?.elements)
|
||||
if !refs.is_empty() {
|
||||
refs.extend(&self.elements);
|
||||
}
|
||||
refs.extend(v.elements);
|
||||
}
|
||||
|
||||
Ok(vm.ctx.new_bytes(refs))
|
||||
|
||||
@@ -263,7 +263,7 @@ impl PyBytesRef {
|
||||
}
|
||||
|
||||
#[pymethod(name = "join")]
|
||||
fn join(self, iter: PyIterable, vm: &VirtualMachine) -> PyResult {
|
||||
fn join(self, iter: PyIterable<PyByteInner>, vm: &VirtualMachine) -> PyResult {
|
||||
self.inner.join(iter, vm)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
use super::objiter::new_stop_iteration;
|
||||
use super::objtype::{isinstance, issubclass, PyClassRef};
|
||||
use crate::frame::{ExecutionResult, FrameRef};
|
||||
use crate::function::OptionalArg;
|
||||
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
pub type PyCoroutineRef = PyRef<PyCoroutine>;
|
||||
|
||||
#[pyclass(name = "coroutine")]
|
||||
#[derive(Debug)]
|
||||
pub struct PyCoroutine {
|
||||
frame: FrameRef,
|
||||
closed: Cell<bool>,
|
||||
}
|
||||
|
||||
impl PyValue for PyCoroutine {
|
||||
@@ -21,14 +25,32 @@ impl PyValue for PyCoroutine {
|
||||
#[pyimpl]
|
||||
impl PyCoroutine {
|
||||
pub fn new(frame: FrameRef, vm: &VirtualMachine) -> PyCoroutineRef {
|
||||
PyCoroutine { frame }.into_ref(vm)
|
||||
PyCoroutine {
|
||||
frame,
|
||||
closed: Cell::new(false),
|
||||
}
|
||||
.into_ref(vm)
|
||||
}
|
||||
|
||||
// TODO: deduplicate this code with objgenerator
|
||||
fn maybe_close(&self, res: &PyResult<ExecutionResult>) {
|
||||
match res {
|
||||
Ok(ExecutionResult::Return(_)) | Err(_) => self.closed.set(true),
|
||||
Ok(ExecutionResult::Yield(_)) => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
pub(crate) fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if self.closed.get() {
|
||||
return Err(new_stop_iteration(vm));
|
||||
}
|
||||
|
||||
self.frame.push_value(value.clone());
|
||||
|
||||
vm.run_frame(self.frame.clone())?.into_result(vm)
|
||||
let result = vm.run_frame(self.frame.clone());
|
||||
self.maybe_close(&result);
|
||||
result?.into_result(vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -39,27 +61,31 @@ impl PyCoroutine {
|
||||
exc_tb: OptionalArg,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
if self.closed.get() {
|
||||
return Err(vm.invoke(exc_type.as_object(), vec![])?);
|
||||
}
|
||||
// TODO what should we do with the other parameters? CPython normalises them with
|
||||
// PyErr_NormalizeException, do we want to do the same.
|
||||
if !issubclass(&exc_type, &vm.ctx.exceptions.base_exception_type) {
|
||||
return Err(vm.new_type_error("Can't throw non exception".to_string()));
|
||||
}
|
||||
vm.frames.borrow_mut().push(self.frame.clone());
|
||||
let result = self
|
||||
.frame
|
||||
.gen_throw(
|
||||
vm,
|
||||
exc_type,
|
||||
exc_val.unwrap_or(vm.get_none()),
|
||||
exc_tb.unwrap_or(vm.get_none()),
|
||||
)
|
||||
.and_then(|res| res.into_result(vm));
|
||||
let result = self.frame.gen_throw(
|
||||
vm,
|
||||
exc_type,
|
||||
exc_val.unwrap_or(vm.get_none()),
|
||||
exc_tb.unwrap_or(vm.get_none()),
|
||||
);
|
||||
self.maybe_close(&result);
|
||||
vm.frames.borrow_mut().pop();
|
||||
result
|
||||
result?.into_result(vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if self.closed.get() {
|
||||
return Ok(());
|
||||
}
|
||||
vm.frames.borrow_mut().push(self.frame.clone());
|
||||
let result = self.frame.gen_throw(
|
||||
vm,
|
||||
@@ -68,6 +94,7 @@ impl PyCoroutine {
|
||||
vm.get_none(),
|
||||
);
|
||||
vm.frames.borrow_mut().pop();
|
||||
self.closed.set(true);
|
||||
match result {
|
||||
Ok(ExecutionResult::Yield(_)) => Err(vm.new_exception(
|
||||
vm.ctx.exceptions.runtime_error.clone(),
|
||||
|
||||
@@ -2,18 +2,22 @@
|
||||
* The mythical generator.
|
||||
*/
|
||||
|
||||
use super::objiter::new_stop_iteration;
|
||||
use super::objtype::{isinstance, issubclass, PyClassRef};
|
||||
use crate::frame::{ExecutionResult, FrameRef};
|
||||
use crate::function::OptionalArg;
|
||||
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
pub type PyGeneratorRef = PyRef<PyGenerator>;
|
||||
|
||||
#[pyclass(name = "generator")]
|
||||
#[derive(Debug)]
|
||||
pub struct PyGenerator {
|
||||
frame: FrameRef,
|
||||
closed: Cell<bool>,
|
||||
}
|
||||
|
||||
impl PyValue for PyGenerator {
|
||||
@@ -25,7 +29,18 @@ impl PyValue for PyGenerator {
|
||||
#[pyimpl]
|
||||
impl PyGenerator {
|
||||
pub fn new(frame: FrameRef, vm: &VirtualMachine) -> PyGeneratorRef {
|
||||
PyGenerator { frame }.into_ref(vm)
|
||||
PyGenerator {
|
||||
frame,
|
||||
closed: Cell::new(false),
|
||||
}
|
||||
.into_ref(vm)
|
||||
}
|
||||
|
||||
fn maybe_close(&self, res: &PyResult<ExecutionResult>) {
|
||||
match res {
|
||||
Ok(ExecutionResult::Return(_)) | Err(_) => self.closed.set(true),
|
||||
Ok(ExecutionResult::Yield(_)) => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
@@ -40,9 +55,15 @@ impl PyGenerator {
|
||||
|
||||
#[pymethod]
|
||||
pub(crate) fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if self.closed.get() {
|
||||
return Err(new_stop_iteration(vm));
|
||||
}
|
||||
|
||||
self.frame.push_value(value.clone());
|
||||
|
||||
vm.run_frame(self.frame.clone())?.into_result(vm)
|
||||
let result = vm.run_frame(self.frame.clone());
|
||||
self.maybe_close(&result);
|
||||
result?.into_result(vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -53,27 +74,31 @@ impl PyGenerator {
|
||||
exc_tb: OptionalArg,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
if self.closed.get() {
|
||||
return Err(vm.invoke(exc_type.as_object(), vec![])?);
|
||||
}
|
||||
// TODO what should we do with the other parameters? CPython normalises them with
|
||||
// PyErr_NormalizeException, do we want to do the same.
|
||||
if !issubclass(&exc_type, &vm.ctx.exceptions.base_exception_type) {
|
||||
return Err(vm.new_type_error("Can't throw non exception".to_string()));
|
||||
}
|
||||
vm.frames.borrow_mut().push(self.frame.clone());
|
||||
let result = self
|
||||
.frame
|
||||
.gen_throw(
|
||||
vm,
|
||||
exc_type,
|
||||
exc_val.unwrap_or(vm.get_none()),
|
||||
exc_tb.unwrap_or(vm.get_none()),
|
||||
)
|
||||
.and_then(|res| res.into_result(vm));
|
||||
let result = self.frame.gen_throw(
|
||||
vm,
|
||||
exc_type,
|
||||
exc_val.unwrap_or(vm.get_none()),
|
||||
exc_tb.unwrap_or(vm.get_none()),
|
||||
);
|
||||
self.maybe_close(&result);
|
||||
vm.frames.borrow_mut().pop();
|
||||
result
|
||||
result?.into_result(vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if self.closed.get() {
|
||||
return Ok(());
|
||||
}
|
||||
vm.frames.borrow_mut().push(self.frame.clone());
|
||||
let result = self.frame.gen_throw(
|
||||
vm,
|
||||
@@ -82,6 +107,7 @@ impl PyGenerator {
|
||||
vm.get_none(),
|
||||
);
|
||||
vm.frames.borrow_mut().pop();
|
||||
self.closed.set(true);
|
||||
match result {
|
||||
Ok(ExecutionResult::Yield(_)) => Err(vm.new_exception(
|
||||
vm.ctx.exceptions.runtime_error.clone(),
|
||||
|
||||
@@ -70,7 +70,7 @@ pub fn get_all<T: TryFromObject>(vm: &VirtualMachine, iter_obj: &PyObjectRef) ->
|
||||
|
||||
pub fn new_stop_iteration(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let stop_iteration_type = vm.ctx.exceptions.stop_iteration.clone();
|
||||
vm.new_exception(stop_iteration_type, "End of iterator".to_string())
|
||||
vm.new_empty_exception(stop_iteration_type).unwrap()
|
||||
}
|
||||
|
||||
pub fn stop_iter_value(vm: &VirtualMachine, exc: &PyObjectRef) -> PyResult {
|
||||
|
||||
@@ -584,23 +584,23 @@ impl PyListRef {
|
||||
}
|
||||
}
|
||||
|
||||
fn delitem(self, subscript: SequenceIndex, vm: &VirtualMachine) -> PyResult {
|
||||
fn delitem(self, subscript: SequenceIndex, vm: &VirtualMachine) -> PyResult<()> {
|
||||
match subscript {
|
||||
SequenceIndex::Int(index) => self.delindex(index, vm),
|
||||
SequenceIndex::Slice(slice) => self.delslice(slice, vm),
|
||||
}
|
||||
}
|
||||
|
||||
fn delindex(self, index: i32, vm: &VirtualMachine) -> PyResult {
|
||||
fn delindex(self, index: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if let Some(pos_index) = self.get_pos(index) {
|
||||
self.elements.borrow_mut().remove(pos_index);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_index_error("Index out of bounds!".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn delslice(self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult {
|
||||
fn delslice(self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let start = slice.start_index(vm)?;
|
||||
let stop = slice.stop_index(vm)?;
|
||||
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
|
||||
@@ -614,20 +614,20 @@ impl PyListRef {
|
||||
match step.to_i32() {
|
||||
Some(1) => {
|
||||
self._del_slice(range);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
Some(num) => {
|
||||
self._del_stepped_slice(range, num as usize);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
self._del_slice(range.start..range.start + 1);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no del to do
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
// calculate the range for the reverse slice, first the bounds needs to be made
|
||||
@@ -651,20 +651,20 @@ impl PyListRef {
|
||||
match (-step).to_i32() {
|
||||
Some(1) => {
|
||||
self._del_slice(range);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
Some(num) => {
|
||||
self._del_stepped_slice_reverse(range, num as usize);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
self._del_slice(range.end - 1..range.end);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no del to do
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use super::objdict::PyDictRef;
|
||||
use super::objiter;
|
||||
use super::objstr::PyStringRef;
|
||||
use super::objtype::{self, PyClassRef};
|
||||
@@ -82,31 +83,44 @@ impl PyMappingProxy {
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
pub fn iter(&self, vm: &VirtualMachine) -> PyResult {
|
||||
match &self.mapping {
|
||||
MappingProxyInner::Dict(d) => objiter::get_iter(vm, d),
|
||||
MappingProxyInner::Class(_c) => Err(vm.new_type_error("Can't get iter".to_string())),
|
||||
}
|
||||
let obj = match &self.mapping {
|
||||
MappingProxyInner::Dict(d) => d.clone(),
|
||||
MappingProxyInner::Class(c) => {
|
||||
// TODO: something that's much more efficient than this
|
||||
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
|
||||
}
|
||||
};
|
||||
objiter::get_iter(vm, &obj)
|
||||
}
|
||||
#[pymethod]
|
||||
pub fn items(&self, vm: &VirtualMachine) -> PyResult {
|
||||
match &self.mapping {
|
||||
MappingProxyInner::Dict(d) => vm.call_method(d, "items", vec![]),
|
||||
MappingProxyInner::Class(_c) => Err(vm.new_type_error("Can't get iter".to_string())),
|
||||
}
|
||||
let obj = match &self.mapping {
|
||||
MappingProxyInner::Dict(d) => d.clone(),
|
||||
MappingProxyInner::Class(c) => {
|
||||
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
|
||||
}
|
||||
};
|
||||
vm.call_method(&obj, "items", vec![])
|
||||
}
|
||||
#[pymethod]
|
||||
pub fn keys(&self, vm: &VirtualMachine) -> PyResult {
|
||||
match &self.mapping {
|
||||
MappingProxyInner::Dict(d) => vm.call_method(d, "keys", vec![]),
|
||||
MappingProxyInner::Class(_c) => Err(vm.new_type_error("Can't get iter".to_string())),
|
||||
}
|
||||
let obj = match &self.mapping {
|
||||
MappingProxyInner::Dict(d) => d.clone(),
|
||||
MappingProxyInner::Class(c) => {
|
||||
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
|
||||
}
|
||||
};
|
||||
vm.call_method(&obj, "keys", vec![])
|
||||
}
|
||||
#[pymethod]
|
||||
pub fn values(&self, vm: &VirtualMachine) -> PyResult {
|
||||
match &self.mapping {
|
||||
MappingProxyInner::Dict(d) => vm.call_method(d, "values", vec![]),
|
||||
MappingProxyInner::Class(_c) => Err(vm.new_type_error("Can't get iter".to_string())),
|
||||
}
|
||||
let obj = match &self.mapping {
|
||||
MappingProxyInner::Dict(d) => d.clone(),
|
||||
MappingProxyInner::Class(c) => {
|
||||
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
|
||||
}
|
||||
};
|
||||
vm.call_method(&obj, "values", vec![])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -564,6 +564,12 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
"MSG_WAITALL" => ctx.new_int(c::MSG_WAITALL),
|
||||
"AI_ALL" => ctx.new_int(c::AI_ALL),
|
||||
"AI_PASSIVE" => ctx.new_int(c::AI_PASSIVE),
|
||||
"IPPROTO_TCP" => ctx.new_int(c::IPPROTO_TCP),
|
||||
"IPPROTO_UDP" => ctx.new_int(c::IPPROTO_UDP),
|
||||
"IPPROTO_IP" => ctx.new_int(c::IPPROTO_IP),
|
||||
"IPPROTO_IPIP" => ctx.new_int(c::IPPROTO_IP),
|
||||
"IPPROTO_IPV6" => ctx.new_int(c::IPPROTO_IPV6),
|
||||
"IPPROTO_NONE" => ctx.new_int(c::IPPROTO_NONE),
|
||||
"socket" => PySocket::make_class(ctx),
|
||||
"inet_aton" => ctx.new_rustfunc(socket_inet_aton),
|
||||
"inet_ntoa" => ctx.new_rustfunc(socket_inet_ntoa),
|
||||
|
||||
@@ -449,8 +449,12 @@ impl VirtualMachine {
|
||||
|
||||
// Container of the virtual machine state:
|
||||
pub fn to_str(&self, obj: &PyObjectRef) -> PyResult<PyStringRef> {
|
||||
let str = self.call_method(&obj, "__str__", vec![])?;
|
||||
TryFromObject::try_from_object(self, str)
|
||||
if obj.class().is(&self.ctx.types.str_type) {
|
||||
Ok(obj.clone().downcast().unwrap())
|
||||
} else {
|
||||
let s = self.call_method(&obj, "__str__", vec![])?;
|
||||
PyStringRef::try_from_object(self, s)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_pystr<'a, T: Into<&'a PyObjectRef>>(&'a self, obj: T) -> PyResult<String> {
|
||||
|
||||
Reference in New Issue
Block a user