From 08593cd9f3b5ceec8966626d6813b21fcb747ed3 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Sat, 7 Mar 2020 14:54:18 -0600 Subject: [PATCH] Do some more refactoring, but better --- vm/src/obj/objasyncgenerator.rs | 76 ++++++++++++++++++++------------- vm/src/obj/objcoroinner.rs | 58 +++++++++++++++---------- vm/src/obj/objcoroutine.rs | 6 +++ vm/src/obj/objgenerator.rs | 6 +++ 4 files changed, 94 insertions(+), 52 deletions(-) diff --git a/vm/src/obj/objasyncgenerator.rs b/vm/src/obj/objasyncgenerator.rs index 40bc4f144..9a552aca2 100644 --- a/vm/src/obj/objasyncgenerator.rs +++ b/vm/src/obj/objasyncgenerator.rs @@ -1,6 +1,7 @@ use super::objcode::PyCodeRef; use super::objcoroinner::{Coro, Variant}; use super::objtype::{self, PyClassRef}; +use crate::exceptions::PyBaseExceptionRef; use crate::frame::FrameRef; use crate::function::OptionalArg; use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue}; @@ -36,6 +37,12 @@ impl PyAsyncGen { .into_ref(vm) } + // TODO: fix function names situation + #[pyproperty(magic)] + fn name(&self, vm: &VirtualMachine) -> PyObjectRef { + vm.get_none() + } + #[pymethod(name = "__aiter__")] fn aiter(zelf: PyRef, _vm: &VirtualMachine) -> PyRef { zelf @@ -297,7 +304,7 @@ impl PyAsyncGenAThrow { } if !vm.is_none(&val) { return Err(vm.new_runtime_error( - "can't send non-None value to a just-started coroutine".to_owned(), + "can't send non-None value to a just-started async generator".to_owned(), )); } self.state.set(AwaitableState::Iter); @@ -306,18 +313,26 @@ impl PyAsyncGenAThrow { let (ty, val, tb) = self.value.clone(); let ret = self.ag.inner.throw(ty, val, tb, vm); let ret = if self.aclose { - self.check_no_ignore(&ret, vm)?; - ret + if self.ignored_close(&ret) { + Err(self.yield_close(vm)) + } else { + ret + } } else { PyAsyncGenWrappedValue::unbox(&self.ag, ret, vm) }; - self.check_error(ret, vm) + ret.map_err(|e| self.check_error(e, vm)) } AwaitableState::Iter => { let ret = self.ag.inner.send(val, vm); if self.aclose { - self.check_no_ignore(&ret, vm)?; - self.check_error(ret, vm) + match ret { + Ok(v) if v.payload_is::() => { + Err(self.yield_close(vm)) + } + Ok(v) => Ok(v), + Err(e) => Err(self.check_error(e, vm)), + } } else { PyAsyncGenWrappedValue::unbox(&self.ag, ret, vm) } @@ -339,12 +354,16 @@ impl PyAsyncGenAThrow { exc_tb.unwrap_or_else(|| vm.get_none()), vm, ); - if self.aclose { - self.check_no_ignore(&ret, vm)?; - self.check_error(ret, vm) + let res = if self.aclose { + if self.ignored_close(&ret) { + Err(self.yield_close(vm)) + } else { + ret + } } else { PyAsyncGenWrappedValue::unbox(&self.ag, ret, vm) - } + }; + res.map_err(|e| self.check_error(e, vm)) } #[pymethod] @@ -352,27 +371,26 @@ impl PyAsyncGenAThrow { self.state.set(AwaitableState::Closed); } - fn check_no_ignore(&self, res: &PyResult, vm: &VirtualMachine) -> PyResult<()> { - if let Ok(ref v) = res { - if v.payload_is::() { - return Err( - vm.new_runtime_error("async generator ignored GeneratorExit".to_owned()) - ); - } - } - Ok(()) + fn ignored_close(&self, res: &PyResult) -> bool { + res.as_ref() + .map_or(false, |v| v.payload_is::()) } - fn check_error(&self, res: PyResult, vm: &VirtualMachine) -> PyResult { - if self.aclose { - if let Err(ref e) = res { - if objtype::isinstance(&e, &vm.ctx.exceptions.stop_async_iteration) - || objtype::isinstance(&e, &vm.ctx.exceptions.generator_exit) - { - return Err(vm.new_exception_empty(vm.ctx.exceptions.stop_iteration.clone())); - } - } + fn yield_close(&self, vm: &VirtualMachine) -> PyBaseExceptionRef { + self.ag.running_async.set(false); + self.state.set(AwaitableState::Closed); + vm.new_runtime_error("async generator ignored GeneratorExit".to_owned()) + } + fn check_error(&self, exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyBaseExceptionRef { + self.ag.running_async.set(false); + self.state.set(AwaitableState::Closed); + if self.aclose + && (objtype::isinstance(&exc, &vm.ctx.exceptions.stop_async_iteration) + || objtype::isinstance(&exc, &vm.ctx.exceptions.generator_exit)) + { + vm.new_exception_empty(vm.ctx.exceptions.stop_iteration.clone()) + } else { + exc } - res } } diff --git a/vm/src/obj/objcoroinner.rs b/vm/src/obj/objcoroinner.rs index 51ab8f12d..7f63da5b4 100644 --- a/vm/src/obj/objcoroinner.rs +++ b/vm/src/obj/objcoroinner.rs @@ -1,4 +1,4 @@ -use super::{objiter, objtype}; +use super::objtype; use crate::exceptions::{self, PyBaseExceptionRef}; use crate::frame::{ExecutionResult, FrameRef}; use crate::pyobject::{PyObjectRef, PyResult}; @@ -71,38 +71,47 @@ impl Coro { ); self.running.set(false); self.started.set(true); - if let Err(ref e) = result { - if objtype::isinstance(e, &vm.ctx.exceptions.stop_iteration) { - let err = - vm.new_runtime_error(format!("{} raised StopIteration", self.variant.name())); - err.set_cause(Some(e.clone())); - return Err(err); - } - if self.variant == Variant::AsyncGen - && objtype::isinstance(e, &vm.ctx.exceptions.stop_async_iteration) - { - let err = - vm.new_runtime_error("async generator raise StopAsyncIteration".to_owned()); - err.set_cause(Some(e.clone())); - return Err(err); - } - } result } pub fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult { if self.closed.get() { - return Err(objiter::new_stop_iteration(vm)); + let cls = if let Variant::AsyncGen = self.variant { + vm.ctx.exceptions.stop_async_iteration.clone() + } else { + vm.ctx.exceptions.stop_iteration.clone() + }; + return Err(vm.new_exception_empty(cls)); } if !self.started.get() && !vm.is_none(&value) { - return Err(vm.new_type_error( - "can't send non-None value to a just-started coroutine".to_string(), - )); + return Err(vm.new_type_error(format!( + "can't send non-None value to a just-started {}", + self.variant.name() + ))); } self.frame.push_value(value.clone()); let result = self.run_with_context(|| vm.run_frame(self.frame.clone()), vm); self.maybe_close(&result); - self.variant.exec_result(result?, vm) + match result { + Ok(exec_res) => self.variant.exec_result(exec_res, vm), + Err(e) => { + if objtype::isinstance(&e, &vm.ctx.exceptions.stop_iteration) { + let err = vm + .new_runtime_error(format!("{} raised StopIteration", self.variant.name())); + err.set_cause(Some(e)); + Err(err) + } else if self.variant == Variant::AsyncGen + && objtype::isinstance(&e, &vm.ctx.exceptions.stop_async_iteration) + { + let err = vm + .new_runtime_error("async generator raised StopAsyncIteration".to_owned()); + err.set_cause(Some(e)); + Err(err) + } else { + Err(e) + } + } + } } pub fn throw( &self, @@ -142,7 +151,7 @@ impl Coro { self.closed.set(true); match result { Ok(ExecutionResult::Yield(_)) => { - Err(vm.new_runtime_error("generator ignored GeneratorExit".to_owned())) + Err(vm.new_runtime_error(format!("{} ignored GeneratorExit", self.variant.name()))) } Err(e) if !is_gen_exit(&e, vm) => Err(e), _ => Ok(()), @@ -161,6 +170,9 @@ impl Coro { pub fn frame(&self) -> FrameRef { self.frame.clone() } + pub fn name(&self) -> String { + self.frame.code.obj_name.clone() + } } pub fn is_gen_exit(exc: &PyBaseExceptionRef, vm: &VirtualMachine) -> bool { diff --git a/vm/src/obj/objcoroutine.rs b/vm/src/obj/objcoroutine.rs index 0b2397878..d1faacc2b 100644 --- a/vm/src/obj/objcoroutine.rs +++ b/vm/src/obj/objcoroutine.rs @@ -34,6 +34,12 @@ impl PyCoroutine { .into_ref(vm) } + // TODO: fix function names situation + #[pyproperty(magic)] + fn name(&self, vm: &VirtualMachine) -> PyObjectRef { + vm.get_none() + } + #[pymethod] fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult { self.inner.send(value, vm) diff --git a/vm/src/obj/objgenerator.rs b/vm/src/obj/objgenerator.rs index 1a2e7d62d..e91e24406 100644 --- a/vm/src/obj/objgenerator.rs +++ b/vm/src/obj/objgenerator.rs @@ -37,6 +37,12 @@ impl PyGenerator { .into_ref(vm) } + // TODO: fix function names situation + #[pyproperty(magic)] + fn name(&self, vm: &VirtualMachine) -> PyObjectRef { + vm.get_none() + } + #[pymethod(name = "__iter__")] fn iter(zelf: PyGeneratorRef) -> PyGeneratorRef { zelf