From c1d14990ac9a616728f726a0d54b2af99d1a416e Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Wed, 18 May 2022 07:12:30 +0900 Subject: [PATCH 1/3] test --- stdlib/src/binascii.rs | 13 +++++++++--- vm/src/exceptions.rs | 46 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/stdlib/src/binascii.rs b/stdlib/src/binascii.rs index 5dad5dce01..8f22630083 100644 --- a/stdlib/src/binascii.rs +++ b/stdlib/src/binascii.rs @@ -6,6 +6,7 @@ pub(super) use decl::crc32; mod decl { use crate::vm::{ builtins::{PyIntRef, PyTypeRef}, + exceptions::SimpleException, function::{ArgAsciiBuffer, ArgBytesLike, OptionalArg}, PyResult, VirtualMachine, }; @@ -57,10 +58,13 @@ mod decl { #[pyfunction(name = "a2b_hex")] #[pyfunction] - fn unhexlify(data: ArgAsciiBuffer, vm: &VirtualMachine) -> PyResult> { + fn unhexlify(data: ArgAsciiBuffer, vm: &VirtualMachine) -> Result, SimpleException> { data.with_ref(|hex_bytes| { if hex_bytes.len() % 2 != 0 { - return Err(vm.new_value_error("Odd-length string".to_owned())); + return Err(SimpleException::with_message( + vm.ctx.exceptions.value_error, + "Odd-length string", + )); } let mut unhex = Vec::::with_capacity(hex_bytes.len() / 2); @@ -68,7 +72,10 @@ mod decl { if let (Some(n1), Some(n2)) = (unhex_nibble(*n1), unhex_nibble(*n2)) { unhex.push(n1 << 4 | n2); } else { - return Err(vm.new_value_error("Non-hexadecimal digit found".to_owned())); + return Err(SimpleException::with_message( + vm.ctx.exceptions.value_error, + "Non-hexadecimal digit found", + )); } } diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 48be00e1d5..5dd09c26ca 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -280,6 +280,52 @@ impl TryFromObject for ExceptionCtor { } } +pub struct SimpleException { + typ: &'static Py, + message: Option<&'static str>, +} + +impl SimpleException { + #[inline] + pub fn new(typ: &'static Py) -> Self { + Self { typ, message: None } + } + #[inline] + pub fn with_message(typ: &'static Py, message: &'static str) -> Self { + let message = Some(message); + Self { typ, message } + } +} + +impl ToPyException for SimpleException { + #[inline] + fn to_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef { + let Self { typ, message } = self; + match message { + Some(message) => vm.new_exception_msg(typ.to_owned(), message.to_owned()), + None => vm.new_exception_empty(typ.to_owned()), + } + } +} + +pub struct DeferredException +where + M: FnOnce(&VirtualMachine) -> String, +{ + typ: &'static Py, + build_message: M, +} + +impl ToPyException for DeferredException +where + M: FnOnce(&VirtualMachine) -> String, +{ + fn to_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef { + let Self { typ, build_message } = self; + vm.new_exception_msg(typ.to_owned(), build_message(vm)) + } +} + impl ExceptionCtor { pub fn instantiate(self, vm: &VirtualMachine) -> PyResult { match self { From 30d52e1f8d71cc0af282d5895d6afef65c7c77ad Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Thu, 2 Jun 2022 07:32:17 +0900 Subject: [PATCH 2/3] working --- vm/src/convert/to_pyobject.rs | 6 ++++++ vm/src/exceptions.rs | 19 ++++++++++--------- vm/src/types/slot.rs | 3 ++- vm/src/vm/vm_new.rs | 8 ++++++++ 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/vm/src/convert/to_pyobject.rs b/vm/src/convert/to_pyobject.rs index 6f8f9931de..a2d2b7bcda 100644 --- a/vm/src/convert/to_pyobject.rs +++ b/vm/src/convert/to_pyobject.rs @@ -16,3 +16,9 @@ pub trait ToPyResult { pub trait ToPyException { fn to_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef; } + +impl ToPyException for Box { + fn to_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef { + self.as_ref().to_pyexception(vm) + } +} diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 5dd09c26ca..686a92ca26 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -308,18 +308,19 @@ impl ToPyException for SimpleException { } } -pub struct DeferredException -where - M: FnOnce(&VirtualMachine) -> String, -{ +pub struct DeferredException { typ: &'static Py, - build_message: M, + build_message: fn(&VirtualMachine) -> String, } -impl ToPyException for DeferredException -where - M: FnOnce(&VirtualMachine) -> String, -{ +impl DeferredException { + #[inline] + pub fn new(typ: &'static Py, build_message: fn(&VirtualMachine) -> String) -> Self { + Self { typ, build_message } + } +} + +impl ToPyException for DeferredException { fn to_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef { let Self { typ, build_message } = self; vm.new_exception_msg(typ.to_owned(), build_message(vm)) diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index f05483886f..b824a0caf9 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -2,7 +2,8 @@ use crate::common::{hash::PyHash, lock::PyRwLock}; use crate::{ builtins::{PyInt, PyStrInterned, PyStrRef, PyType, PyTypeRef}, bytecode::ComparisonOperator, - convert::ToPyResult, + convert::{ToPyException, ToPyResult}, + exceptions::DeferredException, function::Either, function::{FromArgs, FuncArgs, OptionalArg, PyComparisonValue}, identifier, diff --git a/vm/src/vm/vm_new.rs b/vm/src/vm/vm_new.rs index b636f68eac..78fd206963 100644 --- a/vm/src/vm/vm_new.rs +++ b/vm/src/vm/vm_new.rs @@ -7,6 +7,7 @@ use crate::{ PyBaseException, PyBaseExceptionRef, PyDictRef, PyModule, PyStrRef, PyType, PyTypeRef, }, convert::ToPyObject, + exceptions::DeferredException, scope::Scope, vm::VirtualMachine, AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, @@ -96,6 +97,13 @@ impl VirtualMachine { self.new_exception_msg(attribute_error, msg) } + pub fn new_deferred_attribute_error( + &self, + msg: fn(&VirtualMachine) -> String, + ) -> DeferredException { + DeferredException::new(self.ctx.exceptions.attribute_error, msg) + } + pub fn new_type_error(&self, msg: String) -> PyBaseExceptionRef { let type_error = self.ctx.exceptions.type_error.to_owned(); self.new_exception_msg(type_error, msg) From d62bd8278ee22dee9bca8a9c24f91533bf88c01f Mon Sep 17 00:00:00 2001 From: Jeong Yunwon Date: Thu, 2 Jun 2022 08:18:14 +0900 Subject: [PATCH 3/3] working --- vm/src/builtins/object.rs | 8 +++++--- vm/src/convert/to_pyobject.rs | 16 +++++++++++++--- vm/src/object/ext.rs | 1 + vm/src/protocol/object.rs | 1 + vm/src/types/slot.rs | 17 ++++++++++------- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 1be14365d0..45cefeddd5 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -2,9 +2,11 @@ use super::{PyDict, PyDictRef, PyList, PyStr, PyStrRef, PyType, PyTypeRef}; use crate::common::hash::PyHash; use crate::{ class::PyClassImpl, + convert::ToPyException, function::Either, function::{FuncArgs, PyArithmeticValue, PyComparisonValue}, types::PyComparisonOp, + object::PyToResult, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine, }; @@ -292,13 +294,13 @@ impl PyBaseObject { /// Return getattr(self, name). #[pyslot] - pub(crate) fn getattro(obj: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyResult { + pub(crate) fn getattro(obj: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyToResult { vm_trace!("object.__getattribute__({:?}, {:?})", obj, name); - obj.as_object().generic_getattr(name, vm) + obj.generic_getattr(name, vm).map_err(|e| -> Box {Box::new(e) }) } #[pymethod(magic)] - fn getattribute(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult { + fn getattribute(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyToResult { Self::getattro(&obj, name, vm) } diff --git a/vm/src/convert/to_pyobject.rs b/vm/src/convert/to_pyobject.rs index a2d2b7bcda..b1a4aca956 100644 --- a/vm/src/convert/to_pyobject.rs +++ b/vm/src/convert/to_pyobject.rs @@ -14,11 +14,21 @@ pub trait ToPyResult { } pub trait ToPyException { - fn to_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef; + fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef; } -impl ToPyException for Box { +pub trait IntoPyException { + fn into_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef; +} + +// impl ToPyException for Box { +// fn to_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef { +// self.as_ref().to_pyexception(vm) +// } +// } + +impl ToPyException for F where F: FnOnce(&VirtualMachine) -> PyBaseExceptionRef { fn to_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef { - self.as_ref().to_pyexception(vm) + self(vm) } } diff --git a/vm/src/object/ext.rs b/vm/src/object/ext.rs index 0a38913ff2..9a82c1ac65 100644 --- a/vm/src/object/ext.rs +++ b/vm/src/object/ext.rs @@ -28,6 +28,7 @@ Basically reference counting, but then done by rust. /// Both the python object and the python exception are `PyObjectRef` types /// since exceptions are also python objects. pub type PyResult = Result; // A valid value, or an exception +pub type PyToResult = Result>; // TODO: remove these 2 impls impl fmt::Display for PyObjectRef { diff --git a/vm/src/protocol/object.rs b/vm/src/protocol/object.rs index 79e252c4e2..47538ad828 100644 --- a/vm/src/protocol/object.rs +++ b/vm/src/protocol/object.rs @@ -95,6 +95,7 @@ impl PyObject { .mro_find_map(|cls| cls.slots.getattro.load()) .unwrap(); getattro(self, attr_name.clone(), vm).map_err(|exc| { + let exc = exc.to_pyexception(vm); vm.set_attribute_error_context(&exc, self.to_owned(), attr_name); exc }) diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index b824a0caf9..eb601f44c8 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -12,6 +12,7 @@ use crate::{ PySequenceMethods, }, vm::Context, + object::PyToResult, AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; use crossbeam_utils::atomic::AtomicCell; @@ -143,7 +144,7 @@ pub(crate) type AsMappingFunc = fn(&PyObject, &VirtualMachine) -> &'static PyMap pub(crate) type AsNumberFunc = fn(&PyObject, &VirtualMachine) -> &'static PyNumberMethods; pub(crate) type HashFunc = fn(&PyObject, &VirtualMachine) -> PyResult; // CallFunc = GenericMethod -pub(crate) type GetattroFunc = fn(&PyObject, PyStrRef, &VirtualMachine) -> PyResult; +pub(crate) type GetattroFunc = fn(&PyObject, PyStrRef, &VirtualMachine) -> PyToResult; pub(crate) type SetattroFunc = fn(&PyObject, PyStrRef, Option, &VirtualMachine) -> PyResult<()>; pub(crate) type AsBufferFunc = fn(&PyObject, &VirtualMachine) -> PyResult; @@ -227,15 +228,15 @@ fn call_wrapper(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResul vm.call_special_method(zelf.to_owned(), identifier!(vm, __call__), args) } -fn getattro_wrapper(zelf: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyResult { +fn getattro_wrapper(zelf: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyToResult { let __getattribute__ = identifier!(vm, __getattribute__); let __getattr__ = identifier!(vm, __getattr__); match vm.call_special_method(zelf.to_owned(), __getattribute__, (name.clone(),)) { Ok(r) => Ok(r), Err(_) if zelf.class().has_attr(__getattr__) => { - vm.call_special_method(zelf.to_owned(), __getattr__, (name,)) + vm.call_special_method(zelf.to_owned(), __getattr__, (name,)).map_err(|e| -> Box { Box::new(e)}) } - Err(e) => Err(e), + Err(e) => Err(Box::new(e)), } } @@ -774,11 +775,13 @@ impl PyComparisonOp { #[pyimpl] pub trait GetAttr: PyPayload { #[pyslot] - fn slot_getattro(obj: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyResult { + fn slot_getattro(obj: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyToResult { if let Some(zelf) = obj.downcast_ref::() { - Self::getattro(zelf, name, vm) + Self::getattro(zelf, name, vm).map_err(|e| -> Box { + Box::new(e) + }) } else { - Err(vm.new_type_error("unexpected payload for __getattribute__".to_owned())) + Err(Box::new(vm.new_type_error("unexpected payload for __getattribute__".to_owned()))) } }