forked from Rust-related/RustPython
use PyIterReturn for coroutine internal
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use super::{PyCode, PyStrRef, PyTypeRef};
|
||||
use crate::{
|
||||
builtins::PyBaseExceptionRef,
|
||||
coroutine::{Coro, Variant},
|
||||
coroutine::Coro,
|
||||
frame::FrameRef,
|
||||
function::OptionalArg,
|
||||
protocol::PyIterReturn,
|
||||
@@ -34,7 +34,7 @@ impl PyAsyncGen {
|
||||
|
||||
pub fn new(frame: FrameRef, name: PyStrRef) -> Self {
|
||||
PyAsyncGen {
|
||||
inner: Coro::new(frame, Variant::AsyncGen, name),
|
||||
inner: Coro::new(frame, name),
|
||||
running_async: AtomicCell::new(false),
|
||||
}
|
||||
}
|
||||
@@ -50,8 +50,8 @@ impl PyAsyncGen {
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn repr(zelf: PyRef<Self>) -> String {
|
||||
zelf.inner.repr(zelf.get_id())
|
||||
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> String {
|
||||
zelf.inner.repr(zelf.as_object(), zelf.get_id(), vm)
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
@@ -138,17 +138,20 @@ impl PyValue for PyAsyncGenWrappedValue {
|
||||
impl PyAsyncGenWrappedValue {}
|
||||
|
||||
impl PyAsyncGenWrappedValue {
|
||||
fn unbox(ag: &PyAsyncGen, val: PyResult, vm: &VirtualMachine) -> PyResult {
|
||||
if let Err(ref e) = val {
|
||||
if e.isinstance(&vm.ctx.exceptions.stop_async_iteration)
|
||||
|| e.isinstance(&vm.ctx.exceptions.generator_exit)
|
||||
{
|
||||
ag.inner.closed.store(true);
|
||||
}
|
||||
fn unbox(ag: &PyAsyncGen, val: PyResult<PyIterReturn>, vm: &VirtualMachine) -> PyResult {
|
||||
let (closed, async_done) = match &val {
|
||||
Ok(PyIterReturn::StopIteration(_)) => (true, true),
|
||||
Err(e) if e.isinstance(&vm.ctx.exceptions.generator_exit) => (true, true),
|
||||
Err(_) => (false, true),
|
||||
_ => (false, false),
|
||||
};
|
||||
if closed {
|
||||
ag.inner.closed.store(true);
|
||||
}
|
||||
if async_done {
|
||||
ag.running_async.store(false);
|
||||
}
|
||||
let val = val?;
|
||||
|
||||
let val = val?.into_async_pyresult(vm)?;
|
||||
match_class!(match val {
|
||||
val @ Self => {
|
||||
ag.running_async.store(false);
|
||||
@@ -214,7 +217,7 @@ impl PyAsyncGenASend {
|
||||
}
|
||||
}
|
||||
};
|
||||
let res = self.ag.inner.send(val, vm);
|
||||
let res = self.ag.inner.send(self.ag.as_object(), val, vm);
|
||||
let res = PyAsyncGenWrappedValue::unbox(&self.ag, res, vm);
|
||||
if res.is_err() {
|
||||
self.close();
|
||||
@@ -237,6 +240,7 @@ impl PyAsyncGenASend {
|
||||
}
|
||||
|
||||
let res = self.ag.inner.throw(
|
||||
self.ag.as_object(),
|
||||
exc_type,
|
||||
exc_val.unwrap_or_none(vm),
|
||||
exc_tb.unwrap_or_none(vm),
|
||||
@@ -258,8 +262,7 @@ impl PyAsyncGenASend {
|
||||
impl IteratorIterable for PyAsyncGenASend {}
|
||||
impl SlotIterator for PyAsyncGenASend {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
// TODO: Fix zelf.send to return PyIterReturn
|
||||
PyIterReturn::from_result(zelf.send(vm.ctx.none(), vm), vm)
|
||||
PyIterReturn::from_pyresult(zelf.send(vm.ctx.none(), vm), vm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,12 +318,12 @@ impl PyAsyncGenAThrow {
|
||||
self.ag.running_async.store(true);
|
||||
|
||||
let (ty, val, tb) = self.value.clone();
|
||||
let ret = self.ag.inner.throw(ty, val, tb, vm);
|
||||
let ret = self.ag.inner.throw(self.ag.as_object(), ty, val, tb, vm);
|
||||
let ret = if self.aclose {
|
||||
if self.ignored_close(&ret) {
|
||||
Err(self.yield_close(vm))
|
||||
} else {
|
||||
ret
|
||||
ret.and_then(|o| o.into_async_pyresult(vm))
|
||||
}
|
||||
} else {
|
||||
PyAsyncGenWrappedValue::unbox(&self.ag, ret, vm)
|
||||
@@ -328,14 +331,15 @@ impl PyAsyncGenAThrow {
|
||||
ret.map_err(|e| self.check_error(e, vm))
|
||||
}
|
||||
AwaitableState::Iter => {
|
||||
let ret = self.ag.inner.send(val, vm);
|
||||
let ret = self.ag.inner.send(self.ag.as_object(), val, vm);
|
||||
if self.aclose {
|
||||
match ret {
|
||||
Ok(v) if v.payload_is::<PyAsyncGenWrappedValue>() => {
|
||||
Ok(PyIterReturn::Return(v)) if v.payload_is::<PyAsyncGenWrappedValue>() => {
|
||||
Err(self.yield_close(vm))
|
||||
}
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(self.check_error(e, vm)),
|
||||
other => other
|
||||
.and_then(|o| o.into_async_pyresult(vm))
|
||||
.map_err(|e| self.check_error(e, vm)),
|
||||
}
|
||||
} else {
|
||||
PyAsyncGenWrappedValue::unbox(&self.ag, ret, vm)
|
||||
@@ -353,6 +357,7 @@ impl PyAsyncGenAThrow {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
let ret = self.ag.inner.throw(
|
||||
self.ag.as_object(),
|
||||
exc_type,
|
||||
exc_val.unwrap_or_none(vm),
|
||||
exc_tb.unwrap_or_none(vm),
|
||||
@@ -362,7 +367,7 @@ impl PyAsyncGenAThrow {
|
||||
if self.ignored_close(&ret) {
|
||||
Err(self.yield_close(vm))
|
||||
} else {
|
||||
ret
|
||||
ret.and_then(|o| o.into_async_pyresult(vm))
|
||||
}
|
||||
} else {
|
||||
PyAsyncGenWrappedValue::unbox(&self.ag, ret, vm)
|
||||
@@ -375,9 +380,11 @@ impl PyAsyncGenAThrow {
|
||||
self.state.store(AwaitableState::Closed);
|
||||
}
|
||||
|
||||
fn ignored_close(&self, res: &PyResult) -> bool {
|
||||
res.as_ref()
|
||||
.map_or(false, |v| v.payload_is::<PyAsyncGenWrappedValue>())
|
||||
fn ignored_close(&self, res: &PyResult<PyIterReturn>) -> bool {
|
||||
res.as_ref().map_or(false, |v| match v {
|
||||
PyIterReturn::Return(obj) => obj.payload_is::<PyAsyncGenWrappedValue>(),
|
||||
PyIterReturn::StopIteration(_) => false,
|
||||
})
|
||||
}
|
||||
fn yield_close(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
self.ag.running_async.store(false);
|
||||
@@ -401,8 +408,7 @@ impl PyAsyncGenAThrow {
|
||||
impl IteratorIterable for PyAsyncGenAThrow {}
|
||||
impl SlotIterator for PyAsyncGenAThrow {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
// TODO: Fix zelf.send to return PyIterReturn
|
||||
PyIterReturn::from_result(zelf.send(vm.ctx.none(), vm), vm)
|
||||
PyIterReturn::from_pyresult(zelf.send(vm.ctx.none(), vm), vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{PyCode, PyStrRef, PyTypeRef};
|
||||
use crate::{
|
||||
coroutine::{Coro, Variant},
|
||||
coroutine::Coro,
|
||||
frame::FrameRef,
|
||||
function::OptionalArg,
|
||||
protocol::PyIterReturn,
|
||||
@@ -29,7 +29,7 @@ impl PyCoroutine {
|
||||
|
||||
pub fn new(frame: FrameRef, name: PyStrRef) -> Self {
|
||||
PyCoroutine {
|
||||
inner: Coro::new(frame, Variant::Coroutine, name),
|
||||
inner: Coro::new(frame, name),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,24 +44,25 @@ impl PyCoroutine {
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn repr(zelf: PyRef<Self>) -> String {
|
||||
zelf.inner.repr(zelf.get_id())
|
||||
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> String {
|
||||
zelf.inner.repr(zelf.as_object(), zelf.get_id(), vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
self.inner.send(value, vm)
|
||||
fn send(zelf: PyRef<Self>, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
zelf.inner.send(zelf.as_object(), value, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn throw(
|
||||
&self,
|
||||
zelf: PyRef<Self>,
|
||||
exc_type: PyObjectRef,
|
||||
exc_val: OptionalArg,
|
||||
exc_tb: OptionalArg,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
self.inner.throw(
|
||||
) -> PyResult<PyIterReturn> {
|
||||
zelf.inner.throw(
|
||||
zelf.as_object(),
|
||||
exc_type,
|
||||
exc_val.unwrap_or_none(vm),
|
||||
exc_tb.unwrap_or_none(vm),
|
||||
@@ -70,8 +71,8 @@ impl PyCoroutine {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
|
||||
self.inner.close(vm)
|
||||
fn close(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<()> {
|
||||
zelf.inner.close(zelf.as_object(), vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__await__")]
|
||||
@@ -106,8 +107,7 @@ impl PyCoroutine {
|
||||
impl IteratorIterable for PyCoroutine {}
|
||||
impl SlotIterator for PyCoroutine {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
// TODO: Fix zelf.send to return PyIterReturn
|
||||
PyIterReturn::from_result(zelf.send(vm.ctx.none(), vm), vm)
|
||||
Self::send(zelf.clone(), vm.ctx.none(), vm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +127,8 @@ impl PyValue for PyCoroutineWrapper {
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
impl PyCoroutineWrapper {
|
||||
#[pymethod]
|
||||
fn send(&self, val: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
self.coro.send(val, vm)
|
||||
fn send(zelf: PyRef<Self>, val: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
PyCoroutine::send(zelf.coro.clone(), val, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -138,16 +138,15 @@ impl PyCoroutineWrapper {
|
||||
exc_val: OptionalArg,
|
||||
exc_tb: OptionalArg,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
self.coro.throw(exc_type, exc_val, exc_tb, vm)
|
||||
) -> PyResult<PyIterReturn> {
|
||||
PyCoroutine::throw(self.coro.clone(), exc_type, exc_val, exc_tb, vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl IteratorIterable for PyCoroutineWrapper {}
|
||||
impl SlotIterator for PyCoroutineWrapper {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
// TODO: Fix zelf.send to return PyIterReturn
|
||||
PyIterReturn::from_result(zelf.send(vm.ctx.none(), vm), vm)
|
||||
Self::send(zelf.clone(), vm.ctx.none(), vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ impl SlotIterator for PyFilter {
|
||||
} else {
|
||||
// the predicate itself can raise StopIteration which does stop the filter
|
||||
// iteration
|
||||
match PyIterReturn::from_result(vm.invoke(predicate, vec![next_obj.clone()]), vm)? {
|
||||
match PyIterReturn::from_pyresult(vm.invoke(predicate, vec![next_obj.clone()]), vm)?
|
||||
{
|
||||
PyIterReturn::Return(obj) => obj,
|
||||
PyIterReturn::StopIteration(v) => return Ok(PyIterReturn::StopIteration(v)),
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
use super::{PyCode, PyStrRef, PyTypeRef};
|
||||
use crate::{
|
||||
coroutine::{Coro, Variant},
|
||||
coroutine::Coro,
|
||||
frame::FrameRef,
|
||||
function::OptionalArg,
|
||||
protocol::PyIterReturn,
|
||||
@@ -32,7 +32,7 @@ impl PyGenerator {
|
||||
|
||||
pub fn new(frame: FrameRef, name: PyStrRef) -> Self {
|
||||
PyGenerator {
|
||||
inner: Coro::new(frame, Variant::Gen, name),
|
||||
inner: Coro::new(frame, name),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,24 +47,25 @@ impl PyGenerator {
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn repr(zelf: PyRef<Self>) -> String {
|
||||
zelf.inner.repr(zelf.get_id())
|
||||
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> String {
|
||||
zelf.inner.repr(zelf.as_object(), zelf.get_id(), vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
self.inner.send(value, vm)
|
||||
fn send(zelf: PyRef<Self>, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
zelf.inner.send(zelf.as_object(), value, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn throw(
|
||||
&self,
|
||||
zelf: PyRef<Self>,
|
||||
exc_type: PyObjectRef,
|
||||
exc_val: OptionalArg,
|
||||
exc_tb: OptionalArg,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
self.inner.throw(
|
||||
) -> PyResult<PyIterReturn> {
|
||||
zelf.inner.throw(
|
||||
zelf.as_object(),
|
||||
exc_type,
|
||||
exc_val.unwrap_or_none(vm),
|
||||
exc_tb.unwrap_or_none(vm),
|
||||
@@ -73,8 +74,8 @@ impl PyGenerator {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
|
||||
self.inner.close(vm)
|
||||
fn close(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<()> {
|
||||
zelf.inner.close(zelf.as_object(), vm)
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
@@ -98,8 +99,7 @@ impl PyGenerator {
|
||||
impl IteratorIterable for PyGenerator {}
|
||||
impl SlotIterator for PyGenerator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
// TODO: Fix zelf.send to return PyIterReturn
|
||||
PyIterReturn::from_result(zelf.send(vm.ctx.none(), vm), vm)
|
||||
Self::send(zelf.clone(), vm.ctx.none(), vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ impl SlotIterator for PyMap {
|
||||
}
|
||||
|
||||
// the mapper itself can raise StopIteration which does stop the map iteration
|
||||
PyIterReturn::from_result(vm.invoke(&zelf.mapper, next_objs), vm)
|
||||
PyIterReturn::from_pyresult(vm.invoke(&zelf.mapper, next_objs), vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ impl PyType {
|
||||
}
|
||||
"__next__" => {
|
||||
let func: slots::IterNextFunc = |zelf, vm| {
|
||||
PyIterReturn::from_result(
|
||||
PyIterReturn::from_pyresult(
|
||||
vm.call_special_method(zelf.clone(), "__next__", ()),
|
||||
vm,
|
||||
)
|
||||
|
||||
@@ -1,33 +1,26 @@
|
||||
use crate::{
|
||||
builtins::{PyBaseExceptionRef, PyStrRef, PyTypeRef},
|
||||
builtins::{PyBaseExceptionRef, PyStrRef},
|
||||
common::lock::PyMutex,
|
||||
exceptions,
|
||||
frame::{ExecutionResult, FrameRef},
|
||||
PyObjectRef, PyResult, TypeProtocol, VirtualMachine,
|
||||
protocol::PyIterReturn,
|
||||
IdProtocol, PyObjectRef, PyResult, TypeProtocol, VirtualMachine,
|
||||
};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum Variant {
|
||||
Gen,
|
||||
Coroutine,
|
||||
AsyncGen,
|
||||
}
|
||||
impl Variant {
|
||||
fn exec_result(self, res: ExecutionResult, vm: &VirtualMachine) -> PyResult {
|
||||
res.into_result(self == Self::AsyncGen, vm)
|
||||
}
|
||||
fn name(self) -> &'static str {
|
||||
impl ExecutionResult {
|
||||
/// Turn an ExecutionResult into a PyResult that would be returned from a generator or coroutine
|
||||
fn into_iter_return(self, vm: &VirtualMachine) -> PyIterReturn {
|
||||
match self {
|
||||
Self::Gen => "generator",
|
||||
Self::Coroutine => "coroutine",
|
||||
Self::AsyncGen => "async generator",
|
||||
}
|
||||
}
|
||||
fn stop_iteration(self, vm: &VirtualMachine) -> PyTypeRef {
|
||||
match self {
|
||||
Self::AsyncGen => vm.ctx.exceptions.stop_async_iteration.clone(),
|
||||
_ => vm.ctx.exceptions.stop_iteration.clone(),
|
||||
ExecutionResult::Yield(value) => PyIterReturn::Return(value),
|
||||
ExecutionResult::Return(value) => {
|
||||
let arg = if vm.is_none(&value) {
|
||||
None
|
||||
} else {
|
||||
Some(value)
|
||||
};
|
||||
PyIterReturn::StopIteration(arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,9 +28,8 @@ impl Variant {
|
||||
#[derive(Debug)]
|
||||
pub struct Coro {
|
||||
frame: FrameRef,
|
||||
pub closed: AtomicCell<bool>, // redudant?
|
||||
pub closed: AtomicCell<bool>, // TODO: https://github.com/RustPython/RustPython/pull/3183#discussion_r720560652
|
||||
running: AtomicCell<bool>,
|
||||
variant: Variant,
|
||||
// code
|
||||
// _weakreflist
|
||||
name: PyMutex<PyStrRef>,
|
||||
@@ -45,14 +37,24 @@ pub struct Coro {
|
||||
exception: PyMutex<Option<PyBaseExceptionRef>>, // exc_state
|
||||
}
|
||||
|
||||
fn gen_name(gen: &PyObjectRef, vm: &VirtualMachine) -> &'static str {
|
||||
let typ = gen.class();
|
||||
if typ.is(&vm.ctx.types.coroutine_type) {
|
||||
"coroutine"
|
||||
} else if typ.is(&vm.ctx.types.async_generator) {
|
||||
"async generator"
|
||||
} else {
|
||||
"generator"
|
||||
}
|
||||
}
|
||||
|
||||
impl Coro {
|
||||
pub fn new(frame: FrameRef, variant: Variant, name: PyStrRef) -> Self {
|
||||
pub fn new(frame: FrameRef, name: PyStrRef) -> Self {
|
||||
Coro {
|
||||
frame,
|
||||
closed: AtomicCell::new(false),
|
||||
running: AtomicCell::new(false),
|
||||
exception: PyMutex::default(),
|
||||
variant,
|
||||
name: PyMutex::new(name),
|
||||
}
|
||||
}
|
||||
@@ -64,12 +66,17 @@ impl Coro {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_with_context<F>(&self, vm: &VirtualMachine, func: F) -> PyResult<ExecutionResult>
|
||||
fn run_with_context<F>(
|
||||
&self,
|
||||
gen: &PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
func: F,
|
||||
) -> PyResult<ExecutionResult>
|
||||
where
|
||||
F: FnOnce(FrameRef) -> PyResult<ExecutionResult>,
|
||||
{
|
||||
if self.running.compare_exchange(false, true).is_err() {
|
||||
return Err(vm.new_value_error(format!("{} already executing", self.variant.name())));
|
||||
return Err(vm.new_value_error(format!("{} already executing", gen_name(gen, vm))));
|
||||
}
|
||||
|
||||
vm.push_exception(self.exception.lock().take());
|
||||
@@ -82,31 +89,36 @@ impl Coro {
|
||||
result
|
||||
}
|
||||
|
||||
pub fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
pub fn send(
|
||||
&self,
|
||||
gen: &PyObjectRef,
|
||||
value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyIterReturn> {
|
||||
if self.closed.load() {
|
||||
return Err(vm.new_exception_empty(self.variant.stop_iteration(vm)));
|
||||
return Ok(PyIterReturn::StopIteration(None));
|
||||
}
|
||||
let value = if self.frame.lasti() > 0 {
|
||||
Some(value)
|
||||
} else if !vm.is_none(&value) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"can't send non-None value to a just-started {}",
|
||||
self.variant.name()
|
||||
gen_name(gen, vm),
|
||||
)));
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let result = self.run_with_context(vm, |f| f.resume(value, vm));
|
||||
let result = self.run_with_context(gen, vm, |f| f.resume(value, vm));
|
||||
self.maybe_close(&result);
|
||||
match result {
|
||||
Ok(exec_res) => self.variant.exec_result(exec_res, vm),
|
||||
Ok(exec_res) => Ok(exec_res.into_iter_return(vm)),
|
||||
Err(e) => {
|
||||
if e.isinstance(&vm.ctx.exceptions.stop_iteration) {
|
||||
let err = vm
|
||||
.new_runtime_error(format!("{} raised StopIteration", self.variant.name()));
|
||||
let err =
|
||||
vm.new_runtime_error(format!("{} raised StopIteration", gen_name(gen, vm)));
|
||||
err.set_cause(Some(e));
|
||||
Err(err)
|
||||
} else if self.variant == Variant::AsyncGen
|
||||
} else if gen.class().is(&vm.ctx.types.async_generator)
|
||||
&& e.isinstance(&vm.ctx.exceptions.stop_async_iteration)
|
||||
{
|
||||
let err = vm
|
||||
@@ -121,24 +133,25 @@ impl Coro {
|
||||
}
|
||||
pub fn throw(
|
||||
&self,
|
||||
gen: &PyObjectRef,
|
||||
exc_type: PyObjectRef,
|
||||
exc_val: PyObjectRef,
|
||||
exc_tb: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
) -> PyResult<PyIterReturn> {
|
||||
if self.closed.load() {
|
||||
return Err(exceptions::normalize(exc_type, exc_val, exc_tb, vm)?);
|
||||
}
|
||||
let result = self.run_with_context(vm, |f| f.gen_throw(vm, exc_type, exc_val, exc_tb));
|
||||
let result = self.run_with_context(gen, vm, |f| f.gen_throw(vm, exc_type, exc_val, exc_tb));
|
||||
self.maybe_close(&result);
|
||||
self.variant.exec_result(result?, vm)
|
||||
Ok(result?.into_iter_return(vm))
|
||||
}
|
||||
|
||||
pub fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
|
||||
pub fn close(&self, gen: &PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if self.closed.load() {
|
||||
return Ok(());
|
||||
}
|
||||
let result = self.run_with_context(vm, |f| {
|
||||
let result = self.run_with_context(gen, vm, |f| {
|
||||
f.gen_throw(
|
||||
vm,
|
||||
vm.ctx.exceptions.generator_exit.clone().into_object(),
|
||||
@@ -149,7 +162,7 @@ impl Coro {
|
||||
self.closed.store(true);
|
||||
match result {
|
||||
Ok(ExecutionResult::Yield(_)) => {
|
||||
Err(vm.new_runtime_error(format!("{} ignored GeneratorExit", self.variant.name())))
|
||||
Err(vm.new_runtime_error(format!("{} ignored GeneratorExit", gen_name(gen, vm))))
|
||||
}
|
||||
Err(e) if !is_gen_exit(&e, vm) => Err(e),
|
||||
_ => Ok(()),
|
||||
@@ -171,10 +184,10 @@ impl Coro {
|
||||
pub fn set_name(&self, name: PyStrRef) {
|
||||
*self.name.lock() = name;
|
||||
}
|
||||
pub fn repr(&self, id: usize) -> String {
|
||||
pub fn repr(&self, gen: &PyObjectRef, id: usize, vm: &VirtualMachine) -> String {
|
||||
format!(
|
||||
"<{} object {} at {:#x}>",
|
||||
self.variant.name(),
|
||||
gen_name(gen, vm),
|
||||
self.name.lock(),
|
||||
id
|
||||
)
|
||||
|
||||
@@ -128,42 +128,6 @@ pub enum ExecutionResult {
|
||||
Yield(PyObjectRef),
|
||||
}
|
||||
|
||||
impl ExecutionResult {
|
||||
/// Extract an ExecutionResult from a PyResult returned from e.g. gen.__next__() or gen.send()
|
||||
pub fn from_result(vm: &VirtualMachine, res: PyResult) -> PyResult<Self> {
|
||||
match res {
|
||||
Ok(val) => Ok(ExecutionResult::Yield(val)),
|
||||
Err(err) => {
|
||||
if err.isinstance(&vm.ctx.exceptions.stop_iteration) {
|
||||
Ok(ExecutionResult::Return(iterator::stop_iter_value(vm, &err)))
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Turn an ExecutionResult into a PyResult that would be returned from a generator or coroutine
|
||||
pub fn into_result(self, async_stopiter: bool, vm: &VirtualMachine) -> PyResult {
|
||||
match self {
|
||||
ExecutionResult::Yield(value) => Ok(value),
|
||||
ExecutionResult::Return(value) => {
|
||||
let stop_iteration = if async_stopiter {
|
||||
vm.ctx.exceptions.stop_async_iteration.clone()
|
||||
} else {
|
||||
vm.ctx.exceptions.stop_iteration.clone()
|
||||
};
|
||||
let args = if vm.is_none(&value) {
|
||||
vec![]
|
||||
} else {
|
||||
vec![value]
|
||||
};
|
||||
Err(vm.new_exception(stop_iteration, args))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A valid execution result, or an exception
|
||||
pub type FrameResult = PyResult<Option<ExecutionResult>>;
|
||||
|
||||
@@ -428,18 +392,20 @@ impl ExecutingFrame<'_> {
|
||||
exc_val: PyObjectRef,
|
||||
exc_tb: PyObjectRef,
|
||||
) -> PyResult<ExecutionResult> {
|
||||
if let Some(coro) = self.yield_from_target() {
|
||||
if let Some(gen) = self.yield_from_target() {
|
||||
use crate::utils::Either;
|
||||
// borrow checker shenanigans - we only need to use exc_type/val/tb if the following
|
||||
// variable is Some
|
||||
let thrower = if let Some(coro) = self.builtin_coro(coro) {
|
||||
let thrower = if let Some(coro) = self.builtin_coro(gen) {
|
||||
Some(Either::A(coro))
|
||||
} else {
|
||||
vm.get_attribute_opt(coro.clone(), "throw")?.map(Either::B)
|
||||
vm.get_attribute_opt(gen.clone(), "throw")?.map(Either::B)
|
||||
};
|
||||
if let Some(thrower) = thrower {
|
||||
let ret = match thrower {
|
||||
Either::A(coro) => coro.throw(exc_type, exc_val, exc_tb, vm),
|
||||
Either::A(coro) => coro
|
||||
.throw(gen, exc_type, exc_val, exc_tb, vm)
|
||||
.into_pyresult(vm), // FIXME:
|
||||
Either::B(meth) => vm.invoke(&meth, vec![exc_type, exc_val, exc_tb]),
|
||||
};
|
||||
return ret.map(ExecutionResult::Yield).or_else(|err| {
|
||||
@@ -1439,14 +1405,19 @@ impl ExecutingFrame<'_> {
|
||||
})
|
||||
}
|
||||
|
||||
fn _send(&self, coro: &PyObjectRef, val: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
match self.builtin_coro(coro) {
|
||||
Some(coro) => coro.send(val, vm),
|
||||
fn _send(
|
||||
&self,
|
||||
gen: &PyObjectRef,
|
||||
val: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyIterReturn> {
|
||||
match self.builtin_coro(gen) {
|
||||
Some(coro) => coro.send(gen, val, vm),
|
||||
// FIXME: turn return type to PyResult<PyIterReturn> then ExecutionResult will be simplified
|
||||
None if vm.is_none(&val) => PyIter::new(coro).next(vm).into_pyresult(vm),
|
||||
None if vm.is_none(&val) => PyIter::new(gen).next(vm),
|
||||
None => {
|
||||
let meth = vm.get_attribute(coro.clone(), "send")?;
|
||||
vm.invoke(&meth, (val,))
|
||||
let meth = vm.get_attribute(gen.clone(), "send")?;
|
||||
PyIterReturn::from_pyresult(vm.invoke(&meth, (val,)), vm)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1454,20 +1425,18 @@ impl ExecutingFrame<'_> {
|
||||
fn execute_yield_from(&mut self, vm: &VirtualMachine) -> FrameResult {
|
||||
// Value send into iterator:
|
||||
let val = self.pop_value();
|
||||
|
||||
let coro = self.last_value_ref();
|
||||
let result = self._send(coro, val, vm)?;
|
||||
|
||||
let result = self._send(coro, val, vm);
|
||||
|
||||
let result = ExecutionResult::from_result(vm, result)?;
|
||||
|
||||
// PyIterReturn returned from e.g. gen.__next__() or gen.send()
|
||||
match result {
|
||||
ExecutionResult::Yield(value) => {
|
||||
PyIterReturn::Return(value) => {
|
||||
// Set back program counter:
|
||||
self.update_lasti(|i| *i -= 1);
|
||||
Ok(Some(ExecutionResult::Yield(value)))
|
||||
}
|
||||
ExecutionResult::Return(value) => {
|
||||
PyIterReturn::StopIteration(value) => {
|
||||
let value = vm.unwrap_or_none(value);
|
||||
self.pop_value();
|
||||
self.push_value(value);
|
||||
Ok(None)
|
||||
|
||||
@@ -126,7 +126,7 @@ pub enum PyIterReturn<T = PyObjectRef> {
|
||||
}
|
||||
|
||||
impl PyIterReturn {
|
||||
pub fn from_result(result: PyResult, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
pub fn from_pyresult(result: PyResult, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
match result {
|
||||
Ok(obj) => Ok(Self::Return(obj)),
|
||||
Err(err) if err.isinstance(&vm.ctx.exceptions.stop_iteration) => {
|
||||
@@ -136,6 +136,7 @@ impl PyIterReturn {
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_getitem_result(result: PyResult, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
match result {
|
||||
Ok(obj) => Ok(Self::Return(obj)),
|
||||
@@ -149,6 +150,16 @@ impl PyIterReturn {
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_async_pyresult(self, vm: &VirtualMachine) -> PyResult {
|
||||
match self {
|
||||
Self::Return(obj) => Ok(obj),
|
||||
Self::StopIteration(v) => Err({
|
||||
let args = if let Some(v) = v { vec![v] } else { Vec::new() };
|
||||
vm.new_exception(vm.ctx.exceptions.stop_async_iteration.clone(), args)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPyResult for PyIterReturn {
|
||||
|
||||
@@ -371,7 +371,7 @@ mod decl {
|
||||
let function = &zelf.function;
|
||||
match obj {
|
||||
PyIterReturn::Return(obj) => {
|
||||
PyIterReturn::from_result(vm.invoke(function, vm.extract_elements(&obj)?), vm)
|
||||
PyIterReturn::from_pyresult(vm.invoke(function, vm.extract_elements(&obj)?), vm)
|
||||
}
|
||||
PyIterReturn::StopIteration(v) => Ok(PyIterReturn::StopIteration(v)),
|
||||
}
|
||||
|
||||
@@ -590,7 +590,7 @@ impl AwaitPromise {
|
||||
impl IteratorIterable for AwaitPromise {}
|
||||
impl SlotIterator for AwaitPromise {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
PyIterReturn::from_result(zelf.send(None, vm), vm)
|
||||
PyIterReturn::from_pyresult(zelf.send(None, vm), vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user