diff --git a/Cargo.lock b/Cargo.lock index 80ceac53d3a..db1b5d9b465 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3161,6 +3161,7 @@ dependencies = [ "lz4_flex", "malachite-bigint", "num-complex", + "num_enum", "ruff_source_file", "rustpython-wtf8", ] diff --git a/crates/compiler-core/Cargo.toml b/crates/compiler-core/Cargo.toml index f4e619b95a4..6a03f02c24f 100644 --- a/crates/compiler-core/Cargo.toml +++ b/crates/compiler-core/Cargo.toml @@ -17,6 +17,7 @@ bitflags = { workspace = true } itertools = { workspace = true } malachite-bigint = { workspace = true } num-complex = { workspace = true } +num_enum = { workspace = true } lz4_flex = "0.12" diff --git a/crates/compiler-core/src/bytecode/instruction.rs b/crates/compiler-core/src/bytecode/instruction.rs index 1f168749e63..6ce403b9af1 100644 --- a/crates/compiler-core/src/bytecode/instruction.rs +++ b/crates/compiler-core/src/bytecode/instruction.rs @@ -1249,7 +1249,7 @@ impl Arg { #[inline] pub fn new(arg: T) -> (Self, OpArg) { - (Self(PhantomData), OpArg(arg.to_op_arg())) + (Self(PhantomData), OpArg(arg.into())) } #[inline] @@ -1267,7 +1267,7 @@ impl Arg { #[inline(always)] pub fn try_get(self, arg: OpArg) -> Result { - T::from_op_arg(arg.0) + T::try_from(arg.0).map_err(|_| MarshalError::InvalidBytecode) } /// # Safety @@ -1275,7 +1275,7 @@ impl Arg { #[inline(always)] pub unsafe fn get_unchecked(self, arg: OpArg) -> T { // SAFETY: requirements forwarded from caller - unsafe { T::from_op_arg(arg.0).unwrap_unchecked() } + unsafe { T::try_from(arg.0).unwrap_unchecked() } } } diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 6378f04bbf9..7d2fca03988 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -1,17 +1,14 @@ use bitflags::bitflags; +use num_enum::{IntoPrimitive, TryFromPrimitive}; -use core::{fmt, num::NonZeroU8}; +use core::fmt; use crate::{ bytecode::{CodeUnit, instruction::Instruction}, marshal::MarshalError, }; -pub trait OpArgType: Copy { - fn from_op_arg(x: u32) -> Result; - - fn to_op_arg(self) -> u32; -} +pub trait OpArgType: Copy + Into + TryFrom {} /// Opcode argument that may be extended by a prior ExtendedArg. #[derive(Copy, Clone, PartialEq, Eq)] @@ -107,13 +104,34 @@ impl OpArgState { } } +macro_rules! impl_oparg_enum_traits { + ($name:ty) => { + impl From<$name> for u32 { + fn from(value: $name) -> Self { + Self::from(u8::from(value)) + } + } + + impl TryFrom for $name { + type Error = $crate::marshal::MarshalError; + + fn try_from(value: u32) -> Result { + u8::try_from(value) + .map_err(|_| Self::Error::InvalidBytecode) + .map(TryInto::try_into)? + } + } + }; +} + /// Oparg values for [`Instruction::ConvertValue`]. /// /// ## See also /// /// - [CPython FVC_* flags](https://github.com/python/cpython/blob/8183fa5e3f78ca6ab862de7fb8b14f3d929421e0/Include/ceval.h#L129-L132) #[repr(u8)] -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Eq, Hash, IntoPrimitive, PartialEq, TryFromPrimitive)] +#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] pub enum ConvertValueOparg { /// No conversion. /// @@ -121,6 +139,8 @@ pub enum ConvertValueOparg { /// f"{x}" /// f"{x:4}" /// ``` + // Ruff `ConversionFlag::None` is `-1i8`, when its converted to `u8` its value is `u8::MAX`. + #[num_enum(alternatives = [255])] None = 0, /// Converts by calling `str()`. /// @@ -145,6 +165,8 @@ pub enum ConvertValueOparg { Ascii = 3, } +impl_oparg_enum_traits!(ConvertValueOparg); + impl fmt::Display for ConvertValueOparg { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let out = match self { @@ -159,29 +181,12 @@ impl fmt::Display for ConvertValueOparg { } } -impl OpArgType for ConvertValueOparg { - #[inline] - fn from_op_arg(x: u32) -> Result { - Ok(match x { - // Ruff `ConversionFlag::None` is `-1i8`, - // when its converted to `u8` its value is `u8::MAX` - 0 | 255 => Self::None, - 1 => Self::Str, - 2 => Self::Repr, - 3 => Self::Ascii, - _ => return Err(MarshalError::InvalidBytecode), - }) - } - - #[inline] - fn to_op_arg(self) -> u32 { - self as u32 - } -} +impl OpArgType for ConvertValueOparg {} /// Resume type for the RESUME instruction -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -#[repr(u32)] +#[repr(u8)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)] +#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))] pub enum ResumeType { AtFuncStart = 0, AfterYield = 1, @@ -189,145 +194,108 @@ pub enum ResumeType { AfterAwait = 3, } -impl OpArgType for u32 { - #[inline(always)] - fn from_op_arg(x: u32) -> Result { - Ok(x) - } - - #[inline(always)] - fn to_op_arg(self) -> u32 { - self - } -} - -impl OpArgType for bool { - #[inline(always)] - fn from_op_arg(x: u32) -> Result { - Ok(x != 0) - } - - #[inline(always)] - fn to_op_arg(self) -> u32 { - self as u32 - } -} - -macro_rules! op_arg_enum_impl { - (enum $name:ident { $($(#[$var_attr:meta])* $var:ident = $value:literal,)* }) => { - impl OpArgType for $name { - fn to_op_arg(self) -> u32 { - self as u32 - } - - fn from_op_arg(x: u32) -> Result { - Ok(match u8::try_from(x).map_err(|_| MarshalError::InvalidBytecode)? { - $($value => Self::$var,)* - _ => return Err(MarshalError::InvalidBytecode), - }) - } - } - }; -} - -macro_rules! op_arg_enum { - ($(#[$attr:meta])* $vis:vis enum $name:ident { $($(#[$var_attr:meta])* $var:ident = $value:literal,)* }) => { - $(#[$attr])* - $vis enum $name { - $($(#[$var_attr])* $var = $value,)* - } - - op_arg_enum_impl!(enum $name { - $($(#[$var_attr])* $var = $value,)* - }); - }; -} - pub type NameIdx = u32; +impl OpArgType for u32 {} +//impl OpArgType for bool {} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] #[repr(transparent)] pub struct Label(pub u32); -impl OpArgType for Label { - #[inline(always)] - fn from_op_arg(x: u32) -> Result { - Ok(Self(x)) +impl Label { + pub const fn new(value: u32) -> Self { + Self(value) } +} - #[inline(always)] - fn to_op_arg(self) -> u32 { - self.0 +impl From for Label { + fn from(value: u32) -> Self { + Self::new(value) } } +impl From